mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-09 04:23:47 +03:00
Compare commits
1781 Commits
v2_02_112
...
dev-mcsont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf06d942b8 | ||
|
|
83d3cc76f3 | ||
|
|
89574055f7 | ||
|
|
7831a65091 | ||
|
|
15a97cc610 | ||
|
|
3f1c63c812 | ||
|
|
dd52721b68 | ||
|
|
7f125c1116 | ||
|
|
5b04eda93f | ||
|
|
77c31d0c39 | ||
|
|
baf320455b | ||
|
|
bb4d3fa7a7 | ||
|
|
3e18b101a0 | ||
|
|
df190dcfa5 | ||
|
|
e149fe7fdf | ||
|
|
77605457e7 | ||
|
|
0d5b1294f0 | ||
|
|
097d14e64e | ||
|
|
17196103e0 | ||
|
|
ccfc09f79b | ||
|
|
9a3b64e81a | ||
|
|
c2e88d1107 | ||
|
|
406d8ff332 | ||
|
|
00348c0a63 | ||
|
|
ccb8da404d | ||
|
|
28e54032c0 | ||
|
|
bca55c9b20 | ||
|
|
f104a81932 | ||
|
|
3720eb63be | ||
|
|
8b5525383f | ||
|
|
f58c634103 | ||
|
|
175119fdcd | ||
|
|
33a8a2febf | ||
|
|
f32f0bd2a7 | ||
|
|
99237f0908 | ||
|
|
099466939e | ||
|
|
b3c81d02c9 | ||
|
|
5886ff64eb | ||
|
|
a4418b34c1 | ||
|
|
65ec00ce20 | ||
|
|
6e1e0e8813 | ||
|
|
4159680a0e | ||
|
|
76cff10a73 | ||
|
|
1af2ab10d0 | ||
|
|
729f489009 | ||
|
|
5d76bdcdbd | ||
|
|
3b5939bbbb | ||
|
|
a2dd1f6e19 | ||
|
|
c301cc5d38 | ||
|
|
ba41ee1dc9 | ||
|
|
b702d67747 | ||
|
|
44ba862674 | ||
|
|
6624833839 | ||
|
|
b29593378f | ||
|
|
428ca9b120 | ||
|
|
f898cf7539 | ||
|
|
844b009584 | ||
|
|
9ef820a2a5 | ||
|
|
40eea582ae | ||
|
|
b780d329aa | ||
|
|
8f269697d2 | ||
|
|
98d81a43ea | ||
|
|
1a74171ca5 | ||
|
|
51735f09f7 | ||
|
|
3a42c13ccf | ||
|
|
8b965bd3d5 | ||
|
|
1a7bea0f0f | ||
|
|
b5b2a54834 | ||
|
|
21748a8630 | ||
|
|
e5b686d693 | ||
|
|
87a39d8bac | ||
|
|
cff1c728d8 | ||
|
|
2786cd27da | ||
|
|
1a2d0a0c72 | ||
|
|
b1319e0402 | ||
|
|
8be60e6a65 | ||
|
|
39cffa4e9b | ||
|
|
2af696c32f | ||
|
|
4284ba65eb | ||
|
|
aeec62ad19 | ||
|
|
12aa56d298 | ||
|
|
9156c5d088 | ||
|
|
466a1c72b7 | ||
|
|
81e9ab3156 | ||
|
|
15dbd4b56a | ||
|
|
e2ea2a8147 | ||
|
|
941c6354db | ||
|
|
02eb000f51 | ||
|
|
efc76ca33d | ||
|
|
590091a4fa | ||
|
|
9488cbdd0b | ||
|
|
fa9e41d2e3 | ||
|
|
6b0bc5b2d9 | ||
|
|
7ff5b03e5e | ||
|
|
91350f5c6a | ||
|
|
9c5c9e2355 | ||
|
|
cde12cbe9e | ||
|
|
ab6d16a8a5 | ||
|
|
09a62cca0c | ||
|
|
075f85dcb5 | ||
|
|
d2c4ce254b | ||
|
|
7b78d496bf | ||
|
|
19e272ba53 | ||
|
|
73e679f33f | ||
|
|
a0d819172f | ||
|
|
0aee04288e | ||
|
|
ef4d69f456 | ||
|
|
c15649b3af | ||
|
|
f67a52677b | ||
|
|
392248186e | ||
|
|
33465066c5 | ||
|
|
a5c4c4efbd | ||
|
|
83d475626a | ||
|
|
1ea7e2634d | ||
|
|
23d9b17a7b | ||
|
|
c3bfe07f2a | ||
|
|
508f0f5a21 | ||
|
|
df34fcdafd | ||
|
|
a6d1c8ac65 | ||
|
|
7c36d7c90c | ||
|
|
bbef4edd06 | ||
|
|
3f1a3b7090 | ||
|
|
a91fbe9d27 | ||
|
|
ccc39be053 | ||
|
|
0cf787a377 | ||
|
|
acc70de439 | ||
|
|
cf1c2da836 | ||
|
|
c4cc5eabfe | ||
|
|
8cc21354c2 | ||
|
|
2cb1f6eafe | ||
|
|
9322918406 | ||
|
|
83f00e9156 | ||
|
|
4f9e7f692e | ||
|
|
4b586ad3c2 | ||
|
|
256e432e78 | ||
|
|
51ff7d5ed8 | ||
|
|
49e11102c7 | ||
|
|
a11cd2ca2d | ||
|
|
f9926e7e6c | ||
|
|
76ea01dd20 | ||
|
|
362558cd66 | ||
|
|
09a8479cb7 | ||
|
|
0a633750f1 | ||
|
|
0e2261dbd1 | ||
|
|
842a7a17e3 | ||
|
|
f4fb97c850 | ||
|
|
8b9533f38f | ||
|
|
903e9af1b2 | ||
|
|
e261af52eb | ||
|
|
3f03d46fc1 | ||
|
|
0e27210308 | ||
|
|
13086c2523 | ||
|
|
42a9c8b4a6 | ||
|
|
e50583d721 | ||
|
|
c90363b585 | ||
|
|
915f0faac1 | ||
|
|
0641e3a5fd | ||
|
|
11a084cf42 | ||
|
|
d60794c3a3 | ||
|
|
1b1c01a27b | ||
|
|
72d700b064 | ||
|
|
86b04ebd19 | ||
|
|
7e1c08bb6a | ||
|
|
c7b4359ff4 | ||
|
|
5695c6aca6 | ||
|
|
5ac81657e5 | ||
|
|
5bd63df237 | ||
|
|
75420282e1 | ||
|
|
38df48d108 | ||
|
|
21a8ac0cd3 | ||
|
|
1f30ba6178 | ||
|
|
8733a8d890 | ||
|
|
5446d17756 | ||
|
|
c9ff5c8223 | ||
|
|
d99dd4086d | ||
|
|
09981afc1c | ||
|
|
3d03e504cd | ||
|
|
e04424e87e | ||
|
|
277dd0aa7a | ||
|
|
ded9452174 | ||
|
|
4b1cadbd87 | ||
|
|
2506275c3b | ||
|
|
5f7a94a03e | ||
|
|
df59db6048 | ||
|
|
b33d7586e7 | ||
|
|
fb957ef322 | ||
|
|
5e5d48348b | ||
|
|
26da6a3e10 | ||
|
|
4c2cc782aa | ||
|
|
05e7fdd5ce | ||
|
|
796e3fb7e4 | ||
|
|
867a36b419 | ||
|
|
a139275eca | ||
|
|
efcb3bbc8d | ||
|
|
309979d578 | ||
|
|
c805fa7c40 | ||
|
|
634bf8c953 | ||
|
|
be393f6722 | ||
|
|
d94ff20927 | ||
|
|
0173c260d8 | ||
|
|
9d815e5f5a | ||
|
|
7097663ddd | ||
|
|
eab099b221 | ||
|
|
3036620b48 | ||
|
|
d40830a2b1 | ||
|
|
028715b0f0 | ||
|
|
4a74e19f80 | ||
|
|
e773e71910 | ||
|
|
39a97d86f0 | ||
|
|
41fe225b0d | ||
|
|
1945a0f504 | ||
|
|
4e60e62444 | ||
|
|
96a6210198 | ||
|
|
192d9ad977 | ||
|
|
cb82919b0d | ||
|
|
28aff5d240 | ||
|
|
532b2d2d4e | ||
|
|
214e2cddf6 | ||
|
|
0ce150280e | ||
|
|
3a8a37187d | ||
|
|
629398d0f2 | ||
|
|
fd773dffb2 | ||
|
|
001f747963 | ||
|
|
2081071bee | ||
|
|
47f623d64b | ||
|
|
7e63364529 | ||
|
|
2e5bde4a77 | ||
|
|
cfe869692f | ||
|
|
a61f3c5316 | ||
|
|
ce80d73684 | ||
|
|
804c25a81a | ||
|
|
a54b4bba35 | ||
|
|
0a01c5aa36 | ||
|
|
f01b7afa19 | ||
|
|
ffa7b37b28 | ||
|
|
f61a394be4 | ||
|
|
c2ea5b3dee | ||
|
|
199697accf | ||
|
|
cb8f29d147 | ||
|
|
0e3042f488 | ||
|
|
f644431346 | ||
|
|
83a52c07b7 | ||
|
|
7d1dd5f52d | ||
|
|
330d584617 | ||
|
|
11d6f81316 | ||
|
|
f9c8cefd06 | ||
|
|
791e76ff70 | ||
|
|
e0d915a873 | ||
|
|
90ad817a43 | ||
|
|
5bc8c713e2 | ||
|
|
6c0b4a2769 | ||
|
|
afdae26c71 | ||
|
|
b5022102bb | ||
|
|
b7410c95cf | ||
|
|
fcfca57e2e | ||
|
|
0ac10bb23a | ||
|
|
a729b1aa29 | ||
|
|
548c09acfc | ||
|
|
2ce8ee0214 | ||
|
|
cee9ed2244 | ||
|
|
e7e15631dd | ||
|
|
ffeeb5c1e7 | ||
|
|
c356991fa8 | ||
|
|
e42ee69988 | ||
|
|
226e7d7b3c | ||
|
|
cd2e4310b3 | ||
|
|
fd3d795b93 | ||
|
|
729b035edd | ||
|
|
fda853b573 | ||
|
|
280a6275ce | ||
|
|
95b5d24f43 | ||
|
|
19443035a6 | ||
|
|
8b8103efef | ||
|
|
6bc3d72a65 | ||
|
|
854a559a49 | ||
|
|
18dfbbb150 | ||
|
|
0a26c20b88 | ||
|
|
0889cff5d5 | ||
|
|
9b8c876293 | ||
|
|
e94ab01940 | ||
|
|
54c982081f | ||
|
|
a631fa20d0 | ||
|
|
5911fa1d91 | ||
|
|
e1edb5676e | ||
|
|
3670f095c7 | ||
|
|
f11d690967 | ||
|
|
15ae237d2c | ||
|
|
36d16fed1f | ||
|
|
30e489db5e | ||
|
|
2296999cf6 | ||
|
|
d323acdfec | ||
|
|
81b0e9de7c | ||
|
|
587fd6a0e4 | ||
|
|
6cb7f21e38 | ||
|
|
8ff43c3705 | ||
|
|
026db90621 | ||
|
|
b77497cbd8 | ||
|
|
596ec5c74b | ||
|
|
0ec64370b2 | ||
|
|
d7f45ebca5 | ||
|
|
daa94eb792 | ||
|
|
5f990473e4 | ||
|
|
4bc7a86f3a | ||
|
|
ffbf12504d | ||
|
|
330cad1567 | ||
|
|
fa4d2ec241 | ||
|
|
acfc56957c | ||
|
|
3ba431e79e | ||
|
|
d62448cb45 | ||
|
|
1999e368f1 | ||
|
|
fc4f0d3fce | ||
|
|
9403edbb93 | ||
|
|
ab1b54c3e3 | ||
|
|
0f5933ecc1 | ||
|
|
e75b4bc2df | ||
|
|
36b09fd147 | ||
|
|
a26523330e | ||
|
|
2a022e9e6e | ||
|
|
fb12308416 | ||
|
|
f5a3b05c7a | ||
|
|
f868624f85 | ||
|
|
10ccbc5efa | ||
|
|
43d6b5b375 | ||
|
|
869c0bdeb8 | ||
|
|
c71af0895d | ||
|
|
b00ee99a21 | ||
|
|
55c13f3de4 | ||
|
|
9694854082 | ||
|
|
cdca2782d2 | ||
|
|
cebbb0feaf | ||
|
|
6240a7639d | ||
|
|
9e8b3d4a98 | ||
|
|
c27015368b | ||
|
|
5da497d0a8 | ||
|
|
dc261f17e9 | ||
|
|
ee8200f1c6 | ||
|
|
0a389691dc | ||
|
|
32d6ca9196 | ||
|
|
20e317cf92 | ||
|
|
2b9843c20b | ||
|
|
872ea3b987 | ||
|
|
df110bccbe | ||
|
|
a01eb9c451 | ||
|
|
81a9da8f61 | ||
|
|
a3c7e326c3 | ||
|
|
5ce334923f | ||
|
|
49b5022993 | ||
|
|
84d88cb2cf | ||
|
|
f09e4f7b10 | ||
|
|
0a73a5012a | ||
|
|
96dc03b337 | ||
|
|
d1d00fdeec | ||
|
|
00b610e542 | ||
|
|
fc35b6988d | ||
|
|
b86bd3b074 | ||
|
|
3414601788 | ||
|
|
d31c4e0bc1 | ||
|
|
031cd2bb0d | ||
|
|
3c0fc6f0da | ||
|
|
a0cf3d47f1 | ||
|
|
c4f3732c91 | ||
|
|
a9d954cb3c | ||
|
|
6e4f2da9b3 | ||
|
|
ab5df4bc5c | ||
|
|
7bbc128c3d | ||
|
|
cb57f4f89b | ||
|
|
8b6226997e | ||
|
|
f0b3e05add | ||
|
|
09b2649c5f | ||
|
|
cc17210bce | ||
|
|
e5d99cb9e6 | ||
|
|
3c1924c9c0 | ||
|
|
e4d5d05119 | ||
|
|
e3f1b1dccb | ||
|
|
fd238f3c0e | ||
|
|
58713d34dd | ||
|
|
32e22a0037 | ||
|
|
231b7df6cc | ||
|
|
521136181b | ||
|
|
fda19b55b1 | ||
|
|
de4db6a93b | ||
|
|
d797f4d590 | ||
|
|
a37fd93fbb | ||
|
|
8740b7cb77 | ||
|
|
746b1bcf2a | ||
|
|
34c956afc1 | ||
|
|
d0ff35c5a6 | ||
|
|
1307fafe0f | ||
|
|
9886fd236e | ||
|
|
a4fdfc098d | ||
|
|
cbe81ad393 | ||
|
|
8c09f12943 | ||
|
|
19ef3e0f31 | ||
|
|
463f59eca4 | ||
|
|
e4145ebc47 | ||
|
|
567189cc76 | ||
|
|
f4262026b6 | ||
|
|
82a27a85b5 | ||
|
|
ba898b9ab6 | ||
|
|
d827dd8b05 | ||
|
|
e53758c5f6 | ||
|
|
1f27c9f6a4 | ||
|
|
d310e1f907 | ||
|
|
81d4c4a84c | ||
|
|
1c811bfcd9 | ||
|
|
6d9e7d48fb | ||
|
|
c868609cff | ||
|
|
e4b9ac46d7 | ||
|
|
45f3e8bbef | ||
|
|
1fae121b22 | ||
|
|
180f92d3dc | ||
|
|
5476ee8655 | ||
|
|
3c396cf1e1 | ||
|
|
1ea1cb6dc9 | ||
|
|
8821cc416e | ||
|
|
92a4b5cc3c | ||
|
|
c0d6056870 | ||
|
|
23770214a9 | ||
|
|
386e91addb | ||
|
|
62a87c84ed | ||
|
|
ce2e60ab45 | ||
|
|
9c5a85ce24 | ||
|
|
c09dad71fb | ||
|
|
d08427030d | ||
|
|
7b570840cd | ||
|
|
c1bd76d6fc | ||
|
|
a7abade088 | ||
|
|
abb24370e9 | ||
|
|
6e1feb0f73 | ||
|
|
ef7264807f | ||
|
|
bc39506792 | ||
|
|
28b4fa3e27 | ||
|
|
b193809987 | ||
|
|
a8fd88463e | ||
|
|
3a3e17d603 | ||
|
|
40af31729f | ||
|
|
58f8f29c41 | ||
|
|
3d08a49790 | ||
|
|
55a9262bdb | ||
|
|
ba94d0f144 | ||
|
|
ae4db9f302 | ||
|
|
70db1d523d | ||
|
|
8e229cb7ea | ||
|
|
13d3eeb2ee | ||
|
|
dece918bc8 | ||
|
|
b091c37595 | ||
|
|
ca70770cfd | ||
|
|
5243a81c29 | ||
|
|
12acf852c5 | ||
|
|
074b5de771 | ||
|
|
69fa16048a | ||
|
|
b01e9651b0 | ||
|
|
8967776713 | ||
|
|
d1c65d1b28 | ||
|
|
be1db6b6c1 | ||
|
|
4227b2ebb4 | ||
|
|
15e20bb5c0 | ||
|
|
80bc87e377 | ||
|
|
77357081c8 | ||
|
|
4b28383b1c | ||
|
|
94c56559ca | ||
|
|
427d0a5e92 | ||
|
|
623b46a17d | ||
|
|
a606966029 | ||
|
|
79ea81b8a8 | ||
|
|
d4c024c836 | ||
|
|
b297d78367 | ||
|
|
4a6d5e2012 | ||
|
|
9d5cd4ca14 | ||
|
|
0b487802a0 | ||
|
|
f3891e90e3 | ||
|
|
0f3b81bb2e | ||
|
|
00ed523659 | ||
|
|
77fae3d852 | ||
|
|
16ff2d927f | ||
|
|
fc7a27bc3d | ||
|
|
666722324f | ||
|
|
bfb58b7e1c | ||
|
|
8852b25fc7 | ||
|
|
4d5b618d52 | ||
|
|
e6724f0303 | ||
|
|
37dd26e322 | ||
|
|
f10ad95c36 | ||
|
|
9b3dc72506 | ||
|
|
4534f0fbcf | ||
|
|
6a93206882 | ||
|
|
043fb32c4b | ||
|
|
b3cd5d2945 | ||
|
|
6b81ac5807 | ||
|
|
988ca74351 | ||
|
|
86adb6ca63 | ||
|
|
b22b7d7ba9 | ||
|
|
7995eedd35 | ||
|
|
098528513f | ||
|
|
829384f46d | ||
|
|
e96041e18f | ||
|
|
0f45aa7f31 | ||
|
|
2cf3336130 | ||
|
|
a8b9e2eccd | ||
|
|
99f55abc56 | ||
|
|
c2d814e78d | ||
|
|
9e3ef2809a | ||
|
|
48ed8ac50c | ||
|
|
ece758457d | ||
|
|
79e9bde0ea | ||
|
|
08f047eb51 | ||
|
|
9edd2258ff | ||
|
|
13c7bbf8a9 | ||
|
|
533ac4d47d | ||
|
|
f0c18fceb4 | ||
|
|
22a1337a9b | ||
|
|
969ee25a74 | ||
|
|
6cde12a013 | ||
|
|
feb8e9a790 | ||
|
|
8a74d1ec79 | ||
|
|
694c88e031 | ||
|
|
036d90bba6 | ||
|
|
664a9f4830 | ||
|
|
3ea396e9d2 | ||
|
|
819dc1845e | ||
|
|
53c08f0bba | ||
|
|
597de9d586 | ||
|
|
f072a76326 | ||
|
|
856f9cced8 | ||
|
|
ec87e88c52 | ||
|
|
f9f5aac123 | ||
|
|
1134de3c89 | ||
|
|
3b74824985 | ||
|
|
6bd5bf3cb5 | ||
|
|
1aa7fa354e | ||
|
|
5383697c78 | ||
|
|
0b05048341 | ||
|
|
41001dbfdd | ||
|
|
d62a8d2f15 | ||
|
|
f06d866110 | ||
|
|
3638c05ec9 | ||
|
|
54815fff06 | ||
|
|
666c77c0f2 | ||
|
|
cafe145ba2 | ||
|
|
974e7b9220 | ||
|
|
b59cdf0892 | ||
|
|
993fe07a3c | ||
|
|
2bbf2fa8eb | ||
|
|
1c013e7ae2 | ||
|
|
fd1782b5fc | ||
|
|
559ca8bc65 | ||
|
|
2f334afb98 | ||
|
|
88551add97 | ||
|
|
23e8e849e4 | ||
|
|
362a1a5a82 | ||
|
|
ce1528359a | ||
|
|
f02cdcff00 | ||
|
|
1f3d04cddf | ||
|
|
c78033233a | ||
|
|
83541123c8 | ||
|
|
46e6b2b86e | ||
|
|
6ac5689ce4 | ||
|
|
d11f8d4228 | ||
|
|
71dbe47619 | ||
|
|
a5b476a7d3 | ||
|
|
b3997469b5 | ||
|
|
519c309952 | ||
|
|
a161e29c59 | ||
|
|
72f754e2bc | ||
|
|
439a579aa2 | ||
|
|
649c9d4719 | ||
|
|
51f89f2fbd | ||
|
|
e06d188f0d | ||
|
|
fef3cb3f21 | ||
|
|
027fe112ec | ||
|
|
f54198eed6 | ||
|
|
0dae377fbf | ||
|
|
8bc90a25c2 | ||
|
|
b40ccdd57c | ||
|
|
78135c24b4 | ||
|
|
d9c67a9b21 | ||
|
|
e6834b3237 | ||
|
|
c0629c13fe | ||
|
|
f6473baffc | ||
|
|
3e343ba5ef | ||
|
|
6b0c464a34 | ||
|
|
9aabf441bd | ||
|
|
772b54a08b | ||
|
|
e593213b87 | ||
|
|
3cd644aeb5 | ||
|
|
a28fb37b9e | ||
|
|
a5491d3698 | ||
|
|
ca0d9a70d1 | ||
|
|
cf700151eb | ||
|
|
af1c7bf0c7 | ||
|
|
fa11ddd7df | ||
|
|
3e333e9b5c | ||
|
|
1568ed4d20 | ||
|
|
3934ade5a2 | ||
|
|
f4fa3e1a6b | ||
|
|
ce6a0f4469 | ||
|
|
33eb7d7dfb | ||
|
|
705caa8c32 | ||
|
|
c1f5ac3eca | ||
|
|
bcb875dcb1 | ||
|
|
be66243933 | ||
|
|
57534733b7 | ||
|
|
1612c570b6 | ||
|
|
b92e502695 | ||
|
|
27e6aee390 | ||
|
|
8bfcefe11a | ||
|
|
00d24511bc | ||
|
|
03762f42c1 | ||
|
|
ae88bf03a1 | ||
|
|
c3fddb0fbb | ||
|
|
697fb353dc | ||
|
|
2a7c2539c6 | ||
|
|
500fd8b9bf | ||
|
|
b4be988732 | ||
|
|
b785a50da4 | ||
|
|
2bc0525e93 | ||
|
|
85b42d7c95 | ||
|
|
c7fc06a262 | ||
|
|
268f53ed0d | ||
|
|
b93b85378d | ||
|
|
e15db15926 | ||
|
|
2972604f0c | ||
|
|
d947a815e8 | ||
|
|
d10fb73f63 | ||
|
|
64c4106219 | ||
|
|
c45e6e3c78 | ||
|
|
a7101e7bfb | ||
|
|
beb65056cf | ||
|
|
c2d4330f27 | ||
|
|
077645476c | ||
|
|
e9e35b011e | ||
|
|
86a4d47215 | ||
|
|
4a33d57143 | ||
|
|
34a4109946 | ||
|
|
7e728fe1a1 | ||
|
|
96a883a454 | ||
|
|
9ab6bdce01 | ||
|
|
681f779a3c | ||
|
|
ac3143c093 | ||
|
|
d41bab4028 | ||
|
|
3da88b8917 | ||
|
|
9cfa27f9c5 | ||
|
|
c39f3026a8 | ||
|
|
222bb2b88d | ||
|
|
b8538f5dcd | ||
|
|
c4fdcb04be | ||
|
|
0823511262 | ||
|
|
738ae4a77f | ||
|
|
47ac6a1a2e | ||
|
|
3d2c4dc034 | ||
|
|
082fcc53cc | ||
|
|
074295245b | ||
|
|
cb14bbdbc9 | ||
|
|
841c3478fd | ||
|
|
6294509cc6 | ||
|
|
1481125042 | ||
|
|
10d27998b3 | ||
|
|
a9a7c297ae | ||
|
|
023cf21848 | ||
|
|
cb305b9fc0 | ||
|
|
a0cc570f86 | ||
|
|
903569d533 | ||
|
|
d77546773b | ||
|
|
de13abdfdf | ||
|
|
2566bdfbc3 | ||
|
|
143a9d7ee6 | ||
|
|
6e1f421a6d | ||
|
|
fd37eeddd6 | ||
|
|
6b48233f25 | ||
|
|
3ec4813ba2 | ||
|
|
e8dbaf62d3 | ||
|
|
705fee709f | ||
|
|
71f4fbfbde | ||
|
|
16e9b32c2f | ||
|
|
3b6840e099 | ||
|
|
67a61cce1b | ||
|
|
d9d47b7b88 | ||
|
|
181e701cc5 | ||
|
|
a421879bb5 | ||
|
|
3472910177 | ||
|
|
088ee7618d | ||
|
|
a405b89555 | ||
|
|
88760141da | ||
|
|
b174c27d4d | ||
|
|
bfd0689d64 | ||
|
|
0ac20a8fdb | ||
|
|
d16332be72 | ||
|
|
6a8cc1dcd4 | ||
|
|
c923dee8de | ||
|
|
633aea92fb | ||
|
|
e1733a6271 | ||
|
|
114744cee1 | ||
|
|
dfe3eb12d0 | ||
|
|
d3605b81f3 | ||
|
|
4daea88516 | ||
|
|
810ab095e6 | ||
|
|
5fb71bd530 | ||
|
|
dd385eb5ac | ||
|
|
b4e8de3a31 | ||
|
|
36ce97c625 | ||
|
|
3dbb9a57ca | ||
|
|
a900d150e4 | ||
|
|
5bef18f2eb | ||
|
|
622064f00f | ||
|
|
9cee94372a | ||
|
|
3b1422c45c | ||
|
|
335707b0e2 | ||
|
|
82ecfa6f0e | ||
|
|
e944a9c635 | ||
|
|
fe70b03de2 | ||
|
|
a32d5a4afc | ||
|
|
eaa0d927a4 | ||
|
|
454782f1a3 | ||
|
|
7f63fff9c4 | ||
|
|
21c0b1134f | ||
|
|
04ae5007e3 | ||
|
|
a69ded43b0 | ||
|
|
4c629a5257 | ||
|
|
3489e68ef7 | ||
|
|
a3af8b0626 | ||
|
|
92138badd4 | ||
|
|
f6ad48f0e5 | ||
|
|
ded279f826 | ||
|
|
89d355ea04 | ||
|
|
d7b9349ce7 | ||
|
|
d8996a17d1 | ||
|
|
77f0e7a450 | ||
|
|
621398ebb7 | ||
|
|
1587236089 | ||
|
|
125cd06698 | ||
|
|
6f793d34ca | ||
|
|
7b45a1fc60 | ||
|
|
f143ad3a93 | ||
|
|
e29d4773f4 | ||
|
|
77c2d11657 | ||
|
|
02767c5eb1 | ||
|
|
03c4fee5a7 | ||
|
|
a62cd64db6 | ||
|
|
844707067b | ||
|
|
07a34184db | ||
|
|
c794c163b5 | ||
|
|
f6de196c21 | ||
|
|
110a0745cd | ||
|
|
7760665fb8 | ||
|
|
44c7bc0262 | ||
|
|
e217873ed6 | ||
|
|
cf189a572a | ||
|
|
7559d871fb | ||
|
|
a4724350e4 | ||
|
|
a25d92c88b | ||
|
|
982cf44ff0 | ||
|
|
63c5aaaaf2 | ||
|
|
c725648f6c | ||
|
|
20e336f21c | ||
|
|
6575122c63 | ||
|
|
74bf75a2f5 | ||
|
|
1545ebf938 | ||
|
|
9465963faf | ||
|
|
c5ba60827e | ||
|
|
ba2b701f2c | ||
|
|
c23e7ff2a0 | ||
|
|
679b6b5b29 | ||
|
|
bf77f71711 | ||
|
|
4c6b3f5ec3 | ||
|
|
ae76e8f0d0 | ||
|
|
7ee3ccd826 | ||
|
|
9c86d33e68 | ||
|
|
50d70eff35 | ||
|
|
134b727b4f | ||
|
|
b45e9183bc | ||
|
|
00d028fd77 | ||
|
|
3173442984 | ||
|
|
438a65dfdb | ||
|
|
a3e0d830bd | ||
|
|
6f2a617c31 | ||
|
|
69132f55ea | ||
|
|
fd1376ebef | ||
|
|
0a203070f5 | ||
|
|
5577f2f4f0 | ||
|
|
1e6a926e85 | ||
|
|
a9bc53d5f3 | ||
|
|
da1f887060 | ||
|
|
e043e03cd8 | ||
|
|
3d9957e3dd | ||
|
|
857296c823 | ||
|
|
d5adec1056 | ||
|
|
1f318dbcee | ||
|
|
7fe5e4010c | ||
|
|
ce18fb61c0 | ||
|
|
e7eb5b0696 | ||
|
|
9a06ae7b35 | ||
|
|
ac6b355978 | ||
|
|
edbdbddfb6 | ||
|
|
3d5f7f90c8 | ||
|
|
9da07f1d3e | ||
|
|
f715fefe31 | ||
|
|
2c64762a40 | ||
|
|
9c0049b1ce | ||
|
|
632dde0cbc | ||
|
|
c78b6f18d4 | ||
|
|
4f91ad64c3 | ||
|
|
756d027da5 | ||
|
|
fd29c7f3a1 | ||
|
|
7c31293221 | ||
|
|
b89ad7e2d4 | ||
|
|
3225f8d175 | ||
|
|
778b66a719 | ||
|
|
6e4c04b1be | ||
|
|
d3abc25e76 | ||
|
|
f0a4955eb1 | ||
|
|
c254743ef3 | ||
|
|
d1531ab26d | ||
|
|
1aba262edb | ||
|
|
f0268585dd | ||
|
|
8af5f54824 | ||
|
|
c069aff21b | ||
|
|
a72a805896 | ||
|
|
eeb498627c | ||
|
|
b244fffc18 | ||
|
|
da20e0c507 | ||
|
|
f8bf641095 | ||
|
|
9d558fbcc2 | ||
|
|
ba68aed836 | ||
|
|
6d998aa13d | ||
|
|
01b06cb71b | ||
|
|
43224f22e4 | ||
|
|
e8d00e0687 | ||
|
|
55f3369692 | ||
|
|
611c8b6d29 | ||
|
|
5435346052 | ||
|
|
1562cd7320 | ||
|
|
da1527d65d | ||
|
|
925268794f | ||
|
|
f3c7bd4004 | ||
|
|
682e0c898e | ||
|
|
788e4c5423 | ||
|
|
e6b5eb88f2 | ||
|
|
cf5b4a2286 | ||
|
|
f400f9db19 | ||
|
|
7a8ce8dbf7 | ||
|
|
6fba37777c | ||
|
|
08114840ca | ||
|
|
0d300b70f9 | ||
|
|
15939e3435 | ||
|
|
131c657735 | ||
|
|
e5e0e22022 | ||
|
|
e27182249a | ||
|
|
dc49e1cde0 | ||
|
|
aa2d39c2ca | ||
|
|
0cb9df3cec | ||
|
|
caaca15854 | ||
|
|
62ac80c8fa | ||
|
|
30c3bbcd9e | ||
|
|
1bed578535 | ||
|
|
bf2b1986c2 | ||
|
|
fe00b163d6 | ||
|
|
76cc477fba | ||
|
|
2fca6cdeb3 | ||
|
|
0300730cc9 | ||
|
|
9e102ecbd9 | ||
|
|
190e91231c | ||
|
|
463c86008b | ||
|
|
850606e9fa | ||
|
|
77fa958c1e | ||
|
|
d4317c0406 | ||
|
|
d34de2d912 | ||
|
|
b91e1ea95e | ||
|
|
04c77bd886 | ||
|
|
67657f1ff9 | ||
|
|
ba120640b2 | ||
|
|
0d15217a6c | ||
|
|
9f0095fa2c | ||
|
|
bf19bbbd55 | ||
|
|
4f1c1f3d6b | ||
|
|
e93058ed81 | ||
|
|
ce3c457dcc | ||
|
|
239fb95fde | ||
|
|
6cdd153b89 | ||
|
|
333fdfd4b6 | ||
|
|
8d594c409c | ||
|
|
f653b123cf | ||
|
|
c0d30da609 | ||
|
|
b7db994aba | ||
|
|
03aec36fc0 | ||
|
|
a98ceceb1d | ||
|
|
797c18d543 | ||
|
|
3f10dfd6c7 | ||
|
|
8081ee1440 | ||
|
|
cf93fe39e3 | ||
|
|
4931d0132c | ||
|
|
64a9990977 | ||
|
|
a929606f2b | ||
|
|
679f1a9e29 | ||
|
|
4f375d03dd | ||
|
|
f3a19fbe13 | ||
|
|
64b40c5554 | ||
|
|
a42c1c5728 | ||
|
|
57a16abe2c | ||
|
|
1406aba8da | ||
|
|
b7d80806b6 | ||
|
|
6fb2552ef4 | ||
|
|
a2c9ede6b3 | ||
|
|
b184d7a2ca | ||
|
|
3fa66d1036 | ||
|
|
f207a6d353 | ||
|
|
5e38b8439a | ||
|
|
a8fc483ca4 | ||
|
|
7bd1559db6 | ||
|
|
ea846f1ca2 | ||
|
|
02e10f4ccd | ||
|
|
cc560b75aa | ||
|
|
007ac0d36f | ||
|
|
1b43d63368 | ||
|
|
d5cef7413f | ||
|
|
8da7915222 | ||
|
|
2ec51e6185 | ||
|
|
257f7febc7 | ||
|
|
24a92e08c0 | ||
|
|
c3d351ec9b | ||
|
|
e213aa17bd | ||
|
|
cdb7ce6f17 | ||
|
|
100daa7fd8 | ||
|
|
68e8030fe7 | ||
|
|
13e87045fd | ||
|
|
9c2a6de68f | ||
|
|
f5199a1cbd | ||
|
|
d758115786 | ||
|
|
5cfd7074af | ||
|
|
5e0a8fa981 | ||
|
|
2bbf0425e7 | ||
|
|
5420edd56e | ||
|
|
e28ff7e0fc | ||
|
|
d748b3455d | ||
|
|
3eb2d4d2ce | ||
|
|
20e9ec3583 | ||
|
|
62e7a6ca1a | ||
|
|
fabc19b73c | ||
|
|
b5b3ad14a8 | ||
|
|
7de6153395 | ||
|
|
ed8ea6cb2f | ||
|
|
725136b57e | ||
|
|
1806694928 | ||
|
|
e3ccf98023 | ||
|
|
abcab54cca | ||
|
|
3d845e492a | ||
|
|
e047f04394 | ||
|
|
e587b0677b | ||
|
|
be23fae488 | ||
|
|
ca67cf84df | ||
|
|
53aff9322e | ||
|
|
1d832aef09 | ||
|
|
8e509b5dd5 | ||
|
|
f25132b354 | ||
|
|
1dfedcc179 | ||
|
|
cbdf514bbc | ||
|
|
29c709f591 | ||
|
|
eadebc3b61 | ||
|
|
ed2a08bf25 | ||
|
|
5232fd13f3 | ||
|
|
b8dfd7a53d | ||
|
|
28f18404a7 | ||
|
|
3c46428fcd | ||
|
|
950a21d58a | ||
|
|
05934d2538 | ||
|
|
2cea1c1bd9 | ||
|
|
bf5cb4af8e | ||
|
|
87578b5d94 | ||
|
|
6d35c69b06 | ||
|
|
dc5190de74 | ||
|
|
e8c11c7df0 | ||
|
|
c21f1ba07a | ||
|
|
91f737383c | ||
|
|
5bbf083cd1 | ||
|
|
9fc6b654f5 | ||
|
|
7fca7f196d | ||
|
|
81c038934c | ||
|
|
76a0dffe6f | ||
|
|
bda26acf70 | ||
|
|
22ae43a11e | ||
|
|
991d646354 | ||
|
|
32527861d0 | ||
|
|
26f4b1da88 | ||
|
|
079895b8be | ||
|
|
7a5a4f952e | ||
|
|
88421c883e | ||
|
|
2d10a6f6ae | ||
|
|
7a588bce7b | ||
|
|
c90ee0414d | ||
|
|
3f05e662bb | ||
|
|
b09ac72624 | ||
|
|
75aa3e951f | ||
|
|
224e30a4b1 | ||
|
|
31f1375d23 | ||
|
|
4f6660db7d | ||
|
|
74a81a4577 | ||
|
|
bc52f07a8f | ||
|
|
636bcb020a | ||
|
|
9fb93fcd90 | ||
|
|
bee2df3903 | ||
|
|
796dc9c91c | ||
|
|
3542fce0fb | ||
|
|
abdfb1e75b | ||
|
|
6a171bbdf5 | ||
|
|
9273b1a964 | ||
|
|
9c7063ef89 | ||
|
|
79844b9066 | ||
|
|
fee09f0964 | ||
|
|
4ce5b5fdf3 | ||
|
|
a3473e60db | ||
|
|
dd4e6b4e7e | ||
|
|
16e8006eb0 | ||
|
|
c18e969e30 | ||
|
|
0eea780bce | ||
|
|
0480b4743a | ||
|
|
4daede06e5 | ||
|
|
f48a4c391c | ||
|
|
11e0dc40dc | ||
|
|
8f25606d3a | ||
|
|
fc65269d68 | ||
|
|
5a0197121b | ||
|
|
b769183a98 | ||
|
|
9c39d635b6 | ||
|
|
25e7178e59 | ||
|
|
d2c2718c11 | ||
|
|
4388ab477c | ||
|
|
3706abde5e | ||
|
|
13fea87960 | ||
|
|
d6b6246864 | ||
|
|
299a3be0d3 | ||
|
|
bf73ccb848 | ||
|
|
08a82aa940 | ||
|
|
e0a62b8fdc | ||
|
|
b120454b50 | ||
|
|
f0ff3e9982 | ||
|
|
79ec8eb93c | ||
|
|
8b6b90b073 | ||
|
|
244ca7ee77 | ||
|
|
c5b4327f3d | ||
|
|
923902013c | ||
|
|
5d8b31ffad | ||
|
|
4946c64092 | ||
|
|
3be3eb2995 | ||
|
|
0ba332e82a | ||
|
|
15a563c376 | ||
|
|
ea5c1b0a73 | ||
|
|
a1474b98f9 | ||
|
|
90cbc5576f | ||
|
|
8c9ab2a4dd | ||
|
|
3f0434057b | ||
|
|
beb229e1e8 | ||
|
|
6cc37275ce | ||
|
|
ae0014e2df | ||
|
|
afcf472464 | ||
|
|
de6deec3b8 | ||
|
|
d0c46c9ed5 | ||
|
|
71dbfd7c20 | ||
|
|
3fbb7b6e35 | ||
|
|
1bb5b498f0 | ||
|
|
a378e5a6dd | ||
|
|
0c1bda9b53 | ||
|
|
cfb0174fed | ||
|
|
a7d28639eb | ||
|
|
1e3c135d71 | ||
|
|
f50229041b | ||
|
|
a939857a63 | ||
|
|
d9176782fe | ||
|
|
d7888e8316 | ||
|
|
066d0a4e19 | ||
|
|
6e4aee0492 | ||
|
|
82f6dbfaf7 | ||
|
|
de0ce46361 | ||
|
|
8853462528 | ||
|
|
1906619187 | ||
|
|
95da21cc18 | ||
|
|
a8bdfbe959 | ||
|
|
3fc9615d15 | ||
|
|
92607ecfe6 | ||
|
|
33429ea083 | ||
|
|
808f88f9f0 | ||
|
|
81d03b46b0 | ||
|
|
2fea720881 | ||
|
|
4b161de2e5 | ||
|
|
7a64a157e1 | ||
|
|
7f8d942268 | ||
|
|
d8874556cd | ||
|
|
3216a9a819 | ||
|
|
14c3f9603e | ||
|
|
3f8da60079 | ||
|
|
afdff40542 | ||
|
|
30e8b284a7 | ||
|
|
16ee4642c7 | ||
|
|
2e035162a1 | ||
|
|
3b15f79bf0 | ||
|
|
47ed4cdc35 | ||
|
|
9b86e8e8f4 | ||
|
|
0d0d50182d | ||
|
|
caa9223c85 | ||
|
|
85e833c172 | ||
|
|
2b4f10ac66 | ||
|
|
cf4df9e349 | ||
|
|
bff3a1651d | ||
|
|
5723a7cd7e | ||
|
|
de4791c052 | ||
|
|
5cd6381717 | ||
|
|
061e371319 | ||
|
|
105c07d1b4 | ||
|
|
5f6ac1c812 | ||
|
|
9ce52430de | ||
|
|
191f3cf52a | ||
|
|
43a6f9e726 | ||
|
|
53c2c45625 | ||
|
|
e478471dd5 | ||
|
|
5d4695569d | ||
|
|
930f0aae84 | ||
|
|
1a7dd13e70 | ||
|
|
f5466fe435 | ||
|
|
1a814af46b | ||
|
|
22defdac64 | ||
|
|
6cdab82cf3 | ||
|
|
7e58ae7dac | ||
|
|
026c38ac1e | ||
|
|
24352aff2b | ||
|
|
a1dd61459c | ||
|
|
2ebb4f4ca3 | ||
|
|
e3c831030d | ||
|
|
375ed98ae9 | ||
|
|
7a4e27eee5 | ||
|
|
d1a770107d | ||
|
|
75454c2b32 | ||
|
|
4cdf155a87 | ||
|
|
a084b3122f | ||
|
|
c6bcfcba85 | ||
|
|
c969e05aab | ||
|
|
ee6fc17663 | ||
|
|
d5651f44e3 | ||
|
|
96124c6c0b | ||
|
|
fe30658a4d | ||
|
|
c26d81d6e6 | ||
|
|
59c417379e | ||
|
|
fa16c9b7cb | ||
|
|
29220a181a | ||
|
|
e4261ba037 | ||
|
|
0aef2b719f | ||
|
|
0457224feb | ||
|
|
f080ebc123 | ||
|
|
391500643c | ||
|
|
29467abe59 | ||
|
|
0b99d648ef | ||
|
|
695237f2ae | ||
|
|
f814d763c6 | ||
|
|
cc26085b62 | ||
|
|
b851b74cba | ||
|
|
2872e8c289 | ||
|
|
0523c71844 | ||
|
|
f29df9acfe | ||
|
|
2b557b595a | ||
|
|
394250ef67 | ||
|
|
463fd954bb | ||
|
|
4eaa399b54 | ||
|
|
303c5ba803 | ||
|
|
6f3f421228 | ||
|
|
a9d48bae2f | ||
|
|
249d4a921c | ||
|
|
1a7c9ce3bd | ||
|
|
073643c9a2 | ||
|
|
ebde60beab | ||
|
|
a5b34f0f1b | ||
|
|
4459413225 | ||
|
|
f32973c78e | ||
|
|
8fdca0de79 | ||
|
|
035276ab83 | ||
|
|
64353ff74b | ||
|
|
ba049e203b | ||
|
|
87cb0a3e9f | ||
|
|
32a0f625a5 | ||
|
|
4f94669eca | ||
|
|
c88ffbf9df | ||
|
|
93ab6d5184 | ||
|
|
ce3c61c4af | ||
|
|
385457de23 | ||
|
|
d3a591a7b3 | ||
|
|
dc41859220 | ||
|
|
bd84389c68 | ||
|
|
308f9bcc18 | ||
|
|
a701d337d4 | ||
|
|
1966025245 | ||
|
|
a16324b0d3 | ||
|
|
ee65528547 | ||
|
|
536f5fa0a3 | ||
|
|
7a6e3838e9 | ||
|
|
95dbedb301 | ||
|
|
6d1c9a0eb8 | ||
|
|
53ef14fca0 | ||
|
|
e28e22b9e1 | ||
|
|
f199aeb9ea | ||
|
|
7abb7894e4 | ||
|
|
3929b00466 | ||
|
|
65623b63a2 | ||
|
|
5190f56605 | ||
|
|
a098aa419f | ||
|
|
bf2d831e7e | ||
|
|
20c6192fbb | ||
|
|
666738d57a | ||
|
|
139df7c4a3 | ||
|
|
974a029a8a | ||
|
|
04826db7c4 | ||
|
|
663254d7a5 | ||
|
|
b9e6e66de1 | ||
|
|
5f7428e4d5 | ||
|
|
c282a66132 | ||
|
|
7c66850ce5 | ||
|
|
c8caa04b1c | ||
|
|
f1e3e99169 | ||
|
|
e8fa3354f0 | ||
|
|
f9d74ba3d1 | ||
|
|
4b1219ee87 | ||
|
|
9506760c7e | ||
|
|
8a87fadbb0 | ||
|
|
22d43ee14a | ||
|
|
147b0a1700 | ||
|
|
d24b6cfb1f | ||
|
|
f08154cc7b | ||
|
|
b7ebab7657 | ||
|
|
0bffd99daa | ||
|
|
9dbe2d760f | ||
|
|
8759f7d755 | ||
|
|
c9f021de0b | ||
|
|
83587f0555 | ||
|
|
8bb1dfdd32 | ||
|
|
192a83def3 | ||
|
|
6e7b24d34f | ||
|
|
361e2d8df7 | ||
|
|
21343ffbfe | ||
|
|
a515a91fcc | ||
|
|
e4fa756385 | ||
|
|
a13d261466 | ||
|
|
6407d184d1 | ||
|
|
19c3851d9c | ||
|
|
5bf74f2997 | ||
|
|
87941ccd17 | ||
|
|
80f4b4b803 | ||
|
|
32a6c11877 | ||
|
|
1260b86b2b | ||
|
|
6606b1bff3 | ||
|
|
17583f1b59 | ||
|
|
a10a11bd54 | ||
|
|
95fbbf4f40 | ||
|
|
038013cf42 | ||
|
|
ff5217f850 | ||
|
|
36bcbeadd0 | ||
|
|
0e1d1aaca8 | ||
|
|
e6a69af2d7 | ||
|
|
05f23e7763 | ||
|
|
c6d96efc38 | ||
|
|
eded54df7b | ||
|
|
26f5ec0e98 | ||
|
|
1ad9677cb3 | ||
|
|
bbe4f7e4c5 | ||
|
|
243a135fe9 | ||
|
|
bdf4e3e2f2 | ||
|
|
e7e499e80f | ||
|
|
8a2b9f045f | ||
|
|
ed2dcb796f | ||
|
|
a042678a83 | ||
|
|
6cecf61cc3 | ||
|
|
3f7e62b340 | ||
|
|
db5166fbfa | ||
|
|
760cebf47d | ||
|
|
c7290759b0 | ||
|
|
f5cc96a54e | ||
|
|
321e19d9cc | ||
|
|
5dbcbbea58 | ||
|
|
0982c5c79f | ||
|
|
47b704462e | ||
|
|
1d3711c0b2 | ||
|
|
379d9ec8ec | ||
|
|
458b0210d1 | ||
|
|
1334ea214e | ||
|
|
a854546234 | ||
|
|
faccdeda83 | ||
|
|
e9a233ee8e | ||
|
|
08371a8b80 | ||
|
|
588b3bd7a1 | ||
|
|
85ef614b37 | ||
|
|
04101bc430 | ||
|
|
a9b28a4f21 | ||
|
|
7e7411966a | ||
|
|
6a2ae250ff | ||
|
|
60427d5d42 | ||
|
|
4d16bfaabb | ||
|
|
6f68f4364b | ||
|
|
b48ff3b94e | ||
|
|
5e25bca1a9 | ||
|
|
8bb76aea81 | ||
|
|
1e65fdd9ba | ||
|
|
c6a57dc4f3 | ||
|
|
06b408ecce | ||
|
|
190d591fbe | ||
|
|
56606b5f21 | ||
|
|
930fa3290d | ||
|
|
a7bfc2cbb5 | ||
|
|
733bfe36f5 | ||
|
|
67c52a4453 | ||
|
|
e73dad7874 | ||
|
|
bfbb5d269a | ||
|
|
3562b5ab39 | ||
|
|
dcba4781ea | ||
|
|
340369ab25 | ||
|
|
4e6f3e5162 | ||
|
|
2477495922 | ||
|
|
cccc2b2980 | ||
|
|
926b38c0d7 | ||
|
|
1a41e649a6 | ||
|
|
eeaf3f2e88 | ||
|
|
047fe6c59f | ||
|
|
c32efc7f7e | ||
|
|
e09f8a82f1 | ||
|
|
57e9e76da4 | ||
|
|
379fb90b05 | ||
|
|
ee4cd2c737 | ||
|
|
5b154ae4a3 | ||
|
|
9ea77b788b | ||
|
|
8bceb1e0bb | ||
|
|
0a19238aa3 | ||
|
|
a432066c7c | ||
|
|
cb727a1ccc | ||
|
|
66d074e913 | ||
|
|
b5394c8f26 | ||
|
|
71d97fd88a | ||
|
|
efd7480de3 | ||
|
|
1248f94a42 | ||
|
|
bbaabb8a59 | ||
|
|
2c50cbe8cb | ||
|
|
ebb2205b4c | ||
|
|
dd6a202831 | ||
|
|
dd0ee35378 | ||
|
|
a88430c6a1 | ||
|
|
0d313282f2 | ||
|
|
aa30e95271 | ||
|
|
8668a9e81c | ||
|
|
4ff9abd01f | ||
|
|
1e59c0346a | ||
|
|
809a5e142e | ||
|
|
ac6a4cd707 | ||
|
|
7d615a3fe5 | ||
|
|
5793ecd165 | ||
|
|
b18feb98e5 | ||
|
|
df227be37c | ||
|
|
2fc2928978 | ||
|
|
3d406e5a8d | ||
|
|
e15b439bf3 | ||
|
|
c2ed5feee5 | ||
|
|
6b6934b009 | ||
|
|
72e6888dc3 | ||
|
|
0551d1c56e | ||
|
|
a5df78e0f0 | ||
|
|
cc5e3dbf24 | ||
|
|
2a1189ebc3 | ||
|
|
36a6c0df46 | ||
|
|
fcebf27a9f | ||
|
|
4847836310 | ||
|
|
42ba7974c5 | ||
|
|
cfd1b8eae2 | ||
|
|
37a47c0eec | ||
|
|
3361e662f4 | ||
|
|
55dd45239a | ||
|
|
e0946dca69 | ||
|
|
6bc35a351a | ||
|
|
b896bf8f5a | ||
|
|
0c6faaab43 | ||
|
|
97e3e84c2c | ||
|
|
f80e7bb61b | ||
|
|
af395e61d5 | ||
|
|
a18d789684 | ||
|
|
4c184e9d6b | ||
|
|
ed420fb691 | ||
|
|
69b1e32c8a | ||
|
|
373f855684 | ||
|
|
88411fb6f9 | ||
|
|
733e3f6f98 | ||
|
|
10b8d2a4ea | ||
|
|
973afcbb20 | ||
|
|
a009c0fb40 | ||
|
|
4bb60c05bf | ||
|
|
cb144c0097 | ||
|
|
cd1a76a492 | ||
|
|
120e1aa4bd | ||
|
|
6b4066585f | ||
|
|
1ee82b545b | ||
|
|
78d7466713 | ||
|
|
df28c4d912 | ||
|
|
727c7ff85d | ||
|
|
032c9178ca | ||
|
|
d726246f78 | ||
|
|
def0866ded | ||
|
|
737c992431 | ||
|
|
d3f3878ffd | ||
|
|
8cdec4c434 | ||
|
|
f5d06efbab | ||
|
|
1ced5562cd | ||
|
|
993c988895 | ||
|
|
e0ce728579 | ||
|
|
1c005b557a | ||
|
|
969d2bf448 | ||
|
|
66b10d6d12 | ||
|
|
1a72933143 | ||
|
|
e1710f34bb | ||
|
|
e4e703ab60 | ||
|
|
acb6c06207 | ||
|
|
77ceb3ee47 | ||
|
|
9809038b9d | ||
|
|
425c04e4dc | ||
|
|
d303d9973f | ||
|
|
4b7097b96c | ||
|
|
739b751046 | ||
|
|
b1002e98e0 | ||
|
|
65d95caad5 | ||
|
|
d95c6154ff | ||
|
|
e52c998c49 | ||
|
|
d38d047eec | ||
|
|
0e9f3dba75 | ||
|
|
cc755853c2 | ||
|
|
54c2e9859f | ||
|
|
599cb41f99 | ||
|
|
263f7831df | ||
|
|
b88b75f55f | ||
|
|
437b17964c | ||
|
|
bc1bb7f8c5 | ||
|
|
3505e88b18 | ||
|
|
801e47e089 | ||
|
|
79dc8f5ddd | ||
|
|
a8b45b7a4c | ||
|
|
7f2eebf519 | ||
|
|
80cca53611 | ||
|
|
b93f586954 | ||
|
|
00744b053f | ||
|
|
f784c60cd6 | ||
|
|
d6c8f0de28 | ||
|
|
56846d7873 | ||
|
|
984ae7f72d | ||
|
|
e5b345aff3 | ||
|
|
de27324711 | ||
|
|
56011918e6 | ||
|
|
a91bc7a19b | ||
|
|
c3180c4a05 | ||
|
|
a64b39aef8 | ||
|
|
51d96a1703 | ||
|
|
2a19866a74 | ||
|
|
455ef6f2f5 | ||
|
|
123a3383a0 | ||
|
|
2ee3bcb877 | ||
|
|
b6f558adcc | ||
|
|
4e4ea46cfe | ||
|
|
4065741a67 | ||
|
|
43d6b44a9f | ||
|
|
b9a017d94c | ||
|
|
81b34dce61 | ||
|
|
5cd6cce5a4 | ||
|
|
57c39ecbcd | ||
|
|
7c9d690f9e | ||
|
|
6ba05212f7 | ||
|
|
4686b8cea5 | ||
|
|
45e2aee8f9 | ||
|
|
78ba413ed1 | ||
|
|
d8983d4bd4 | ||
|
|
c96e42006d | ||
|
|
72ee3f920b | ||
|
|
839ea48aa9 | ||
|
|
210a66fbf8 | ||
|
|
17575403d4 | ||
|
|
1f727f3f3d | ||
|
|
3af008d405 | ||
|
|
2a8dc7fb53 | ||
|
|
d571eab3b2 | ||
|
|
5d833fd458 | ||
|
|
a6d006d9db | ||
|
|
41c2e07a8d | ||
|
|
e4d5e22c91 | ||
|
|
c2b7642d4d | ||
|
|
580370bea3 | ||
|
|
7a0aa25c28 | ||
|
|
f3cc6576ee | ||
|
|
734a183c56 | ||
|
|
bd0806e1f5 | ||
|
|
c6f9c46223 | ||
|
|
ad0267b2ad | ||
|
|
c82c69bb56 | ||
|
|
b6884f8a87 | ||
|
|
8b80e949ea | ||
|
|
d04c7ca0b6 | ||
|
|
68f7b422c1 | ||
|
|
f1d273a0b0 | ||
|
|
93d8455faa | ||
|
|
003bf24723 | ||
|
|
7ed8fc8f7d | ||
|
|
f9df76f8b3 | ||
|
|
e2dbf44116 | ||
|
|
eaa9f35540 | ||
|
|
c2aa918c53 | ||
|
|
19bb62e2ec | ||
|
|
f9dfc5f8a4 | ||
|
|
8646b50aa9 | ||
|
|
f28407943f | ||
|
|
eec99ffa8c | ||
|
|
34e818042e | ||
|
|
f0d314bd6d | ||
|
|
fa2e84caa8 | ||
|
|
f96c310eea | ||
|
|
0abad40f41 | ||
|
|
e3ac180ab3 | ||
|
|
6380869f27 | ||
|
|
2b6f9152cc | ||
|
|
285db7a240 | ||
|
|
dcf5182a96 | ||
|
|
4b5ae31404 | ||
|
|
d5537e7d6b | ||
|
|
d488f03229 | ||
|
|
a8eb702093 | ||
|
|
d74c147223 | ||
|
|
10c992e861 | ||
|
|
b3caba849d | ||
|
|
23b5a006d4 | ||
|
|
a665b90623 | ||
|
|
3fbea6029d | ||
|
|
e8cc9254e0 | ||
|
|
48275c7836 | ||
|
|
246fecee27 | ||
|
|
feb2c7bc47 | ||
|
|
2bc76bcdab | ||
|
|
efb3e7ca00 | ||
|
|
8c8fb67fc2 | ||
|
|
dc1d157878 | ||
|
|
d27833ba7c | ||
|
|
f3bf89ebcc | ||
|
|
0bd2a9b7b1 | ||
|
|
b4215f956f | ||
|
|
5698953948 | ||
|
|
9752ee8ed2 | ||
|
|
df27c64041 | ||
|
|
f53fcc0746 | ||
|
|
bdd0bc83eb | ||
|
|
7957fc4a44 | ||
|
|
c5a120c443 | ||
|
|
fa46385164 | ||
|
|
bf16937869 | ||
|
|
d2dbc65f00 | ||
|
|
9dfbce0aa7 | ||
|
|
b726d66882 | ||
|
|
1ec2023cbf | ||
|
|
9d6a92b4d0 | ||
|
|
bf1f22cc99 | ||
|
|
f476655fee | ||
|
|
f73526f58c | ||
|
|
9dd81df8b2 | ||
|
|
99c443facc | ||
|
|
d0837dcceb | ||
|
|
71e88f761d | ||
|
|
04b60e9274 | ||
|
|
40102ae014 | ||
|
|
a29a3ed3c3 | ||
|
|
e8aab3a7fd | ||
|
|
434031719e | ||
|
|
c99cb20715 | ||
|
|
28ba0450e9 | ||
|
|
1c7a509bed | ||
|
|
787f6ce04a | ||
|
|
2fc126b00d | ||
|
|
9c030e81a4 | ||
|
|
590fbd8961 | ||
|
|
bf8943b0f6 | ||
|
|
c50a90c9e6 | ||
|
|
fbfde21e7c | ||
|
|
578b236a19 | ||
|
|
d021284bcf | ||
|
|
2055b04c11 | ||
|
|
2e35c68122 | ||
|
|
c35503e0f7 | ||
|
|
8650404df1 | ||
|
|
531cc58d89 | ||
|
|
8dc1da2cbe | ||
|
|
bfeabea631 | ||
|
|
c3bb6d77dd | ||
|
|
4f1309080a | ||
|
|
d2d3f0d747 | ||
|
|
553f37da71 | ||
|
|
93b9015760 | ||
|
|
b254d330e4 | ||
|
|
3e11d85c77 | ||
|
|
dab3ebce4c | ||
|
|
4f5ce1fa43 | ||
|
|
4b099d06b1 | ||
|
|
0fddc5ab5c | ||
|
|
e0dc3d5efb | ||
|
|
bea003e94c | ||
|
|
57f67ce855 | ||
|
|
fa01faaa4a | ||
|
|
25d906dbde | ||
|
|
7cfc9a4f64 | ||
|
|
338d98be97 | ||
|
|
7bcb3fb02d | ||
|
|
5e8f362c9e | ||
|
|
a164d603d3 | ||
|
|
404c834e14 | ||
|
|
87e80b6aac | ||
|
|
158e998876 | ||
|
|
75b786c5ef | ||
|
|
a625812bec | ||
|
|
3b78d5237d | ||
|
|
3cef00c4ca | ||
|
|
d80d832ae9 | ||
|
|
ae8b9baa04 | ||
|
|
b3a348c03c | ||
|
|
e34b004422 | ||
|
|
64d8ed502d | ||
|
|
07eb1c7dc8 | ||
|
|
8f90f632f5 | ||
|
|
e5ffacc434 | ||
|
|
651549594e | ||
|
|
302b6c99a7 | ||
|
|
0bcc0cf95d | ||
|
|
b64da4d8b5 | ||
|
|
3a7c47af0e | ||
|
|
57d74a45a0 | ||
|
|
c1f246fedf | ||
|
|
eac4e1e939 | ||
|
|
4a55175bac | ||
|
|
2908ab3eed | ||
|
|
1e050a77ff | ||
|
|
0869631d7d | ||
|
|
0b7ccf835b | ||
|
|
d0f26440ee | ||
|
|
d202f43fff | ||
|
|
cdd17eee37 | ||
|
|
8804023825 | ||
|
|
99d895014d | ||
|
|
8dbe767340 | ||
|
|
1e4a4d48ae | ||
|
|
6a77b6f43c | ||
|
|
fb7e2ff493 | ||
|
|
db7351d313 | ||
|
|
08ac12d5e7 | ||
|
|
c0e17bca90 | ||
|
|
9dbeacf303 | ||
|
|
aaecbb1818 | ||
|
|
ff1eca3b6f | ||
|
|
e97023804a | ||
|
|
0987f290a7 | ||
|
|
509650ec4c | ||
|
|
cba6186325 | ||
|
|
3e0ed83bc8 | ||
|
|
57af48d734 | ||
|
|
da9da0d8c2 | ||
|
|
028ff30947 | ||
|
|
7e85d4f5f6 | ||
|
|
f6f32f39e4 | ||
|
|
aaf25ec6bd | ||
|
|
e471ea7890 | ||
|
|
00ad13eb71 | ||
|
|
2e905d4540 | ||
|
|
3b02ccd201 | ||
|
|
3ec482a379 | ||
|
|
b21a8412c4 | ||
|
|
00b36ef06a | ||
|
|
5378a1a63e | ||
|
|
f94f8463b0 | ||
|
|
4c62215bd1 | ||
|
|
42d71b9af3 | ||
|
|
f867dc6b29 | ||
|
|
f3bd9a2797 | ||
|
|
00d53d5fc1 | ||
|
|
5edf6a56c4 | ||
|
|
44394cd246 | ||
|
|
a5baf13a06 | ||
|
|
a057f40155 | ||
|
|
de53e0955d | ||
|
|
9258e57a50 | ||
|
|
e492861749 | ||
|
|
6521c4b215 | ||
|
|
530ebd8976 | ||
|
|
5b2726fc61 | ||
|
|
2c3db52356 | ||
|
|
9290854163 | ||
|
|
4bfdb01f78 | ||
|
|
c8890e3ac1 | ||
|
|
193f9b26a0 | ||
|
|
86ae68a5f7 | ||
|
|
2cd98b2782 | ||
|
|
2de11c9e9e | ||
|
|
13e2049c32 | ||
|
|
62f3a4d2d8 | ||
|
|
cd3b6070aa | ||
|
|
2aca834724 | ||
|
|
e50c9bd7cd | ||
|
|
d184e8d0ba | ||
|
|
74e6135c4f | ||
|
|
1e80265c36 | ||
|
|
a058fab118 | ||
|
|
8bc7b4f926 | ||
|
|
fb220314ec | ||
|
|
b9601b8353 | ||
|
|
ced0c17f21 | ||
|
|
1445a74d76 | ||
|
|
14472d62ba | ||
|
|
a6a7a3a074 | ||
|
|
ccdea661fa | ||
|
|
678cc4e375 | ||
|
|
8eb111dfb8 | ||
|
|
0782309713 | ||
|
|
4607cbcb0d | ||
|
|
fc935495c8 | ||
|
|
75d79f3dad | ||
|
|
4dc602f79b | ||
|
|
6ce8e57989 | ||
|
|
089bdc0be4 | ||
|
|
71271cf905 | ||
|
|
c75ae0846e | ||
|
|
4b9b8e1282 | ||
|
|
310beb73a8 | ||
|
|
c164f59631 | ||
|
|
f67e1fadb0 | ||
|
|
d22ffd8c28 | ||
|
|
0050480c0e | ||
|
|
de2c5ab2ac | ||
|
|
8bc9966763 | ||
|
|
274a7a68b8 | ||
|
|
956c192841 | ||
|
|
687029cbbd | ||
|
|
9f2961f259 | ||
|
|
e55c6999ae | ||
|
|
a61c5c5b3a | ||
|
|
8d8c1b6624 | ||
|
|
c75548300d | ||
|
|
d7985ebead | ||
|
|
4a52a9212c | ||
|
|
7639eae891 | ||
|
|
74ed1ba9f9 | ||
|
|
422d1ac8d2 | ||
|
|
5226181329 | ||
|
|
10330b8782 | ||
|
|
731e99025b | ||
|
|
53d2db31c6 | ||
|
|
01760967b4 | ||
|
|
aaa6205d5a | ||
|
|
cf37c04347 | ||
|
|
542b03ee00 | ||
|
|
740fcdae7d | ||
|
|
3a1c609ac4 | ||
|
|
776934aa08 | ||
|
|
b622a7fe3f | ||
|
|
513105c6ac | ||
|
|
27182e1ddb | ||
|
|
fd32bb1991 | ||
|
|
b6f921e5cb | ||
|
|
38200c2000 | ||
|
|
f36080a05d | ||
|
|
d8923457b8 | ||
|
|
06e3f1757e | ||
|
|
01bbbc27bf | ||
|
|
474c6a5271 | ||
|
|
271252eff7 | ||
|
|
88e944b5a3 | ||
|
|
428b9fcd87 | ||
|
|
7278556c76 | ||
|
|
49e3fd1ce8 | ||
|
|
6308a8b06d | ||
|
|
48874703d2 | ||
|
|
4de7699855 | ||
|
|
83308fdff9 | ||
|
|
efe5245e47 | ||
|
|
c3e2990359 | ||
|
|
8cb79dad0b | ||
|
|
fba86dd42b | ||
|
|
359dc6fa76 | ||
|
|
c03d8473ea | ||
|
|
ce8730b508 | ||
|
|
60cc666c94 | ||
|
|
57c618b0ed | ||
|
|
112302d41a | ||
|
|
eccc97f15a | ||
|
|
ba23023464 | ||
|
|
131aaeb634 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,13 +1,16 @@
|
|||||||
*.5
|
*.5
|
||||||
|
*.7
|
||||||
*.8
|
*.8
|
||||||
*.a
|
*.a
|
||||||
*.d
|
*.d
|
||||||
*.o
|
*.o
|
||||||
|
*.orig
|
||||||
*.pc
|
*.pc
|
||||||
*.pot
|
*.pot
|
||||||
|
*.rej
|
||||||
*.so
|
*.so
|
||||||
*.so.*
|
*.so.*
|
||||||
*.swp
|
*.sw*
|
||||||
*~
|
*~
|
||||||
|
|
||||||
.export.sym
|
.export.sym
|
||||||
@@ -17,11 +20,11 @@
|
|||||||
Makefile
|
Makefile
|
||||||
make.tmpl
|
make.tmpl
|
||||||
|
|
||||||
configure.h
|
|
||||||
version.h
|
|
||||||
|
|
||||||
/autom4te.cache/
|
/autom4te.cache/
|
||||||
|
/autoscan.log
|
||||||
/config.log
|
/config.log
|
||||||
/config.status
|
/config.status
|
||||||
|
/configure.scan
|
||||||
/cscope.out
|
/cscope.out
|
||||||
|
/tags
|
||||||
/tmp/
|
/tmp/
|
||||||
|
|||||||
64
Makefile.in
64
Makefile.in
@@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of LVM2.
|
# This file is part of LVM2.
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
abs_top_builddir = @abs_top_builddir@
|
||||||
|
abs_top_srcdir = @abs_top_srcdir@
|
||||||
|
|
||||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||||
|
|
||||||
@@ -91,10 +93,47 @@ cscope.out:
|
|||||||
all: cscope.out
|
all: cscope.out
|
||||||
endif
|
endif
|
||||||
DISTCLEAN_TARGETS += cscope.out
|
DISTCLEAN_TARGETS += cscope.out
|
||||||
|
CLEAN_DIRS += autom4te.cache
|
||||||
|
|
||||||
check check_system check_cluster check_local check_lvmetad unit: all
|
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
|
||||||
$(MAKE) -C test $(@)
|
$(MAKE) -C test $(@)
|
||||||
|
|
||||||
|
conf.generate: tools
|
||||||
|
|
||||||
|
# how to use parenthesis in makefiles
|
||||||
|
leftparen:=(
|
||||||
|
LVM_VER := $(firstword $(subst $(leftparen), ,$(LVM_VERSION)))
|
||||||
|
VER := LVM2.$(LVM_VER)
|
||||||
|
# release file name
|
||||||
|
FILE_VER := $(VER).tgz
|
||||||
|
CLEAN_TARGETS += $(FILE_VER)
|
||||||
|
CLEAN_DIRS += $(rpmbuilddir)
|
||||||
|
|
||||||
|
dist:
|
||||||
|
@echo "Generating $(FILE_VER)";\
|
||||||
|
(cd $(top_srcdir); git ls-tree -r HEAD --name-only | xargs tar --transform "s,^,$(VER)/," -c) | gzip >$(FILE_VER)
|
||||||
|
|
||||||
|
rpm: dist
|
||||||
|
$(RM) -r $(rpmbuilddir)/SOURCES
|
||||||
|
$(MKDIR_P) $(rpmbuilddir)/SOURCES
|
||||||
|
$(LN_S) -f $(abs_top_builddir)/$(FILE_VER) $(rpmbuilddir)/SOURCES
|
||||||
|
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
|
||||||
|
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
||||||
|
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
||||||
|
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
|
||||||
|
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
|
||||||
|
sed -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
||||||
|
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
||||||
|
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
|
||||||
|
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
||||||
|
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||||
|
|
||||||
|
generate: conf.generate
|
||||||
|
$(MAKE) -C conf generate
|
||||||
|
|
||||||
|
all_man:
|
||||||
|
$(MAKE) -C man all_man
|
||||||
|
|
||||||
install_system_dirs:
|
install_system_dirs:
|
||||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||||
@@ -114,6 +153,9 @@ install_systemd_generators:
|
|||||||
install_systemd_units:
|
install_systemd_units:
|
||||||
$(MAKE) -C scripts install_systemd_units
|
$(MAKE) -C scripts install_systemd_units
|
||||||
|
|
||||||
|
install_all_man:
|
||||||
|
$(MAKE) -C man install_all_man
|
||||||
|
|
||||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||||
install_python_bindings:
|
install_python_bindings:
|
||||||
$(MAKE) -C liblvm/python install_python_bindings
|
$(MAKE) -C liblvm/python install_python_bindings
|
||||||
@@ -122,8 +164,11 @@ endif
|
|||||||
install_tmpfiles_configuration:
|
install_tmpfiles_configuration:
|
||||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||||
|
|
||||||
LCOV_TRACES = libdm.info lib.info tools.info \
|
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||||
daemons/dmeventd.info daemons/clvmd.info
|
libdaemon/client.info libdaemon/server.info \
|
||||||
|
daemons/clvmd.info daemons/dmeventd.info \
|
||||||
|
daemons/lvmetad.info
|
||||||
|
|
||||||
CLEAN_TARGETS += $(LCOV_TRACES)
|
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||||
|
|
||||||
ifneq ("$(LCOV)", "")
|
ifneq ("$(LCOV)", "")
|
||||||
@@ -152,7 +197,7 @@ lcov: $(LCOV_TRACES)
|
|||||||
$(RM) -r $(LCOV_REPORTS_DIR)
|
$(RM) -r $(LCOV_REPORTS_DIR)
|
||||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||||
for i in $(LCOV_TRACES); do \
|
for i in $(LCOV_TRACES); do \
|
||||||
test -s $$i && lc="$$lc $$i"; \
|
test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
|
||||||
done; \
|
done; \
|
||||||
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
||||||
-o $(LCOV_REPORTS_DIR) $$lc
|
-o $(LCOV_REPORTS_DIR) $$lc
|
||||||
@@ -184,3 +229,12 @@ memcheck: test-programs
|
|||||||
ruby-test:
|
ruby-test:
|
||||||
$(RUBY) report-generators/test/ts.rb
|
$(RUBY) report-generators/test/ts.rb
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(shell which ctags),)
|
||||||
|
.PHONY: tags
|
||||||
|
tags:
|
||||||
|
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||||
|
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||||
|
|
||||||
|
CLEAN_TARGETS += tags
|
||||||
|
endif
|
||||||
|
|||||||
2
README
2
README
@@ -18,7 +18,7 @@ Mailing list for general discussion related to LVM2:
|
|||||||
|
|
||||||
Mailing lists for LVM2 development, patches and commits:
|
Mailing lists for LVM2 development, patches and commits:
|
||||||
lvm-devel@redhat.com
|
lvm-devel@redhat.com
|
||||||
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
|
Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
|
||||||
|
|
||||||
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
|
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
|
||||||
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
|
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.02.91-git (2014-11-11)
|
1.02.111-git (2015-10-30)
|
||||||
|
|||||||
363
WHATS_NEW
363
WHATS_NEW
@@ -1,3 +1,366 @@
|
|||||||
|
Version 2.02.134 -
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Version 2.02.133 - 30th October 2015
|
||||||
|
====================================
|
||||||
|
Support repeated -o|--options for reporting commands.
|
||||||
|
Support -o- and -o# for reporting commands to remove and compact fields.
|
||||||
|
Fix missing PVs from pvs output if vgremove is run concurrently.
|
||||||
|
Remove unwanted error message when running pvs/vgs/lvs and vgremove at once.
|
||||||
|
Check newly created VG's metadata do not overlap in metadata ring buffer.
|
||||||
|
Check metadata area size is at least the minimum size defined for the format.
|
||||||
|
Thin pool targets uses low_water_mark from profile.
|
||||||
|
Dropping 'yet' from error of unsupported thick snapshot of snapshots.
|
||||||
|
Do not support unpartitioned DASD devices with CDL formatted with pvcreate.
|
||||||
|
For thins use flush for suspend only when volume size is reduced.
|
||||||
|
Enable code which detects the need of flush during suspend.
|
||||||
|
Ensure --use-policy will resize volume to fit below threshold.
|
||||||
|
Correct percentage evaluation when checking thin-pool over threshold.
|
||||||
|
Fix lvmcache to move PV from VG to orphans if VG is removed and lvmetad used.
|
||||||
|
Fix lvmcache to not cache even invalid info about PV which got removed.
|
||||||
|
Support checking of memlock daemon counter.
|
||||||
|
Allow all log levels to be used with the lvmetad -l option.
|
||||||
|
Add optional shutdown when idle support for lvmetad.
|
||||||
|
Fix missing in-sync progress info while lvconvert used with lvmpolld.
|
||||||
|
Add report/compact_output_cols to lvm.conf to define report cols to compact.
|
||||||
|
Do not change logging in lvm2 library when it's already set.
|
||||||
|
Check for enough space in thin-pool in command before creating new thin.
|
||||||
|
Make libblkid detect all copies of the same signature if use_blkid_wiping=1.
|
||||||
|
Fix vgimportclone with -n to not add number unnecessarily to base VG name.
|
||||||
|
Cleanup vgimportclone script and remove dependency on awk, grep, cut and tr.
|
||||||
|
Add vg_missing_pv_count report field to report number of missing PVs in a VG.
|
||||||
|
Properly identify internal LV holding sanlock locks within lv_role field.
|
||||||
|
Add metadata_devices and seg_metadata_le_ranges report fields for raid vols.
|
||||||
|
Fix lvm2-{activation,clvmd,cmirrord,monitor} service to exec before mounting.
|
||||||
|
|
||||||
|
Version 2.02.132 - 22nd September 2015
|
||||||
|
======================================
|
||||||
|
Fix lvmconf to set locking_type=2 if external locking library is requested.
|
||||||
|
Remove verbose message when rescanning an unchanged device. (2.02.119)
|
||||||
|
Add origin_uuid, mirror_log_uuid, move_pv_uuid, convert_lv_uuid report fields.
|
||||||
|
Add pool_lv_uuid, metadata_lv_uuid, data_lv_uuid reporting fields.
|
||||||
|
Fix PV label processing failure after pvcreate in lvm shell with lvmetad.
|
||||||
|
|
||||||
|
Version 2.02.131 - 15th September 2015
|
||||||
|
======================================
|
||||||
|
Rename 'make install_full_man' to install_all_man and add all_man target.
|
||||||
|
Fix vgimportclone cache_dir path name (2.02.115).
|
||||||
|
Swapping of LV identifiers handles more complex LVs.
|
||||||
|
Use passed list of PVS when allocating space in lvconvert --thinpool.
|
||||||
|
Disallow usage of --stripe and --stripesize when creating cache pool.
|
||||||
|
Warn user when caching raid or thin pool data LV.
|
||||||
|
When layering LV, move LV flags with segments.
|
||||||
|
Ignore persistent cache if configuration changed. (2.02.127)
|
||||||
|
Fix devices/filter to be applied before disk-accessing filters. (2.02.112)
|
||||||
|
Make tags only when requested via 'make tags'.
|
||||||
|
Configure supports --disable-dependency-tracking for one-time builds.
|
||||||
|
Fix usage of configure.h when building in srcdir != builddir.
|
||||||
|
|
||||||
|
Version 2.02.130 - 5th September 2015
|
||||||
|
=====================================
|
||||||
|
Fix use of uninitialized device status if reading outdated .cache record.
|
||||||
|
Restore support for --monitor option in lvcreate (2.02.112).
|
||||||
|
Read thin-pool data and metadata percent without flush.
|
||||||
|
Detect blocked thin-pool and avoid scanning their thin volumes.
|
||||||
|
Check if dm device is usable before checking its size (2.02.116).
|
||||||
|
Extend parsing of cache_check version in configure.
|
||||||
|
Make lvpoll error messages visible in lvmpolld's stderr and in syslog.
|
||||||
|
Add 'make install_full_man' to install all man pages regardless of config.
|
||||||
|
|
||||||
|
Version 2.02.129 - 26th August 2015
|
||||||
|
===================================
|
||||||
|
Drop error message when vgdisplay encounters an exported VG. (2.02.27)
|
||||||
|
Fix shared library generation to stop exporting internal functions.(2.02.120)
|
||||||
|
Accept --cachemode with lvconvert.
|
||||||
|
Fix and improve reporting properties of cache-pool.
|
||||||
|
Enable usage of --cachepolicy and --cachesetting with lvconvert.
|
||||||
|
Don't allow to reduce size of thin-pool metadata.
|
||||||
|
Fix debug buffer overflows in cmirrord logging.
|
||||||
|
Add --foreground and --help to cmirrord.
|
||||||
|
|
||||||
|
Version 2.02.128 - 17th August 2015
|
||||||
|
===================================
|
||||||
|
Allocation setting cache_pool_cachemode is replaced by cache_mode.
|
||||||
|
Don't attempt to close config file that couldn't be opened.
|
||||||
|
Check for valid cache mode in validation of cache segment.
|
||||||
|
Change internal interface handling cache mode and policy.
|
||||||
|
When no cache policy specified, prefer smq (if available) over mq.
|
||||||
|
Add demo cache-mq and cache-smq profiles.
|
||||||
|
Add cmd profilable allocation/cache_policy,cache_settings,cache_mode.
|
||||||
|
Require cache_check 0.5.4 for use of --clear-needs-check-flag.
|
||||||
|
Fix lvmetad udev rules to not override SYSTEMD_WANTS, add the service instead.
|
||||||
|
|
||||||
|
Version 2.02.127 - 10th August 2015
|
||||||
|
===================================
|
||||||
|
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
|
||||||
|
Order fields in struct cmd_context more logically.
|
||||||
|
Add lock_type to lvmcache VG summary and info structs.
|
||||||
|
Fix regression in cache causing some PVs to bypass filters (2.02.105).
|
||||||
|
Make configure --enable-realtime the default now.
|
||||||
|
Update .gitignore and configure.in files to reflect usage of current tree.
|
||||||
|
|
||||||
|
Version 2.02.126 - 24th July 2015
|
||||||
|
=================================
|
||||||
|
Fix long option hyphen removal. (2.02.122)
|
||||||
|
Fix clvmd freeze if client disappears without first releasing its locks.
|
||||||
|
Fix lvconvert segfaults while performing snapshots merge.
|
||||||
|
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
|
||||||
|
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
|
||||||
|
Fix alloc segfault when extending LV with fewer stripes than in first seg.
|
||||||
|
Fix handling of cache policy name.
|
||||||
|
Set cache policy before with the first lvm2 cache pool metadata commit.
|
||||||
|
Fix detection of thin-pool overprovisioning (2.02.124).
|
||||||
|
Fix lvmpolld segfaults on 32 bit architectures.
|
||||||
|
Add lvmlockd lock_args validation to vg_validate.
|
||||||
|
Fix ignored --startstopservices option if running lvmconf with systemd.
|
||||||
|
Hide sanlock LVs when processing LVs in VG unless named or --all used.
|
||||||
|
|
||||||
|
Version 2.02.125 - 7th July 2015
|
||||||
|
================================
|
||||||
|
Fix getline memory usage in lvmpolld.
|
||||||
|
Add support --clear-needs-check-flag for cache_check of cache pool metadata.
|
||||||
|
Add lvmetactl for developer use only.
|
||||||
|
Rename global/lock_retries to lvmlockd_retries.
|
||||||
|
Replace --enable-lvmlockd by --enable-lockd-sanlock and --enable-lockd-dlm.
|
||||||
|
|
||||||
|
Version 2.02.124 - 3rd July 2015
|
||||||
|
================================
|
||||||
|
Move sending thin pool messages from resume to suspend phase.
|
||||||
|
Report warning when pool is overprovisioned and not auto resized.
|
||||||
|
Recognize free-form date/time values for lv_time field in selection criteria.
|
||||||
|
Added experimental lvmlockd with configure --enable-lvmlockd.
|
||||||
|
Fix regression in select to match string fields if using synonyms (2.02.123).
|
||||||
|
Fix regression when printing more lv names via display_lvname (2.02.122).
|
||||||
|
Add missing error logging to unlock_vg and sync_local_dev_names callers.
|
||||||
|
|
||||||
|
Version 2.02.123 - 30th June 2015
|
||||||
|
=================================
|
||||||
|
Add report/time_format lvm.conf option to define time format for report.
|
||||||
|
Fix makefile shell compare == when building lvmetad lvmpolld (2.02.120).
|
||||||
|
Add --type full to lvmconfig for full configuration tree view.
|
||||||
|
Add undocumented environment variables to lvm man page. (2.02.119)
|
||||||
|
Add device synchronization point before activating a new snapshot.
|
||||||
|
Add --withspaces to lvmconfig to add spaces in output for better readability.
|
||||||
|
Add custom main function to libdaemon.
|
||||||
|
Use lvmetad to track out-of-date metadata discovered.
|
||||||
|
|
||||||
|
Version 2.02.122 - 20th June 2015
|
||||||
|
=================================
|
||||||
|
Flush stdout before printing to stderr.
|
||||||
|
Use pre-allocated buffer for printed LV names in display_lvname.
|
||||||
|
Support thins with size of external origin unaligned with thin pool chunk.
|
||||||
|
Allow extension of reduced thin volumes with external origins.
|
||||||
|
Consider snapshot and origin LV as unusable if component devices suspended.
|
||||||
|
Fix lvmconfig segfault on settings with undefined default value (2.02.120).
|
||||||
|
Add explicit 's' (shared) LV activation mode.
|
||||||
|
Ignore hyphens in long options names (i.e. --long-option == --longoption).
|
||||||
|
|
||||||
|
Version 2.02.121 - 12th June 2015
|
||||||
|
=================================
|
||||||
|
Distinguish between on-disk and lvmetad versions of text metadata.
|
||||||
|
Remove DL_LIBS from Makefiles for daemons that don't need them.
|
||||||
|
Zero errno in before strtoul call in dmsetup if tested after the call.
|
||||||
|
Zero errno in before strtoul call in lvmpolld.
|
||||||
|
Fix a segfault in pvscan --cache --background command.
|
||||||
|
Fix test for AREA_PV when checking for failed mirrors.
|
||||||
|
Do not use --sysinit in lvm2-activation{-early,-net}.service if lvmpolld used.
|
||||||
|
Maintain outdated PV info in lvmetad till all old metadata is gone from disk.
|
||||||
|
Do not fail polling when poll LV not found (already finished or removed).
|
||||||
|
Replace poll_get_copy_vg/lv fns with vg_read() and find_lv() in polldaemon.
|
||||||
|
Close all device fds only in before sleep call in polldaemon.
|
||||||
|
Simplify Makefile targets that generate exported symbols.
|
||||||
|
Move various -D settings from Makefiles to configure.h.
|
||||||
|
|
||||||
|
Version 2.02.120 - 15th May 2015
|
||||||
|
================================
|
||||||
|
Make various adjustments to Makefile compilation flags.
|
||||||
|
Add lvmpolld debug message class.
|
||||||
|
Add lvmpolld client mode for querying running server instance for status info.
|
||||||
|
Fix some libdaemon socket creation and reuse error paths.
|
||||||
|
Daemons (libdaemon) support exit on idle also in non-systemd environment.
|
||||||
|
Provide make dist and make rpm targets
|
||||||
|
Configure lvm.conf for use_lvmetad and use_lvmpolld.
|
||||||
|
Add lvpoll for cmdline communication with lvmpolld.
|
||||||
|
Add lvmpolld acting as a free-standing version of polldaemon.
|
||||||
|
Avoid repeated identical lvmetad VG lookups in commands processing all VGs.
|
||||||
|
Handle switches to alternative duplicate PVs efficiently with lvmetad.
|
||||||
|
Properly validate PV size for pvcreate --restorefile.
|
||||||
|
Fix check if pvcreate wiped device (2.02.117).
|
||||||
|
Fix storing of vgid when caching metadata (2.02.118).
|
||||||
|
Fix recursive lvm-config man page. (2.02.119)
|
||||||
|
Refactor polldaemon interfaces to poll every operation by VG/LV couple
|
||||||
|
Skip wait after testing in _wait_for_single_lv when polling finished
|
||||||
|
Return 'None' in python for empty string properties instead of crashing.
|
||||||
|
Distinguish signed numerical property type in reports for lvm2app library.
|
||||||
|
Reread raid completion status immediately when progress appears to be zero.
|
||||||
|
lvm2app closes locking on lvm_quit().
|
||||||
|
Configure detects /run or /var/run.
|
||||||
|
Add missing newline in clvmd --help output.
|
||||||
|
|
||||||
|
Version 2.02.119 - 2nd May 2015
|
||||||
|
===============================
|
||||||
|
New LVM_LOG_FILE_EPOCH, LVM_EXPECTED_EXIT_STATUS env vars. Man page to follow.
|
||||||
|
Remove detailed content from lvm.conf man page: use lvmconfig instead.
|
||||||
|
Generate complete config files with lvmconfig or 'make generate'.
|
||||||
|
Also display info on deprecated config with lvmconfig --withcomments.
|
||||||
|
Display version since which config is deprecated in lvmconfig --withversions.
|
||||||
|
Add --showdeprecated to lvmconfig to also display deprecated settings.
|
||||||
|
Hide deprecated settings in lvmconfig output for all types but current,diff.
|
||||||
|
Introduce support for exit on idle feature in libdaemon
|
||||||
|
Add --showunsupported to lvmconfig to also display unsupported settings.
|
||||||
|
Display unsupported settings for lvmconfig --type current,diff only by default
|
||||||
|
Honour lvmconfig --ignoreunsupported and --ignoreadvanced for all --type.
|
||||||
|
Make python bindings usable with python3 (and compatible with 2.6 & 2.7).
|
||||||
|
Add lvmconfig -l|--list as shortcut for lvmconfig --type list --withsummary.
|
||||||
|
Add lvmconfig --type list to display plain list of configuration settings.
|
||||||
|
Introduce lvmconfig as the preferred form of 'lvm dumpconfig'.
|
||||||
|
Add lv_ancestors and lv_descendants reporting fields.
|
||||||
|
Add --ignorelocal option to dumpconfig to ignore the local section.
|
||||||
|
Close connection to lvmetad after fork.
|
||||||
|
Make lvchange able to resume background pvmove polling again.
|
||||||
|
Split pvmove update metadata fn in an initial one and a subsequent one.
|
||||||
|
Refactor shared pvmove and lvconvert code into new _poll files.
|
||||||
|
Add --unconfigured option to dumpconfig to print strings unconfigured.
|
||||||
|
Add --withsummary option to dumpconfig to print first line - summary comment.
|
||||||
|
Use number of device holders to help choose between duplicate PVs.
|
||||||
|
Try to make lvmetad and non-lvmetad duplicate PV handling as similar as poss.
|
||||||
|
Issue warnings about duplicate PVs discovered by lvmetad.
|
||||||
|
Track alternative devices with matching PVIDs in lvmetad.
|
||||||
|
Check for lvm binary in blkdeactivate and skip LVM processing if not present.
|
||||||
|
Add --enable-halvm and --disable-halvm options to lvmconf script.
|
||||||
|
Add --services, --mirrorservice and --startstopservices option to lvmconf.
|
||||||
|
Use proper default value of global/use_lvmetad when processing lvmconf script.
|
||||||
|
Respect allocation/cling_tag_list during intial contiguous allocation.
|
||||||
|
Add A_PARTITION_BY_TAGS set when allocated areas should not share tags.
|
||||||
|
Make changes persist with python addTag/removeTag.
|
||||||
|
Set correct vgid when updating cache when writing PV metadata.
|
||||||
|
More efficient clvmd singlenode locking emulation.
|
||||||
|
Reject lvcreate -m with raid4/5/6 to avoid unexpected layout.
|
||||||
|
Don't skip invalidation of cached orphans if vg write lck is held (2.02.118).
|
||||||
|
Log relevant PV tags when using cling allocation.
|
||||||
|
Add str_list_add_list() to combine two lists.
|
||||||
|
Fix LV processing with selection to always do the selection on initial state.
|
||||||
|
Add internal LV_REMOVED LV status flag.
|
||||||
|
|
||||||
|
Version 2.02.118 - 23rd March 2015
|
||||||
|
==================================
|
||||||
|
Store metadata size + checksum in lvmcache and add struct lvmcache_vgsummary.
|
||||||
|
Remove inaccessible clustered PVs from 'pvs -a'.
|
||||||
|
Don't invalidate cached orphan information while global lock is held.
|
||||||
|
Avoid rescan of all devices when requested pvscan for removed device.
|
||||||
|
Measure configuration timestamps with nanoseconds when available.
|
||||||
|
Disable lvchange of major and minor of pool LVs.
|
||||||
|
Fix pvscan --cache to not scan and read ignored metadata areas on PVs.
|
||||||
|
Add After=iscsi-shutdown.service to blk-availability.service systemd unit.
|
||||||
|
Disallow vgconvert from changing metadata format when lvmetad is used.
|
||||||
|
Don't do a full read of VG when creating a new VG with an existing name.
|
||||||
|
Reduce amount of VG metadata parsing when looking for vgname on a PV.
|
||||||
|
Avoid reparsing same metadata when reading same metadata from multiple PVs.
|
||||||
|
Save extra device open/close when scanning device for size.
|
||||||
|
Fix seg_monitor field to report status also for mirrors and thick snapshots.
|
||||||
|
Replace LVM_WRITE with LVM_WRITE_LOCKED flags in metadata if system ID is set.
|
||||||
|
Remove ACCESS_NEEDS_SYSTEM_ID VG status flag. (2.02.117)
|
||||||
|
Enable system ID features.
|
||||||
|
|
||||||
|
Version 2.02.117 - 4th March 2015
|
||||||
|
=================================
|
||||||
|
Add CFG_DISABLED for new system ID config settings that must not yet be used.
|
||||||
|
Preserve original format type field when processing backup files.
|
||||||
|
Implement status action for lvm2-monitor initscript to display monitored LVs.
|
||||||
|
Allow lvchange -p to change kernel state only if metadata state differs.
|
||||||
|
Fix incorrect persistent .cache after report with label fields only (2.02.106).
|
||||||
|
Reinstate PV tag recognition for pvs if reporting label fields only (2.02.105).
|
||||||
|
Rescan devices before vgimport with lvmetad so exported VG is seen.
|
||||||
|
Fix hang by adjusting cluster mirror regionsize, avoiding CPG msg limit.
|
||||||
|
Do not crash when --cachepolicy is given without --cachesettings.
|
||||||
|
Add NEEDS_FOREIGN_VGS flag to vgimport so --foreign is always supplied.
|
||||||
|
Add --foreign to the 6 display and reporting tools and vgcfgbackup.
|
||||||
|
Install /etc/lvm/lvmlocal.conf template with local section for systemid.
|
||||||
|
Record creation_host_system_id in lvm2 metadata (never set yet).
|
||||||
|
Reinstate recursive config file tag section processing. (2.02.99)
|
||||||
|
Add 'lvm systemid' to display the current system ID (never set yet).
|
||||||
|
Fix configure to properly recognize --with-default-raid10-segtype option.
|
||||||
|
Do not refresh filters/rescan if no signature is wiped during pvcreate.
|
||||||
|
Enforce none external dev info for wiping during pvcreate to avoid races.
|
||||||
|
Add global/system_id_source and system_id_file to lvm.conf (disabled).
|
||||||
|
Add support for VG system_id to control host access to VGs.
|
||||||
|
Update vgextend to use process_each_vg.
|
||||||
|
Add --ignoreskippedcluster to pvchange.
|
||||||
|
Allow pvchange to modify several properties at once.
|
||||||
|
Update pvchange to use process_each_pv.
|
||||||
|
Fix pvs -a used with lvmetad to filter out devices unsuitable for PVs.
|
||||||
|
Fix selection to recognize units for ba_start, vg_free and seg_start fields.
|
||||||
|
Add support for -S/--select to vgexport and vgimport.
|
||||||
|
Add support for -S/--select to vgdisplay, lvdisplay and pvdisplay without -C.
|
||||||
|
Add support for -S/--select to vgremove and lvremove.
|
||||||
|
Add support for -S/--select to vgchange,lvchange and pvchange.
|
||||||
|
Add infrastructure to support selection for non-reporting tools.
|
||||||
|
Add LVM_COMMAND_PROFILE env var to set default command profile name to use.
|
||||||
|
Set CLOEXEC flag on file descriptors originating in libdaemon.
|
||||||
|
|
||||||
|
Version 2.02.116 - 30th January 2015
|
||||||
|
====================================
|
||||||
|
Deactivate unused thin pools activated with lvm2 pre-2.02.112 versions.
|
||||||
|
Check lock holding LV when lvconverting stacked raid LV in cluster.
|
||||||
|
Support udev external dev info for filters: PV min size, mpath, md, partition.
|
||||||
|
Add fw_raid_component_detection lvm.conf option to enable FW raid detection.
|
||||||
|
Add devices/external_device_info_source lvm.conf option ("none" by default).
|
||||||
|
Scan pools in for_each_sub_lv() and add for_each_sub_lv_except_pools().
|
||||||
|
Fix lvm2app lvm_lv_get_property return value for fields with info/status ioctl.
|
||||||
|
Fix lvm2app regression in lvm_lv_get_attr causing unknown values (2.02.115).
|
||||||
|
Set default cache_mode to writehrough when missing in metadata.
|
||||||
|
Preserve chunk size with repair and metadata swap of a thin pool.
|
||||||
|
Fix raid --splitmirror 1 functionality (2.02.112).
|
||||||
|
Fix tree preload to handle splitting raid images.
|
||||||
|
Do not support unpartitioned DASD devices.
|
||||||
|
Improve config validation to check if setting with string value can be empty.
|
||||||
|
|
||||||
|
Version 2.02.115 - 21st January 2015
|
||||||
|
====================================
|
||||||
|
Report segment types without monitoring support as undefined.
|
||||||
|
Support lvchange --errorwhenfull for thin pools.
|
||||||
|
Improve the processing and reporting of duplicate PVs.
|
||||||
|
Report lv_health_status and health attribute also for thin pool.
|
||||||
|
Add lv_when_full reporting field.
|
||||||
|
Add support for lvcreate --errorwhenfull y|n for thin pools.
|
||||||
|
Fix lvconvert --repair to honour resilience requirement for segmented RAID LV.
|
||||||
|
Filter out partitioned device-mapper devices as unsuitable for use as PVs.
|
||||||
|
Also notify lvmetad about filtered device if using pvscan --cache DevicePath.
|
||||||
|
Use LVM's own selection instead of awk expressions in clvmd startup scripts.
|
||||||
|
Do not filter out snapshot origin LVs as unusable devices for an LVM stack.
|
||||||
|
Fix incorrect rimage names when converting from mirror to raid1 LV (2.02.112).
|
||||||
|
Introduce pvremove_many to avoid excessive metadata re-reading and messages.
|
||||||
|
Check for cmirror availability during cluster mirror creation and activation.
|
||||||
|
Add cache_policy and cache_settings reporting fields.
|
||||||
|
Add missing recognition for --binary option with {pv,vg,lv}display -C.
|
||||||
|
Fix vgimportclone to notify lvmetad about changes done if lvmetad is used.
|
||||||
|
Fix vgimportclone to properly override config if it is missing in lvm.conf.
|
||||||
|
Fix automatic use of configure --enable-udev-systemd-background-jobs.
|
||||||
|
Correctly rename active split LV with -splitmirrors for raid1.
|
||||||
|
Add report/compact_output to lvm.conf to enable/disable compact report output.
|
||||||
|
Still restrict mirror region size to power of 2 when VG extent size is not.
|
||||||
|
|
||||||
|
Version 2.02.114 - 28th November 2014
|
||||||
|
=====================================
|
||||||
|
Release socket in daemon_close and protocol string in daemon_open error path.
|
||||||
|
Add --cachepolicy and --cachesettings to lvcreate.
|
||||||
|
Fix regression when parsing /dev/mapper dir (2.02.112).
|
||||||
|
Fix missing rounding to 64KB when estimating optimal thin pool chunk size.
|
||||||
|
Fix typo in clvmd initscript causing CLVMD_STOP_TIMEOUT var to be ignored.
|
||||||
|
Fix size in pvresize "Resizing to ..." verbose msg to show proper result size.
|
||||||
|
|
||||||
|
Version 2.02.113 - 24th November 2014
|
||||||
|
=====================================
|
||||||
|
Add --cachepolicy and --cachesettings options to lvchange.
|
||||||
|
Validate that converted volume and specified pool volume differ in lvconvert.
|
||||||
|
Fix regression in vgscan --mknodes usage (2.02.112).
|
||||||
|
Respect --prefix when setting CLMVD_PATH configure (2.02.89).
|
||||||
|
Default to configure --enable-udev-systemd-background-jobs for systemd>=205.
|
||||||
|
Fix ignore_vg() to properly react on various vg_read errors (2.02.112).
|
||||||
|
Failed recovery returns FAILED_RECOVERY status flag for vg_read().
|
||||||
|
Exit with non-zero status code when pvck encounters a problem.
|
||||||
|
Fix clean_tree after activation/resume for cache target (2.02.112).
|
||||||
|
|
||||||
Version 2.02.112 - 11th November 2014
|
Version 2.02.112 - 11th November 2014
|
||||||
=====================================
|
=====================================
|
||||||
Add cache_{read,write}_{hits,misses} reporting fields.
|
Add cache_{read,write}_{hits,misses} reporting fields.
|
||||||
|
|||||||
184
WHATS_NEW_DM
184
WHATS_NEW_DM
@@ -1,3 +1,187 @@
|
|||||||
|
Version 1.02.111 -
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Version 1.02.110 - 30th October 2015
|
||||||
|
====================================
|
||||||
|
Disable thin monitoring plugin when it fails too often (>10 times).
|
||||||
|
Fix/restore parsing of empty field '-' when processing dmeventd event.
|
||||||
|
Enhance dm_tree_node_size_changed() to recognize size reduction.
|
||||||
|
Support exit on idle for dmenventd (1 hour).
|
||||||
|
Add support to allow unmonitor device from plugin itself.
|
||||||
|
New design for thread co-operation in dmeventd.
|
||||||
|
Dmeventd read device status with 'noflush'.
|
||||||
|
Dmeventd closes control device when no device is monitored.
|
||||||
|
Thin plugin for dmeventd improved percentage usage.
|
||||||
|
Snapshot plugin for dmeventd improved percentage usage.
|
||||||
|
Add dm_hold_control_dev to allow holding of control device open.
|
||||||
|
Add dm_report_compact_given_fields to remove given empty fields from report.
|
||||||
|
Use libdm status parsing and local mem raid dmeventd plugin.
|
||||||
|
Use local mem pool and lock only lvm2 execution for mirror dmeventd plugin.
|
||||||
|
Lock protect only lvm2 execution for snapshot and thin dmeventd plugin.
|
||||||
|
Use local mempool for raid and mirror plugins.
|
||||||
|
Reworked thread initialization for dmeventd plugins.
|
||||||
|
Dmeventd handles snapshot overflow for now equally as invalid.
|
||||||
|
Convert dmeventd to use common logging macro system from libdm.
|
||||||
|
Return -ENOMEM when device registration fails instead of 0 (=success).
|
||||||
|
Enforce writethrough mode for cleaner policy.
|
||||||
|
Add support for recognition and deactivation of MD devices to blkdeactivate.
|
||||||
|
Move target status functions out of libdm-deptree.
|
||||||
|
Correct use of max_write_behind parameter when generating raid target line.
|
||||||
|
Fix dm-event systemd service to make sure it is executed before mounting.
|
||||||
|
|
||||||
|
Version 1.02.109 - 22nd September 2016
|
||||||
|
======================================
|
||||||
|
Update man pages for dmsetup and dmstats.
|
||||||
|
Improve help text for dmsetup.
|
||||||
|
Use --noflush and --nolockfs when removing device with --force.
|
||||||
|
Parse new Overflow status string for snapshot target.
|
||||||
|
Check dir path components are valid if using dm_create_dir, error out if not.
|
||||||
|
Fix /dev/mapper handling to remove dangling entries if symlinks are found.
|
||||||
|
Make it possible to use blank value as selection for string list report field.
|
||||||
|
|
||||||
|
Version 1.02.108 - 15th September 2015
|
||||||
|
======================================
|
||||||
|
Do not check for full thin pool when activating without messages (1.02.107).
|
||||||
|
|
||||||
|
Version 1.02.107 - 5th September 2015
|
||||||
|
=====================================
|
||||||
|
Parse thin-pool status with one single routine internally.
|
||||||
|
Add --histogram to select default histogram fields for list and report.
|
||||||
|
Add report fields for displaying latency histogram configuration and data.
|
||||||
|
Add dmstats --bounds to specify histogram boundaries for a new region.
|
||||||
|
Add dm_histogram_to_string() to format histogram data in string form.
|
||||||
|
Add public methods to libdm to access numerical histogram config and data.
|
||||||
|
Parse and store histogram data in dm_stats_list() and dm_stats_populate().
|
||||||
|
Add an argument to specify histogram bounds to dm_stats_create_region().
|
||||||
|
Add dm_histogram_bounds_from_{string,uint64_t}() to parse histogram bounds.
|
||||||
|
Add dm_histogram handle type to represent a latency histogram and its bounds.
|
||||||
|
Fix devmapper.pc pkgconfig file to not reference non-existent rt.pc file.
|
||||||
|
Reinstate dm_task_get_info@Base to libdevmapper exports. (1.02.106)
|
||||||
|
|
||||||
|
Version 1.02.106 - 26th August 2015
|
||||||
|
===================================
|
||||||
|
Add 'precise' column to statistics reports.
|
||||||
|
Add --precise switch to 'dmstats create' to request nanosecond counters.
|
||||||
|
Add precise argument to dm_stats_create_region().
|
||||||
|
Add support to libdm-stats for precise_timestamps
|
||||||
|
|
||||||
|
Version 1.02.105 - 17th August 2015
|
||||||
|
===================================
|
||||||
|
Fix 'dmstats list -o all' segfault.
|
||||||
|
Separate dmstats statistics fields from region information fields.
|
||||||
|
Add interval and interval_ns fields to dmstats reports.
|
||||||
|
Do not include internal glibc headers in libdm-timestamp.c (1.02.104)
|
||||||
|
Exit immediately if no device is supplied to dmsetup wipe_table.
|
||||||
|
Suppress dmsetup report headings when no data is output. (1.02.104)
|
||||||
|
Adjust dmsetup usage/help output selection to match command invoked.
|
||||||
|
Fix dmsetup -o all to select correct fields in splitname report.
|
||||||
|
Restructure internal dmsetup argument handling across all commands.
|
||||||
|
Add dm_report_is_empty() to indicate there is no data awaiting output.
|
||||||
|
Add more arg validation for dm_tree_node_add_cache_target().
|
||||||
|
Add --alldevices switch to replace use of --force for stats create / delete.
|
||||||
|
|
||||||
|
Version 1.02.104 - 10th August 2015
|
||||||
|
===================================
|
||||||
|
Add dmstats.8 man page
|
||||||
|
Add dmstats --segments switch to create one region per device segment.
|
||||||
|
Add dmstats --regionid, --allregions to specify a single / all stats regions.
|
||||||
|
Add dmstats --allprograms for stats commands that filter by program ID.
|
||||||
|
Add dmstats --auxdata and --programid args to specify aux data and program ID.
|
||||||
|
Add report stats sub-command to provide repeating stats reports.
|
||||||
|
Add clear, delete, list, and print stats sub-commands.
|
||||||
|
Add create stats sub-command and --start, --length, --areas and --areasize.
|
||||||
|
Recognize 'dmstats' as an alias for 'dmsetup stats' when run with this name.
|
||||||
|
Add a 'stats' command to dmsetup to configure, manage and report stats data.
|
||||||
|
Add statistics fields to dmsetup -o.
|
||||||
|
Add libdm-stats library to allow management of device-mapper statistics.
|
||||||
|
Add --nosuffix to suppress dmsetup unit suffixes in report output.
|
||||||
|
Add --units to control dmsetup report field output units.
|
||||||
|
Add support to redisplay column headings for repeating column reports.
|
||||||
|
Fix report header and row resource leaks.
|
||||||
|
Report timestamps of ioctls with dmsetup -vvv.
|
||||||
|
Recognize report field name variants without any underscores too.
|
||||||
|
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
||||||
|
Add dm_timestamp functions to libdevmapper.
|
||||||
|
Recognise vg/lv name format in dmsetup.
|
||||||
|
Move size display code to libdevmapper as dm_size_to_string.
|
||||||
|
|
||||||
|
Version 1.02.103 - 24th July 2015
|
||||||
|
=================================
|
||||||
|
Introduce libdevmapper wrappers for all malloc-related functions.
|
||||||
|
|
||||||
|
Version 1.02.102 - 7th July 2015
|
||||||
|
================================
|
||||||
|
Include tool.h for default non-library use.
|
||||||
|
Introduce format macros with embedded % such as FMTu64.
|
||||||
|
|
||||||
|
Version 1.02.101 - 3rd July 2015
|
||||||
|
================================
|
||||||
|
Add experimental support to passing messages in suspend tree.
|
||||||
|
Add dm_report_value_cache_{set,get} to support caching during report/select.
|
||||||
|
Add dm_report_reserved_handler to handle report reserved value actions.
|
||||||
|
Support dynamic value in select: DM_REPORT_FIELD_RESERVED_VALUE_DYNAMIC_VALUE.
|
||||||
|
Support fuzzy names in select: DM_REPORT_FIELD_RESERVED_VALUE_FUZZY_NAMES.
|
||||||
|
Thin pool trace messages show a device name and major:minor.
|
||||||
|
|
||||||
|
Version 1.02.100 - 30th June 2015
|
||||||
|
=================================
|
||||||
|
Add since, after, until and before time operators to be used in selection.
|
||||||
|
Add support for time in reports and selection: DM_REPORT_FIELD_TYPE_TIME.
|
||||||
|
Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
|
||||||
|
Support report reserved value names: DM_REPORT_FIELD_RESERVED_VALUE_NAMED.
|
||||||
|
Add DM_CONFIG_VALUE_FMT_{INT_OCTAL,STRING_NO_QUOTES} config value format flag.
|
||||||
|
Add DM_CONFIG_VALUE_FMT_COMMON_{ARRAY,EXTRA_SPACE} config value format flag.
|
||||||
|
Add dm_config_value_{get,set}_format_flags to get and set config value format.
|
||||||
|
|
||||||
|
Version 1.02.99 - 20th June 2015
|
||||||
|
================================
|
||||||
|
New dm_tree_node_set_thin_pool_read_only(DM_1_02_99) for read-only thin pool.
|
||||||
|
Enhance error message when thin-pool message fails.
|
||||||
|
Fix dmeventd logging to avoid threaded use of static variable.
|
||||||
|
Remove redundant dmeventd SIGALRM coded.
|
||||||
|
|
||||||
|
Version 1.02.98 - 12th June 2015
|
||||||
|
================================
|
||||||
|
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
|
||||||
|
Use copy of errno made after each dm ioctl call in case errno changes later.
|
||||||
|
|
||||||
|
Version 1.02.97 - 15th May 2015
|
||||||
|
===============================
|
||||||
|
New dm_task_get_info(DM_1_02_97) supports internal_suspend state.
|
||||||
|
New symbols are versioned and comes with versioned symbol name (DM_1_02_97).
|
||||||
|
|
||||||
|
Version 1.02.96 - 2nd May 2015
|
||||||
|
==============================
|
||||||
|
Fix selection to not match if using reserved value in criteria with >,<,>=,<.
|
||||||
|
Fix selection to not match reserved values for size fields if using >,<,>=,<.
|
||||||
|
Include uuid or device number in log message after ioctl failure.
|
||||||
|
Add DM_INTERNAL_SUSPEND_FLAG to dm-ioctl.h.
|
||||||
|
Install blkdeactivate script and its man page with make install_device-mapper.
|
||||||
|
|
||||||
|
Version 1.02.95 - 15th March 2015
|
||||||
|
=================================
|
||||||
|
Makefile regenerated.
|
||||||
|
|
||||||
|
Version 1.02.94 - 4th March 2015
|
||||||
|
================================
|
||||||
|
Add dm_report_object_is_selected for generalized interface for report/select.
|
||||||
|
|
||||||
|
Version 1.02.93 - 21st January 2015
|
||||||
|
===================================
|
||||||
|
Reduce severity of ioctl error message when dmeventd waitevent is interrupted.
|
||||||
|
Report 'unknown version' when incompatible version numbers were not obtained.
|
||||||
|
Report more info from thin pool status (out of data, metadata-ro, fail).
|
||||||
|
Support error_if_no_space for thin pool target.
|
||||||
|
Fix segfault while using selection with regex and unbuffered reporting.
|
||||||
|
Add dm_report_compact_fields to remove empty fields from report output.
|
||||||
|
Remove unimplemented dm_report_set_output_selection from libdevmapper.h.
|
||||||
|
|
||||||
|
Version 1.02.92 - 24th November 2014
|
||||||
|
====================================
|
||||||
|
Fix memory corruption with sorting empty string lists (1.02.86).
|
||||||
|
Fix man dmsetup.8 syntax warning of Groff
|
||||||
|
Accept unquoted strings and / in place of {} when parsing configs.
|
||||||
|
|
||||||
Version 1.02.91 - 11th November 2014
|
Version 1.02.91 - 11th November 2014
|
||||||
====================================
|
====================================
|
||||||
Update cache creation and dm_config_node to pass policy.
|
Update cache creation and dm_config_node to pass policy.
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ AC_DEFUN([AC_TRY_CCFLAG],
|
|||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl AC_IF_YES([TEST-FOR-YES], [ACTION-IF-TRUE], [ACTION-IF-FALSE])
|
||||||
|
dnl AS_IF() abstraction, checks shell variable for 'yes'
|
||||||
|
AC_DEFUN([AC_IF_YES], [AS_IF([test $$1 = yes], [$2], [$3])])
|
||||||
|
|
||||||
dnl AC_TRY_LDFLAGS([LDFLAGS], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS])
|
dnl AC_TRY_LDFLAGS([LDFLAGS], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS])
|
||||||
dnl check if $CC supports given ld flags
|
dnl check if $CC supports given ld flags
|
||||||
|
|
||||||
|
|||||||
6
aclocal.m4
vendored
6
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
|||||||
# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
|
# generated automatically by aclocal 1.15 -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
|
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
@@ -15,7 +15,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
|
|||||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||||
# serial 1 (pkg-config-0.24)
|
# serial 1 (pkg-config-0.24)
|
||||||
#
|
#
|
||||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
# Copyright (c) 2004 Scott James Remnant <scott@netsplit.com>.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
6
conf/.gitignore
vendored
Normal file
6
conf/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
command_profile_template.profile
|
||||||
|
example.conf
|
||||||
|
lvmlocal.conf
|
||||||
|
metadata_profile_template.profile
|
||||||
|
configure.h
|
||||||
|
lvm-version.h
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of LVM2.
|
# This file is part of LVM2.
|
||||||
#
|
#
|
||||||
@@ -17,24 +17,41 @@ top_builddir = @top_builddir@
|
|||||||
|
|
||||||
CONFSRC=example.conf
|
CONFSRC=example.conf
|
||||||
CONFDEST=lvm.conf
|
CONFDEST=lvm.conf
|
||||||
|
CONFLOCAL=lvmlocal.conf
|
||||||
|
|
||||||
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
||||||
PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile
|
PROFILES=$(PROFILE_TEMPLATES) \
|
||||||
|
$(srcdir)/cache-mq.profile \
|
||||||
|
$(srcdir)/cache-smq.profile \
|
||||||
|
$(srcdir)/thin-generic.profile \
|
||||||
|
$(srcdir)/thin-performance.profile
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
.PHONY: install_conf install_localconf install_profiles
|
||||||
|
|
||||||
|
generate:
|
||||||
|
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal --withspaces) > example.conf.in
|
||||||
|
(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --withspaces local) > lvmlocal.conf.in
|
||||||
|
|
||||||
install_conf: $(CONFSRC)
|
install_conf: $(CONFSRC)
|
||||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||||
echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \
|
echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \
|
||||||
$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \
|
$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
install_localconf: $(CONFLOCAL)
|
||||||
|
@if [ ! -e $(confdir)/$(CONFLOCAL) ]; then \
|
||||||
|
echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL)"; \
|
||||||
|
$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL); \
|
||||||
|
fi
|
||||||
|
|
||||||
install_profiles: $(PROFILES)
|
install_profiles: $(PROFILES)
|
||||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
|
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
|
||||||
$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
|
$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
|
||||||
|
|
||||||
install_lvm2: install_conf install_profiles
|
install_lvm2: install_conf install_localconf install_profiles
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|
||||||
DISTCLEAN_TARGETS += $(CONFSRC) $(PROFILE_TEMPLATES)
|
DISTCLEAN_TARGETS += $(CONFSRC) $(CONFLOCAL) $(PROFILE_TEMPLATES)
|
||||||
|
|||||||
20
conf/cache-mq.profile
Normal file
20
conf/cache-mq.profile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Demo configuration 'mq' cache policy
|
||||||
|
#
|
||||||
|
# Note: This policy has been deprecated in favor of the smq policy
|
||||||
|
# keyword "default" means, setting is left with kernel defaults.
|
||||||
|
#
|
||||||
|
|
||||||
|
allocation {
|
||||||
|
cache_pool_chunk_size = 64
|
||||||
|
cache_mode = "writethrough"
|
||||||
|
cache_policy = "mq"
|
||||||
|
cache_settings {
|
||||||
|
mq {
|
||||||
|
sequential_threshold = "default" # #nr_sequential_ios
|
||||||
|
random_threshold = "default" # #nr_random_ios
|
||||||
|
read_promote_adjustment = "default"
|
||||||
|
write_promote_adjustment = "default"
|
||||||
|
discard_promote_adjustment = "default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
conf/cache-smq.profile
Normal file
14
conf/cache-smq.profile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Demo configuration 'smq' cache policy
|
||||||
|
#
|
||||||
|
# The stochastic multi-queue (smq) policy addresses some of the problems
|
||||||
|
# with the multiqueue (mq) policy and uses less memory.
|
||||||
|
#
|
||||||
|
|
||||||
|
allocation {
|
||||||
|
cache_pool_chunk_size = 64
|
||||||
|
cache_mode = "writethrough"
|
||||||
|
cache_policy = "smq"
|
||||||
|
cache_settings {
|
||||||
|
# currently no settins for "smq" policy
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ global {
|
|||||||
lvdisplay_shows_full_device_path=0
|
lvdisplay_shows_full_device_path=0
|
||||||
}
|
}
|
||||||
report {
|
report {
|
||||||
|
compact_output=0
|
||||||
aligned=1
|
aligned=1
|
||||||
buffered=1
|
buffered=1
|
||||||
headings=1
|
headings=1
|
||||||
|
|||||||
23
conf/example.conf.base
Normal file
23
conf/example.conf.base
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# This is an example configuration file for the LVM2 system.
|
||||||
|
# It contains the default settings that would be used if there was no
|
||||||
|
# @DEFAULT_SYS_DIR@/lvm.conf file.
|
||||||
|
#
|
||||||
|
# Refer to 'man lvm.conf' for further information including the file layout.
|
||||||
|
#
|
||||||
|
# Refer to 'man lvm.conf' for information about how settings configured in
|
||||||
|
# this file are combined with built-in values and command line options to
|
||||||
|
# arrive at the final values used by LVM.
|
||||||
|
#
|
||||||
|
# Refer to 'man lvmconfig' for information about displaying the built-in
|
||||||
|
# and configured values used by LVM.
|
||||||
|
#
|
||||||
|
# If a default value is set in this file (not commented out), then a
|
||||||
|
# new version of LVM using this file will continue using that value,
|
||||||
|
# even if the new version of LVM changes the built-in default value.
|
||||||
|
#
|
||||||
|
# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
|
||||||
|
# the environment variable LVM_SYSTEM_DIR before running the tools.
|
||||||
|
#
|
||||||
|
# N.B. Take care that each setting only appears once if uncommenting
|
||||||
|
# example settings in this file.
|
||||||
|
|
||||||
2810
conf/example.conf.in
2810
conf/example.conf.in
File diff suppressed because it is too large
Load Diff
19
conf/lvmlocal.conf.base
Normal file
19
conf/lvmlocal.conf.base
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# This is a local configuration file template for the LVM2 system
|
||||||
|
# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
|
||||||
|
#
|
||||||
|
# Refer to 'man lvm.conf' for information about the file layout.
|
||||||
|
#
|
||||||
|
# To put this file in a different directory and override
|
||||||
|
# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
|
||||||
|
# running the tools.
|
||||||
|
#
|
||||||
|
# The lvmlocal.conf file is normally expected to contain only the
|
||||||
|
# "local" section which contains settings that should not be shared or
|
||||||
|
# repeated among different hosts. (But if other sections are present,
|
||||||
|
# they *will* get processed. Settings in this file override equivalent
|
||||||
|
# ones in lvm.conf and are in turn overridden by ones in any enabled
|
||||||
|
# lvm_<tag>.conf files.)
|
||||||
|
#
|
||||||
|
# Please take care that each setting only appears once if uncommenting
|
||||||
|
# example settings in this file and never copy this file between hosts.
|
||||||
|
|
||||||
56
conf/lvmlocal.conf.in
Normal file
56
conf/lvmlocal.conf.in
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# This is a local configuration file template for the LVM2 system
|
||||||
|
# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
|
||||||
|
#
|
||||||
|
# Refer to 'man lvm.conf' for information about the file layout.
|
||||||
|
#
|
||||||
|
# To put this file in a different directory and override
|
||||||
|
# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
|
||||||
|
# running the tools.
|
||||||
|
#
|
||||||
|
# The lvmlocal.conf file is normally expected to contain only the
|
||||||
|
# "local" section which contains settings that should not be shared or
|
||||||
|
# repeated among different hosts. (But if other sections are present,
|
||||||
|
# they *will* get processed. Settings in this file override equivalent
|
||||||
|
# ones in lvm.conf and are in turn overridden by ones in any enabled
|
||||||
|
# lvm_<tag>.conf files.)
|
||||||
|
#
|
||||||
|
# Please take care that each setting only appears once if uncommenting
|
||||||
|
# example settings in this file and never copy this file between hosts.
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration section local.
|
||||||
|
# LVM settings that are specific to the local host.
|
||||||
|
local {
|
||||||
|
|
||||||
|
# Configuration option local/system_id.
|
||||||
|
# Defines the local system ID for lvmlocal mode.
|
||||||
|
# This is used when global/system_id_source is set to 'lvmlocal' in the
|
||||||
|
# main configuration file, e.g. lvm.conf. When used, it must be set to
|
||||||
|
# a unique value among all hosts sharing access to the storage,
|
||||||
|
# e.g. a host name.
|
||||||
|
#
|
||||||
|
# Example
|
||||||
|
# Set no system ID:
|
||||||
|
# system_id = ""
|
||||||
|
# Set the system_id to a specific name:
|
||||||
|
# system_id = "host1"
|
||||||
|
#
|
||||||
|
# This configuration option has an automatic default value.
|
||||||
|
# system_id = ""
|
||||||
|
|
||||||
|
# Configuration option local/extra_system_ids.
|
||||||
|
# A list of extra VG system IDs the local host can access.
|
||||||
|
# VGs with the system IDs listed here (in addition to the host's own
|
||||||
|
# system ID) can be fully accessed by the local host. (These are
|
||||||
|
# system IDs that the host sees in VGs, not system IDs that identify
|
||||||
|
# the local host, which is determined by system_id_source.)
|
||||||
|
# Use this only after consulting 'man lvmsystemid' to be certain of
|
||||||
|
# correct usage and possible dangers.
|
||||||
|
# This configuration option does not have a default value defined.
|
||||||
|
|
||||||
|
# Configuration option local/host_id.
|
||||||
|
# The lvmlockd sanlock host_id.
|
||||||
|
# This must be unique among all hosts, and must be between 1 and 2000.
|
||||||
|
# This configuration option has an automatic default value.
|
||||||
|
# host_id = 0
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ allocation {
|
|||||||
thin_pool_zero=1
|
thin_pool_zero=1
|
||||||
thin_pool_discards="passdown"
|
thin_pool_discards="passdown"
|
||||||
thin_pool_chunk_size_policy="generic"
|
thin_pool_chunk_size_policy="generic"
|
||||||
# thin_pool_chunk_size=64
|
# thin_pool_chunk_size=128
|
||||||
}
|
}
|
||||||
activation {
|
activation {
|
||||||
thin_pool_autoextend_threshold=100
|
thin_pool_autoextend_threshold=100
|
||||||
|
|||||||
421
configure.in
421
configure.in
@@ -1,6 +1,6 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||||
## Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
|
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
##
|
##
|
||||||
## This copyrighted material is made available to anyone wishing to use,
|
## This copyrighted material is made available to anyone wishing to use,
|
||||||
## modify, copy, or redistribute it subject to the terms and conditions
|
## modify, copy, or redistribute it subject to the terms and conditions
|
||||||
@@ -16,7 +16,7 @@ AC_PREREQ(2.61)
|
|||||||
dnl -- Process this file with autoconf to produce a configure script.
|
dnl -- Process this file with autoconf to produce a configure script.
|
||||||
AC_INIT
|
AC_INIT
|
||||||
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
|
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
|
||||||
AC_CONFIG_HEADERS([lib/misc/configure.h])
|
AC_CONFIG_HEADERS([include/configure.h])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Setup the directory where autoconf has auxilary files
|
dnl -- Setup the directory where autoconf has auxilary files
|
||||||
@@ -26,10 +26,9 @@ AC_CONFIG_AUX_DIR(autoconf)
|
|||||||
dnl -- Get system type
|
dnl -- Get system type
|
||||||
AC_CANONICAL_TARGET([])
|
AC_CANONICAL_TARGET([])
|
||||||
|
|
||||||
|
AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
|
||||||
case "$host_os" in
|
case "$host_os" in
|
||||||
linux*)
|
linux*)
|
||||||
CFLAGS="$CFLAGS"
|
|
||||||
COPTIMISE_FLAG="-O2"
|
|
||||||
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
|
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
|
||||||
ELDFLAGS="-Wl,--export-dynamic"
|
ELDFLAGS="-Wl,--export-dynamic"
|
||||||
# FIXME Generate list and use --dynamic-list=.dlopen.sym
|
# FIXME Generate list and use --dynamic-list=.dlopen.sym
|
||||||
@@ -39,6 +38,10 @@ case "$host_os" in
|
|||||||
LIB_SUFFIX=so
|
LIB_SUFFIX=so
|
||||||
DEVMAPPER=yes
|
DEVMAPPER=yes
|
||||||
LVMETAD=no
|
LVMETAD=no
|
||||||
|
LVMPOLLD=no
|
||||||
|
LVMLOCKD=no
|
||||||
|
LOCKDSANLOCK=no
|
||||||
|
LOCKDDLM=no
|
||||||
ODIRECT=yes
|
ODIRECT=yes
|
||||||
DM_IOCTLS=yes
|
DM_IOCTLS=yes
|
||||||
SELINUX=yes
|
SELINUX=yes
|
||||||
@@ -48,7 +51,6 @@ case "$host_os" in
|
|||||||
;;
|
;;
|
||||||
darwin*)
|
darwin*)
|
||||||
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
|
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
|
||||||
COPTIMISE_FLAG="-O2"
|
|
||||||
CLDFLAGS="$CLDFLAGS"
|
CLDFLAGS="$CLDFLAGS"
|
||||||
ELDFLAGS=
|
ELDFLAGS=
|
||||||
CLDWHOLEARCHIVE="-all_load"
|
CLDWHOLEARCHIVE="-all_load"
|
||||||
@@ -68,7 +70,12 @@ esac
|
|||||||
dnl -- Checks for programs.
|
dnl -- Checks for programs.
|
||||||
AC_PROG_SED
|
AC_PROG_SED
|
||||||
AC_PROG_AWK
|
AC_PROG_AWK
|
||||||
|
save_CFLAGS=$CFLAGS
|
||||||
|
save_CXXFLAGS=$CXXFLAGS
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
AC_PROG_CXX
|
||||||
|
CFLAGS=$save_CFLAGS
|
||||||
|
CXXFLAGS=$save_CXXFLAGS
|
||||||
|
|
||||||
dnl probably no longer needed in 2008, but...
|
dnl probably no longer needed in 2008, but...
|
||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
@@ -84,14 +91,19 @@ AC_PATH_TOOL(CSCOPE_CMD, cscope)
|
|||||||
dnl -- Check for header files.
|
dnl -- Check for header files.
|
||||||
AC_HEADER_DIRENT
|
AC_HEADER_DIRENT
|
||||||
AC_HEADER_MAJOR
|
AC_HEADER_MAJOR
|
||||||
|
AC_HEADER_STDBOOL
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_HEADER_SYS_WAIT
|
AC_HEADER_SYS_WAIT
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
|
|
||||||
AC_CHECK_HEADERS([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
|
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
|
||||||
langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
|
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
|
||||||
sys/wait.h time.h], ,
|
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
|
||||||
[AC_MSG_ERROR(bailing out)])
|
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
|
||||||
|
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||||
|
unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h)
|
||||||
|
|
||||||
case "$host_os" in
|
case "$host_os" in
|
||||||
linux*)
|
linux*)
|
||||||
@@ -100,16 +112,13 @@ case "$host_os" in
|
|||||||
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
|
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
|
|
||||||
stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
|
|
||||||
sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)])
|
|
||||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Check for typedefs, structures, and compiler characteristics.
|
dnl -- Check for typedefs, structures, and compiler characteristics.
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
AC_C_INLINE
|
AC_C_INLINE
|
||||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||||
|
AC_CHECK_TYPES([ptrdiff_t])
|
||||||
|
AC_STRUCT_TM
|
||||||
AC_TYPE_OFF_T
|
AC_TYPE_OFF_T
|
||||||
AC_TYPE_PID_T
|
AC_TYPE_PID_T
|
||||||
AC_TYPE_SIGNAL
|
AC_TYPE_SIGNAL
|
||||||
@@ -125,15 +134,13 @@ AC_TYPE_UINT8_T
|
|||||||
AC_TYPE_UINT16_T
|
AC_TYPE_UINT16_T
|
||||||
AC_TYPE_UINT32_T
|
AC_TYPE_UINT32_T
|
||||||
AC_TYPE_UINT64_T
|
AC_TYPE_UINT64_T
|
||||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
|
||||||
AC_STRUCT_TM
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Check for functions
|
dnl -- Check for functions
|
||||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize \
|
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
|
||||||
gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
|
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
|
||||||
strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
|
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
|
||||||
strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||||
AC_FUNC_ALLOCA
|
AC_FUNC_ALLOCA
|
||||||
AC_FUNC_CLOSEDIR_VOID
|
AC_FUNC_CLOSEDIR_VOID
|
||||||
AC_FUNC_CHOWN
|
AC_FUNC_CHOWN
|
||||||
@@ -141,12 +148,22 @@ AC_FUNC_FORK
|
|||||||
AC_FUNC_LSTAT
|
AC_FUNC_LSTAT
|
||||||
AC_FUNC_MALLOC
|
AC_FUNC_MALLOC
|
||||||
AC_FUNC_MEMCMP
|
AC_FUNC_MEMCMP
|
||||||
|
AC_FUNC_MKTIME
|
||||||
AC_FUNC_MMAP
|
AC_FUNC_MMAP
|
||||||
AC_FUNC_REALLOC
|
AC_FUNC_REALLOC
|
||||||
AC_FUNC_STAT
|
AC_FUNC_STAT
|
||||||
AC_FUNC_STRTOD
|
AC_FUNC_STRTOD
|
||||||
AC_FUNC_VPRINTF
|
AC_FUNC_VPRINTF
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Disable dependency tracking
|
||||||
|
AC_MSG_CHECKING(whether to enable dependency tracking)
|
||||||
|
AC_ARG_ENABLE(dependency-tracking,
|
||||||
|
AC_HELP_STRING([--disable-dependency-tracking],
|
||||||
|
[speeds up one-time build.]),
|
||||||
|
USE_TRACKING=$enableval, USE_TRACKING=yes)
|
||||||
|
AC_MSG_RESULT($USE_TRACKING)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Enables statically-linked tools
|
dnl -- Enables statically-linked tools
|
||||||
AC_MSG_CHECKING(whether to use static linking)
|
AC_MSG_CHECKING(whether to use static linking)
|
||||||
@@ -167,6 +184,9 @@ AC_SUBST(HAVE_FULL_RELRO)
|
|||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||||
AC_PREFIX_DEFAULT(/usr)
|
AC_PREFIX_DEFAULT(/usr)
|
||||||
|
if test "$prefix" = NONE; then
|
||||||
|
datarootdir=${ac_default_prefix}/share
|
||||||
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Setup the ownership of the files
|
dnl -- Setup the ownership of the files
|
||||||
@@ -197,6 +217,7 @@ AC_ARG_WITH(device-uid,
|
|||||||
[set the owner used for new device nodes [UID=0]]),
|
[set the owner used for new device nodes [UID=0]]),
|
||||||
DM_DEVICE_UID=$withval, DM_DEVICE_UID=0)
|
DM_DEVICE_UID=$withval, DM_DEVICE_UID=0)
|
||||||
AC_MSG_RESULT($DM_DEVICE_UID)
|
AC_MSG_RESULT($DM_DEVICE_UID)
|
||||||
|
AC_DEFINE_UNQUOTED([DM_DEVICE_UID], [$DM_DEVICE_UID], [Define default owner for device node])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Setup device group ownership
|
dnl -- Setup device group ownership
|
||||||
@@ -207,6 +228,7 @@ AC_ARG_WITH(device-gid,
|
|||||||
[set the group used for new device nodes [GID=0]]),
|
[set the group used for new device nodes [GID=0]]),
|
||||||
DM_DEVICE_GID=$withval, DM_DEVICE_GID=0)
|
DM_DEVICE_GID=$withval, DM_DEVICE_GID=0)
|
||||||
AC_MSG_RESULT($DM_DEVICE_GID)
|
AC_MSG_RESULT($DM_DEVICE_GID)
|
||||||
|
AC_DEFINE_UNQUOTED([DM_DEVICE_GID], [$DM_DEVICE_GID], [Define default group for device node])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Setup device mode
|
dnl -- Setup device mode
|
||||||
@@ -217,6 +239,7 @@ AC_ARG_WITH(device-mode,
|
|||||||
[set the mode used for new device nodes [MODE=0600]]),
|
[set the mode used for new device nodes [MODE=0600]]),
|
||||||
DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600)
|
DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600)
|
||||||
AC_MSG_RESULT($DM_DEVICE_MODE)
|
AC_MSG_RESULT($DM_DEVICE_MODE)
|
||||||
|
AC_DEFINE_UNQUOTED([DM_DEVICE_MODE], [$DM_DEVICE_MODE], [Define default mode for device node])
|
||||||
|
|
||||||
AC_MSG_CHECKING(when to create device nodes)
|
AC_MSG_CHECKING(when to create device nodes)
|
||||||
AC_ARG_WITH(device-nodes-on,
|
AC_ARG_WITH(device-nodes-on,
|
||||||
@@ -256,8 +279,13 @@ AC_ARG_ENABLE(lvm1_fallback,
|
|||||||
AC_MSG_RESULT($LVM1_FALLBACK)
|
AC_MSG_RESULT($LVM1_FALLBACK)
|
||||||
|
|
||||||
if test "$LVM1_FALLBACK" = yes; then
|
if test "$LVM1_FALLBACK" = yes; then
|
||||||
|
DEFAULT_FALLBACK_TO_LVM1=1
|
||||||
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
|
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
|
||||||
|
else
|
||||||
|
DEFAULT_FALLBACK_TO_LVM1=0
|
||||||
fi
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1],
|
||||||
|
[Fall back to LVM1 by default if device-mapper is missing from the kernel.])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- format1 inclusion type
|
dnl -- format1 inclusion type
|
||||||
@@ -353,7 +381,7 @@ AC_ARG_WITH(default-mirror-segtype,
|
|||||||
AC_HELP_STRING([--with-default-mirror-segtype=TYPE],
|
AC_HELP_STRING([--with-default-mirror-segtype=TYPE],
|
||||||
[default mirror segtype: raid1/mirror [raid1]]),
|
[default mirror segtype: raid1/mirror [raid1]]),
|
||||||
DEFAULT_MIRROR_SEGTYPE=$withval, DEFAULT_MIRROR_SEGTYPE="raid1")
|
DEFAULT_MIRROR_SEGTYPE=$withval, DEFAULT_MIRROR_SEGTYPE="raid1")
|
||||||
AC_ARG_WITH(default-raid10r-segtype,
|
AC_ARG_WITH(default-raid10-segtype,
|
||||||
AC_HELP_STRING([--with-default-raid10-segtype=TYPE],
|
AC_HELP_STRING([--with-default-raid10-segtype=TYPE],
|
||||||
[default mirror segtype: raid10/mirror [raid10]]),
|
[default mirror segtype: raid10/mirror [raid10]]),
|
||||||
DEFAULT_RAID10_SEGTYPE=$withval, DEFAULT_RAID10_SEGTYPE="raid10")
|
DEFAULT_RAID10_SEGTYPE=$withval, DEFAULT_RAID10_SEGTYPE="raid10")
|
||||||
@@ -545,6 +573,12 @@ case "$CACHE" in
|
|||||||
*) AC_MSG_ERROR([--with-cache parameter invalid]) ;;
|
*) AC_MSG_ERROR([--with-cache parameter invalid]) ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
dnl -- cache_check needs-check flag
|
||||||
|
AC_ARG_ENABLE(cache_check_needs_check,
|
||||||
|
AC_HELP_STRING([--disable-cache_check_needs_check],
|
||||||
|
[required if cache_check version is < 0.5]),
|
||||||
|
CACHE_CHECK_NEEDS_CHECK=$enableval, CACHE_CHECK_NEEDS_CHECK=yes)
|
||||||
|
|
||||||
# Test if necessary cache tools are available
|
# Test if necessary cache tools are available
|
||||||
# if not - use plain defaults and warn user
|
# if not - use plain defaults and warn user
|
||||||
case "$CACHE" in
|
case "$CACHE" in
|
||||||
@@ -558,6 +592,28 @@ case "$CACHE" in
|
|||||||
CACHE_CONFIGURE_WARN=y
|
CACHE_CONFIGURE_WARN=y
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||||
|
$CACHE_CHECK_CMD -V 2>/dev/null >conftest.tmp
|
||||||
|
read -r CACHE_CHECK_VSN < conftest.tmp
|
||||||
|
IFS=.- read -r CACHE_CHECK_VSN_MAJOR CACHE_CHECK_VSN_MINOR CACHE_CHECK_VSN_PATCH LEFTOVER < conftest.tmp
|
||||||
|
rm -f conftest.tmp
|
||||||
|
|
||||||
|
# Require version >= 0.5.4 for --clear-needs-check-flag
|
||||||
|
if test -z "$CACHE_CHECK_VSN_MAJOR" \
|
||||||
|
|| test -z "$CACHE_CHECK_VSN_MINOR" \
|
||||||
|
|| test -z "$CACHE_CHECK_VSN_PATCH"; then
|
||||||
|
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
|
||||||
|
CACHE_CHECK_VERSION_WARN=y
|
||||||
|
CACHE_CHECK_NEEDS_CHECK=no
|
||||||
|
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 ; then
|
||||||
|
if test "$CACHE_CHECK_VSN_MINOR" -lt 5 \
|
||||||
|
|| test "$CACHE_CHECK_VSN_MINOR" -eq 5 -a "$CACHE_CHECK_VSN_PATCH" -lt 4; then
|
||||||
|
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
||||||
|
CACHE_CHECK_VERSION_WARN=y
|
||||||
|
CACHE_CHECK_NEEDS_CHECK=no
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# Empty means a config way to ignore cache dumping
|
# Empty means a config way to ignore cache dumping
|
||||||
if test "$CACHE_DUMP_CMD" = "autodetect"; then
|
if test "$CACHE_DUMP_CMD" = "autodetect"; then
|
||||||
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
|
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
|
||||||
@@ -585,6 +641,12 @@ case "$CACHE" in
|
|||||||
CACHE_CONFIGURE_WARN=y
|
CACHE_CONFIGURE_WARN=y
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether cache_check supports the needs-check flag])
|
||||||
|
AC_MSG_RESULT([$CACHE_CHECK_NEEDS_CHECK])
|
||||||
|
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||||
|
AC_DEFINE([CACHE_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'cache_check' tool requires the --clear-needs-check-flag option])
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -613,8 +675,8 @@ AC_MSG_RESULT($READLINE)
|
|||||||
dnl -- Disable realtime clock support
|
dnl -- Disable realtime clock support
|
||||||
AC_MSG_CHECKING(whether to enable realtime support)
|
AC_MSG_CHECKING(whether to enable realtime support)
|
||||||
AC_ARG_ENABLE(realtime,
|
AC_ARG_ENABLE(realtime,
|
||||||
AC_HELP_STRING([--enable-realtime], [enable realtime clock support]),
|
AC_HELP_STRING([--disable-realtime], [disable realtime clock support]),
|
||||||
REALTIME=$enableval)
|
REALTIME=$enableval, REALTIME=yes)
|
||||||
AC_MSG_RESULT($REALTIME)
|
AC_MSG_RESULT($REALTIME)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -644,28 +706,32 @@ pkg_config_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
AC_MSG_CHECKING(for default run directory)
|
||||||
|
RUN_DIR="/run"
|
||||||
|
test -d "/run" || RUN_DIR="/var/run"
|
||||||
|
AC_MSG_RESULT($RUN_DIR)
|
||||||
dnl -- Set up pidfile and run directory
|
dnl -- Set up pidfile and run directory
|
||||||
AH_TEMPLATE(DEFAULT_PID_DIR)
|
AH_TEMPLATE(DEFAULT_PID_DIR)
|
||||||
AC_ARG_WITH(default-pid-dir,
|
AC_ARG_WITH(default-pid-dir,
|
||||||
AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
|
AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
|
||||||
[Default directory to keep PID files in. [/var/run]]),
|
[Default directory to keep PID files in. [autodetect]]),
|
||||||
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR="/var/run")
|
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR=$RUN_DIR)
|
||||||
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
||||||
[Default directory to keep PID files in.])
|
[Default directory to keep PID files in.])
|
||||||
|
|
||||||
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
|
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
|
||||||
AC_ARG_WITH(default-dm-run-dir,
|
AC_ARG_WITH(default-dm-run-dir,
|
||||||
AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
|
AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
|
||||||
[ Default DM run directory. [/var/run]]),
|
[ Default DM run directory. [autodetect]]),
|
||||||
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR="/var/run")
|
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR=$RUN_DIR)
|
||||||
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
||||||
[Default DM run directory.])
|
[Default DM run directory.])
|
||||||
|
|
||||||
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
|
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
|
||||||
AC_ARG_WITH(default-run-dir,
|
AC_ARG_WITH(default-run-dir,
|
||||||
AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
|
AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
|
||||||
[Default LVM run directory. [/var/run/lvm]]),
|
[Default LVM run directory. [autodetect_run_dir/lvm]]),
|
||||||
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="/var/run/lvm")
|
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="$RUN_DIR/lvm")
|
||||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||||
[Default LVM run directory.])
|
[Default LVM run directory.])
|
||||||
|
|
||||||
@@ -961,6 +1027,8 @@ AC_TRY_CCFLAG([-Wjump-misses-init], [HAVE_WJUMP], [], [])
|
|||||||
AC_SUBST(HAVE_WJUMP)
|
AC_SUBST(HAVE_WJUMP)
|
||||||
AC_TRY_CCFLAG([-Wclobbered], [HAVE_WCLOBBERED], [], [])
|
AC_TRY_CCFLAG([-Wclobbered], [HAVE_WCLOBBERED], [], [])
|
||||||
AC_SUBST(HAVE_WCLOBBERED)
|
AC_SUBST(HAVE_WCLOBBERED)
|
||||||
|
AC_TRY_CCFLAG([-Wsync-nand], [HAVE_WSYNCNAND], [], [])
|
||||||
|
AC_SUBST(HAVE_WSYNCNAND)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Override optimisation
|
dnl -- Override optimisation
|
||||||
@@ -1013,6 +1081,13 @@ if test "$TESTING" = yes; then
|
|||||||
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
|
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Set LVM2 testsuite data
|
||||||
|
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
|
||||||
|
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
|
||||||
|
AC_DEFINE_UNQUOTED(TESTSUITE_DATA, ["$(eval echo $(eval echo $TESTSUITE_DATA))"], [Path to testsuite data])
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Enable valgrind awareness of memory pools
|
dnl -- Enable valgrind awareness of memory pools
|
||||||
AC_MSG_CHECKING(whether to enable valgrind awareness of pools)
|
AC_MSG_CHECKING(whether to enable valgrind awareness of pools)
|
||||||
@@ -1022,12 +1097,16 @@ AC_ARG_ENABLE(valgrind_pool,
|
|||||||
VALGRIND_POOL=$enableval, VALGRIND_POOL=no)
|
VALGRIND_POOL=$enableval, VALGRIND_POOL=no)
|
||||||
AC_MSG_RESULT($VALGRIND_POOL)
|
AC_MSG_RESULT($VALGRIND_POOL)
|
||||||
|
|
||||||
if test "$VALGRIND_POOL" = yes; then
|
pkg_config_init
|
||||||
pkg_config_init
|
PKG_CHECK_MODULES(VALGRIND, valgrind, [HAVE_VALGRIND=yes], [if test x$VALGRIND_POOL = xyes; then AC_MSG_ERROR(bailing out); fi])
|
||||||
PKG_CHECK_MODULES(VALGRIND, valgrind, [], [AC_MSG_ERROR(bailing out)])
|
AC_SUBST(VALGRIND_CFLAGS)
|
||||||
|
|
||||||
|
if test x$HAVE_VALGRIND = xyes; then
|
||||||
|
AC_DEFINE([HAVE_VALGRIND], 1, [valgrind.h found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test x$VALGRIND_POOL = xyes; then
|
||||||
AC_DEFINE([VALGRIND_POOL], 1, [Enable a valgrind aware build of pool])
|
AC_DEFINE([VALGRIND_POOL], 1, [Enable a valgrind aware build of pool])
|
||||||
AC_SUBST(VALGRIND_POOL)
|
|
||||||
AC_SUBST(VALGRIND_CFLAGS)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -1054,7 +1133,106 @@ AC_MSG_RESULT($LVMETAD)
|
|||||||
|
|
||||||
BUILD_LVMETAD=$LVMETAD
|
BUILD_LVMETAD=$LVMETAD
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Build lvmpolld
|
||||||
|
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||||
|
AC_ARG_ENABLE(lvmpolld,
|
||||||
|
AC_HELP_STRING([--enable-lvmpolld],
|
||||||
|
[enable the LVM Polling Daemon]),
|
||||||
|
LVMPOLLD=$enableval)
|
||||||
|
AC_MSG_RESULT($LVMPOLLD)
|
||||||
|
|
||||||
|
BUILD_LVMPOLLD=$LVMPOLLD
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Build lockdsanlock
|
||||||
|
AC_MSG_CHECKING(whether to build lockdsanlock)
|
||||||
|
AC_ARG_ENABLE(lockd-sanlock,
|
||||||
|
AC_HELP_STRING([--enable-lockd-sanlock],
|
||||||
|
[enable the LVM lock daemon using sanlock]),
|
||||||
|
LOCKDSANLOCK=$enableval)
|
||||||
|
AC_MSG_RESULT($LOCKDSANLOCK)
|
||||||
|
|
||||||
|
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
|
||||||
|
|
||||||
|
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||||
|
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Look for sanlock libraries
|
||||||
|
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||||
|
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
|
||||||
|
BUILD_LVMLOCKD=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Build lockddlm
|
||||||
|
AC_MSG_CHECKING(whether to build lockddlm)
|
||||||
|
AC_ARG_ENABLE(lockd-dlm,
|
||||||
|
AC_HELP_STRING([--enable-lockd-dlm],
|
||||||
|
[enable the LVM lock daemon using dlm]),
|
||||||
|
LOCKDDLM=$enableval)
|
||||||
|
AC_MSG_RESULT($LOCKDDLM)
|
||||||
|
|
||||||
|
BUILD_LOCKDDLM=$LOCKDDLM
|
||||||
|
|
||||||
|
if test "$BUILD_LOCKDDLM" = yes; then
|
||||||
|
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Look for dlm libraries
|
||||||
|
if test "$BUILD_LOCKDDLM" = yes; then
|
||||||
|
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
|
||||||
|
BUILD_LVMLOCKD=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Build lvmlockd
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(whether to build lvmlockd)
|
||||||
|
AC_MSG_RESULT($BUILD_LVMLOCKD)
|
||||||
|
|
||||||
|
if test "$BUILD_LVMLOCKD" = yes; then
|
||||||
|
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
|
||||||
|
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
|
||||||
|
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||||
|
AC_ARG_ENABLE(use_lvmlockd,
|
||||||
|
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||||
|
[disable usage of LVM lock daemon]),
|
||||||
|
[case ${enableval} in
|
||||||
|
yes) DEFAULT_USE_LVMLOCKD=1 ;;
|
||||||
|
*) DEFAULT_USE_LVMLOCKD=0 ;;
|
||||||
|
esac], DEFAULT_USE_LVMLOCKD=1)
|
||||||
|
AC_MSG_RESULT($DEFAULT_USE_LVMLOCKD)
|
||||||
|
AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.])
|
||||||
|
|
||||||
|
AC_ARG_WITH(lvmlockd-pidfile,
|
||||||
|
AC_HELP_STRING([--with-lvmlockd-pidfile=PATH],
|
||||||
|
[lvmlockd pidfile [PID_DIR/lvmlockd.pid]]),
|
||||||
|
LVMLOCKD_PIDFILE=$withval,
|
||||||
|
LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid")
|
||||||
|
AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"],
|
||||||
|
[Path to lvmlockd pidfile.])
|
||||||
|
else
|
||||||
|
DEFAULT_USE_LVMLOCKD=0
|
||||||
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
|
||||||
|
[Use lvmlockd by default.])
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
dnl -- Check lvmetad
|
||||||
if test "$BUILD_LVMETAD" = yes; then
|
if test "$BUILD_LVMETAD" = yes; then
|
||||||
|
AC_MSG_CHECKING([defaults for use_lvmetad])
|
||||||
|
AC_ARG_ENABLE(use_lvmetad,
|
||||||
|
AC_HELP_STRING([--disable-use-lvmetad],
|
||||||
|
[disable usage of LVM Metadata Daemon]),
|
||||||
|
[case ${enableval} in
|
||||||
|
yes) DEFAULT_USE_LVMETAD=1 ;;
|
||||||
|
*) DEFAULT_USE_LVMETAD=0 ;;
|
||||||
|
esac], DEFAULT_USE_LVMETAD=1)
|
||||||
|
AC_MSG_RESULT($DEFAULT_USE_LVMETAD)
|
||||||
AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
|
AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
|
||||||
|
|
||||||
AC_ARG_WITH(lvmetad-pidfile,
|
AC_ARG_WITH(lvmetad-pidfile,
|
||||||
@@ -1064,9 +1242,41 @@ if test "$BUILD_LVMETAD" = yes; then
|
|||||||
LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
|
LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
|
||||||
AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
|
AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
|
||||||
[Path to lvmetad pidfile.])
|
[Path to lvmetad pidfile.])
|
||||||
|
else
|
||||||
|
DEFAULT_USE_LVMETAD=0
|
||||||
fi
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
|
||||||
|
[Use lvmetad by default.])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
dnl -- Check lvmpolld
|
||||||
|
if test "$BUILD_LVMPOLLD" = yes; then
|
||||||
|
AC_MSG_CHECKING([defaults for use_lvmpolld])
|
||||||
|
AC_ARG_ENABLE(use_lvmpolld,
|
||||||
|
AC_HELP_STRING([--disable-use-lvmpolld],
|
||||||
|
[disable usage of LVM Poll Daemon]),
|
||||||
|
[case ${enableval} in
|
||||||
|
yes) DEFAULT_USE_LVMPOLLD=1 ;;
|
||||||
|
*) DEFAULT_USE_LVMPOLLD=0 ;;
|
||||||
|
esac], DEFAULT_USE_LVMPOLLD=1)
|
||||||
|
AC_MSG_RESULT($DEFAULT_USE_LVMPOLLD)
|
||||||
|
AC_DEFINE([LVMPOLLD_SUPPORT], 1, [Define to 1 to include code that uses lvmpolld.])
|
||||||
|
|
||||||
|
AC_ARG_WITH(lvmpolld-pidfile,
|
||||||
|
AC_HELP_STRING([--with-lvmpolld-pidfile=PATH],
|
||||||
|
[lvmpolld pidfile [PID_DIR/lvmpolld.pid]]),
|
||||||
|
LVMPOLLD_PIDFILE=$withval,
|
||||||
|
LVMPOLLD_PIDFILE="$DEFAULT_PID_DIR/lvmpolld.pid")
|
||||||
|
AC_DEFINE_UNQUOTED(LVMPOLLD_PIDFILE, ["$LVMPOLLD_PIDFILE"],
|
||||||
|
[Path to lvmpolld pidfile.])
|
||||||
|
else
|
||||||
|
DEFAULT_USE_LVMPOLLD=0
|
||||||
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
|
||||||
|
[Use lvmpolld by default.])
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
|
||||||
dnl -- Enable blkid wiping functionality
|
dnl -- Enable blkid wiping functionality
|
||||||
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
|
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
|
||||||
AC_ARG_ENABLE(blkid_wiping,
|
AC_ARG_ENABLE(blkid_wiping,
|
||||||
@@ -1086,19 +1296,39 @@ if test "$BLKID_WIPING" != no; then
|
|||||||
fi])
|
fi])
|
||||||
if test "$BLKID_WIPING" = yes; then
|
if test "$BLKID_WIPING" = yes; then
|
||||||
BLKID_PC="blkid"
|
BLKID_PC="blkid"
|
||||||
|
DEFAULT_USE_BLKID_WIPING=1
|
||||||
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
|
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
|
||||||
|
else
|
||||||
|
DEFAULT_USE_BLKID_WIPING=1
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
DEFAULT_USE_BLKID_WIPING=0
|
||||||
fi
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_USE_BLKID_WIPING, [$DEFAULT_USE_BLKID_WIPING],
|
||||||
|
[Use blkid wiping by default.])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
|
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
|
||||||
|
dnl -- Requires systemd version 205 at least (including support for systemd-run)
|
||||||
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
|
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
|
||||||
AC_ARG_ENABLE(udev-systemd-background-jobs,
|
AC_ARG_ENABLE(udev-systemd-background-jobs,
|
||||||
AC_HELP_STRING([--disable-udev-systemd-background-jobs],
|
AC_HELP_STRING([--disable-udev-systemd-background-jobs],
|
||||||
[disable udev-systemd protocol to instantiate a service for background job]),
|
[disable udev-systemd protocol to instantiate a service for background job]),
|
||||||
UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval, UDEV_SYSTEMD_BACKGROUND_JOBS=yes)
|
UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval,
|
||||||
|
UDEV_SYSTEMD_BACKGROUND_JOBS=maybe)
|
||||||
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
|
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||||
|
|
||||||
|
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
|
||||||
|
pkg_config_init
|
||||||
|
PKG_CHECK_MODULES(SYSTEMD, systemd >= 205,
|
||||||
|
[test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe && UDEV_SYSTEMD_BACKGROUND_JOBS=yes],
|
||||||
|
[if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe; then
|
||||||
|
UDEV_SYSTEMD_BACKGROUND_JOBS=no
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([bailing out... systemd >= 205 is required])
|
||||||
|
fi])
|
||||||
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Enable udev synchronisation
|
dnl -- Enable udev synchronisation
|
||||||
AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
|
AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
|
||||||
@@ -1148,11 +1378,11 @@ AC_ARG_ENABLE(compat,
|
|||||||
[enable support for old device-mapper versions]),
|
[enable support for old device-mapper versions]),
|
||||||
DM_COMPAT=$enableval, DM_COMPAT=no)
|
DM_COMPAT=$enableval, DM_COMPAT=no)
|
||||||
|
|
||||||
if test "$DM_COMPAT" = yes; then
|
AS_IF([test "$DM_COMPAT" = yes],
|
||||||
AC_MSG_ERROR([--enable-compat is not currently supported.
|
[AC_DEFINE([DM_COMPAT], 1, [Define to enable compat protocol])
|
||||||
|
AC_MSG_ERROR([--enable-compat is not currently supported.
|
||||||
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
|
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
|
||||||
ioctl protocol is supported.])
|
ioctl protocol is supported.])])
|
||||||
fi
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Compatible units suffix mode
|
dnl -- Compatible units suffix mode
|
||||||
@@ -1172,6 +1402,8 @@ AC_ARG_ENABLE(ioctl,
|
|||||||
AC_HELP_STRING([--disable-ioctl],
|
AC_HELP_STRING([--disable-ioctl],
|
||||||
[disable ioctl calls to device-mapper in the kernel]),
|
[disable ioctl calls to device-mapper in the kernel]),
|
||||||
DM_IOCTLS=$enableval)
|
DM_IOCTLS=$enableval)
|
||||||
|
AS_IF([test "$DM_IOCTLS" = yes],
|
||||||
|
[AC_DEFINE([DM_IOCTLS], 1, [Define to enable ioctls calls to kernel])])
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Disable O_DIRECT
|
dnl -- Disable O_DIRECT
|
||||||
@@ -1314,6 +1546,10 @@ if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
|||||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
AC_CHECK_LIB(m, log10,
|
||||||
|
[M_LIBS="-lm"], hard_bailout)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
|
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
|
||||||
[PTHREAD_LIBS="-lpthread"], hard_bailout)
|
[PTHREAD_LIBS="-lpthread"], hard_bailout)
|
||||||
@@ -1354,11 +1590,24 @@ if test "$REALTIME" = yes; then
|
|||||||
if test "$HAVE_REALTIME" = yes; then
|
if test "$HAVE_REALTIME" = yes; then
|
||||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||||
LIBS="-lrt $LIBS"
|
LIBS="-lrt $LIBS"
|
||||||
|
RT_LIB="-lrt"
|
||||||
else
|
else
|
||||||
AC_MSG_WARN(Disabling realtime clock)
|
AC_MSG_WARN(Disabling realtime clock)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl Check if the system has struct stat st_ctim.
|
||||||
|
AC_CACHE_CHECK([for struct stat has st_ctim.],
|
||||||
|
[ac_cv_stat_st_ctim],
|
||||||
|
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||||
|
[#include <sys/stat.h>
|
||||||
|
long bar(void) { struct stat s; return (long)(s.st_ctim.tv_sec + s.st_ctim.tv_nsec);}]
|
||||||
|
)], [ac_cv_stat_st_ctim=yes], [ac_cv_stat_st_ctim=no])])
|
||||||
|
|
||||||
|
AC_IF_YES(ac_cv_stat_st_ctim,
|
||||||
|
AC_DEFINE(HAVE_STAT_ST_CTIM, 1,
|
||||||
|
[Define if struct stat has a field st_ctim with timespec for ctime]))
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- Check for getopt
|
dnl -- Check for getopt
|
||||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
|
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
|
||||||
@@ -1418,14 +1667,16 @@ if test "$INTL" = yes; then
|
|||||||
# FIXME - Move this - can be device-mapper too
|
# FIXME - Move this - can be device-mapper too
|
||||||
INTL_PACKAGE="lvm2"
|
INTL_PACKAGE="lvm2"
|
||||||
AC_PATH_TOOL(MSGFMT, msgfmt)
|
AC_PATH_TOOL(MSGFMT, msgfmt)
|
||||||
if [[ -z "$MSGFMT" ]]; then
|
|
||||||
AC_MSG_ERROR([msgfmt not found in path $PATH])
|
AS_IF([test -z "$MSGFMT"], [AC_MSG_ERROR([msgfmt not found in path $PATH])])
|
||||||
fi
|
|
||||||
|
|
||||||
AC_ARG_WITH(localedir,
|
AC_ARG_WITH(localedir,
|
||||||
AC_HELP_STRING([--with-localedir=DIR],
|
AC_HELP_STRING([--with-localedir=DIR],
|
||||||
[translation files in DIR [PREFIX/share/locale]]),
|
[locale-dependent data [DATAROOTDIR/locale]]),
|
||||||
LOCALEDIR=$withval, LOCALEDIR='${prefix}/share/locale')
|
localedir=$withval, localedir=${localedir-'${datarootdir}/locale'})
|
||||||
|
AC_DEFINE_UNQUOTED([INTL_PACKAGE], ["$INTL_PACKAGE"], [Internalization package])
|
||||||
|
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
|
||||||
|
AC_DEFINE_UNQUOTED([LOCALEDIR], ["$(eval echo $(eval echo $localedir))"], [Locale-dependent data])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -1434,6 +1685,8 @@ AC_ARG_WITH(confdir,
|
|||||||
AC_HELP_STRING([--with-confdir=DIR],
|
AC_HELP_STRING([--with-confdir=DIR],
|
||||||
[configuration files in DIR [/etc]]),
|
[configuration files in DIR [/etc]]),
|
||||||
CONFDIR=$withval, CONFDIR='/etc')
|
CONFDIR=$withval, CONFDIR='/etc')
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_ETC_DIR, ["$CONFDIR"],
|
||||||
|
[Default system configuration directory.])
|
||||||
|
|
||||||
AC_ARG_WITH(staticdir,
|
AC_ARG_WITH(staticdir,
|
||||||
AC_HELP_STRING([--with-staticdir=DIR],
|
AC_HELP_STRING([--with-staticdir=DIR],
|
||||||
@@ -1488,6 +1741,19 @@ if test "$READLINE" = yes; then
|
|||||||
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
|
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$BUILD_CMIRRORD" = yes; then
|
||||||
|
AC_CHECK_FUNCS(atexit,,hard_bailout)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$BUILD_LVMLOCKD" = yes; then
|
||||||
|
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$BUILD_LVMPOLLD" = yes; then
|
||||||
|
AC_CHECK_FUNCS(strpbrk,,hard_bailout)
|
||||||
|
AC_FUNC_STRERROR_R
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$CLVMD" != none; then
|
if test "$CLVMD" != none; then
|
||||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
||||||
@@ -1530,12 +1796,10 @@ test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
|
|||||||
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
||||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||||
|
|
||||||
if test "$CLVMD" != none; then
|
clvmd_prefix=$ac_default_prefix
|
||||||
clvmd_prefix=$ac_default_prefix
|
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
|
||||||
fi
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
dnl -- dmeventd pidfile and executable path
|
dnl -- dmeventd pidfile and executable path
|
||||||
@@ -1624,14 +1888,14 @@ test "$interface" != ioctl && AC_MSG_ERROR([--with-interface=ioctl required. fs
|
|||||||
AC_MSG_RESULT($interface)
|
AC_MSG_RESULT($interface)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\""
|
read DM_LIB_VERSION < "$srcdir"/VERSION_DM 2>/dev/null || DM_LIB_VERSION=Unknown
|
||||||
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version])
|
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, "$DM_LIB_VERSION", [Library version])
|
||||||
|
|
||||||
DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'`
|
DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'`
|
||||||
|
|
||||||
LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\""
|
read VER < "$srcdir"/VERSION 2>/dev/null || VER=Unknown
|
||||||
|
|
||||||
VER=`cat "$srcdir"/VERSION`
|
LVM_VERSION=\"$VER\"
|
||||||
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
||||||
VER=`echo "$VER" | $AWK '{print $1}'`
|
VER=`echo "$VER" | $AWK '{print $1}'`
|
||||||
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
||||||
@@ -1645,10 +1909,13 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
|
|||||||
AC_SUBST(APPLIB)
|
AC_SUBST(APPLIB)
|
||||||
AC_SUBST(AWK)
|
AC_SUBST(AWK)
|
||||||
AC_SUBST(BLKID_PC)
|
AC_SUBST(BLKID_PC)
|
||||||
AC_SUBST(BLKID_WIPING)
|
|
||||||
AC_SUBST(BUILD_CMIRRORD)
|
AC_SUBST(BUILD_CMIRRORD)
|
||||||
AC_SUBST(BUILD_DMEVENTD)
|
AC_SUBST(BUILD_DMEVENTD)
|
||||||
AC_SUBST(BUILD_LVMETAD)
|
AC_SUBST(BUILD_LVMETAD)
|
||||||
|
AC_SUBST(BUILD_LVMPOLLD)
|
||||||
|
AC_SUBST(BUILD_LVMLOCKD)
|
||||||
|
AC_SUBST(BUILD_LOCKDSANLOCK)
|
||||||
|
AC_SUBST(BUILD_LOCKDDLM)
|
||||||
AC_SUBST(CACHE)
|
AC_SUBST(CACHE)
|
||||||
AC_SUBST(CFLAGS)
|
AC_SUBST(CFLAGS)
|
||||||
AC_SUBST(CFLOW_CMD)
|
AC_SUBST(CFLOW_CMD)
|
||||||
@@ -1678,6 +1945,7 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR)
|
|||||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
||||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
||||||
AC_SUBST(DEFAULT_LOCK_DIR)
|
AC_SUBST(DEFAULT_LOCK_DIR)
|
||||||
|
AC_SUBST(DEFAULT_FALLBACK_TO_LVM1)
|
||||||
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
|
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
|
||||||
AC_SUBST(DEFAULT_PID_DIR)
|
AC_SUBST(DEFAULT_PID_DIR)
|
||||||
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
|
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
|
||||||
@@ -1685,31 +1953,28 @@ AC_SUBST(DEFAULT_RAID10_SEGTYPE)
|
|||||||
AC_SUBST(DEFAULT_RUN_DIR)
|
AC_SUBST(DEFAULT_RUN_DIR)
|
||||||
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
|
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
|
||||||
AC_SUBST(DEFAULT_SYS_DIR)
|
AC_SUBST(DEFAULT_SYS_DIR)
|
||||||
|
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
|
||||||
|
AC_SUBST(DEFAULT_USE_LVMETAD)
|
||||||
|
AC_SUBST(DEFAULT_USE_LVMPOLLD)
|
||||||
|
AC_SUBST(DEFAULT_USE_LVMLOCKD)
|
||||||
AC_SUBST(DEVMAPPER)
|
AC_SUBST(DEVMAPPER)
|
||||||
AC_SUBST(DLM_CFLAGS)
|
AC_SUBST(DLM_CFLAGS)
|
||||||
AC_SUBST(DLM_LIBS)
|
AC_SUBST(DLM_LIBS)
|
||||||
AC_SUBST(DL_LIBS)
|
AC_SUBST(DL_LIBS)
|
||||||
AC_SUBST(DMEVENTD)
|
AC_SUBST(DMEVENTD)
|
||||||
AC_SUBST(DMEVENTD_PATH)
|
AC_SUBST(DMEVENTD_PATH)
|
||||||
AC_SUBST(DM_COMPAT)
|
|
||||||
AC_SUBST(DM_DEVICE_GID)
|
|
||||||
AC_SUBST(DM_DEVICE_MODE)
|
|
||||||
AC_SUBST(DM_DEVICE_UID)
|
|
||||||
AC_SUBST(DM_IOCTLS)
|
|
||||||
AC_SUBST(DM_LIB_VERSION)
|
|
||||||
AC_SUBST(DM_LIB_PATCHLEVEL)
|
AC_SUBST(DM_LIB_PATCHLEVEL)
|
||||||
AC_SUBST(ELDFLAGS)
|
AC_SUBST(ELDFLAGS)
|
||||||
AC_SUBST(FSADM)
|
AC_SUBST(FSADM)
|
||||||
AC_SUBST(BLKDEACTIVATE)
|
AC_SUBST(BLKDEACTIVATE)
|
||||||
AC_SUBST(HAVE_LIBDL)
|
AC_SUBST(HAVE_LIBDL)
|
||||||
AC_SUBST(HAVE_REALTIME)
|
AC_SUBST(HAVE_REALTIME)
|
||||||
|
AC_SUBST(HAVE_VALGRIND)
|
||||||
AC_SUBST(INTL)
|
AC_SUBST(INTL)
|
||||||
AC_SUBST(INTL_PACKAGE)
|
|
||||||
AC_SUBST(JOBS)
|
AC_SUBST(JOBS)
|
||||||
AC_SUBST(LDDEPS)
|
AC_SUBST(LDDEPS)
|
||||||
AC_SUBST(LIBS)
|
AC_SUBST(LIBS)
|
||||||
AC_SUBST(LIB_SUFFIX)
|
AC_SUBST(LIB_SUFFIX)
|
||||||
AC_SUBST(LOCALEDIR)
|
|
||||||
AC_SUBST(LVM1)
|
AC_SUBST(LVM1)
|
||||||
AC_SUBST(LVM1_FALLBACK)
|
AC_SUBST(LVM1_FALLBACK)
|
||||||
AC_SUBST(LVM_VERSION)
|
AC_SUBST(LVM_VERSION)
|
||||||
@@ -1720,6 +1985,7 @@ AC_SUBST(LVM_PATCHLEVEL)
|
|||||||
AC_SUBST(LVM_PATH)
|
AC_SUBST(LVM_PATH)
|
||||||
AC_SUBST(LVM_RELEASE)
|
AC_SUBST(LVM_RELEASE)
|
||||||
AC_SUBST(LVM_RELEASE_DATE)
|
AC_SUBST(LVM_RELEASE_DATE)
|
||||||
|
AC_SUBST(localedir)
|
||||||
AC_SUBST(MANGLING)
|
AC_SUBST(MANGLING)
|
||||||
AC_SUBST(MIRRORS)
|
AC_SUBST(MIRRORS)
|
||||||
AC_SUBST(MSGFMT)
|
AC_SUBST(MSGFMT)
|
||||||
@@ -1727,6 +1993,7 @@ AC_SUBST(OCF)
|
|||||||
AC_SUBST(OCFDIR)
|
AC_SUBST(OCFDIR)
|
||||||
AC_SUBST(PKGCONFIG)
|
AC_SUBST(PKGCONFIG)
|
||||||
AC_SUBST(POOL)
|
AC_SUBST(POOL)
|
||||||
|
AC_SUBST(M_LIBS)
|
||||||
AC_SUBST(PTHREAD_LIBS)
|
AC_SUBST(PTHREAD_LIBS)
|
||||||
AC_SUBST(PYTHON)
|
AC_SUBST(PYTHON)
|
||||||
AC_SUBST(PYTHON_BINDINGS)
|
AC_SUBST(PYTHON_BINDINGS)
|
||||||
@@ -1735,6 +2002,7 @@ AC_SUBST(PYTHON_LIBDIRS)
|
|||||||
AC_SUBST(QUORUM_CFLAGS)
|
AC_SUBST(QUORUM_CFLAGS)
|
||||||
AC_SUBST(QUORUM_LIBS)
|
AC_SUBST(QUORUM_LIBS)
|
||||||
AC_SUBST(RAID)
|
AC_SUBST(RAID)
|
||||||
|
AC_SUBST(RT_LIB)
|
||||||
AC_SUBST(READLINE_LIBS)
|
AC_SUBST(READLINE_LIBS)
|
||||||
AC_SUBST(REPLICATORS)
|
AC_SUBST(REPLICATORS)
|
||||||
AC_SUBST(SACKPT_CFLAGS)
|
AC_SUBST(SACKPT_CFLAGS)
|
||||||
@@ -1747,6 +2015,7 @@ AC_SUBST(SNAPSHOTS)
|
|||||||
AC_SUBST(STATICDIR)
|
AC_SUBST(STATICDIR)
|
||||||
AC_SUBST(STATIC_LINK)
|
AC_SUBST(STATIC_LINK)
|
||||||
AC_SUBST(TESTING)
|
AC_SUBST(TESTING)
|
||||||
|
AC_SUBST(TESTSUITE_DATA)
|
||||||
AC_SUBST(THIN)
|
AC_SUBST(THIN)
|
||||||
AC_SUBST(THIN_CHECK_CMD)
|
AC_SUBST(THIN_CHECK_CMD)
|
||||||
AC_SUBST(THIN_DUMP_CMD)
|
AC_SUBST(THIN_DUMP_CMD)
|
||||||
@@ -1762,9 +2031,13 @@ AC_SUBST(UDEV_SYNC)
|
|||||||
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||||
|
AC_SUBST(USE_TRACKING)
|
||||||
|
AC_SUBST(VALGRIND_POOL)
|
||||||
AC_SUBST(WRITE_INSTALL)
|
AC_SUBST(WRITE_INSTALL)
|
||||||
AC_SUBST(DMEVENTD_PIDFILE)
|
AC_SUBST(DMEVENTD_PIDFILE)
|
||||||
AC_SUBST(LVMETAD_PIDFILE)
|
AC_SUBST(LVMETAD_PIDFILE)
|
||||||
|
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||||
|
AC_SUBST(LVMLOCKD_PIDFILE)
|
||||||
AC_SUBST(CLVMD_PIDFILE)
|
AC_SUBST(CLVMD_PIDFILE)
|
||||||
AC_SUBST(CMIRRORD_PIDFILE)
|
AC_SUBST(CMIRRORD_PIDFILE)
|
||||||
AC_SUBST(interface)
|
AC_SUBST(interface)
|
||||||
@@ -1798,8 +2071,11 @@ daemons/dmeventd/plugins/mirror/Makefile
|
|||||||
daemons/dmeventd/plugins/snapshot/Makefile
|
daemons/dmeventd/plugins/snapshot/Makefile
|
||||||
daemons/dmeventd/plugins/thin/Makefile
|
daemons/dmeventd/plugins/thin/Makefile
|
||||||
daemons/lvmetad/Makefile
|
daemons/lvmetad/Makefile
|
||||||
|
daemons/lvmpolld/Makefile
|
||||||
|
daemons/lvmlockd/Makefile
|
||||||
conf/Makefile
|
conf/Makefile
|
||||||
conf/example.conf
|
conf/example.conf
|
||||||
|
conf/lvmlocal.conf
|
||||||
conf/command_profile_template.profile
|
conf/command_profile_template.profile
|
||||||
conf/metadata_profile_template.profile
|
conf/metadata_profile_template.profile
|
||||||
include/.symlinks
|
include/.symlinks
|
||||||
@@ -1810,7 +2086,7 @@ lib/format_pool/Makefile
|
|||||||
lib/locking/Makefile
|
lib/locking/Makefile
|
||||||
lib/mirror/Makefile
|
lib/mirror/Makefile
|
||||||
lib/replicator/Makefile
|
lib/replicator/Makefile
|
||||||
lib/misc/lvm-version.h
|
include/lvm-version.h
|
||||||
lib/raid/Makefile
|
lib/raid/Makefile
|
||||||
lib/snapshot/Makefile
|
lib/snapshot/Makefile
|
||||||
lib/thin/Makefile
|
lib/thin/Makefile
|
||||||
@@ -1840,6 +2116,11 @@ scripts/lvm2_cmirrord_systemd_red_hat.service
|
|||||||
scripts/lvm2_lvmetad_init_red_hat
|
scripts/lvm2_lvmetad_init_red_hat
|
||||||
scripts/lvm2_lvmetad_systemd_red_hat.service
|
scripts/lvm2_lvmetad_systemd_red_hat.service
|
||||||
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
||||||
|
scripts/lvm2_lvmpolld_init_red_hat
|
||||||
|
scripts/lvm2_lvmpolld_systemd_red_hat.service
|
||||||
|
scripts/lvm2_lvmpolld_systemd_red_hat.socket
|
||||||
|
scripts/lvm2_lvmlockd_systemd_red_hat.service
|
||||||
|
scripts/lvm2_lvmlocking_systemd_red_hat.service
|
||||||
scripts/lvm2_monitoring_init_red_hat
|
scripts/lvm2_monitoring_init_red_hat
|
||||||
scripts/lvm2_monitoring_systemd_red_hat.service
|
scripts/lvm2_monitoring_systemd_red_hat.service
|
||||||
scripts/lvm2_pvscan_systemd_red_hat@.service
|
scripts/lvm2_pvscan_systemd_red_hat@.service
|
||||||
@@ -1856,10 +2137,14 @@ unit-tests/mm/Makefile
|
|||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
test -n "$THIN_CONFIGURE_WARN" && AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])
|
AS_IF([test -n "$THIN_CONFIGURE_WARN"],
|
||||||
|
[AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])])
|
||||||
|
|
||||||
test -n "$THIN_CHECK_VERSION_WARN" && AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])
|
AS_IF([test -n "$THIN_CHECK_VERSION_WARN"],
|
||||||
|
[AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])])
|
||||||
|
|
||||||
test -n "$CACHE_CONFIGURE_WARN" && AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])
|
AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
|
||||||
|
[AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])])
|
||||||
|
|
||||||
test "$ODIRECT" = yes || AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])
|
AS_IF([test "$ODIRECT" != yes],
|
||||||
|
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of LVM2.
|
# This file is part of LVM2.
|
||||||
#
|
#
|
||||||
@@ -15,7 +15,7 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
.PHONY: dmeventd clvmd cmirrord lvmetad
|
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
|
||||||
|
|
||||||
ifneq ("@CLVMD@", "none")
|
ifneq ("@CLVMD@", "none")
|
||||||
SUBDIRS += clvmd
|
SUBDIRS += clvmd
|
||||||
@@ -36,8 +36,16 @@ ifeq ("@BUILD_LVMETAD@", "yes")
|
|||||||
SUBDIRS += lvmetad
|
SUBDIRS += lvmetad
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||||
|
SUBDIRS += lvmpolld
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LVMLOCKD@", "yes")
|
||||||
|
SUBDIRS += lvmlockd
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),distclean)
|
ifeq ($(MAKECMDGOALS),distclean)
|
||||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad
|
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|||||||
1
daemons/clvmd/.gitignore
vendored
Normal file
1
daemons/clvmd/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
clvmd
|
||||||
@@ -36,10 +36,6 @@ SOURCES = \
|
|||||||
lvm-functions.c \
|
lvm-functions.c \
|
||||||
refresh_clvmd.c
|
refresh_clvmd.c
|
||||||
|
|
||||||
ifeq ("@DEBUG@", "yes")
|
|
||||||
DEFS += -DDEBUG
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
|
ifneq (,$(findstring cman,, "@CLVMD@,"))
|
||||||
SOURCES += clvmd-cman.c
|
SOURCES += clvmd-cman.c
|
||||||
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
|
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
|
|||||||
int lkid;
|
int lkid;
|
||||||
char *lockname;
|
char *lockname;
|
||||||
|
|
||||||
|
DEBUGLOG("Client thread cleanup (%p)\n", client);
|
||||||
if (!client->bits.localsock.private)
|
if (!client->bits.localsock.private)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -331,7 +332,7 @@ void cmd_client_cleanup(struct local_client *client)
|
|||||||
dm_hash_iterate(v, lock_hash) {
|
dm_hash_iterate(v, lock_hash) {
|
||||||
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
|
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
|
||||||
lockname = dm_hash_get_key(lock_hash, v);
|
lockname = dm_hash_get_key(lock_hash, v);
|
||||||
DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
|
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
|
||||||
(void) sync_unlock(lockname, lkid);
|
(void) sync_unlock(lockname, lkid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +340,6 @@ void cmd_client_cleanup(struct local_client *client)
|
|||||||
client->bits.localsock.private = NULL;
|
client->bits.localsock.private = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int restart_clvmd(void)
|
static int restart_clvmd(void)
|
||||||
{
|
{
|
||||||
const char **argv;
|
const char **argv;
|
||||||
|
|||||||
@@ -18,15 +18,10 @@
|
|||||||
#ifndef _LVM_CLVMD_COMMON_H
|
#ifndef _LVM_CLVMD_COMMON_H
|
||||||
#define _LVM_CLVMD_COMMON_H
|
#define _LVM_CLVMD_COMMON_H
|
||||||
|
|
||||||
#include "configure.h"
|
|
||||||
|
|
||||||
#define _REENTRANT
|
#define _REENTRANT
|
||||||
#define _GNU_SOURCE
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
|
|
||||||
#include "libdevmapper.h"
|
#include "tool.h"
|
||||||
|
|
||||||
#include "lvm-logging.h"
|
#include "lvm-logging.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
|||||||
struct node_info *ninfo;
|
struct node_info *ninfo;
|
||||||
|
|
||||||
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
||||||
"%" PRIsize_t " left, %" PRIsize_t " members\n",
|
FMTsize_t " left, %" PRIsize_t " members\n",
|
||||||
joined_list_entries, left_list_entries, member_list_entries);
|
joined_list_entries, left_list_entries, member_list_entries);
|
||||||
|
|
||||||
for (i=0; i<joined_list_entries; i++) {
|
for (i=0; i<joined_list_entries; i++) {
|
||||||
|
|||||||
@@ -208,8 +208,6 @@ static int _lock_resource(const char *resource, int mode, int flags, int *lockid
|
|||||||
pthread_mutex_lock(&_lock_mutex);
|
pthread_mutex_lock(&_lock_mutex);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
|
||||||
|
|
||||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||||
if (flags & LCKF_CONVERT) {
|
if (flags & LCKF_CONVERT) {
|
||||||
/* In real DLM, lock is identified only by lockid, resource is not used */
|
/* In real DLM, lock is identified only by lockid, resource is not used */
|
||||||
@@ -269,12 +267,14 @@ retry:
|
|||||||
dm_list_add(head, &lck->list);
|
dm_list_add(head, &lck->list);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||||
pthread_mutex_unlock(&_lock_mutex);
|
pthread_mutex_unlock(&_lock_mutex);
|
||||||
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
||||||
resource, lck->lockid, _get_mode(lck->mode));
|
resource, lck->lockid, _get_mode(lck->mode));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
bad:
|
bad:
|
||||||
|
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||||
pthread_mutex_unlock(&_lock_mutex);
|
pthread_mutex_unlock(&_lock_mutex);
|
||||||
DEBUGLOG("Failed to lock resource %s\n", resource);
|
DEBUGLOG("Failed to lock resource %s\n", resource);
|
||||||
|
|
||||||
|
|||||||
@@ -153,16 +153,11 @@ static if_type_t get_cluster_type(void);
|
|||||||
static void usage(const char *prog, FILE *file)
|
static void usage(const char *prog, FILE *file)
|
||||||
{
|
{
|
||||||
fprintf(file, "Usage: %s [options]\n"
|
fprintf(file, "Usage: %s [options]\n"
|
||||||
" -V Show version of clvmd\n"
|
|
||||||
" -h Show this help information\n"
|
|
||||||
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
|
||||||
" -f Don't fork, run in the foreground\n"
|
|
||||||
" -E<lockuuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
|
||||||
" -R Tell all running clvmds in the cluster to reload their device cache\n"
|
|
||||||
" -S Restart clvmd, preserving exclusive locks\n"
|
|
||||||
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
||||||
" -t<secs> Command timeout (default 60 seconds)\n"
|
" -d[<n>] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||||
" -T<secs> Startup timeout (default none)\n"
|
" -E<uuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
||||||
|
" -f Don't fork, run in the foreground\n"
|
||||||
|
" -h Show this help information\n"
|
||||||
" -I<cmgr> Cluster manager (default: auto)\n"
|
" -I<cmgr> Cluster manager (default: auto)\n"
|
||||||
" Available cluster managers: "
|
" Available cluster managers: "
|
||||||
#ifdef USE_COROSYNC
|
#ifdef USE_COROSYNC
|
||||||
@@ -177,6 +172,12 @@ static void usage(const char *prog, FILE *file)
|
|||||||
#ifdef USE_SINGLENODE
|
#ifdef USE_SINGLENODE
|
||||||
"singlenode "
|
"singlenode "
|
||||||
#endif
|
#endif
|
||||||
|
"\n"
|
||||||
|
" -R Tell all running clvmds in the cluster to reload their device cache\n"
|
||||||
|
" -S Restart clvmd, preserving exclusive locks\n"
|
||||||
|
" -t<secs> Command timeout (default: 60 seconds)\n"
|
||||||
|
" -T<secs> Startup timeout (default: 0 seconds)\n"
|
||||||
|
" -V Show version of clvmd\n"
|
||||||
"\n", prog);
|
"\n", prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +223,7 @@ void debuglog(const char *fmt, ...)
|
|||||||
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
|
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
fflush(stderr);
|
||||||
break;
|
break;
|
||||||
case DEBUG_SYSLOG:
|
case DEBUG_SYSLOG:
|
||||||
if (!syslog_init) {
|
if (!syslog_init) {
|
||||||
@@ -597,7 +599,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* This needs to be started after cluster initialisation
|
/* This needs to be started after cluster initialisation
|
||||||
as it may need to take out locks */
|
as it may need to take out locks */
|
||||||
DEBUGLOG("starting LVM thread\n");
|
DEBUGLOG("Starting LVM thread\n");
|
||||||
|
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
|
||||||
|
local_client_head.fd, &local_client_head, newfd->fd, newfd);
|
||||||
|
|
||||||
/* Don't let anyone else to do work until we are started */
|
/* Don't let anyone else to do work until we are started */
|
||||||
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
|
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
|
||||||
@@ -697,7 +701,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
|||||||
newfd->type = LOCAL_SOCK;
|
newfd->type = LOCAL_SOCK;
|
||||||
newfd->callback = local_sock_callback;
|
newfd->callback = local_sock_callback;
|
||||||
newfd->bits.localsock.all_success = 1;
|
newfd->bits.localsock.all_success = 1;
|
||||||
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
|
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
|
||||||
*new_client = newfd;
|
*new_client = newfd;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -849,18 +853,48 @@ static void main_loop(int cmd_timeout)
|
|||||||
struct local_client *thisfd;
|
struct local_client *thisfd;
|
||||||
struct timeval tv = { cmd_timeout, 0 };
|
struct timeval tv = { cmd_timeout, 0 };
|
||||||
int quorate = clops->is_quorate();
|
int quorate = clops->is_quorate();
|
||||||
|
int client_count = 0;
|
||||||
|
int max_fd = 0;
|
||||||
|
struct local_client *lastfd = &local_client_head;
|
||||||
|
struct local_client *nextfd = local_client_head.next;
|
||||||
|
|
||||||
/* Wait on the cluster FD and all local sockets/pipes */
|
/* Wait on the cluster FD and all local sockets/pipes */
|
||||||
local_client_head.fd = clops->get_main_cluster_fd();
|
local_client_head.fd = clops->get_main_cluster_fd();
|
||||||
FD_ZERO(&in);
|
FD_ZERO(&in);
|
||||||
|
|
||||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||||
|
client_count++;
|
||||||
|
max_fd = max(max_fd, thisfd->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_fd > FD_SETSIZE - 32) {
|
||||||
|
fprintf(stderr, "WARNING: There are too many connections to clvmd. Investigate and take action now!\n");
|
||||||
|
fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
|
||||||
|
|
||||||
|
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
|
||||||
|
struct local_client *free_fd = thisfd;
|
||||||
|
lastfd->next = nextfd;
|
||||||
|
DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
|
||||||
|
|
||||||
|
/* Queue cleanup, this also frees the client struct */
|
||||||
|
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastfd = thisfd;
|
||||||
|
|
||||||
if (thisfd->removeme)
|
if (thisfd->removeme)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* if the cluster is not quorate then don't listen for new requests */
|
/* if the cluster is not quorate then don't listen for new requests */
|
||||||
if ((thisfd->type != LOCAL_RENDEZVOUS &&
|
if ((thisfd->type != LOCAL_RENDEZVOUS &&
|
||||||
thisfd->type != LOCAL_SOCK) || quorate)
|
thisfd->type != LOCAL_SOCK) || quorate)
|
||||||
FD_SET(thisfd->fd, &in);
|
if (thisfd->fd < FD_SETSIZE)
|
||||||
|
FD_SET(thisfd->fd, &in);
|
||||||
}
|
}
|
||||||
|
|
||||||
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
|
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
|
||||||
@@ -876,31 +910,22 @@ static void main_loop(int cmd_timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (select_status > 0) {
|
if (select_status > 0) {
|
||||||
struct local_client *lastfd = NULL;
|
|
||||||
char csid[MAX_CSID_LEN];
|
char csid[MAX_CSID_LEN];
|
||||||
char buf[max_cluster_message];
|
char buf[max_cluster_message];
|
||||||
|
|
||||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||||
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
|
if (thisfd->fd < FD_SETSIZE && FD_ISSET(thisfd->fd, &in)) {
|
||||||
struct local_client *free_fd = thisfd;
|
|
||||||
lastfd->next = thisfd->next;
|
|
||||||
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
|
|
||||||
|
|
||||||
/* Queue cleanup, this also frees the client struct */
|
|
||||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FD_ISSET(thisfd->fd, &in)) {
|
|
||||||
struct local_client *newfd = NULL;
|
struct local_client *newfd = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* FIXME Remove from main thread in case it blocks! */
|
||||||
/* Do callback */
|
/* Do callback */
|
||||||
ret = thisfd->callback(thisfd, buf, sizeof(buf),
|
ret = thisfd->callback(thisfd, buf, sizeof(buf),
|
||||||
csid, &newfd);
|
csid, &newfd);
|
||||||
/* Ignore EAGAIN */
|
/* Ignore EAGAIN */
|
||||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR))
|
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Got error or EOF: Remove it from the list safely */
|
/* Got error or EOF: Remove it from the list safely */
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
@@ -914,17 +939,16 @@ static void main_loop(int cmd_timeout)
|
|||||||
DEBUGLOG("ret == %d, errno = %d. removing client\n",
|
DEBUGLOG("ret == %d, errno = %d. removing client\n",
|
||||||
ret, errno);
|
ret, errno);
|
||||||
thisfd->removeme = 1;
|
thisfd->removeme = 1;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New client...simply add it to the list */
|
/* New client...simply add it to the list */
|
||||||
if (newfd) {
|
if (newfd) {
|
||||||
newfd->next = thisfd->next;
|
newfd->next = thisfd->next;
|
||||||
thisfd->next = newfd;
|
thisfd->next = newfd;
|
||||||
break;
|
thisfd = newfd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastfd = thisfd;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1128,7 +1152,7 @@ static void dump_message(char *buf, int len)
|
|||||||
row[j] = buf[i];
|
row[j] = buf[i];
|
||||||
str[j] = (isprint(buf[i])) ? buf[i] : ' ';
|
str[j] = (isprint(buf[i])) ? buf[i] : ' ';
|
||||||
|
|
||||||
if ((j == 8) || (i + 1 == len)) {
|
if (i + 1 == len) {
|
||||||
for (;j < 8; ++j) {
|
for (;j < 8; ++j) {
|
||||||
row[j] = 0;
|
row[j] = 0;
|
||||||
str[j] = ' ';
|
str[j] = ' ';
|
||||||
@@ -1417,7 +1441,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
|||||||
thisfd->bits.localsock.in_progress = TRUE;
|
thisfd->bits.localsock.in_progress = TRUE;
|
||||||
thisfd->bits.localsock.state = PRE_COMMAND;
|
thisfd->bits.localsock.state = PRE_COMMAND;
|
||||||
thisfd->bits.localsock.cleanup_needed = 1;
|
thisfd->bits.localsock.cleanup_needed = 1;
|
||||||
DEBUGLOG("Creating pre&post thread\n");
|
DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
|
||||||
status = pthread_create(&thisfd->bits.localsock.threadid,
|
status = pthread_create(&thisfd->bits.localsock.threadid,
|
||||||
&stack_attr, pre_and_post_thread, thisfd);
|
&stack_attr, pre_and_post_thread, thisfd);
|
||||||
DEBUGLOG("Created pre&post thread, state = %d\n", status);
|
DEBUGLOG("Created pre&post thread, state = %d\n", status);
|
||||||
@@ -1671,7 +1695,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
|||||||
sigset_t ss;
|
sigset_t ss;
|
||||||
int pipe_fd = client->bits.localsock.pipe;
|
int pipe_fd = client->bits.localsock.pipe;
|
||||||
|
|
||||||
DEBUGLOG("Pre&post thread (%p), pipe %d\n", client, pipe_fd);
|
DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
|
||||||
pthread_mutex_lock(&client->bits.localsock.mutex);
|
pthread_mutex_lock(&client->bits.localsock.mutex);
|
||||||
|
|
||||||
/* Ignore SIGUSR1 (handled by master process) but enable
|
/* Ignore SIGUSR1 (handled by master process) but enable
|
||||||
@@ -1691,7 +1715,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
|||||||
if ((status = do_pre_command(client)))
|
if ((status = do_pre_command(client)))
|
||||||
client->bits.localsock.all_success = 0;
|
client->bits.localsock.all_success = 0;
|
||||||
|
|
||||||
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe %d\n",
|
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
|
||||||
client, status, pipe_fd);
|
client, status, pipe_fd);
|
||||||
|
|
||||||
/* Tell the parent process we have finished this bit */
|
/* Tell the parent process we have finished this bit */
|
||||||
@@ -1973,7 +1997,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
|
|||||||
{
|
{
|
||||||
/* If msg is NULL then this is a cleanup request */
|
/* If msg is NULL then this is a cleanup request */
|
||||||
if (cmd->msg == NULL) {
|
if (cmd->msg == NULL) {
|
||||||
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
|
DEBUGLOG("process_work_item: free %p\n", cmd->client);
|
||||||
cmd_client_cleanup(cmd->client);
|
cmd_client_cleanup(cmd->client);
|
||||||
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
|
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
|
||||||
pthread_cond_destroy(&cmd->client->bits.localsock.cond);
|
pthread_cond_destroy(&cmd->client->bits.localsock.cond);
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ static const char *decode_flags(unsigned char flags)
|
|||||||
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
||||||
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
||||||
flags & LCK_TEST_MODE ? "TEST|" : "",
|
flags & LCK_TEST_MODE ? "TEST|" : "",
|
||||||
flags & LCK_CONVERT ? "CONVERT|" : "",
|
flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
|
||||||
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
||||||
flags & LCK_REVERT_MODE ? "REVERT|" : "");
|
flags & LCK_REVERT_MODE ? "REVERT|" : "");
|
||||||
|
|
||||||
@@ -375,7 +375,7 @@ static int do_activate_lv(char *resource, unsigned char command, unsigned char l
|
|||||||
* of exclusive lock to shared one during activation.
|
* of exclusive lock to shared one during activation.
|
||||||
*/
|
*/
|
||||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||||
status = hold_lock(resource, mode, LCKF_NOQUEUE | (lock_flags & LCK_CONVERT ? LCKF_CONVERT:0));
|
status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
|
||||||
if (status) {
|
if (status) {
|
||||||
/* Return an LVM-sensible error for this.
|
/* Return an LVM-sensible error for this.
|
||||||
* Forcing EIO makes the upper level return this text
|
* Forcing EIO makes the upper level return this text
|
||||||
@@ -510,7 +510,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
|||||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||||
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
|
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
|
||||||
|
|
||||||
if (!cmd->config_initialized || config_files_changed(cmd)) {
|
if (!cmd->initialized.config || config_files_changed(cmd)) {
|
||||||
/* Reinitialise various settings inc. logging, filters */
|
/* Reinitialise various settings inc. logging, filters */
|
||||||
if (do_refresh_cache()) {
|
if (do_refresh_cache()) {
|
||||||
log_error("Updated config file invalid. Aborting.");
|
log_error("Updated config file invalid. Aborting.");
|
||||||
@@ -899,7 +899,7 @@ int init_clvm(struct dm_hash_table *excl_uuid)
|
|||||||
if (!get_initial_state(excl_uuid))
|
if (!get_initial_state(excl_uuid))
|
||||||
log_error("Cannot load initial lock states.");
|
log_error("Cannot load initial lock states.");
|
||||||
|
|
||||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1))) {
|
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||||
log_error("Failed to allocate command context");
|
log_error("Failed to allocate command context");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
1
daemons/cmirrord/.gitignore
vendored
Normal file
1
daemons/cmirrord/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
cmirrord
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "link_mon.h"
|
#include "link_mon.h"
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@@ -32,14 +33,49 @@ static void daemonize(void);
|
|||||||
static void init_all(void);
|
static void init_all(void);
|
||||||
static void cleanup_all(void);
|
static void cleanup_all(void);
|
||||||
|
|
||||||
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
|
static void usage (FILE *dest)
|
||||||
{
|
{
|
||||||
daemonize();
|
fprintf (dest, "Usage: cmirrord [options]\n"
|
||||||
|
" -f, --foreground stay in the foreground, log to the terminal\n"
|
||||||
|
" -h, --help print this help\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int foreground_mode = 0;
|
||||||
|
struct option longopts[] = {
|
||||||
|
{ "foreground", no_argument, NULL, 'f' },
|
||||||
|
{ "help" , no_argument, NULL, 'h' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'f':
|
||||||
|
foreground_mode = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
usage (stdout);
|
||||||
|
exit (0);
|
||||||
|
default:
|
||||||
|
usage (stderr);
|
||||||
|
exit (2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (optind < argc) {
|
||||||
|
usage (stderr);
|
||||||
|
exit (2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foreground_mode)
|
||||||
|
daemonize();
|
||||||
|
|
||||||
init_all();
|
init_all();
|
||||||
|
|
||||||
/* Parent can now exit, we're ready to handle requests */
|
/* Parent can now exit, we're ready to handle requests */
|
||||||
kill(getppid(), SIGTERM);
|
if (!foreground_mode)
|
||||||
|
kill(getppid(), SIGTERM);
|
||||||
|
|
||||||
LOG_PRINT("Starting cmirrord:");
|
LOG_PRINT("Starting cmirrord:");
|
||||||
LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
|
LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
|
||||||
@@ -209,6 +245,16 @@ static void daemonize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* init_all
|
||||||
|
*
|
||||||
|
* Initialize modules. Exit on failure.
|
||||||
|
*/
|
||||||
|
static void init_all(void)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
|
(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
|
||||||
if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
|
if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
|
||||||
@@ -227,16 +273,6 @@ static void daemonize(void)
|
|||||||
signal(SIGUSR2, &sig_handler);
|
signal(SIGUSR2, &sig_handler);
|
||||||
sigemptyset(&signal_mask);
|
sigemptyset(&signal_mask);
|
||||||
signal_received = 0;
|
signal_received = 0;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* init_all
|
|
||||||
*
|
|
||||||
* Initialize modules. Exit on failure.
|
|
||||||
*/
|
|
||||||
static void init_all(void)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((r = init_local()) ||
|
if ((r = init_local()) ||
|
||||||
(r = init_cluster())) {
|
(r = init_cluster())) {
|
||||||
|
|||||||
@@ -104,10 +104,11 @@ static SaVersionT version = { 'B', 1, 1 };
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUGGING_HISTORY 100
|
#define DEBUGGING_HISTORY 100
|
||||||
|
#define DEBUGGING_BUFLEN 128
|
||||||
#define LOG_SPRINT(cc, f, arg...) do { \
|
#define LOG_SPRINT(cc, f, arg...) do { \
|
||||||
cc->idx++; \
|
cc->idx++; \
|
||||||
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
||||||
sprintf(cc->debugging[cc->idx], f, ## arg); \
|
snprintf(cc->debugging[cc->idx], DEBUGGING_BUFLEN, f, ## arg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int log_resp_rec = 0;
|
static int log_resp_rec = 0;
|
||||||
@@ -150,7 +151,7 @@ struct clog_cpg {
|
|||||||
uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS];
|
uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS];
|
||||||
struct checkpoint_data *checkpoint_list;
|
struct checkpoint_data *checkpoint_list;
|
||||||
int idx;
|
int idx;
|
||||||
char debugging[DEBUGGING_HISTORY][128];
|
char debugging[DEBUGGING_HISTORY][DEBUGGING_BUFLEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dm_list clog_cpg_list;
|
static struct dm_list clog_cpg_list;
|
||||||
@@ -1294,7 +1295,9 @@ static void cpg_join_callback(struct clog_cpg *match,
|
|||||||
uint32_t my_pid = (uint32_t)getpid();
|
uint32_t my_pid = (uint32_t)getpid();
|
||||||
uint32_t lowest = match->lowest_id;
|
uint32_t lowest = match->lowest_id;
|
||||||
struct clog_request *rq;
|
struct clog_request *rq;
|
||||||
char dbuf[32] = { 0 };
|
char dbuf[64] = { 0 };
|
||||||
|
char *dbuf_p = dbuf;
|
||||||
|
size_t dbuf_rem = sizeof dbuf;
|
||||||
|
|
||||||
/* Assign my_cluster_id */
|
/* Assign my_cluster_id */
|
||||||
if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
|
if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
|
||||||
@@ -1310,9 +1313,17 @@ static void cpg_join_callback(struct clog_cpg *match,
|
|||||||
if (joined->nodeid == my_cluster_id)
|
if (joined->nodeid == my_cluster_id)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i < member_list_entries - 1; i++)
|
for (i = 0; i < member_list_entries - 1; i++) {
|
||||||
sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid);
|
int written = snprintf(dbuf_p, dbuf_rem, "%u-", member_list[i].nodeid);
|
||||||
sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid);
|
if (written < 0) continue; /* impossible */
|
||||||
|
if ((unsigned)written >= dbuf_rem) {
|
||||||
|
dbuf_rem = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dbuf_rem -= written;
|
||||||
|
dbuf_p += written;
|
||||||
|
}
|
||||||
|
snprintf(dbuf_p, dbuf_rem, "(%u)", joined->nodeid);
|
||||||
LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]",
|
LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]",
|
||||||
SHORT_UUID(match->name.value), joined->nodeid, dbuf);
|
SHORT_UUID(match->name.value), joined->nodeid, dbuf);
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,13 @@
|
|||||||
#define LOG_OFFSET 2
|
#define LOG_OFFSET 2
|
||||||
|
|
||||||
#define RESYNC_HISTORY 50
|
#define RESYNC_HISTORY 50
|
||||||
|
#define RESYNC_BUFLEN 128
|
||||||
//static char resync_history[RESYNC_HISTORY][128];
|
//static char resync_history[RESYNC_HISTORY][128];
|
||||||
//static int idx = 0;
|
//static int idx = 0;
|
||||||
#define LOG_SPRINT(_lc, f, arg...) do { \
|
#define LOG_SPRINT(_lc, f, arg...) do { \
|
||||||
lc->idx++; \
|
lc->idx++; \
|
||||||
lc->idx = lc->idx % RESYNC_HISTORY; \
|
lc->idx = lc->idx % RESYNC_HISTORY; \
|
||||||
sprintf(lc->resync_history[lc->idx], f, ## arg); \
|
snprintf(lc->resync_history[lc->idx], RESYNC_BUFLEN, f, ## arg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
struct log_header {
|
struct log_header {
|
||||||
@@ -88,7 +89,7 @@ struct log_c {
|
|||||||
size_t disk_size; /* size of disk_buffer in bytes */
|
size_t disk_size; /* size of disk_buffer in bytes */
|
||||||
void *disk_buffer; /* aligned memory for O_DIRECT */
|
void *disk_buffer; /* aligned memory for O_DIRECT */
|
||||||
int idx;
|
int idx;
|
||||||
char resync_history[RESYNC_HISTORY][128];
|
char resync_history[RESYNC_HISTORY][RESYNC_BUFLEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mark_entry {
|
struct mark_entry {
|
||||||
@@ -1444,7 +1445,7 @@ static int disk_status_info(struct log_c *lc, struct dm_ulog_request *rq)
|
|||||||
char *data = (char *)rq->data;
|
char *data = (char *)rq->data;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
if(fstat(lc->disk_fd, &statbuf)) {
|
if (fstat(lc->disk_fd, &statbuf)) {
|
||||||
rq->error = -errno;
|
rq->error = -errno;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
@@ -1507,7 +1508,7 @@ static int disk_status_table(struct log_c *lc, struct dm_ulog_request *rq)
|
|||||||
char *data = (char *)rq->data;
|
char *data = (char *)rq->data;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
if(fstat(lc->disk_fd, &statbuf)) {
|
if (fstat(lc->disk_fd, &statbuf)) {
|
||||||
rq->error = -errno;
|
rq->error = -errno;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|||||||
1
daemons/dmeventd/.gitignore
vendored
Normal file
1
daemons/dmeventd/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dmeventd
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of the device-mapper userspace tools.
|
* This file is part of the device-mapper userspace tools.
|
||||||
*
|
*
|
||||||
@@ -12,23 +12,22 @@
|
|||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "dm-logging.h"
|
||||||
#include "dmlib.h"
|
#include "dmlib.h"
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
//#include "libmultilog.h"
|
|
||||||
#include "dmeventd.h"
|
#include "dmeventd.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
static int _debug_level = 0;
|
||||||
|
static int _use_syslog = 0;
|
||||||
static int _sequence_nr = 0;
|
static int _sequence_nr = 0;
|
||||||
|
|
||||||
struct dm_event_handler {
|
struct dm_event_handler {
|
||||||
@@ -199,7 +198,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg)
|
|||||||
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
||||||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
||||||
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
||||||
"Expected %d:%d but received %s", getpid(),
|
"Expected %d:%d but received %s.", getpid(),
|
||||||
_sequence_nr, msg->data);
|
_sequence_nr, msg->data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -234,7 +233,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
|||||||
FD_SET(fifos->server, &fds);
|
FD_SET(fifos->server, &fds);
|
||||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||||
if (ret < 0 && errno != EINTR) {
|
if (ret < 0 && errno != EINTR) {
|
||||||
log_error("Unable to read from event server");
|
log_error("Unable to read from event server.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((ret == 0) && (i > 4) && !bytes) {
|
if ((ret == 0) && (i > 4) && !bytes) {
|
||||||
@@ -300,7 +299,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
log_error("Unable to talk to event daemon");
|
log_error("Unable to talk to event daemon.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
@@ -309,7 +308,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if ((errno == EINTR) || (errno == EAGAIN))
|
if ((errno == EINTR) || (errno == EAGAIN))
|
||||||
continue;
|
continue;
|
||||||
log_error("Unable to talk to event daemon");
|
log_error("Unable to talk to event daemon.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,7 +320,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
FD_SET(fifos->client, &fds);
|
FD_SET(fifos->client, &fds);
|
||||||
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
||||||
if ((ret < 0) && (errno != EINTR)) {
|
if ((ret < 0) && (errno != EINTR)) {
|
||||||
log_error("Unable to talk to event daemon");
|
log_error("Unable to talk to event daemon.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} while (ret < 1);
|
} while (ret < 1);
|
||||||
@@ -331,7 +330,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
|||||||
if ((errno == EINTR) || (errno == EAGAIN))
|
if ((errno == EINTR) || (errno == EAGAIN))
|
||||||
continue;
|
continue;
|
||||||
else {
|
else {
|
||||||
log_error("Unable to talk to event daemon");
|
log_error("Unable to talk to event daemon.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +360,7 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
|||||||
getpid(), _sequence_nr,
|
getpid(), _sequence_nr,
|
||||||
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
||||||
< 0) {
|
< 0) {
|
||||||
log_error("_daemon_talk: message allocation failed");
|
log_error("_daemon_talk: message allocation failed.");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
msg->cmd = cmd;
|
msg->cmd = cmd;
|
||||||
@@ -449,11 +448,11 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
|||||||
|
|
||||||
else if (!pid) {
|
else if (!pid) {
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
log_error("Unable to exec dmeventd: %s", strerror(errno));
|
log_error("Unable to exec dmeventd: %s.", strerror(errno));
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
} else {
|
} else {
|
||||||
if (waitpid(pid, &status, 0) < 0)
|
if (waitpid(pid, &status, 0) < 0)
|
||||||
log_error("Unable to start dmeventd: %s",
|
log_error("Unable to start dmeventd: %s.",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
else if (WEXITSTATUS(status))
|
else if (WEXITSTATUS(status))
|
||||||
log_error("Unable to start dmeventd.");
|
log_error("Unable to start dmeventd.");
|
||||||
@@ -526,7 +525,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
|||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
|
|
||||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||||
log_error("_get_device_info: dm_task creation for info failed");
|
log_error("_get_device_info: dm_task creation for info failed.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,17 +543,17 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
|||||||
|
|
||||||
/* FIXME Add name or uuid or devno to messages */
|
/* FIXME Add name or uuid or devno to messages */
|
||||||
if (!dm_task_run(dmt)) {
|
if (!dm_task_run(dmt)) {
|
||||||
log_error("_get_device_info: dm_task_run() failed");
|
log_error("_get_device_info: dm_task_run() failed.");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &info)) {
|
if (!dm_task_get_info(dmt, &info)) {
|
||||||
log_error("_get_device_info: failed to get info for device");
|
log_error("_get_device_info: failed to get info for device.");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.exists) {
|
if (!info.exists) {
|
||||||
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found",
|
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.",
|
||||||
dmevh->uuid ? : "",
|
dmevh->uuid ? : "",
|
||||||
(!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
|
(!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
|
||||||
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
||||||
@@ -623,12 +622,12 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
|||||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
||||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
||||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
||||||
log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso);
|
log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso);
|
||||||
|
|
||||||
|
|
||||||
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||||
log_error("%s: event registration failed: %s",
|
log_error("%s: event registration failed: %s.",
|
||||||
dm_task_get_name(dmt),
|
dm_task_get_name(dmt),
|
||||||
msg.data ? msg.data : strerror(-err));
|
msg.data ? msg.data : strerror(-err));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -655,7 +654,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
|||||||
|
|
||||||
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||||
log_error("%s: event deregistration failed: %s",
|
log_error("%s: event deregistration failed: %s.",
|
||||||
dm_task_get_name(dmt),
|
dm_task_get_name(dmt),
|
||||||
msg.data ? msg.data : strerror(-err));
|
msg.data ? msg.data : strerror(-err));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -828,6 +827,79 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dm_event_log_set(int debug_level, int use_syslog)
|
||||||
|
{
|
||||||
|
_debug_level = debug_level;
|
||||||
|
_use_syslog = use_syslog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dm_event_log(const char *subsys, int level, const char *file,
|
||||||
|
int line, int dm_errno_or_class,
|
||||||
|
const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static time_t start = 0;
|
||||||
|
const char *indent = "";
|
||||||
|
FILE *stream = stdout;
|
||||||
|
int prio = -1;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
|
||||||
|
case _LOG_DEBUG:
|
||||||
|
if (_debug_level < 3)
|
||||||
|
return;
|
||||||
|
prio = LOG_DEBUG;
|
||||||
|
indent = " ";
|
||||||
|
break;
|
||||||
|
case _LOG_INFO:
|
||||||
|
if (_debug_level < 2)
|
||||||
|
return;
|
||||||
|
prio = LOG_INFO;
|
||||||
|
indent = " ";
|
||||||
|
break;
|
||||||
|
case _LOG_NOTICE:
|
||||||
|
if (_debug_level < 1)
|
||||||
|
return;
|
||||||
|
prio = LOG_NOTICE;
|
||||||
|
indent = " ";
|
||||||
|
break;
|
||||||
|
case _LOG_WARN:
|
||||||
|
prio = LOG_WARNING;
|
||||||
|
break;
|
||||||
|
case _LOG_ERR:
|
||||||
|
prio = LOG_ERR;
|
||||||
|
stream = stderr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prio = LOG_CRIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Serialize to keep lines readable */
|
||||||
|
pthread_mutex_lock(&_log_mutex);
|
||||||
|
|
||||||
|
if (_use_syslog) {
|
||||||
|
vsyslog(prio, format, ap);
|
||||||
|
} else {
|
||||||
|
now = time(NULL);
|
||||||
|
if (!start)
|
||||||
|
start = now;
|
||||||
|
now -= start;
|
||||||
|
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||||
|
(int)now / 60, (int)now % 60,
|
||||||
|
// TODO: Maybe use shorter ID
|
||||||
|
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||||
|
(int)pthread_self(), subsys,
|
||||||
|
(_debug_level > 3) ? "" : indent);
|
||||||
|
if (_debug_level > 3)
|
||||||
|
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||||
|
vfprintf(stream, _(format), ap);
|
||||||
|
fputc('\n', stream);
|
||||||
|
fflush(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_log_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0 /* left out for now */
|
#if 0 /* left out for now */
|
||||||
|
|
||||||
static char *_skip_string(char *src, const int delimiter)
|
static char *_skip_string(char *src, const int delimiter)
|
||||||
@@ -861,7 +933,7 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
|||||||
0, 0))) {
|
0, 0))) {
|
||||||
char *p = _skip_string(msg.data, ' ');
|
char *p = _skip_string(msg.data, ' ');
|
||||||
if (!p) {
|
if (!p) {
|
||||||
log_error("malformed reply from dmeventd '%s'\n",
|
log_error("Malformed reply from dmeventd '%s'.",
|
||||||
msg.data);
|
msg.data);
|
||||||
dm_free(msg.data);
|
dm_free(msg.data);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of the device-mapper userspace tools.
|
* This file is part of the device-mapper userspace tools.
|
||||||
*
|
*
|
||||||
@@ -105,6 +105,25 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
|||||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||||
|
|
||||||
|
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
|
||||||
|
void dm_event_log_set(int debug_level, int use_syslog);
|
||||||
|
|
||||||
|
/* Log messages acroding to current debug level */
|
||||||
|
__attribute__((format(printf, 6, 0)))
|
||||||
|
void dm_event_log(const char *subsys, int level, const char *file,
|
||||||
|
int line, int dm_errno_or_class,
|
||||||
|
const char *format, va_list ap);
|
||||||
|
/* Macro to route print_log do dm_event_log() */
|
||||||
|
#define DM_EVENT_LOG_FN(subsys) \
|
||||||
|
void print_log(int level, const char *file, int line, int dm_errno_or_class,\
|
||||||
|
const char *format, ...)\
|
||||||
|
{\
|
||||||
|
va_list ap;\
|
||||||
|
va_start(ap, format);\
|
||||||
|
dm_event_log(subsys, level, file, line, dm_errno_or_class, format, ap);\
|
||||||
|
va_end(ap);\
|
||||||
|
}
|
||||||
|
|
||||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||||
detailed descriptions. */
|
detailed descriptions. */
|
||||||
// FIXME misuse of bitmask as enum
|
// FIXME misuse of bitmask as enum
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -13,15 +13,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include "lvm2cmd.h"
|
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
|
#include "libdevmapper-event.h"
|
||||||
|
#include "lvm2cmd.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
extern int dmeventd_debug;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* register_device() is called first and performs initialisation.
|
* register_device() is called first and performs initialisation.
|
||||||
@@ -36,48 +32,19 @@ static int _register_count = 0;
|
|||||||
static struct dm_pool *_mem_pool = NULL;
|
static struct dm_pool *_mem_pool = NULL;
|
||||||
static void *_lvm_handle = NULL;
|
static void *_lvm_handle = NULL;
|
||||||
|
|
||||||
|
DM_EVENT_LOG_FN("lvm")
|
||||||
|
|
||||||
|
static void _lvm2_print_log(int level, const char *file, int line,
|
||||||
|
int dm_errno_or_class, const char *msg)
|
||||||
|
{
|
||||||
|
print_log(level, file, line, dm_errno_or_class, "%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently only one event can be processed at a time.
|
* Currently only one event can be processed at a time.
|
||||||
*/
|
*/
|
||||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME Do not pass things directly to syslog, rather use the existing logging
|
|
||||||
* facilities to sort logging ... however that mechanism needs to be somehow
|
|
||||||
* configurable and we don't have that option yet
|
|
||||||
*/
|
|
||||||
static void _temporary_log_fn(int level,
|
|
||||||
const char *file __attribute__((unused)),
|
|
||||||
int line __attribute__((unused)),
|
|
||||||
int dm_errno __attribute__((unused)),
|
|
||||||
const char *message)
|
|
||||||
{
|
|
||||||
level &= ~(_LOG_STDERR | _LOG_ONCE);
|
|
||||||
|
|
||||||
switch (level) {
|
|
||||||
case _LOG_DEBUG:
|
|
||||||
if (dmeventd_debug >= 3)
|
|
||||||
syslog(LOG_DEBUG, "%s", message);
|
|
||||||
break;
|
|
||||||
case _LOG_INFO:
|
|
||||||
if (dmeventd_debug >= 2)
|
|
||||||
syslog(LOG_INFO, "%s", message);
|
|
||||||
break;
|
|
||||||
case _LOG_NOTICE:
|
|
||||||
if (dmeventd_debug >= 1)
|
|
||||||
syslog(LOG_NOTICE, "%s", message);
|
|
||||||
break;
|
|
||||||
case _LOG_WARN:
|
|
||||||
syslog(LOG_WARNING, "%s", message);
|
|
||||||
break;
|
|
||||||
case _LOG_ERR:
|
|
||||||
syslog(LOG_ERR, "%s", message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
syslog(LOG_CRIT, "%s", message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dmeventd_lvm2_lock(void)
|
void dmeventd_lvm2_lock(void)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&_event_mutex);
|
pthread_mutex_lock(&_event_mutex);
|
||||||
@@ -94,23 +61,26 @@ int dmeventd_lvm2_init(void)
|
|||||||
|
|
||||||
pthread_mutex_lock(&_register_mutex);
|
pthread_mutex_lock(&_register_mutex);
|
||||||
|
|
||||||
/*
|
|
||||||
* Need some space for allocations. 1024 should be more
|
|
||||||
* than enough for what we need (device mapper name splitting)
|
|
||||||
*/
|
|
||||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!_lvm_handle) {
|
if (!_lvm_handle) {
|
||||||
lvm2_log_fn(_temporary_log_fn);
|
lvm2_log_fn(_lvm2_print_log);
|
||||||
if (!(_lvm_handle = lvm2_init())) {
|
|
||||||
dm_pool_destroy(_mem_pool);
|
if (!(_lvm_handle = lvm2_init()))
|
||||||
_mem_pool = NULL;
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need some space for allocations. 1024 should be more
|
||||||
|
* than enough for what we need (device mapper name splitting)
|
||||||
|
*/
|
||||||
|
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) {
|
||||||
|
lvm2_exit(_lvm_handle);
|
||||||
|
_lvm_handle = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
||||||
/* FIXME Temporary: move to dmeventd core */
|
/* FIXME Temporary: move to dmeventd core */
|
||||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||||
|
log_debug("lvm plugin initilized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_register_count++;
|
_register_count++;
|
||||||
@@ -126,11 +96,13 @@ void dmeventd_lvm2_exit(void)
|
|||||||
pthread_mutex_lock(&_register_mutex);
|
pthread_mutex_lock(&_register_mutex);
|
||||||
|
|
||||||
if (!--_register_count) {
|
if (!--_register_count) {
|
||||||
|
log_debug("lvm plugin shuting down.");
|
||||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||||
dm_pool_destroy(_mem_pool);
|
dm_pool_destroy(_mem_pool);
|
||||||
_mem_pool = NULL;
|
_mem_pool = NULL;
|
||||||
lvm2_exit(_lvm_handle);
|
lvm2_exit(_lvm_handle);
|
||||||
_lvm_handle = NULL;
|
_lvm_handle = NULL;
|
||||||
|
log_debug("lvm plugin exited.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_register_mutex);
|
pthread_mutex_unlock(&_register_mutex);
|
||||||
@@ -153,8 +125,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||||
syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
|
log_error("Unable to determine VG name from %s.",
|
||||||
device);
|
device);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +140,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
|||||||
dm_pool_free(mem, vg);
|
dm_pool_free(mem, vg);
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
|
log_error("Unable to form LVM command. (too long).");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -39,4 +39,36 @@ struct dm_pool *dmeventd_lvm2_pool(void);
|
|||||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||||
const char *cmd, const char *device);
|
const char *cmd, const char *device);
|
||||||
|
|
||||||
|
#define dmeventd_lvm2_run_with_lock(cmdline) \
|
||||||
|
({\
|
||||||
|
int rc;\
|
||||||
|
dmeventd_lvm2_lock();\
|
||||||
|
rc = dmeventd_lvm2_run(cmdline);\
|
||||||
|
dmeventd_lvm2_unlock();\
|
||||||
|
rc;\
|
||||||
|
})
|
||||||
|
|
||||||
|
#define dmeventd_lvm2_init_with_pool(name, st) \
|
||||||
|
({\
|
||||||
|
struct dm_pool *mem;\
|
||||||
|
st = NULL;\
|
||||||
|
if (dmeventd_lvm2_init()) {\
|
||||||
|
if ((mem = dm_pool_create(name, 2048)) &&\
|
||||||
|
(st = dm_pool_zalloc(mem, sizeof(*st))))\
|
||||||
|
st->mem = mem;\
|
||||||
|
else {\
|
||||||
|
if (mem)\
|
||||||
|
dm_pool_destroy(mem);\
|
||||||
|
dmeventd_lvm2_exit();\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
st;\
|
||||||
|
})
|
||||||
|
|
||||||
|
#define dmeventd_lvm2_exit_with_pool(pool) \
|
||||||
|
do {\
|
||||||
|
dm_pool_destroy(pool->mem);\
|
||||||
|
dmeventd_lvm2_exit();\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#endif /* _DMEVENTD_LVMWRAP_H */
|
#endif /* _DMEVENTD_LVMWRAP_H */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -13,20 +13,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "defaults.h"
|
#include "defaults.h"
|
||||||
|
|
||||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
|
||||||
/* FIXME Missing openlog? */
|
|
||||||
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
|
||||||
/* FIXME Reformat to 80 char lines. */
|
/* FIXME Reformat to 80 char lines. */
|
||||||
|
|
||||||
#define ME_IGNORE 0
|
#define ME_IGNORE 0
|
||||||
#define ME_INSYNC 1
|
#define ME_INSYNC 1
|
||||||
#define ME_FAILURE 2
|
#define ME_FAILURE 2
|
||||||
|
|
||||||
|
struct dso_state {
|
||||||
|
struct dm_pool *mem;
|
||||||
|
char cmd_lvscan[512];
|
||||||
|
char cmd_lvconvert[512];
|
||||||
|
};
|
||||||
|
|
||||||
|
DM_EVENT_LOG_FN("mirr")
|
||||||
|
|
||||||
static int _process_status_code(const char status_code, const char *dev_name,
|
static int _process_status_code(const char status_code, const char *dev_name,
|
||||||
const char *dev_type, int r)
|
const char *dev_type, int r)
|
||||||
{
|
{
|
||||||
@@ -39,18 +43,15 @@ static int _process_status_code(const char status_code, const char *dev_name,
|
|||||||
* U => Unclassified failure (bug)
|
* U => Unclassified failure (bug)
|
||||||
*/
|
*/
|
||||||
if (status_code == 'F') {
|
if (status_code == 'F') {
|
||||||
syslog(LOG_ERR, "%s device %s flush failed.",
|
log_error("%s device %s flush failed.", dev_type, dev_name);
|
||||||
dev_type, dev_name);
|
|
||||||
r = ME_FAILURE;
|
r = ME_FAILURE;
|
||||||
} else if (status_code == 'S')
|
} else if (status_code == 'S')
|
||||||
syslog(LOG_ERR, "%s device %s sync failed.",
|
log_error("%s device %s sync failed.", dev_type, dev_name);
|
||||||
dev_type, dev_name);
|
|
||||||
else if (status_code == 'R')
|
else if (status_code == 'R')
|
||||||
syslog(LOG_ERR, "%s device %s read failed.",
|
log_error("%s device %s read failed.", dev_type, dev_name);
|
||||||
dev_type, dev_name);
|
|
||||||
else if (status_code != 'A') {
|
else if (status_code != 'A') {
|
||||||
syslog(LOG_ERR, "%s device %s has failed (%c).",
|
log_error("%s device %s has failed (%c).",
|
||||||
dev_type, dev_name, status_code);
|
dev_type, dev_name, status_code);
|
||||||
r = ME_FAILURE;
|
r = ME_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,52 +126,49 @@ out:
|
|||||||
|
|
||||||
out_parse:
|
out_parse:
|
||||||
dm_free(args);
|
dm_free(args);
|
||||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
log_error("Unable to parse mirror status string.");
|
||||||
|
|
||||||
return ME_IGNORE;
|
return ME_IGNORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _remove_failed_devices(const char *device)
|
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
|
||||||
char cmd_str[CMD_SIZE];
|
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
||||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
log_info("Re-scan of mirrored device failed.");
|
||||||
"--repair --use-policies", device))
|
|
||||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
|
||||||
|
|
||||||
r = dmeventd_lvm2_run(cmd_str);
|
/* if repair goes OK, report success even if lvscan has failed */
|
||||||
|
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
||||||
|
|
||||||
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
log_info("Repair of mirrored device %s.",
|
||||||
(r) ? "finished successfully" : "failed");
|
(r) ? "finished successfully" : "failed");
|
||||||
|
|
||||||
return (r) ? 0 : -1;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **unused __attribute__((unused)))
|
void **user)
|
||||||
{
|
{
|
||||||
|
struct dso_state *state = *user;
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
char *params;
|
char *params;
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
|
|
||||||
dmeventd_lvm2_lock();
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
next = dm_get_next_target(dmt, next, &start, &length,
|
next = dm_get_next_target(dmt, next, &start, &length,
|
||||||
&target_type, ¶ms);
|
&target_type, ¶ms);
|
||||||
|
|
||||||
if (!target_type) {
|
if (!target_type) {
|
||||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
log_info("%s mapping lost.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(target_type, "mirror")) {
|
if (strcmp(target_type, "mirror")) {
|
||||||
syslog(LOG_INFO, "%s has unmirrored portion.", device);
|
log_info("%s has unmirrored portion.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,54 +178,75 @@ void process_event(struct dm_task *dmt,
|
|||||||
_part_ of the device is in sync
|
_part_ of the device is in sync
|
||||||
Also, this is not an error
|
Also, this is not an error
|
||||||
*/
|
*/
|
||||||
syslog(LOG_NOTICE, "%s is now in-sync.", device);
|
log_notice("%s is now in-sync.", device);
|
||||||
break;
|
break;
|
||||||
case ME_FAILURE:
|
case ME_FAILURE:
|
||||||
syslog(LOG_ERR, "Device failure in %s.", device);
|
log_error("Device failure in %s.", device);
|
||||||
if (_remove_failed_devices(device))
|
if (!_remove_failed_devices(state->cmd_lvscan,
|
||||||
|
state->cmd_lvconvert))
|
||||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
|
log_error("Failed to remove faulty devices in %s.",
|
||||||
device);
|
device);
|
||||||
/* Should check before warning user that device is now linear
|
/* Should check before warning user that device is now linear
|
||||||
else
|
else
|
||||||
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
log_notice("%s is now a linear device.",
|
||||||
device);
|
device);
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case ME_IGNORE:
|
case ME_IGNORE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME Provide value then! */
|
/* FIXME Provide value then! */
|
||||||
syslog(LOG_INFO, "Unknown event received.");
|
log_info("Unknown event received.");
|
||||||
}
|
}
|
||||||
} while (next);
|
} while (next);
|
||||||
|
|
||||||
dmeventd_lvm2_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **unused __attribute__((unused)))
|
void **user)
|
||||||
{
|
{
|
||||||
if (!dmeventd_lvm2_init())
|
struct dso_state *state;
|
||||||
return 0;
|
|
||||||
|
|
||||||
syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
|
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
|
||||||
|
goto_bad;
|
||||||
|
|
||||||
|
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
||||||
|
"lvscan --cache", device)) {
|
||||||
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
goto_bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
||||||
|
"lvconvert --repair --use-policies", device)) {
|
||||||
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
goto_bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
*user = state;
|
||||||
|
|
||||||
|
log_info("Monitoring mirror device %s for events.", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
bad:
|
||||||
|
log_error("Failed to monitor mirror %s.", device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unregister_device(const char *device,
|
int unregister_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **unused __attribute__((unused)))
|
void **user)
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
|
struct dso_state *state = *user;
|
||||||
device);
|
|
||||||
dmeventd_lvm2_exit();
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
log_info("No longer monitoring mirror device %s for events.",
|
||||||
|
device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -13,168 +13,133 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
|
struct dso_state {
|
||||||
|
struct dm_pool *mem;
|
||||||
|
char cmd_lvscan[512];
|
||||||
|
char cmd_lvconvert[512];
|
||||||
|
int failed;
|
||||||
|
};
|
||||||
|
|
||||||
|
DM_EVENT_LOG_FN("raid")
|
||||||
|
|
||||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
|
||||||
/* FIXME Missing openlog? */
|
|
||||||
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
|
||||||
/* FIXME Reformat to 80 char lines. */
|
/* FIXME Reformat to 80 char lines. */
|
||||||
|
|
||||||
/*
|
static int _process_raid_event(struct dso_state *state, char *params, const char *device)
|
||||||
* run_repair is a close copy to
|
|
||||||
* plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
|
|
||||||
*/
|
|
||||||
static int run_repair(const char *device)
|
|
||||||
{
|
{
|
||||||
int r;
|
struct dm_status_raid *status;
|
||||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
const char *d;
|
||||||
char cmd_str[CMD_SIZE];
|
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
if (!dm_get_status_raid(state->mem, params, &status)) {
|
||||||
"lvscan --cache", device))
|
log_error("Failed to process status line for %s.", device);
|
||||||
return -1;
|
return 0;
|
||||||
|
|
||||||
r = dmeventd_lvm2_run(cmd_str);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
syslog(LOG_INFO, "Re-scan of RAID device %s failed.", device);
|
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
|
||||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
|
||||||
"--repair --use-policies", device))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* if repair goes OK, report success even if lvscan has failed */
|
|
||||||
r = dmeventd_lvm2_run(cmd_str);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
syslog(LOG_INFO, "Repair of RAID device %s failed.", device);
|
|
||||||
|
|
||||||
return (r) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _process_raid_event(char *params, const char *device)
|
|
||||||
{
|
|
||||||
int i, n, failure = 0;
|
|
||||||
char *p, *a[4];
|
|
||||||
char *raid_type;
|
|
||||||
char *num_devices;
|
|
||||||
char *health_chars;
|
|
||||||
char *resync_ratio;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RAID parms: <raid_type> <#raid_disks> \
|
|
||||||
* <health chars> <resync ratio>
|
|
||||||
*/
|
|
||||||
if (!dm_split_words(params, 4, 0, a)) {
|
|
||||||
syslog(LOG_ERR, "Failed to process status line for %s\n",
|
|
||||||
device);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
raid_type = a[0];
|
|
||||||
num_devices = a[1];
|
|
||||||
health_chars = a[2];
|
|
||||||
resync_ratio = a[3];
|
|
||||||
|
|
||||||
if (!(n = atoi(num_devices))) {
|
|
||||||
syslog(LOG_ERR, "Failed to parse number of devices for %s: %s",
|
|
||||||
device, num_devices);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
if ((d = strchr(status->dev_health, 'D'))) {
|
||||||
switch (health_chars[i]) {
|
if (state->failed)
|
||||||
case 'A':
|
goto out; /* already reported */
|
||||||
/* Device is 'A'live and well */
|
|
||||||
case 'a':
|
log_error("Device #%d of %s array, %s, has failed.",
|
||||||
/* Device is 'a'live, but not yet in-sync */
|
(int)(d - status->dev_health),
|
||||||
break;
|
status->raid_type, device);
|
||||||
case 'D':
|
|
||||||
syslog(LOG_ERR,
|
state->failed = 1;
|
||||||
"Device #%d of %s array, %s, has failed.",
|
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
|
||||||
i, raid_type, device);
|
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
|
||||||
failure++;
|
|
||||||
break;
|
/* if repair goes OK, report success even if lvscan has failed */
|
||||||
default:
|
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
||||||
/* Unhandled character returned from kernel */
|
log_info("Repair of RAID device %s failed.", device);
|
||||||
break;
|
dm_pool_free(state->mem, status);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (failure)
|
} else {
|
||||||
return run_repair(device);
|
state->failed = 0;
|
||||||
|
log_info("%s array, %s, is %s in-sync.",
|
||||||
|
status->raid_type, device,
|
||||||
|
(status->insync_regions == status->total_regions) ? "now" : "not");
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
|
dm_pool_free(state->mem, status);
|
||||||
|
|
||||||
p = strstr(resync_ratio, "/");
|
return 1;
|
||||||
if (!p) {
|
|
||||||
syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s",
|
|
||||||
device, resync_ratio);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
p[0] = '\0';
|
|
||||||
syslog(LOG_INFO, "%s array, %s, is %s in-sync.",
|
|
||||||
raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **unused __attribute__((unused)))
|
void **user)
|
||||||
{
|
{
|
||||||
|
struct dso_state *state = *user;
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
char *params;
|
char *params;
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
|
|
||||||
dmeventd_lvm2_lock();
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
next = dm_get_next_target(dmt, next, &start, &length,
|
next = dm_get_next_target(dmt, next, &start, &length,
|
||||||
&target_type, ¶ms);
|
&target_type, ¶ms);
|
||||||
|
|
||||||
if (!target_type) {
|
if (!target_type) {
|
||||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
log_info("%s mapping lost.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(target_type, "raid")) {
|
if (strcmp(target_type, "raid")) {
|
||||||
syslog(LOG_INFO, "%s has non-raid portion.", device);
|
log_info("%s has non-raid portion.", device);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_process_raid_event(params, device))
|
if (!_process_raid_event(state, params, device))
|
||||||
syslog(LOG_ERR, "Failed to process event for %s",
|
log_error("Failed to process event for %s.",
|
||||||
device);
|
device);
|
||||||
} while (next);
|
} while (next);
|
||||||
|
|
||||||
dmeventd_lvm2_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **unused __attribute__((unused)))
|
void **user)
|
||||||
{
|
{
|
||||||
if (!dmeventd_lvm2_init())
|
struct dso_state *state;
|
||||||
return 0;
|
|
||||||
|
|
||||||
syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
|
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
|
||||||
|
goto_bad;
|
||||||
|
|
||||||
|
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
||||||
|
"lvscan --cache", device) ||
|
||||||
|
!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
||||||
|
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||||
|
"--repair --use-policies", device)) {
|
||||||
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
goto_bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
*user = state;
|
||||||
|
|
||||||
|
log_info("Monitoring RAID device %s for events.", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
bad:
|
||||||
|
log_error("Failed to monitor RAID %s.", device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unregister_device(const char *device,
|
int unregister_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **unused __attribute__((unused)))
|
void **user)
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
|
struct dso_state *state = *user;
|
||||||
device);
|
|
||||||
dmeventd_lvm2_exit();
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
log_info("No longer monitoring RAID device %s for events.",
|
||||||
|
device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -13,31 +13,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
/* FIXME Missing openlog? */
|
#include <pthread.h>
|
||||||
|
|
||||||
/* First warning when snapshot is 80% full. */
|
/* First warning when snapshot is 80% full. */
|
||||||
#define WARNING_THRESH 80
|
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||||
/* Run a check every 5%. */
|
/* Run a check every 5%. */
|
||||||
#define CHECK_STEP 5
|
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||||
/* Do not bother checking snapshots less than 50% full. */
|
/* Do not bother checking snapshots less than 50% full. */
|
||||||
#define CHECK_MINIMUM 50
|
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||||
|
|
||||||
#define UMOUNT_COMMAND "/bin/umount"
|
#define UMOUNT_COMMAND "/bin/umount"
|
||||||
|
|
||||||
struct dso_state {
|
struct dso_state {
|
||||||
struct dm_pool *mem;
|
struct dm_pool *mem;
|
||||||
int percent_check;
|
dm_percent_t percent_check;
|
||||||
uint64_t known_size;
|
uint64_t known_size;
|
||||||
char cmd_str[1024];
|
char cmd_lvextend[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DM_EVENT_LOG_FN("snap")
|
||||||
|
|
||||||
static int _run(const char *cmd, ...)
|
static int _run(const char *cmd, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -62,7 +62,7 @@ static int _run(const char *cmd, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
execvp(cmd, (char **)argv);
|
execvp(cmd, (char **)argv);
|
||||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
log_sys_error("exec", cmd);
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,18 +81,56 @@ static int _run(const char *cmd, ...)
|
|||||||
|
|
||||||
static int _extend(const char *cmd)
|
static int _extend(const char *cmd)
|
||||||
{
|
{
|
||||||
return dmeventd_lvm2_run(cmd);
|
log_debug("Extending snapshot via %s.", cmd);
|
||||||
|
return dmeventd_lvm2_run_with_lock(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SNAPSHOT_REMOVE
|
||||||
|
/* Remove invalid snapshot from dm-table */
|
||||||
|
/* Experimental for now and not used by default */
|
||||||
|
static int _remove(const char *uuid)
|
||||||
|
{
|
||||||
|
int r = 1;
|
||||||
|
uint32_t cookie = 0;
|
||||||
|
struct dm_task *dmt;
|
||||||
|
|
||||||
|
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!dm_task_set_uuid(dmt, uuid)) {
|
||||||
|
r = 0;
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_task_retry_remove(dmt);
|
||||||
|
|
||||||
|
if (!dm_task_set_cookie(dmt, &cookie, 0)) {
|
||||||
|
r = 0;
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dm_task_run(dmt)) {
|
||||||
|
r = 0;
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif /* SNAPSHOT_REMOVE */
|
||||||
|
|
||||||
static void _umount(const char *device, int major, int minor)
|
static void _umount(const char *device, int major, int minor)
|
||||||
{
|
{
|
||||||
FILE *mounts;
|
FILE *mounts;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
char *words[3];
|
char *words[3];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
const char procmounts[] = "/proc/mounts";
|
||||||
|
|
||||||
if (!(mounts = fopen("/proc/mounts", "r"))) {
|
if (!(mounts = fopen(procmounts, "r"))) {
|
||||||
syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device);
|
log_sys_error("fopen", procmounts);
|
||||||
|
log_error("Not umounting %s.", device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,21 +150,22 @@ static void _umount(const char *device, int major, int minor)
|
|||||||
if (S_ISBLK(st.st_mode) &&
|
if (S_ISBLK(st.st_mode) &&
|
||||||
major(st.st_rdev) == major &&
|
major(st.st_rdev) == major &&
|
||||||
minor(st.st_rdev) == minor) {
|
minor(st.st_rdev) == minor) {
|
||||||
syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
|
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
|
||||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||||
syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
|
log_error("Failed to umount snapshot %s from %s: %s.",
|
||||||
device, words[1], strerror(errno));
|
device, words[1], strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fclose(mounts))
|
if (fclose(mounts))
|
||||||
syslog(LOG_ERR, "Failed to close /proc/mounts.\n");
|
log_sys_error("close", procmounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **private)
|
void **user)
|
||||||
{
|
{
|
||||||
|
struct dso_state *state = *user;
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
@@ -134,28 +173,47 @@ void process_event(struct dm_task *dmt,
|
|||||||
struct dm_status_snapshot *status = NULL;
|
struct dm_status_snapshot *status = NULL;
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
int percent;
|
int percent;
|
||||||
struct dso_state *state = *private;
|
struct dm_info info;
|
||||||
|
|
||||||
/* No longer monitoring, waiting for remove */
|
/* No longer monitoring, waiting for remove */
|
||||||
if (!state->percent_check)
|
if (!state->percent_check)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dmeventd_lvm2_lock();
|
|
||||||
|
|
||||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
if (!target_type)
|
if (!target_type || strcmp(target_type, "snapshot")) {
|
||||||
goto out;
|
log_error("Target %s is not snapshot.", target_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dm_get_status_snapshot(state->mem, params, &status))
|
if (!dm_get_status_snapshot(state->mem, params, &status)) {
|
||||||
goto out;
|
log_error("Cannot parse snapshot %s state: %s.", device, params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (status->invalid) {
|
/*
|
||||||
struct dm_info info;
|
* If the snapshot has been invalidated or we failed to parse
|
||||||
if (dm_task_get_info(dmt, &info)) {
|
* the status string. Report the full status string to syslog.
|
||||||
dmeventd_lvm2_unlock();
|
*/
|
||||||
|
if (status->invalid || status->overflow || !status->total_sectors) {
|
||||||
|
log_warn("WARNING: Snapshot %s changed state to: %s and should be removed.",
|
||||||
|
device, params);
|
||||||
|
state->percent_check = 0;
|
||||||
|
if (dm_task_get_info(dmt, &info))
|
||||||
_umount(device, info.major, info.minor);
|
_umount(device, info.major, info.minor);
|
||||||
return;
|
#ifdef SNAPSHOT_REMOVE
|
||||||
} /* else; too bad, but this is best-effort thing... */
|
/* Maybe configurable ? */
|
||||||
|
_remove(dm_task_get_uuid(dmt));
|
||||||
|
#endif
|
||||||
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length <= (status->used_sectors - status->metadata_sectors)) {
|
||||||
|
/* TODO eventually recognize earlier when room is enough */
|
||||||
|
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
||||||
|
device);
|
||||||
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Snapshot size had changed. Clear the threshold. */
|
/* Snapshot size had changed. Clear the threshold. */
|
||||||
@@ -164,69 +222,50 @@ void process_event(struct dm_task *dmt,
|
|||||||
state->known_size = status->total_sectors;
|
state->known_size = status->total_sectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
percent = dm_make_percent(status->used_sectors, status->total_sectors);
|
||||||
* If the snapshot has been invalidated or we failed to parse
|
|
||||||
* the status string. Report the full status string to syslog.
|
|
||||||
*/
|
|
||||||
if (status->invalid || !status->total_sectors) {
|
|
||||||
syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
|
|
||||||
state->percent_check = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
percent = (int) (100 * status->used_sectors / status->total_sectors);
|
|
||||||
if (percent >= state->percent_check) {
|
if (percent >= state->percent_check) {
|
||||||
/* Usage has raised more than CHECK_STEP since the last
|
/* Usage has raised more than CHECK_STEP since the last
|
||||||
time. Run actions. */
|
time. Run actions. */
|
||||||
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||||
|
|
||||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||||
syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
|
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
|
||||||
/* Try to extend the snapshot, in accord with user-set policies */
|
device, dm_percent_to_float(percent));
|
||||||
if (!_extend(state->cmd_str))
|
|
||||||
syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Try to extend the snapshot, in accord with user-set policies */
|
||||||
|
if (!_extend(state->cmd_lvextend))
|
||||||
|
log_error("Failed to extend snapshot %s.", device);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
if (status)
|
dm_pool_free(state->mem, status);
|
||||||
dm_pool_free(state->mem, status);
|
|
||||||
dmeventd_lvm2_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **private)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dm_pool *statemem = NULL;
|
|
||||||
struct dso_state *state;
|
struct dso_state *state;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_init())
|
if (!dmeventd_lvm2_init_with_pool("snapshot_state", state))
|
||||||
goto out;
|
goto_bad;
|
||||||
|
|
||||||
if (!(statemem = dm_pool_create("snapshot_state", 512)) ||
|
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
|
||||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))))
|
sizeof(state->cmd_lvextend),
|
||||||
goto bad;
|
"lvextend --use-policies", device)) {
|
||||||
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
|
goto_bad;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dmeventd_lvm2_command(statemem, state->cmd_str,
|
|
||||||
sizeof(state->cmd_str),
|
|
||||||
"lvextend --use-policies", device))
|
|
||||||
goto bad;
|
|
||||||
|
|
||||||
state->mem = statemem;
|
|
||||||
state->percent_check = CHECK_MINIMUM;
|
state->percent_check = CHECK_MINIMUM;
|
||||||
*private = state;
|
*user = state;
|
||||||
|
|
||||||
syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
|
log_info("Monitoring snapshot %s.", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
bad:
|
||||||
if (statemem)
|
log_error("Failed to monitor snapshot %s.", device);
|
||||||
dm_pool_destroy(statemem);
|
|
||||||
dmeventd_lvm2_exit();
|
|
||||||
out:
|
|
||||||
syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -235,13 +274,12 @@ int unregister_device(const char *device,
|
|||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **private)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *private;
|
struct dso_state *state = *user;
|
||||||
|
|
||||||
syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
dm_pool_destroy(state->mem);
|
log_info("No longer monitoring snapshot %s.", device);
|
||||||
dmeventd_lvm2_exit();
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -12,25 +12,33 @@
|
|||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h" /* using here lvm log */
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
/* FIXME Missing openlog? */
|
#include <pthread.h>
|
||||||
|
|
||||||
/* First warning when thin is 80% full. */
|
/* TODO - move this mountinfo code into library to be reusable */
|
||||||
#define WARNING_THRESH 80
|
#ifdef __linux__
|
||||||
|
# include "kdev_t.h"
|
||||||
|
#else
|
||||||
|
# define MAJOR(x) major((x))
|
||||||
|
# define MINOR(x) minor((x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* First warning when thin data or metadata is 80% full. */
|
||||||
|
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||||
/* Run a check every 5%. */
|
/* Run a check every 5%. */
|
||||||
#define CHECK_STEP 5
|
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||||
/* Do not bother checking thins less than 50% full. */
|
/* Do not bother checking thin data or metadata is less than 50% full. */
|
||||||
#define CHECK_MINIMUM 50
|
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||||
|
|
||||||
#define UMOUNT_COMMAND "/bin/umount"
|
#define UMOUNT_COMMAND "/bin/umount"
|
||||||
|
|
||||||
|
#define MAX_FAILS (10)
|
||||||
|
|
||||||
#define THIN_DEBUG 0
|
#define THIN_DEBUG 0
|
||||||
|
|
||||||
struct dso_state {
|
struct dso_state {
|
||||||
@@ -39,18 +47,11 @@ struct dso_state {
|
|||||||
int data_percent_check;
|
int data_percent_check;
|
||||||
uint64_t known_metadata_size;
|
uint64_t known_metadata_size;
|
||||||
uint64_t known_data_size;
|
uint64_t known_data_size;
|
||||||
|
unsigned fails;
|
||||||
char cmd_str[1024];
|
char cmd_str[1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DM_EVENT_LOG_FN("thin")
|
||||||
/* TODO - move this mountinfo code into library to be reusable */
|
|
||||||
#ifdef __linux__
|
|
||||||
# include "kdev_t.h"
|
|
||||||
#else
|
|
||||||
# define MAJOR(x) major((x))
|
|
||||||
# define MINOR(x) minor((x))
|
|
||||||
# define MKDEV(x,y) makedev((x),(y))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Get dependencies for device, and try to find matching device */
|
/* Get dependencies for device, and try to find matching device */
|
||||||
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
|
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
|
||||||
@@ -93,8 +94,8 @@ static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_mino
|
|||||||
{
|
{
|
||||||
char dev_name[PATH_MAX];
|
char dev_name[PATH_MAX];
|
||||||
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
||||||
syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
|
log_debug("Found %s (%u:%u) depends on %s.",
|
||||||
name, major, *dev_minor, dev_name);
|
name, major, *dev_minor, dev_name);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
r = 1;
|
r = 1;
|
||||||
@@ -141,14 +142,6 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _extend(struct dso_state *state)
|
|
||||||
{
|
|
||||||
#if THIN_DEBUG
|
|
||||||
syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str);
|
|
||||||
#endif
|
|
||||||
return dmeventd_lvm2_run(state->cmd_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _run(const char *cmd, ...)
|
static int _run(const char *cmd, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -168,12 +161,12 @@ static int _run(const char *cmd, ...)
|
|||||||
argv = alloca(sizeof(const char *) * (argc + 1));
|
argv = alloca(sizeof(const char *) * (argc + 1));
|
||||||
|
|
||||||
argv[0] = cmd;
|
argv[0] = cmd;
|
||||||
va_start(ap, cmd);
|
va_start(ap, cmd);
|
||||||
while ((argv[++i] = va_arg(ap, const char *)));
|
while ((argv[++i] = va_arg(ap, const char *)));
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
execvp(cmd, (char **)argv);
|
execvp(cmd, (char **)argv);
|
||||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
log_sys_error("exec", cmd);
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,9 +184,9 @@ static int _run(const char *cmd, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct mountinfo_s {
|
struct mountinfo_s {
|
||||||
|
const char *device;
|
||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
||||||
const char *device;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||||
@@ -202,11 +195,11 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
|||||||
struct mountinfo_s *data = cb_data;
|
struct mountinfo_s *data = cb_data;
|
||||||
|
|
||||||
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
||||||
syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
|
log_info("Unmounting thin volume %s from %s.",
|
||||||
data->device, target);
|
data->device, target);
|
||||||
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
||||||
syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
|
log_error("Failed to umount thin %s from %s: %s.",
|
||||||
data->device, target, strerror(errno));
|
data->device, target, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -216,78 +209,94 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
|||||||
* Find all thin pool users and try to umount them.
|
* Find all thin pool users and try to umount them.
|
||||||
* TODO: work with read-only thin pool support
|
* TODO: work with read-only thin pool support
|
||||||
*/
|
*/
|
||||||
static void _umount(struct dm_task *dmt, const char *device)
|
static void _umount(struct dm_task *dmt)
|
||||||
{
|
{
|
||||||
/* TODO: Convert to use hash to reduce memory usage */
|
/* TODO: Convert to use hash to reduce memory usage */
|
||||||
static const size_t MINORS = (1U << 20); /* 20 bit */
|
static const size_t MINORS = (1U << 20); /* 20 bit */
|
||||||
struct mountinfo_s data = {
|
struct mountinfo_s data = { NULL };
|
||||||
.device = device,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &data.info))
|
if (!dm_task_get_info(dmt, &data.info))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dmeventd_lvm2_unlock();
|
data.device = dm_task_get_name(dmt);
|
||||||
|
|
||||||
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
||||||
syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
|
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
||||||
syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
|
log_error("Failed to detect mounted volumes for %s.", data.device);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_mountinfo_read(_umount_device, &data)) {
|
if (!dm_mountinfo_read(_umount_device, &data)) {
|
||||||
syslog(LOG_ERR, "Could not parse mountinfo file.\n");
|
log_error("Could not parse mountinfo file.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (data.minors)
|
if (data.minors)
|
||||||
dm_bitset_destroy(data.minors);
|
dm_bitset_destroy(data.minors);
|
||||||
dmeventd_lvm2_lock();
|
}
|
||||||
|
|
||||||
|
static void _use_policy(struct dm_task *dmt, struct dso_state *state)
|
||||||
|
{
|
||||||
|
#if THIN_DEBUG
|
||||||
|
log_info("dmeventd executes: %s.", state->cmd_str);
|
||||||
|
#endif
|
||||||
|
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
||||||
|
log_error("Failed to extend thin pool %s.",
|
||||||
|
dm_task_get_name(dmt));
|
||||||
|
_umount(dmt);
|
||||||
|
state->fails++;
|
||||||
|
} else
|
||||||
|
state->fails = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_event(struct dm_task *dmt,
|
void process_event(struct dm_task *dmt,
|
||||||
enum dm_event_mask event __attribute__((unused)),
|
enum dm_event_mask event __attribute__((unused)),
|
||||||
void **private)
|
void **user)
|
||||||
{
|
{
|
||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
int percent;
|
int percent;
|
||||||
struct dso_state *state = *private;
|
struct dso_state *state = *user;
|
||||||
struct dm_status_thin_pool *tps = NULL;
|
struct dm_status_thin_pool *tps = NULL;
|
||||||
void *next = NULL;
|
void *next = NULL;
|
||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *target_type = NULL;
|
char *target_type = NULL;
|
||||||
char *params;
|
char *params;
|
||||||
|
int needs_policy = 0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* No longer monitoring, waiting for remove */
|
/* No longer monitoring, waiting for remove */
|
||||||
if (!state->meta_percent_check && !state->data_percent_check)
|
if (!state->meta_percent_check && !state->data_percent_check)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
dmeventd_lvm2_lock();
|
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||||
|
/* Error -> no need to check and do instant resize */
|
||||||
|
_use_policy(dmt, state);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
|
|
||||||
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
||||||
syslog(LOG_ERR, "Invalid target type.\n");
|
log_error("Invalid target type.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
||||||
syslog(LOG_ERR, "Failed to parse status.\n");
|
log_error("Failed to parse status.");
|
||||||
_umount(dmt, device);
|
_umount(dmt);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if THIN_DEBUG
|
#if THIN_DEBUG
|
||||||
syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
|
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
|
||||||
" %" PRIu64 " / %" PRIu64 ".\n", state,
|
FMTu64 "/" FMTu64 ".",
|
||||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||||
tps->used_data_blocks, tps->total_data_blocks);
|
tps->used_data_blocks, tps->total_data_blocks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Thin pool size had changed. Clear the threshold. */
|
/* Thin pool size had changed. Clear the threshold. */
|
||||||
@@ -301,7 +310,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
state->known_data_size = tps->total_data_blocks;
|
state->known_data_size = tps->total_data_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
|
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
||||||
if (percent >= state->metadata_percent_check) {
|
if (percent >= state->metadata_percent_check) {
|
||||||
/*
|
/*
|
||||||
* Usage has raised more than CHECK_STEP since the last
|
* Usage has raised more than CHECK_STEP since the last
|
||||||
@@ -311,18 +320,12 @@ void process_event(struct dm_task *dmt,
|
|||||||
|
|
||||||
/* FIXME: extension of metadata needs to be written! */
|
/* FIXME: extension of metadata needs to be written! */
|
||||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||||
syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
|
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
|
||||||
device, percent);
|
device, dm_percent_to_float(percent));
|
||||||
/* Try to extend the metadata, in accord with user-set policies */
|
needs_policy = 1;
|
||||||
if (!_extend(state)) {
|
|
||||||
syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
|
|
||||||
device);
|
|
||||||
_umount(dmt, device);
|
|
||||||
}
|
|
||||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
|
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
|
||||||
if (percent >= state->data_percent_check) {
|
if (percent >= state->data_percent_check) {
|
||||||
/*
|
/*
|
||||||
* Usage has raised more than CHECK_STEP since
|
* Usage has raised more than CHECK_STEP since
|
||||||
@@ -331,56 +334,53 @@ void process_event(struct dm_task *dmt,
|
|||||||
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||||
|
|
||||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||||
syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
|
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
|
||||||
/* Try to extend the thin data, in accord with user-set policies */
|
device, dm_percent_to_float(percent));
|
||||||
if (!_extend(state)) {
|
needs_policy = 1;
|
||||||
syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
|
|
||||||
state->data_percent_check = 0;
|
|
||||||
_umount(dmt, device);
|
|
||||||
}
|
|
||||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needs_policy)
|
||||||
|
_use_policy(dmt, state);
|
||||||
out:
|
out:
|
||||||
if (tps)
|
if (tps)
|
||||||
dm_pool_free(state->mem, tps);
|
dm_pool_free(state->mem, tps);
|
||||||
|
|
||||||
dmeventd_lvm2_unlock();
|
if (state->fails >= MAX_FAILS) {
|
||||||
|
log_warn("WARNING: Dropping monitoring of %s. "
|
||||||
|
"lvm2 command fails too often (%u times in raw).",
|
||||||
|
device, state->fails);
|
||||||
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **private)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dm_pool *statemem = NULL;
|
|
||||||
struct dso_state *state;
|
struct dso_state *state;
|
||||||
|
|
||||||
if (!dmeventd_lvm2_init())
|
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
|
||||||
goto bad;
|
goto_bad;
|
||||||
|
|
||||||
if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
|
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
|
||||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
|
|
||||||
!dmeventd_lvm2_command(statemem, state->cmd_str,
|
|
||||||
sizeof(state->cmd_str),
|
sizeof(state->cmd_str),
|
||||||
"lvextend --use-policies",
|
"lvextend --use-policies",
|
||||||
device)) {
|
device)) {
|
||||||
if (statemem)
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
dm_pool_destroy(statemem);
|
goto_bad;
|
||||||
dmeventd_lvm2_exit();
|
|
||||||
goto bad;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state->mem = statemem;
|
|
||||||
state->metadata_percent_check = CHECK_MINIMUM;
|
state->metadata_percent_check = CHECK_MINIMUM;
|
||||||
state->data_percent_check = CHECK_MINIMUM;
|
state->data_percent_check = CHECK_MINIMUM;
|
||||||
*private = state;
|
*user = state;
|
||||||
|
|
||||||
syslog(LOG_INFO, "Monitoring thin %s.\n", device);
|
log_info("Monitoring thin %s.", device);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
bad:
|
||||||
syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
|
log_error("Failed to monitor thin %s.", device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -389,13 +389,12 @@ int unregister_device(const char *device,
|
|||||||
const char *uuid __attribute__((unused)),
|
const char *uuid __attribute__((unused)),
|
||||||
int major __attribute__((unused)),
|
int major __attribute__((unused)),
|
||||||
int minor __attribute__((unused)),
|
int minor __attribute__((unused)),
|
||||||
void **private)
|
void **user)
|
||||||
{
|
{
|
||||||
struct dso_state *state = *private;
|
struct dso_state *state = *user;
|
||||||
|
|
||||||
syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
|
dmeventd_lvm2_exit_with_pool(state);
|
||||||
dm_pool_destroy(state->mem);
|
log_info("No longer monitoring thin %s.", device);
|
||||||
dmeventd_lvm2_exit();
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
2
daemons/lvmetad/.gitignore
vendored
Normal file
2
daemons/lvmetad/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lvmetad
|
||||||
|
lvmetactl
|
||||||
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
|||||||
SOURCES = lvmetad-core.c
|
SOURCES = lvmetad-core.c
|
||||||
SOURCES2 = testclient.c
|
SOURCES2 = testclient.c
|
||||||
|
|
||||||
TARGETS = lvmetad lvmetad-testclient
|
TARGETS = lvmetad lvmetactl
|
||||||
|
|
||||||
.PHONY: install_lvmetad
|
.PHONY: install_lvmetad
|
||||||
|
|
||||||
@@ -39,8 +39,13 @@ CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
|||||||
|
|
||||||
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||||
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
|
|
||||||
|
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
|
||||||
|
|
||||||
|
CLEAN_TARGETS += lvmetactl.o
|
||||||
|
|
||||||
# TODO: No idea. No idea how to test either.
|
# TODO: No idea. No idea how to test either.
|
||||||
#ifneq ("$(CFLOW_CMD)", "")
|
#ifneq ("$(CFLOW_CMD)", "")
|
||||||
|
|||||||
208
daemons/lvmetad/lvmetactl.c
Normal file
208
daemons/lvmetad/lvmetactl.c
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
|
#include "lvmetad-client.h"
|
||||||
|
|
||||||
|
daemon_handle h;
|
||||||
|
|
||||||
|
static void print_reply(daemon_reply reply)
|
||||||
|
{
|
||||||
|
const char *a = daemon_reply_str(reply, "response", NULL);
|
||||||
|
const char *b = daemon_reply_str(reply, "status", NULL);
|
||||||
|
const char *c = daemon_reply_str(reply, "reason", NULL);
|
||||||
|
|
||||||
|
printf("response \"%s\" status \"%s\" reason \"%s\"\n",
|
||||||
|
a ? a : "", b ? b : "", c ? c : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
char *cmd;
|
||||||
|
char *uuid;
|
||||||
|
char *name;
|
||||||
|
int val;
|
||||||
|
int ver;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("lvmetactl dump\n");
|
||||||
|
printf("lvmetactl pv_list\n");
|
||||||
|
printf("lvmetactl vg_list\n");
|
||||||
|
printf("lvmetactl vg_lookup_name <name>\n");
|
||||||
|
printf("lvmetactl vg_lookup_uuid <uuid>\n");
|
||||||
|
printf("lvmetactl pv_lookup_uuid <uuid>\n");
|
||||||
|
printf("lvmetactl set_global_invalid 0|1\n");
|
||||||
|
printf("lvmetactl get_global_invalid\n");
|
||||||
|
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
|
||||||
|
printf("lvmetactl vg_lock_type <uuid>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = argv[1];
|
||||||
|
|
||||||
|
h = lvmetad_open(NULL);
|
||||||
|
|
||||||
|
if (!strcmp(cmd, "dump")) {
|
||||||
|
reply = daemon_send_simple(h, "dump",
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "pv_list")) {
|
||||||
|
reply = daemon_send_simple(h, "pv_list",
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "vg_list")) {
|
||||||
|
reply = daemon_send_simple(h, "vg_list",
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "set_global_invalid")) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("set_global_invalid 0|1\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
val = atoi(argv[2]);
|
||||||
|
|
||||||
|
reply = daemon_send_simple(h, "set_global_info",
|
||||||
|
"global_invalid = %d", val,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
print_reply(reply);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "get_global_invalid")) {
|
||||||
|
reply = daemon_send_simple(h, "get_global_info",
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "set_vg_version")) {
|
||||||
|
if (argc < 5) {
|
||||||
|
printf("set_vg_version <uuid> <name> <ver>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uuid = argv[2];
|
||||||
|
name = argv[3];
|
||||||
|
ver = atoi(argv[4]);
|
||||||
|
|
||||||
|
if ((strlen(uuid) == 1) && (uuid[0] == '-'))
|
||||||
|
uuid = NULL;
|
||||||
|
if ((strlen(name) == 1) && (name[0] == '-'))
|
||||||
|
name = NULL;
|
||||||
|
|
||||||
|
if (uuid && name) {
|
||||||
|
reply = daemon_send_simple(h, "set_vg_info",
|
||||||
|
"uuid = %s", uuid,
|
||||||
|
"name = %s", name,
|
||||||
|
"version = %d", ver,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
} else if (uuid) {
|
||||||
|
reply = daemon_send_simple(h, "set_vg_info",
|
||||||
|
"uuid = %s", uuid,
|
||||||
|
"version = %d", ver,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
} else if (name) {
|
||||||
|
reply = daemon_send_simple(h, "set_vg_info",
|
||||||
|
"name = %s", name,
|
||||||
|
"version = %d", ver,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
printf("name or uuid required\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_reply(reply);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "vg_lookup_name")) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("vg_lookup_name <name>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
name = argv[2];
|
||||||
|
|
||||||
|
reply = daemon_send_simple(h, "vg_lookup",
|
||||||
|
"name = %s", name,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "vg_lookup_uuid")) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("vg_lookup_uuid <uuid>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uuid = argv[2];
|
||||||
|
|
||||||
|
reply = daemon_send_simple(h, "vg_lookup",
|
||||||
|
"uuid = %s", uuid,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "vg_lock_type")) {
|
||||||
|
struct dm_config_node *metadata;
|
||||||
|
const char *lock_type;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("vg_lock_type <uuid>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uuid = argv[2];
|
||||||
|
|
||||||
|
reply = daemon_send_simple(h, "vg_lookup",
|
||||||
|
"uuid = %s", uuid,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
/* printf("%s\n", reply.buffer.mem); */
|
||||||
|
|
||||||
|
metadata = dm_config_find_node(reply.cft->root, "metadata");
|
||||||
|
if (!metadata) {
|
||||||
|
printf("no metadata\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
|
||||||
|
if (!lock_type) {
|
||||||
|
printf("no lock_type\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
printf("lock_type %s\n", lock_type);
|
||||||
|
|
||||||
|
} else if (!strcmp(cmd, "pv_lookup_uuid")) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("pv_lookup_uuid <uuid>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uuid = argv[2];
|
||||||
|
|
||||||
|
reply = daemon_send_simple(h, "pv_lookup",
|
||||||
|
"uuid = %s", uuid,
|
||||||
|
"token = %s", "skip",
|
||||||
|
NULL);
|
||||||
|
printf("%s\n", reply.buffer.mem);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf("unknown command\n");
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
out_close:
|
||||||
|
daemon_close(h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Red Hat, Inc.
|
* Copyright (C) 2012-2015 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -14,24 +14,117 @@
|
|||||||
|
|
||||||
#define _XOPEN_SOURCE 500 /* pthread */
|
#define _XOPEN_SOURCE 500 /* pthread */
|
||||||
|
|
||||||
#include "configure.h"
|
#define _REENTRANT
|
||||||
|
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
#include "daemon-io.h"
|
#include "daemon-io.h"
|
||||||
#include "config-util.h"
|
|
||||||
#include "daemon-server.h"
|
#include "daemon-server.h"
|
||||||
#include "daemon-log.h"
|
#include "daemon-log.h"
|
||||||
#include "lvm-version.h"
|
#include "lvm-version.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <math.h> /* fabs() */
|
|
||||||
#include <float.h> /* DBL_EPSILON */
|
|
||||||
|
|
||||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* valid/invalid state of cached metadata
|
||||||
|
*
|
||||||
|
* Normally when using lvmetad, the state is kept up-to-date through a
|
||||||
|
* combination of notifications from clients and updates triggered by uevents.
|
||||||
|
* When using lvmlockd, the lvmetad state is expected to become out of
|
||||||
|
* date (invalid/stale) when other hosts make changes to the metadata on disk.
|
||||||
|
*
|
||||||
|
* To deal with this, the metadata cached in lvmetad can be flagged as invalid.
|
||||||
|
* This invalid flag is returned along with the metadata when read by a
|
||||||
|
* command. The command can check for the invalid flag and decide that it
|
||||||
|
* should either use the stale metadata (uncommon), or read the latest metadata
|
||||||
|
* from disk rather than using the invalid metadata that was returned. If the
|
||||||
|
* command reads the latest metadata from disk, it can choose to send it to
|
||||||
|
* lvmetad to update the cached copy and clear the invalid flag in lvmetad.
|
||||||
|
* Otherwise, the next command to read the metadata from lvmetad will also
|
||||||
|
* receive the invalid metadata with the invalid flag (and like the previous
|
||||||
|
* command, it too may choose to read the latest metadata from disk and can
|
||||||
|
* then also choose to update the lvmetad copy.)
|
||||||
|
*
|
||||||
|
* For purposes of tracking the invalid state, LVM metadata is considered
|
||||||
|
* to be either VG-specific or global. VG-specific metadata is metadata
|
||||||
|
* that is isolated to a VG, such as the LVs it contains. Global
|
||||||
|
* metadata is metadata that is not isolated to a single VG. Global
|
||||||
|
* metdata includes:
|
||||||
|
* . the VG namespace (which VG names are used)
|
||||||
|
* . the set of orphan PVs (which PVs are in VGs and which are not)
|
||||||
|
* . properties of orphan PVs (the size of an orphan PV)
|
||||||
|
*
|
||||||
|
* If the metadata for a single VG becomes invalid, the VGFL_INVALID
|
||||||
|
* flag can be set in the vg_info struct for that VG. If the global
|
||||||
|
* metdata becomes invalid, the GLFL_INVALID flag can be set in the
|
||||||
|
* lvmetad daemon state.
|
||||||
|
*
|
||||||
|
* If a command reads VG metadata and VGFL_INVALID is set, an
|
||||||
|
* extra config node called "vg_invalid" is added to the config
|
||||||
|
* data returned to the command.
|
||||||
|
*
|
||||||
|
* If a command reads global metdata and GLFL_INVALID is set, an
|
||||||
|
* extra config node called "global_invalid" is added to the
|
||||||
|
* config data returned to the command.
|
||||||
|
*
|
||||||
|
* If a command sees vg_invalid, and wants the latest VG metadata,
|
||||||
|
* it only needs to scan disks of the PVs in that VG.
|
||||||
|
* It can then use vg_update to send the latest metadata to lvmetad
|
||||||
|
* which clears the VGFL_INVALID flag.
|
||||||
|
*
|
||||||
|
* If a command sees global_invalid, and wants the latest metadata,
|
||||||
|
* it should scan all devices to update lvmetad, and then send
|
||||||
|
* lvmetad the "set_global_info global_invalid=0" message to clear
|
||||||
|
* GLFL_INVALID.
|
||||||
|
*
|
||||||
|
* (When rescanning devices to update lvmetad, the command must use
|
||||||
|
* the global filter cmd->lvmetad_filter so that it processes the same
|
||||||
|
* devices that are seen by lvmetad.)
|
||||||
|
*
|
||||||
|
* The lvmetad INVALID flags can be set by sending lvmetad the messages:
|
||||||
|
*
|
||||||
|
* . set_vg_info with the latest VG seqno. If the VG seqno is larger
|
||||||
|
* than the cached VG seqno, VGFL_INVALID is set for the VG.
|
||||||
|
*
|
||||||
|
* . set_global_info with global_invalid=1 sets GLFL_INVALID.
|
||||||
|
*
|
||||||
|
* Different entities could use these functions to invalidate metadata
|
||||||
|
* if/when they detected that the cache is stale. How they detect that
|
||||||
|
* the cache is stale depends on the details of the specific entity.
|
||||||
|
*
|
||||||
|
* In the case of lvmlockd, it embeds values into its locks to keep track
|
||||||
|
* of when other nodes have changed metadata on disk related to those locks.
|
||||||
|
* When acquring locks it can look at these values and detect that
|
||||||
|
* the metadata associated with the lock has been changed.
|
||||||
|
* When the values change, it uses set_vg_info/set_global_info to
|
||||||
|
* invalidate the lvmetad cache.
|
||||||
|
*
|
||||||
|
* The values that lvmlockd distributes through its locks are the
|
||||||
|
* latest VG seqno in VG locks and a global counter in the global lock.
|
||||||
|
* When a host acquires a VG lock and sees that the embedded seqno is
|
||||||
|
* larger than it was previously, it knows that it should invalidate the
|
||||||
|
* lvmetad cache for the VG. If the host acquires the global lock
|
||||||
|
* and sees that the counter is larger than previously, it knows that
|
||||||
|
* it should invalidate the global info in lvmetad. This invalidation
|
||||||
|
* is done before the lock is returned to the command. This way the
|
||||||
|
* invalid flag will be set on the metadata before the command reads
|
||||||
|
* it from lvmetad.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct vg_info {
|
||||||
|
int64_t external_version;
|
||||||
|
uint32_t flags; /* VGFL_ */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GLFL_INVALID 0x00000001
|
||||||
|
#define VGFL_INVALID 0x00000001
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
daemon_idle *idle;
|
||||||
log_state *log; /* convenience */
|
log_state *log; /* convenience */
|
||||||
const char *log_config;
|
const char *log_config;
|
||||||
|
|
||||||
@@ -40,6 +133,8 @@ typedef struct {
|
|||||||
|
|
||||||
struct dm_hash_table *vgid_to_metadata;
|
struct dm_hash_table *vgid_to_metadata;
|
||||||
struct dm_hash_table *vgid_to_vgname;
|
struct dm_hash_table *vgid_to_vgname;
|
||||||
|
struct dm_hash_table *vgid_to_outdated_pvs;
|
||||||
|
struct dm_hash_table *vgid_to_info;
|
||||||
struct dm_hash_table *vgname_to_vgid;
|
struct dm_hash_table *vgname_to_vgid;
|
||||||
struct dm_hash_table *pvid_to_vgid;
|
struct dm_hash_table *pvid_to_vgid;
|
||||||
struct {
|
struct {
|
||||||
@@ -50,6 +145,7 @@ typedef struct {
|
|||||||
pthread_mutex_t pvid_to_vgid;
|
pthread_mutex_t pvid_to_vgid;
|
||||||
} lock;
|
} lock;
|
||||||
char token[128];
|
char token[128];
|
||||||
|
uint32_t flags; /* GLFL_ */
|
||||||
pthread_mutex_t token_lock;
|
pthread_mutex_t token_lock;
|
||||||
} lvmetad_state;
|
} lvmetad_state;
|
||||||
|
|
||||||
@@ -60,17 +156,19 @@ static void destroy_metadata_hashes(lvmetad_state *s)
|
|||||||
dm_hash_iterate(n, s->vgid_to_metadata)
|
dm_hash_iterate(n, s->vgid_to_metadata)
|
||||||
dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n));
|
dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n));
|
||||||
|
|
||||||
|
dm_hash_iterate(n, s->vgid_to_outdated_pvs)
|
||||||
|
dm_config_destroy(dm_hash_get_data(s->vgid_to_outdated_pvs, n));
|
||||||
|
|
||||||
dm_hash_iterate(n, s->pvid_to_pvmeta)
|
dm_hash_iterate(n, s->pvid_to_pvmeta)
|
||||||
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
|
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
|
||||||
|
|
||||||
dm_hash_destroy(s->pvid_to_pvmeta);
|
dm_hash_destroy(s->pvid_to_pvmeta);
|
||||||
dm_hash_destroy(s->vgid_to_metadata);
|
dm_hash_destroy(s->vgid_to_metadata);
|
||||||
dm_hash_destroy(s->vgid_to_vgname);
|
dm_hash_destroy(s->vgid_to_vgname);
|
||||||
|
dm_hash_destroy(s->vgid_to_outdated_pvs);
|
||||||
|
dm_hash_destroy(s->vgid_to_info);
|
||||||
dm_hash_destroy(s->vgname_to_vgid);
|
dm_hash_destroy(s->vgname_to_vgid);
|
||||||
|
|
||||||
dm_hash_iterate(n, s->device_to_pvid)
|
|
||||||
dm_free(dm_hash_get_data(s->device_to_pvid, n));
|
|
||||||
|
|
||||||
dm_hash_destroy(s->device_to_pvid);
|
dm_hash_destroy(s->device_to_pvid);
|
||||||
dm_hash_destroy(s->pvid_to_vgid);
|
dm_hash_destroy(s->pvid_to_vgid);
|
||||||
}
|
}
|
||||||
@@ -81,6 +179,8 @@ static void create_metadata_hashes(lvmetad_state *s)
|
|||||||
s->device_to_pvid = dm_hash_create(32);
|
s->device_to_pvid = dm_hash_create(32);
|
||||||
s->vgid_to_metadata = dm_hash_create(32);
|
s->vgid_to_metadata = dm_hash_create(32);
|
||||||
s->vgid_to_vgname = dm_hash_create(32);
|
s->vgid_to_vgname = dm_hash_create(32);
|
||||||
|
s->vgid_to_outdated_pvs = dm_hash_create(32);
|
||||||
|
s->vgid_to_info = dm_hash_create(32);
|
||||||
s->pvid_to_vgid = dm_hash_create(32);
|
s->pvid_to_vgid = dm_hash_create(32);
|
||||||
s->vgname_to_vgid = dm_hash_create(32);
|
s->vgname_to_vgid = dm_hash_create(32);
|
||||||
}
|
}
|
||||||
@@ -244,6 +344,30 @@ static int update_pv_status(lvmetad_state *s,
|
|||||||
return complete;
|
return complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dm_config_node *add_last_node(struct dm_config_tree *cft, const char *node_name)
|
||||||
|
{
|
||||||
|
struct dm_config_node *cn, *last;
|
||||||
|
|
||||||
|
cn = cft->root;
|
||||||
|
last = cn;
|
||||||
|
|
||||||
|
while (cn->sib) {
|
||||||
|
last = cn->sib;
|
||||||
|
cn = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
cn = dm_config_create_node(cft, node_name);
|
||||||
|
if (!cn)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cn->v = NULL;
|
||||||
|
cn->sib = NULL;
|
||||||
|
cn->parent = cft->root;
|
||||||
|
last->sib = cn;
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid,
|
static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid,
|
||||||
struct dm_config_tree *cft,
|
struct dm_config_tree *cft,
|
||||||
struct dm_config_node *parent,
|
struct dm_config_node *parent,
|
||||||
@@ -307,6 +431,9 @@ static response pv_list(lvmetad_state *s, request r)
|
|||||||
cn = make_pv_node(s, id, res.cft, cn_pvs, cn);
|
cn = make_pv_node(s, id, res.cft, cn_pvs, cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->flags & GLFL_INVALID)
|
||||||
|
add_last_node(res.cft, "global_invalid");
|
||||||
|
|
||||||
unlock_pvid_to_pvmeta(s);
|
unlock_pvid_to_pvmeta(s);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -351,6 +478,9 @@ static response pv_lookup(lvmetad_state *s, request r)
|
|||||||
pv->key = "physical_volume";
|
pv->key = "physical_volume";
|
||||||
unlock_pvid_to_pvmeta(s);
|
unlock_pvid_to_pvmeta(s);
|
||||||
|
|
||||||
|
if (s->flags & GLFL_INVALID)
|
||||||
|
add_last_node(res.cft, "global_invalid");
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,14 +549,87 @@ static response vg_list(lvmetad_state *s, request r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unlock_vgid_to_metadata(s);
|
unlock_vgid_to_metadata(s);
|
||||||
|
|
||||||
|
if (s->flags & GLFL_INVALID)
|
||||||
|
add_last_node(res.cft, "global_invalid");
|
||||||
bad:
|
bad:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvid)
|
||||||
|
{
|
||||||
|
struct dm_config_tree *pvmeta, *outdated_pvs;
|
||||||
|
struct dm_config_node *list, *cft_vgid;
|
||||||
|
struct dm_config_value *v;
|
||||||
|
|
||||||
|
lock_pvid_to_pvmeta(s);
|
||||||
|
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
|
||||||
|
unlock_pvid_to_pvmeta(s);
|
||||||
|
|
||||||
|
/* if the MDA exists and is used, it will have ignore=0 set */
|
||||||
|
if (!pvmeta ||
|
||||||
|
(dm_config_find_int64(pvmeta->root, "pvmeta/mda0/ignore", 1) &&
|
||||||
|
dm_config_find_int64(pvmeta->root, "pvmeta/mda1/ignore", 1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WARN(s, "PV %s has outdated metadata", pvid);
|
||||||
|
|
||||||
|
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
|
||||||
|
if (!outdated_pvs) {
|
||||||
|
if (!(outdated_pvs = dm_config_from_string("outdated_pvs/pv_list = []")) ||
|
||||||
|
!(cft_vgid = make_text_node(outdated_pvs, "vgid", dm_pool_strdup(outdated_pvs->mem, vgid),
|
||||||
|
outdated_pvs->root, NULL)))
|
||||||
|
abort();
|
||||||
|
if (!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
|
||||||
|
abort();
|
||||||
|
DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
|
||||||
|
}
|
||||||
|
|
||||||
|
list = dm_config_find_node(outdated_pvs->root, "outdated_pvs/pv_list");
|
||||||
|
v = list->v;
|
||||||
|
while (v) {
|
||||||
|
if (v->type != DM_CFG_EMPTY_ARRAY && !strcmp(v->v.str, pvid))
|
||||||
|
return;
|
||||||
|
v = v->next;
|
||||||
|
}
|
||||||
|
if (!(v = dm_config_create_value(outdated_pvs)))
|
||||||
|
abort();
|
||||||
|
v->type = DM_CFG_STRING;
|
||||||
|
v->v.str = dm_pool_strdup(outdated_pvs->mem, pvid);
|
||||||
|
v->next = list->v;
|
||||||
|
list->v = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void chain_outdated_pvs(lvmetad_state *s, const char *vgid, struct dm_config_tree *metadata_cft, struct dm_config_node *metadata)
|
||||||
|
{
|
||||||
|
struct dm_config_tree *cft = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid), *pvmeta;
|
||||||
|
struct dm_config_node *pv, *res, *out_pvs = cft ? dm_config_find_node(cft->root, "outdated_pvs/pv_list") : NULL;
|
||||||
|
struct dm_config_value *pvs_v = out_pvs ? out_pvs->v : NULL;
|
||||||
|
if (!pvs_v)
|
||||||
|
return;
|
||||||
|
if (!(res = make_config_node(metadata_cft, "outdated_pvs", metadata_cft->root, 0)))
|
||||||
|
return; /* oops */
|
||||||
|
res->sib = metadata->child;
|
||||||
|
metadata->child = res;
|
||||||
|
for (; pvs_v && pvs_v->type != DM_CFG_EMPTY_ARRAY; pvs_v = pvs_v->next) {
|
||||||
|
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvs_v->v.str);
|
||||||
|
if (!pvmeta) {
|
||||||
|
WARN(s, "metadata for PV %s not found", pvs_v->v.str);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(pv = dm_config_clone_node(metadata_cft, pvmeta->root, 0)))
|
||||||
|
continue;
|
||||||
|
pv->key = dm_config_find_str(pv, "pvmeta/id", NULL);
|
||||||
|
pv->sib = res->child;
|
||||||
|
res->child = pv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static response vg_lookup(lvmetad_state *s, request r)
|
static response vg_lookup(lvmetad_state *s, request r)
|
||||||
{
|
{
|
||||||
struct dm_config_tree *cft;
|
struct dm_config_tree *cft;
|
||||||
struct dm_config_node *metadata, *n;
|
struct dm_config_node *metadata, *n;
|
||||||
|
struct vg_info *info;
|
||||||
response res = { 0 };
|
response res = { 0 };
|
||||||
|
|
||||||
const char *uuid = daemon_request_str(r, "uuid", NULL);
|
const char *uuid = daemon_request_str(r, "uuid", NULL);
|
||||||
@@ -489,6 +692,17 @@ static response vg_lookup(lvmetad_state *s, request r)
|
|||||||
unlock_vg(s, uuid);
|
unlock_vg(s, uuid);
|
||||||
|
|
||||||
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
|
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
|
||||||
|
chain_outdated_pvs(s, uuid, res.cft, n);
|
||||||
|
|
||||||
|
if (s->flags & GLFL_INVALID)
|
||||||
|
add_last_node(res.cft, "global_invalid");
|
||||||
|
|
||||||
|
info = dm_hash_lookup(s->vgid_to_info, uuid);
|
||||||
|
if (info && (info->flags & VGFL_INVALID)) {
|
||||||
|
n = add_last_node(res.cft, "vg_invalid");
|
||||||
|
if (!n)
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
bad:
|
bad:
|
||||||
@@ -496,65 +710,13 @@ bad:
|
|||||||
return reply_fail("out of memory");
|
return reply_fail("out of memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test if the doubles are close enough to be considered equal */
|
|
||||||
static int close_enough(double d1, double d2)
|
|
||||||
{
|
|
||||||
return fabs(d1 - d2) < DBL_EPSILON;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
|
|
||||||
{
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if (a->type > b->type)
|
|
||||||
return 1;
|
|
||||||
if (a->type < b->type)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
switch (a->type) {
|
|
||||||
case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
|
|
||||||
case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
|
|
||||||
case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
|
|
||||||
case DM_CFG_EMPTY_ARRAY: return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == 0 && a->next && b->next)
|
|
||||||
r = compare_value(a->next, b->next);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
if (a->v && b->v)
|
|
||||||
result = compare_value(a->v, b->v);
|
|
||||||
if (a->v && !b->v)
|
|
||||||
result = 1;
|
|
||||||
if (!a->v && b->v)
|
|
||||||
result = -1;
|
|
||||||
if (a->child && b->child)
|
|
||||||
result = compare_config(a->child, b->child);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
// DEBUGLOG("config inequality at %s / %s", a->key, b->key);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a->sib && b->sib)
|
|
||||||
result = compare_config(a->sib, b->sib);
|
|
||||||
if (a->sib && !b->sib)
|
|
||||||
result = 1;
|
|
||||||
if (!a->sib && b->sib)
|
|
||||||
result = -1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
|
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
|
||||||
|
|
||||||
|
enum update_pvid_mode { UPDATE_ONLY, REMOVE_EMPTY, MARK_OUTDATED };
|
||||||
|
|
||||||
/* You need to be holding the pvid_to_vgid lock already to call this. */
|
/* You need to be holding the pvid_to_vgid lock already to call this. */
|
||||||
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
||||||
const char *vgid, int nuke_empty)
|
const char *vgid, int mode)
|
||||||
{
|
{
|
||||||
struct dm_config_node *pv;
|
struct dm_config_node *pv;
|
||||||
struct dm_hash_table *to_check;
|
struct dm_hash_table *to_check;
|
||||||
@@ -574,11 +736,14 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
|||||||
if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
|
if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (nuke_empty &&
|
if (mode == REMOVE_EMPTY &&
|
||||||
(vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
|
(vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
|
||||||
!dm_hash_insert(to_check, vgid_old, (void*) 1))
|
!dm_hash_insert(to_check, vgid_old, (void*) 1))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (mode == MARK_OUTDATED)
|
||||||
|
mark_outdated_pv(s, vgid, pvid);
|
||||||
|
|
||||||
if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
|
if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -602,10 +767,11 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
|||||||
/* A pvid map lock needs to be held if update_pvids = 1. */
|
/* A pvid map lock needs to be held if update_pvids = 1. */
|
||||||
static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
|
static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
|
||||||
{
|
{
|
||||||
struct dm_config_tree *old;
|
struct dm_config_tree *old, *outdated_pvs;
|
||||||
const char *oldname;
|
const char *oldname;
|
||||||
lock_vgid_to_metadata(s);
|
lock_vgid_to_metadata(s);
|
||||||
old = dm_hash_lookup(s->vgid_to_metadata, vgid);
|
old = dm_hash_lookup(s->vgid_to_metadata, vgid);
|
||||||
|
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
|
||||||
oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
|
oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
|
||||||
|
|
||||||
if (!old) {
|
if (!old) {
|
||||||
@@ -619,12 +785,15 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
|
|||||||
dm_hash_remove(s->vgid_to_metadata, vgid);
|
dm_hash_remove(s->vgid_to_metadata, vgid);
|
||||||
dm_hash_remove(s->vgid_to_vgname, vgid);
|
dm_hash_remove(s->vgid_to_vgname, vgid);
|
||||||
dm_hash_remove(s->vgname_to_vgid, oldname);
|
dm_hash_remove(s->vgname_to_vgid, oldname);
|
||||||
|
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
|
||||||
unlock_vgid_to_metadata(s);
|
unlock_vgid_to_metadata(s);
|
||||||
|
|
||||||
if (update_pvids)
|
if (update_pvids)
|
||||||
/* FIXME: What should happen when update fails */
|
/* FIXME: What should happen when update fails */
|
||||||
update_pvid_to_vgid(s, old, "#orphan", 0);
|
update_pvid_to_vgid(s, old, "#orphan", 0);
|
||||||
dm_config_destroy(old);
|
dm_config_destroy(old);
|
||||||
|
if (outdated_pvs)
|
||||||
|
dm_config_destroy(outdated_pvs);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +837,7 @@ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_p
|
|||||||
* this function, so they can be safely destroyed after update_metadata returns
|
* this function, so they can be safely destroyed after update_metadata returns
|
||||||
* (anything that might have been retained is copied). */
|
* (anything that might have been retained is copied). */
|
||||||
static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
|
static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
|
||||||
struct dm_config_node *metadata, int64_t *oldseq)
|
struct dm_config_node *metadata, int64_t *oldseq, const char *pvid)
|
||||||
{
|
{
|
||||||
struct dm_config_tree *cft = NULL;
|
struct dm_config_tree *cft = NULL;
|
||||||
struct dm_config_tree *old;
|
struct dm_config_tree *old;
|
||||||
@@ -717,6 +886,10 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
|
|||||||
|
|
||||||
if (seq < haveseq) {
|
if (seq < haveseq) {
|
||||||
DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
|
DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
|
||||||
|
|
||||||
|
if (pvid)
|
||||||
|
mark_outdated_pv(s, dm_config_find_str(old->root, "metadata/id", NULL), pvid);
|
||||||
|
|
||||||
/* TODO: notify the client that their metadata is out of date? */
|
/* TODO: notify the client that their metadata is out of date? */
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -739,6 +912,8 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
|
|||||||
|
|
||||||
if (haveseq >= 0 && haveseq < seq) {
|
if (haveseq >= 0 && haveseq < seq) {
|
||||||
INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
|
INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
|
||||||
|
if (oldseq)
|
||||||
|
update_pvid_to_vgid(s, old, vgid, MARK_OUTDATED);
|
||||||
/* temporarily orphan all of our PVs */
|
/* temporarily orphan all of our PVs */
|
||||||
update_pvid_to_vgid(s, old, "#orphan", 0);
|
update_pvid_to_vgid(s, old, "#orphan", 0);
|
||||||
}
|
}
|
||||||
@@ -773,12 +948,46 @@ out: /* FIXME: We should probably abort() on partial failures. */
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dev_t device_remove(lvmetad_state *s, struct dm_config_tree *pvmeta, dev_t device)
|
||||||
|
{
|
||||||
|
struct dm_config_node *pvmeta_tmp;
|
||||||
|
struct dm_config_value *v = NULL;
|
||||||
|
dev_t alt_device = 0, prim_device = 0;
|
||||||
|
|
||||||
|
if ((pvmeta_tmp = dm_config_find_node(pvmeta->root, "pvmeta/devices_alternate")))
|
||||||
|
v = pvmeta_tmp->v;
|
||||||
|
|
||||||
|
prim_device = dm_config_find_int64(pvmeta->root, "pvmeta/device", 0);
|
||||||
|
|
||||||
|
/* it is the primary device */
|
||||||
|
if (device > 0 && device == prim_device && pvmeta_tmp && pvmeta_tmp->v)
|
||||||
|
{
|
||||||
|
alt_device = pvmeta_tmp->v->v.i;
|
||||||
|
pvmeta_tmp->v = pvmeta_tmp->v->next;
|
||||||
|
pvmeta_tmp = dm_config_find_node(pvmeta->root, "pvmeta/device");
|
||||||
|
pvmeta_tmp->v->v.i = alt_device;
|
||||||
|
} else if (device != prim_device)
|
||||||
|
alt_device = prim_device;
|
||||||
|
|
||||||
|
/* it is an alternate device */
|
||||||
|
if (device > 0 && v && v->v.i == device)
|
||||||
|
pvmeta_tmp->v = v->next;
|
||||||
|
else while (device > 0 && pvmeta_tmp && v) {
|
||||||
|
if (v->next && v->next->v.i == device)
|
||||||
|
v->next = v->next->next;
|
||||||
|
v = v->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return alt_device;
|
||||||
|
}
|
||||||
|
|
||||||
static response pv_gone(lvmetad_state *s, request r)
|
static response pv_gone(lvmetad_state *s, request r)
|
||||||
{
|
{
|
||||||
const char *pvid = daemon_request_str(r, "uuid", NULL);
|
const char *pvid = daemon_request_str(r, "uuid", NULL);
|
||||||
int64_t device = daemon_request_int(r, "device", 0);
|
int64_t device = daemon_request_int(r, "device", 0);
|
||||||
|
int64_t alt_device = 0;
|
||||||
struct dm_config_tree *pvmeta;
|
struct dm_config_tree *pvmeta;
|
||||||
char *pvid_old, *vgid;
|
char *vgid;
|
||||||
|
|
||||||
DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device);
|
DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device);
|
||||||
|
|
||||||
@@ -792,15 +1001,18 @@ static response pv_gone(lvmetad_state *s, request r)
|
|||||||
|
|
||||||
DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
|
DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
|
||||||
|
|
||||||
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
|
if (!(pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid)))
|
||||||
pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
|
return reply_unknown("PVID does not exist");
|
||||||
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
|
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
|
||||||
|
|
||||||
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
|
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
|
||||||
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
|
||||||
unlock_pvid_to_pvmeta(s);
|
|
||||||
|
|
||||||
dm_free(pvid_old);
|
if (!(alt_device = device_remove(s, pvmeta, device)))
|
||||||
|
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
||||||
|
|
||||||
|
DEBUGLOG(s, "pv_gone alt_device = %" PRIu64, alt_device);
|
||||||
|
|
||||||
|
unlock_pvid_to_pvmeta(s);
|
||||||
|
|
||||||
if (vgid) {
|
if (vgid) {
|
||||||
if (!(vgid = dm_strdup(vgid)))
|
if (!(vgid = dm_strdup(vgid)))
|
||||||
@@ -812,12 +1024,15 @@ static response pv_gone(lvmetad_state *s, request r)
|
|||||||
dm_free(vgid);
|
dm_free(vgid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pvmeta)
|
if (!alt_device)
|
||||||
return reply_unknown("PVID does not exist");
|
dm_config_destroy(pvmeta);
|
||||||
|
|
||||||
dm_config_destroy(pvmeta);
|
if (alt_device) {
|
||||||
|
return daemon_reply_simple("OK",
|
||||||
return daemon_reply_simple("OK", NULL);
|
"device = %"PRId64, alt_device,
|
||||||
|
NULL);
|
||||||
|
} else
|
||||||
|
return daemon_reply_simple("OK", NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
static response pv_clear_all(lvmetad_state *s, request r)
|
static response pv_clear_all(lvmetad_state *s, request r)
|
||||||
@@ -845,11 +1060,11 @@ static response pv_found(lvmetad_state *s, request r)
|
|||||||
const char *vgname = daemon_request_str(r, "vgname", NULL);
|
const char *vgname = daemon_request_str(r, "vgname", NULL);
|
||||||
const char *vgid = daemon_request_str(r, "metadata/id", NULL);
|
const char *vgid = daemon_request_str(r, "metadata/id", NULL);
|
||||||
const char *vgid_old = NULL;
|
const char *vgid_old = NULL;
|
||||||
struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta");
|
struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta"), *altdev = NULL;
|
||||||
|
struct dm_config_value *altdev_v;
|
||||||
uint64_t device, device_old_pvid = 0;
|
uint64_t device, device_old_pvid = 0;
|
||||||
struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL;
|
struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL;
|
||||||
char *old;
|
char *old;
|
||||||
char *pvid_dup;
|
|
||||||
int complete = 0, orphan = 0;
|
int complete = 0, orphan = 0;
|
||||||
int64_t seqno = -1, seqno_old = -1, changed = 0;
|
int64_t seqno = -1, seqno_old = -1, changed = 0;
|
||||||
|
|
||||||
@@ -861,12 +1076,8 @@ static response pv_found(lvmetad_state *s, request r)
|
|||||||
if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device))
|
if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device))
|
||||||
return reply_fail("need PV device number");
|
return reply_fail("need PV device number");
|
||||||
|
|
||||||
if (!(cft = dm_config_create()) ||
|
if (!(cft = dm_config_create()))
|
||||||
(!(pvid_dup = dm_strdup(pvid)))) {
|
|
||||||
if (cft)
|
|
||||||
dm_config_destroy(cft);
|
|
||||||
return reply_fail("out of memory");
|
return reply_fail("out of memory");
|
||||||
}
|
|
||||||
|
|
||||||
lock_pvid_to_pvmeta(s);
|
lock_pvid_to_pvmeta(s);
|
||||||
|
|
||||||
@@ -875,7 +1086,6 @@ static response pv_found(lvmetad_state *s, request r)
|
|||||||
|
|
||||||
if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) {
|
if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) {
|
||||||
pvmeta_old_dev = dm_hash_lookup(s->pvid_to_pvmeta, old);
|
pvmeta_old_dev = dm_hash_lookup(s->pvid_to_pvmeta, old);
|
||||||
dm_hash_remove(s->pvid_to_pvmeta, old);
|
|
||||||
vgid_old = dm_hash_lookup(s->pvid_to_vgid, old);
|
vgid_old = dm_hash_lookup(s->pvid_to_vgid, old);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -885,35 +1095,69 @@ static response pv_found(lvmetad_state *s, request r)
|
|||||||
if (!(cft->root = dm_config_clone_node(cft, pvmeta, 0)))
|
if (!(cft->root = dm_config_clone_node(cft, pvmeta, 0)))
|
||||||
goto out_of_mem;
|
goto out_of_mem;
|
||||||
|
|
||||||
|
pvid = dm_config_find_str(cft->root, "pvmeta/id", NULL);
|
||||||
|
|
||||||
if (!pvmeta_old_pvid || compare_config(pvmeta_old_pvid->root, cft->root))
|
if (!pvmeta_old_pvid || compare_config(pvmeta_old_pvid->root, cft->root))
|
||||||
changed |= 1;
|
changed |= 1;
|
||||||
|
|
||||||
if (pvmeta_old_pvid && device != device_old_pvid) {
|
if (pvmeta_old_pvid && device != device_old_pvid) {
|
||||||
DEBUGLOG(s, "pv %s no longer on device %" PRIu64, pvid, device_old_pvid);
|
DEBUGLOG(s, "PV %s duplicated on device %" PRIu64, pvid, device_old_pvid);
|
||||||
dm_free(dm_hash_lookup_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid)));
|
|
||||||
dm_hash_remove_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid));
|
dm_hash_remove_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid));
|
||||||
|
if (!dm_hash_insert_binary(s->device_to_pvid, &device_old_pvid,
|
||||||
|
sizeof(device_old_pvid), (void*)pvid))
|
||||||
|
goto out_of_mem;
|
||||||
|
if ((altdev = dm_config_find_node(pvmeta_old_pvid->root, "pvmeta/devices_alternate"))) {
|
||||||
|
altdev = dm_config_clone_node(cft, altdev, 0);
|
||||||
|
chain_node(altdev, cft->root, 0);
|
||||||
|
} else
|
||||||
|
if (!(altdev = make_config_node(cft, "devices_alternate", cft->root, 0)))
|
||||||
|
goto out_of_mem;
|
||||||
|
altdev_v = altdev->v;
|
||||||
|
while (1) {
|
||||||
|
if (altdev_v && altdev_v->v.i == device_old_pvid)
|
||||||
|
break;
|
||||||
|
if (altdev_v)
|
||||||
|
altdev_v = altdev_v->next;
|
||||||
|
if (!altdev_v) {
|
||||||
|
if (!(altdev_v = dm_config_create_value(cft)))
|
||||||
|
goto out_of_mem;
|
||||||
|
altdev_v->next = altdev->v;
|
||||||
|
altdev->v = altdev_v;
|
||||||
|
altdev->v->v.i = device_old_pvid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
altdev_v = altdev->v;
|
||||||
|
while (altdev_v) {
|
||||||
|
if (altdev_v->next && altdev_v->next->v.i == device)
|
||||||
|
altdev_v->next = altdev_v->next->next;
|
||||||
|
altdev_v = altdev_v->next;
|
||||||
|
}
|
||||||
changed |= 1;
|
changed |= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) ||
|
if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) ||
|
||||||
!dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) {
|
!dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid)) {
|
||||||
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
||||||
out_of_mem:
|
out_of_mem:
|
||||||
unlock_pvid_to_pvmeta(s);
|
unlock_pvid_to_pvmeta(s);
|
||||||
dm_config_destroy(cft);
|
dm_config_destroy(cft);
|
||||||
dm_free(pvid_dup);
|
|
||||||
dm_free(old);
|
dm_free(old);
|
||||||
return reply_fail("out of memory");
|
return reply_fail("out of memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock_pvid_to_pvmeta(s);
|
unlock_pvid_to_pvmeta(s);
|
||||||
|
|
||||||
dm_free(old);
|
|
||||||
|
|
||||||
if (pvmeta_old_pvid)
|
if (pvmeta_old_pvid)
|
||||||
dm_config_destroy(pvmeta_old_pvid);
|
dm_config_destroy(pvmeta_old_pvid);
|
||||||
if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid)
|
if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid) {
|
||||||
dm_config_destroy(pvmeta_old_dev);
|
dev_t d = dm_config_find_int64(pvmeta_old_dev->root, "pvmeta/device", 0);
|
||||||
|
WARN(s, "pv_found: stray device %"PRId64, d);
|
||||||
|
if (!device_remove(s, pvmeta_old_dev, device)) {
|
||||||
|
dm_hash_remove(s->pvid_to_pvmeta, old);
|
||||||
|
dm_config_destroy(pvmeta_old_dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
if (!vgid)
|
if (!vgid)
|
||||||
@@ -924,7 +1168,7 @@ out_of_mem:
|
|||||||
if (daemon_request_int(r, "metadata/seqno", -1) < 0)
|
if (daemon_request_int(r, "metadata/seqno", -1) < 0)
|
||||||
return reply_fail("need VG seqno");
|
return reply_fail("need VG seqno");
|
||||||
|
|
||||||
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old))
|
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old, pvid))
|
||||||
return reply_fail("metadata update failed");
|
return reply_fail("metadata update failed");
|
||||||
changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1));
|
changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1));
|
||||||
} else {
|
} else {
|
||||||
@@ -972,6 +1216,39 @@ out_of_mem:
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static response vg_clear_outdated_pvs(lvmetad_state *s, request r)
|
||||||
|
{
|
||||||
|
struct dm_config_tree *outdated_pvs;
|
||||||
|
const char *vgid = daemon_request_str(r, "vgid", NULL);
|
||||||
|
|
||||||
|
if (!vgid)
|
||||||
|
return reply_fail("need VG UUID");
|
||||||
|
|
||||||
|
if ((outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid))) {
|
||||||
|
dm_config_destroy(outdated_pvs);
|
||||||
|
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
|
||||||
|
}
|
||||||
|
return daemon_reply_simple("OK", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vg_info_update(lvmetad_state *s, const char *uuid,
|
||||||
|
struct dm_config_node *metadata)
|
||||||
|
{
|
||||||
|
struct vg_info *info;
|
||||||
|
int64_t cache_version;
|
||||||
|
|
||||||
|
cache_version = dm_config_find_int64(metadata, "metadata/seqno", -1);
|
||||||
|
if (cache_version == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
info = (struct vg_info *) dm_hash_lookup(s->vgid_to_info, uuid);
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cache_version >= info->external_version)
|
||||||
|
info->flags &= ~VGFL_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
static response vg_update(lvmetad_state *s, request r)
|
static response vg_update(lvmetad_state *s, request r)
|
||||||
{
|
{
|
||||||
struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
|
struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
|
||||||
@@ -987,8 +1264,10 @@ static response vg_update(lvmetad_state *s, request r)
|
|||||||
|
|
||||||
/* TODO defer metadata update here; add a separate vg_commit
|
/* TODO defer metadata update here; add a separate vg_commit
|
||||||
* call; if client does not commit, die */
|
* call; if client does not commit, die */
|
||||||
if (!update_metadata(s, vgname, vgid, metadata, NULL))
|
if (!update_metadata(s, vgname, vgid, metadata, NULL, NULL))
|
||||||
return reply_fail("metadata update failed");
|
return reply_fail("metadata update failed");
|
||||||
|
|
||||||
|
vg_info_update(s, vgid, metadata);
|
||||||
}
|
}
|
||||||
return daemon_reply_simple("OK", NULL);
|
return daemon_reply_simple("OK", NULL);
|
||||||
}
|
}
|
||||||
@@ -1009,6 +1288,80 @@ static response vg_remove(lvmetad_state *s, request r)
|
|||||||
return daemon_reply_simple("OK", NULL);
|
return daemon_reply_simple("OK", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static response set_global_info(lvmetad_state *s, request r)
|
||||||
|
{
|
||||||
|
const int global_invalid = daemon_request_int(r, "global_invalid", -1);
|
||||||
|
|
||||||
|
if (global_invalid == 1)
|
||||||
|
s->flags |= GLFL_INVALID;
|
||||||
|
|
||||||
|
else if (global_invalid == 0)
|
||||||
|
s->flags &= ~GLFL_INVALID;
|
||||||
|
|
||||||
|
return daemon_reply_simple("OK", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static response get_global_info(lvmetad_state *s, request r)
|
||||||
|
{
|
||||||
|
return daemon_reply_simple("OK", "global_invalid = %d",
|
||||||
|
(s->flags & GLFL_INVALID) ? 1 : 0,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static response set_vg_info(lvmetad_state *s, request r)
|
||||||
|
{
|
||||||
|
struct dm_config_tree *vg;
|
||||||
|
struct vg_info *info;
|
||||||
|
const char *name;
|
||||||
|
const char *uuid;
|
||||||
|
const int64_t new_version = daemon_request_int(r, "version", -1);
|
||||||
|
int64_t cache_version;
|
||||||
|
|
||||||
|
if (new_version == -1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!(uuid = daemon_request_str(r, "uuid", NULL)))
|
||||||
|
goto use_name;
|
||||||
|
|
||||||
|
if ((vg = dm_hash_lookup(s->vgid_to_metadata, uuid)))
|
||||||
|
goto vers;
|
||||||
|
use_name:
|
||||||
|
if (!(name = daemon_request_str(r, "name", NULL)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!(uuid = dm_hash_lookup(s->vgname_to_vgid, name)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!(vg = dm_hash_lookup(s->vgid_to_metadata, uuid)))
|
||||||
|
goto out;
|
||||||
|
vers:
|
||||||
|
if (!new_version)
|
||||||
|
goto inval;
|
||||||
|
|
||||||
|
cache_version = dm_config_find_int64(vg->root, "metadata/seqno", -1);
|
||||||
|
|
||||||
|
if (cache_version != -1 && new_version != -1 && cache_version >= new_version)
|
||||||
|
goto out;
|
||||||
|
inval:
|
||||||
|
info = dm_hash_lookup(s->vgid_to_info, uuid);
|
||||||
|
if (!info) {
|
||||||
|
info = malloc(sizeof(struct vg_info));
|
||||||
|
if (!info)
|
||||||
|
goto bad;
|
||||||
|
memset(info, 0, sizeof(struct vg_info));
|
||||||
|
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->external_version = new_version;
|
||||||
|
info->flags |= VGFL_INVALID;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return daemon_reply_simple("OK", NULL);
|
||||||
|
bad:
|
||||||
|
return reply_fail("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr)
|
static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr)
|
||||||
{
|
{
|
||||||
struct dm_hash_node *n;
|
struct dm_hash_node *n;
|
||||||
@@ -1046,6 +1399,52 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
|
|||||||
buffer_append(buf, "}\n");
|
buffer_append(buf, "}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _dump_info_version(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
|
||||||
|
{
|
||||||
|
char *append;
|
||||||
|
struct dm_hash_node *n = dm_hash_get_first(ht);
|
||||||
|
struct vg_info *info;
|
||||||
|
|
||||||
|
buffer_append(buf, name);
|
||||||
|
buffer_append(buf, " {\n");
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
const char *key = dm_hash_get_key(ht, n);
|
||||||
|
info = dm_hash_get_data(ht, n);
|
||||||
|
buffer_append(buf, " ");
|
||||||
|
(void) dm_asprintf(&append, "%s = %lld", key, (long long)info->external_version);
|
||||||
|
if (append)
|
||||||
|
buffer_append(buf, append);
|
||||||
|
buffer_append(buf, "\n");
|
||||||
|
dm_free(append);
|
||||||
|
n = dm_hash_get_next(ht, n);
|
||||||
|
}
|
||||||
|
buffer_append(buf, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _dump_info_flags(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
|
||||||
|
{
|
||||||
|
char *append;
|
||||||
|
struct dm_hash_node *n = dm_hash_get_first(ht);
|
||||||
|
struct vg_info *info;
|
||||||
|
|
||||||
|
buffer_append(buf, name);
|
||||||
|
buffer_append(buf, " {\n");
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
const char *key = dm_hash_get_key(ht, n);
|
||||||
|
info = dm_hash_get_data(ht, n);
|
||||||
|
buffer_append(buf, " ");
|
||||||
|
(void) dm_asprintf(&append, "%s = %llx", key, (long long)info->flags);
|
||||||
|
if (append)
|
||||||
|
buffer_append(buf, append);
|
||||||
|
buffer_append(buf, "\n");
|
||||||
|
dm_free(append);
|
||||||
|
n = dm_hash_get_next(ht, n);
|
||||||
|
}
|
||||||
|
buffer_append(buf, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
static response dump(lvmetad_state *s)
|
static response dump(lvmetad_state *s)
|
||||||
{
|
{
|
||||||
response res = { 0 };
|
response res = { 0 };
|
||||||
@@ -1068,6 +1467,9 @@ static response dump(lvmetad_state *s)
|
|||||||
buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
|
buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
|
||||||
_dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
|
_dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
|
||||||
|
|
||||||
|
buffer_append(b, "\n# VGID to outdated PVs mapping\n\n");
|
||||||
|
_dump_cft(b, s->vgid_to_outdated_pvs, "outdated_pvs/vgid");
|
||||||
|
|
||||||
buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
|
buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
|
||||||
_dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);
|
_dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);
|
||||||
|
|
||||||
@@ -1077,6 +1479,12 @@ static response dump(lvmetad_state *s)
|
|||||||
buffer_append(b, "\n# DEVICE to PVID mapping\n\n");
|
buffer_append(b, "\n# DEVICE to PVID mapping\n\n");
|
||||||
_dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1);
|
_dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1);
|
||||||
|
|
||||||
|
buffer_append(b, "\n# VGID to INFO version mapping\n\n");
|
||||||
|
_dump_info_version(b, s->vgid_to_info, "vgid_to_info", 0);
|
||||||
|
|
||||||
|
buffer_append(b, "\n# VGID to INFO flags mapping\n\n");
|
||||||
|
_dump_info_flags(b, s->vgid_to_info, "vgid_to_info", 0);
|
||||||
|
|
||||||
unlock_pvid_to_vgid(s);
|
unlock_pvid_to_vgid(s);
|
||||||
unlock_pvid_to_pvmeta(s);
|
unlock_pvid_to_pvmeta(s);
|
||||||
unlock_vgid_to_metadata(s);
|
unlock_vgid_to_metadata(s);
|
||||||
@@ -1098,7 +1506,7 @@ static response handler(daemon_state s, client_handle h, request r)
|
|||||||
return daemon_reply_simple("OK", NULL);
|
return daemon_reply_simple("OK", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(token, state->token) && strcmp(rq, "dump")) {
|
if (strcmp(token, state->token) && strcmp(rq, "dump") && strcmp(token, "skip")) {
|
||||||
pthread_mutex_unlock(&state->token_lock);
|
pthread_mutex_unlock(&state->token_lock);
|
||||||
return daemon_reply_simple("token_mismatch",
|
return daemon_reply_simple("token_mismatch",
|
||||||
"expected = %s", state->token,
|
"expected = %s", state->token,
|
||||||
@@ -1127,6 +1535,9 @@ static response handler(daemon_state s, client_handle h, request r)
|
|||||||
if (!strcmp(rq, "vg_update"))
|
if (!strcmp(rq, "vg_update"))
|
||||||
return vg_update(state, r);
|
return vg_update(state, r);
|
||||||
|
|
||||||
|
if (!strcmp(rq, "vg_clear_outdated_pvs"))
|
||||||
|
return vg_clear_outdated_pvs(state, r);
|
||||||
|
|
||||||
if (!strcmp(rq, "vg_remove"))
|
if (!strcmp(rq, "vg_remove"))
|
||||||
return vg_remove(state, r);
|
return vg_remove(state, r);
|
||||||
|
|
||||||
@@ -1139,6 +1550,15 @@ static response handler(daemon_state s, client_handle h, request r)
|
|||||||
if (!strcmp(rq, "vg_list"))
|
if (!strcmp(rq, "vg_list"))
|
||||||
return vg_list(state, r);
|
return vg_list(state, r);
|
||||||
|
|
||||||
|
if (!strcmp(rq, "set_global_info"))
|
||||||
|
return set_global_info(state, r);
|
||||||
|
|
||||||
|
if (!strcmp(rq, "get_global_info"))
|
||||||
|
return get_global_info(state, r);
|
||||||
|
|
||||||
|
if (!strcmp(rq, "set_vg_info"))
|
||||||
|
return set_vg_info(state, r);
|
||||||
|
|
||||||
if (!strcmp(rq, "dump"))
|
if (!strcmp(rq, "dump"))
|
||||||
return dump(state);
|
return dump(state);
|
||||||
|
|
||||||
@@ -1174,6 +1594,9 @@ static int init(daemon_state *s)
|
|||||||
/* if (ls->initial_registrations)
|
/* if (ls->initial_registrations)
|
||||||
_process_initial_registrations(ds->initial_registrations); */
|
_process_initial_registrations(ds->initial_registrations); */
|
||||||
|
|
||||||
|
if (ls->idle)
|
||||||
|
ls->idle->is_idle = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1196,21 +1619,39 @@ static int fini(daemon_state *s)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
unsigned long l;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
l = strtoul(str, &endptr, 10);
|
||||||
|
if (errno || *endptr || l >= UINT_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*max_timeouts = (unsigned) l;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void usage(const char *prog, FILE *file)
|
static void usage(const char *prog, FILE *file)
|
||||||
{
|
{
|
||||||
fprintf(file, "Usage:\n"
|
fprintf(file, "Usage:\n"
|
||||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
|
"%s [-V] [-h] [-f] [-l level[,level ...]] [-s path] [-t secs]\n\n"
|
||||||
" -V Show version of lvmetad\n"
|
" -V Show version of lvmetad\n"
|
||||||
" -h Show this help information\n"
|
" -h Show this help information\n"
|
||||||
" -f Don't fork, run in the foreground\n"
|
" -f Don't fork, run in the foreground\n"
|
||||||
" -l Logging message level (-l {all|wire|debug})\n"
|
" -l Logging message levels (all,fatal,error,warn,info,wire,debug)\n"
|
||||||
" -p Set path to the pidfile\n"
|
" -p Set path to the pidfile\n"
|
||||||
" -s Set path to the socket to listen on\n\n", prog);
|
" -s Set path to the socket to listen on\n"
|
||||||
|
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
signed char opt;
|
signed char opt;
|
||||||
|
struct timeval timeout;
|
||||||
|
daemon_idle di = { .ptimeout = &timeout };
|
||||||
lvmetad_state ls = { .log_config = "" };
|
lvmetad_state ls = { .log_config = "" };
|
||||||
daemon_state s = {
|
daemon_state s = {
|
||||||
.daemon_fini = fini,
|
.daemon_fini = fini,
|
||||||
@@ -1225,7 +1666,7 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
// use getopt_long
|
// use getopt_long
|
||||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:")) != EOF) {
|
while ((opt = getopt(argc, argv, "?fhVl:p:s:t:")) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(argv[0], stdout);
|
usage(argv[0], stdout);
|
||||||
@@ -1245,6 +1686,15 @@ int main(int argc, char *argv[])
|
|||||||
case 's': // --socket
|
case 's': // --socket
|
||||||
s.socket_path = optarg;
|
s.socket_path = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||||
|
fprintf(stderr, "Invalid value of timeout parameter.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
/* 0 equals to wait indefinitely */
|
||||||
|
if (di.max_timeouts)
|
||||||
|
s.idle = ls.idle = &di;
|
||||||
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("lvmetad version: " LVM_VERSION "\n");
|
printf("lvmetad version: " LVM_VERSION "\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011-2014 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
#include "lvmetad-client.h"
|
#include "lvmetad-client.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "lvmcache.h"
|
#include "lvmcache.h"
|
||||||
@@ -105,15 +120,17 @@ void _dump_vg(daemon_handle h, const char *uuid)
|
|||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
daemon_handle h = lvmetad_open();
|
daemon_handle h = lvmetad_open();
|
||||||
|
/* FIXME Missing error path */
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
int i;
|
int i;
|
||||||
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0);
|
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
|
||||||
for (i = 1; i < argc; ++i) {
|
for (i = 1; i < argc; ++i) {
|
||||||
const char *uuid = NULL;
|
const char *uuid = NULL;
|
||||||
scan(h, argv[i]);
|
scan(h, argv[i]);
|
||||||
}
|
}
|
||||||
destroy_toolcontext(cmd);
|
destroy_toolcontext(cmd);
|
||||||
|
/* FIXME Missing lvmetad_close() */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +139,6 @@ int main(int argc, char **argv) {
|
|||||||
_dump_vg(h, vgid);
|
_dump_vg(h, vgid);
|
||||||
_pv_add(h, uuid3, NULL);
|
_pv_add(h, uuid3, NULL);
|
||||||
|
|
||||||
daemon_close(h);
|
daemon_close(h); /* FIXME lvmetad_close? */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
2
daemons/lvmlockd/.gitignore
vendored
Normal file
2
daemons/lvmlockd/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lvmlockctl
|
||||||
|
lvmlockd
|
||||||
66
daemons/lvmlockd/Makefile.in
Normal file
66
daemons/lvmlockd/Makefile.in
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of LVM2.
|
||||||
|
#
|
||||||
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
# of the GNU Lesser General Public License v.2.1.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
SOURCES = lvmlockd-core.c
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||||
|
SOURCES += lvmlockd-sanlock.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||||
|
SOURCES += lvmlockd-dlm.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
TARGETS = lvmlockd lvmlockctl
|
||||||
|
|
||||||
|
.PHONY: install_lvmlockd
|
||||||
|
|
||||||
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||||
|
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
|
||||||
|
|
||||||
|
LIBS += $(PTHREAD_LIBS)
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||||
|
LIBS += -lsanlock_client
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||||
|
LIBS += -ldlm_lt
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDFLAGS += -L$(top_builddir)/libdaemon/server
|
||||||
|
CLDFLAGS += -L$(top_builddir)/libdaemon/server
|
||||||
|
|
||||||
|
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||||
|
|
||||||
|
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LVMLIBS)
|
||||||
|
|
||||||
|
install_lvmlockd: lvmlockd
|
||||||
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
|
install_lvmlockctl: lvmlockctl
|
||||||
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
|
install_lvm2: install_lvmlockd install_lvmlockctl
|
||||||
|
|
||||||
|
install: install_lvm2
|
||||||
753
daemons/lvmlockd/lvmlockctl.c
Normal file
753
daemons/lvmlockd/lvmlockctl.c
Normal file
@@ -0,0 +1,753 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
|
#include "lvmlockd-client.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
static int quit = 0;
|
||||||
|
static int info = 0;
|
||||||
|
static int dump = 0;
|
||||||
|
static int wait_opt = 0;
|
||||||
|
static int force_opt = 0;
|
||||||
|
static int kill_vg = 0;
|
||||||
|
static int drop_vg = 0;
|
||||||
|
static int gl_enable = 0;
|
||||||
|
static int gl_disable = 0;
|
||||||
|
static int stop_lockspaces = 0;
|
||||||
|
static char *arg_vg_name = NULL;
|
||||||
|
|
||||||
|
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
|
||||||
|
#define DUMP_BUF_SIZE (1024 * 1024)
|
||||||
|
static char dump_buf[DUMP_BUF_SIZE+1];
|
||||||
|
static int dump_len;
|
||||||
|
static struct sockaddr_un dump_addr;
|
||||||
|
static socklen_t dump_addrlen;
|
||||||
|
|
||||||
|
daemon_handle _lvmlockd;
|
||||||
|
|
||||||
|
#define log_error(fmt, args...) \
|
||||||
|
do { \
|
||||||
|
printf(fmt "\n", ##args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MAX_LINE 512
|
||||||
|
|
||||||
|
/* copied from lvmlockd-internal.h */
|
||||||
|
#define MAX_NAME 64
|
||||||
|
#define MAX_ARGS 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lvmlockd dumps the client info before the lockspaces,
|
||||||
|
* so we can look up client info when printing lockspace info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_CLIENTS 100
|
||||||
|
|
||||||
|
struct client_info {
|
||||||
|
uint32_t client_id;
|
||||||
|
int pid;
|
||||||
|
char name[MAX_NAME+1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct client_info clients[MAX_CLIENTS];
|
||||||
|
static int num_clients;
|
||||||
|
|
||||||
|
static void save_client_info(char *line)
|
||||||
|
{
|
||||||
|
uint32_t pid = 0;
|
||||||
|
int fd = 0;
|
||||||
|
int pi = 0;
|
||||||
|
uint32_t client_id = 0;
|
||||||
|
char name[MAX_NAME+1] = { 0 };
|
||||||
|
|
||||||
|
sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
|
||||||
|
&pid, &fd, &pi, &client_id, name);
|
||||||
|
|
||||||
|
clients[num_clients].client_id = client_id;
|
||||||
|
clients[num_clients].pid = pid;
|
||||||
|
strcpy(clients[num_clients].name, name);
|
||||||
|
num_clients++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_client_info(uint32_t client_id, uint32_t *pid, char *cl_name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_clients; i++) {
|
||||||
|
if (clients[i].client_id == client_id) {
|
||||||
|
*pid = clients[i].pid;
|
||||||
|
strcpy(cl_name, clients[i].name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int first_ls = 1;
|
||||||
|
|
||||||
|
static void format_info_ls(char *line)
|
||||||
|
{
|
||||||
|
char ls_name[MAX_NAME+1] = { 0 };
|
||||||
|
char vg_name[MAX_NAME+1] = { 0 };
|
||||||
|
char vg_uuid[MAX_NAME+1] = { 0 };
|
||||||
|
char vg_sysid[MAX_NAME+1] = { 0 };
|
||||||
|
char lock_args[MAX_ARGS+1] = { 0 };
|
||||||
|
char lock_type[MAX_NAME+1] = { 0 };
|
||||||
|
|
||||||
|
sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
|
||||||
|
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
|
||||||
|
|
||||||
|
if (!first_ls)
|
||||||
|
printf("\n");
|
||||||
|
first_ls = 0;
|
||||||
|
|
||||||
|
printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
|
||||||
|
|
||||||
|
printf("LS %s %s\n", lock_type, ls_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_info_ls_action(char *line)
|
||||||
|
{
|
||||||
|
uint32_t client_id = 0;
|
||||||
|
char flags[MAX_NAME+1] = { 0 };
|
||||||
|
char version[MAX_NAME+1] = { 0 };
|
||||||
|
char op[MAX_NAME+1] = { 0 };
|
||||||
|
uint32_t pid = 0;
|
||||||
|
char cl_name[MAX_NAME+1] = { 0 };
|
||||||
|
|
||||||
|
sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
|
||||||
|
&client_id, flags, version, op);
|
||||||
|
|
||||||
|
find_client_info(client_id, &pid, cl_name);
|
||||||
|
|
||||||
|
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_info_r(char *line, char *r_name_out, char *r_type_out)
|
||||||
|
{
|
||||||
|
char r_name[MAX_NAME+1] = { 0 };
|
||||||
|
char r_type[4] = { 0 };
|
||||||
|
char mode[4] = { 0 };
|
||||||
|
char sh_count[MAX_NAME+1] = { 0 };
|
||||||
|
uint32_t ver = 0;
|
||||||
|
|
||||||
|
sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
|
||||||
|
r_name, r_type, mode, sh_count, &ver);
|
||||||
|
|
||||||
|
strcpy(r_name_out, r_name);
|
||||||
|
strcpy(r_type_out, r_type);
|
||||||
|
|
||||||
|
/* when mode is not un, wait and print each lk line */
|
||||||
|
if (strcmp(mode, "un"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* when mode is un, there will be no lk lines, so print now */
|
||||||
|
|
||||||
|
if (!strcmp(r_type, "gl")) {
|
||||||
|
printf("LK GL un ver %u\n", ver);
|
||||||
|
|
||||||
|
} else if (!strcmp(r_type, "vg")) {
|
||||||
|
printf("LK VG un ver %u\n", ver);
|
||||||
|
|
||||||
|
} else if (!strcmp(r_type, "lv")) {
|
||||||
|
printf("LK LV un %s\n", r_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_info_lk(char *line, char *r_name, char *r_type)
|
||||||
|
{
|
||||||
|
char mode[4] = { 0 };
|
||||||
|
uint32_t ver = 0;
|
||||||
|
char flags[MAX_NAME+1] = { 0 };
|
||||||
|
uint32_t client_id = 0;
|
||||||
|
uint32_t pid = 0;
|
||||||
|
char cl_name[MAX_NAME+1] = { 0 };
|
||||||
|
|
||||||
|
if (!r_name[0] || !r_type[0]) {
|
||||||
|
printf("format_info_lk error r_name %s r_type %s\n", r_name, r_type);
|
||||||
|
printf("%s\n", line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
|
||||||
|
mode, &ver, flags, &client_id);
|
||||||
|
|
||||||
|
find_client_info(client_id, &pid, cl_name);
|
||||||
|
|
||||||
|
if (!strcmp(r_type, "gl")) {
|
||||||
|
printf("LK GL %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
|
||||||
|
|
||||||
|
} else if (!strcmp(r_type, "vg")) {
|
||||||
|
printf("LK VG %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
|
||||||
|
|
||||||
|
} else if (!strcmp(r_type, "lv")) {
|
||||||
|
printf("LK LV %s %s\n", mode, r_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_info_r_action(char *line, char *r_name, char *r_type)
|
||||||
|
{
|
||||||
|
uint32_t client_id = 0;
|
||||||
|
char flags[MAX_NAME+1] = { 0 };
|
||||||
|
char version[MAX_NAME+1] = { 0 };
|
||||||
|
char op[MAX_NAME+1] = { 0 };
|
||||||
|
char rt[4] = { 0 };
|
||||||
|
char mode[4] = { 0 };
|
||||||
|
char lm[MAX_NAME+1] = { 0 };
|
||||||
|
char result[MAX_NAME+1] = { 0 };
|
||||||
|
char lm_rv[MAX_NAME+1] = { 0 };
|
||||||
|
uint32_t pid = 0;
|
||||||
|
char cl_name[MAX_NAME+1] = { 0 };
|
||||||
|
|
||||||
|
if (!r_name[0] || !r_type[0]) {
|
||||||
|
printf("format_info_r_action error r_name %s r_type %s\n", r_name, r_type);
|
||||||
|
printf("%s\n", line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
|
||||||
|
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
|
||||||
|
|
||||||
|
find_client_info(client_id, &pid, cl_name);
|
||||||
|
|
||||||
|
if (strcmp(op, "lock")) {
|
||||||
|
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(r_type, "gl")) {
|
||||||
|
printf("LW GL %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
|
||||||
|
|
||||||
|
} else if (!strcmp(r_type, "vg")) {
|
||||||
|
printf("LW VG %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
|
||||||
|
|
||||||
|
} else if (!strcmp(r_type, "lv")) {
|
||||||
|
printf("LW LV %s %s\n", mode, r_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_info_line(char *line, char *r_name, char *r_type)
|
||||||
|
{
|
||||||
|
if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
|
||||||
|
/* only print this in the raw info dump */
|
||||||
|
|
||||||
|
} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
|
||||||
|
save_client_info(line);
|
||||||
|
|
||||||
|
} else if (!strncmp(line, "info=ls ", strlen("info=ls "))) {
|
||||||
|
format_info_ls(line);
|
||||||
|
|
||||||
|
} else if (!strncmp(line, "info=ls_action ", strlen("info=ls_action "))) {
|
||||||
|
format_info_ls_action(line);
|
||||||
|
|
||||||
|
} else if (!strncmp(line, "info=r ", strlen("info=r "))) {
|
||||||
|
/*
|
||||||
|
* r_name/r_type are reset when a new resource is found.
|
||||||
|
* They are reused for the lock and action lines that
|
||||||
|
* follow a resource line.
|
||||||
|
*/
|
||||||
|
memset(r_name, 0, MAX_NAME+1);
|
||||||
|
memset(r_type, 0, MAX_NAME+1);
|
||||||
|
format_info_r(line, r_name, r_type);
|
||||||
|
|
||||||
|
} else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
|
||||||
|
/* will use info from previous r */
|
||||||
|
format_info_lk(line, r_name, r_type);
|
||||||
|
|
||||||
|
} else if (!strncmp(line, "info=r_action ", strlen("info=r_action "))) {
|
||||||
|
/* will use info from previous r */
|
||||||
|
format_info_r_action(line, r_name, r_type);
|
||||||
|
} else {
|
||||||
|
printf("UN %s\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_info(void)
|
||||||
|
{
|
||||||
|
char line[MAX_LINE];
|
||||||
|
char r_name[MAX_NAME+1];
|
||||||
|
char r_type[MAX_NAME+1];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
memset(line, 0, sizeof(line));
|
||||||
|
|
||||||
|
for (i = 0; i < dump_len; i++) {
|
||||||
|
line[j++] = dump_buf[i];
|
||||||
|
|
||||||
|
if ((line[j-1] == '\n') || (line[j-1] == '\0')) {
|
||||||
|
format_info_line(line, r_name, r_type);
|
||||||
|
j = 0;
|
||||||
|
memset(line, 0, sizeof(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static daemon_reply _lvmlockd_send(const char *req_name, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
daemon_reply repl;
|
||||||
|
daemon_request req;
|
||||||
|
|
||||||
|
req = daemon_request_make(req_name);
|
||||||
|
|
||||||
|
va_start(ap, req_name);
|
||||||
|
daemon_request_extend_v(req, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
repl = daemon_send(_lvmlockd, req);
|
||||||
|
|
||||||
|
daemon_request_destroy(req);
|
||||||
|
|
||||||
|
return repl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See the same in lib/locking/lvmlockd.c */
|
||||||
|
#define NO_LOCKD_RESULT -1000
|
||||||
|
|
||||||
|
static int _lvmlockd_result(daemon_reply reply, int *result)
|
||||||
|
{
|
||||||
|
int reply_result;
|
||||||
|
|
||||||
|
if (reply.error) {
|
||||||
|
log_error("lvmlockd_result reply error %d", reply.error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||||
|
log_error("lvmlockd_result bad response");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
|
||||||
|
if (reply_result == -1000) {
|
||||||
|
log_error("lvmlockd_result no op_result");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = reply_result;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_quit(void)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
reply = daemon_send_simple(_lvmlockd, "quit", NULL);
|
||||||
|
|
||||||
|
if (reply.error) {
|
||||||
|
log_error("reply error %d", reply.error);
|
||||||
|
rv = reply.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setup_dump_socket(void)
|
||||||
|
{
|
||||||
|
int s, rv;
|
||||||
|
|
||||||
|
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||||
|
if (s < 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
memset(&dump_addr, 0, sizeof(dump_addr));
|
||||||
|
dump_addr.sun_family = AF_LOCAL;
|
||||||
|
strcpy(&dump_addr.sun_path[1], DUMP_SOCKET_NAME);
|
||||||
|
dump_addrlen = sizeof(sa_family_t) + strlen(dump_addr.sun_path+1) + 1;
|
||||||
|
|
||||||
|
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
|
||||||
|
if (rv < 0) {
|
||||||
|
rv = -errno;
|
||||||
|
if (!close(s))
|
||||||
|
log_error("failed to close dump socket");
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_dump(const char *req_name)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
int result;
|
||||||
|
int fd, rv = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
fd = setup_dump_socket();
|
||||||
|
if (fd < 0) {
|
||||||
|
log_error("socket error %d", fd);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply = daemon_send_simple(_lvmlockd, req_name, NULL);
|
||||||
|
|
||||||
|
if (reply.error) {
|
||||||
|
log_error("reply error %d", reply.error);
|
||||||
|
rv = reply.error;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = daemon_reply_int(reply, "result", 0);
|
||||||
|
dump_len = daemon_reply_int(reply, "dump_len", 0);
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
rv = result;
|
||||||
|
log_error("result %d", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dump_len)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
memset(dump_buf, 0, sizeof(dump_buf));
|
||||||
|
|
||||||
|
retry:
|
||||||
|
rv = recvfrom(fd, dump_buf + count, dump_len - count, MSG_WAITALL,
|
||||||
|
(struct sockaddr *)&dump_addr, &dump_addrlen);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("recvfrom error %d %d", rv, errno);
|
||||||
|
rv = -errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
count += rv;
|
||||||
|
|
||||||
|
if (count < dump_len)
|
||||||
|
goto retry;
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
if ((info && dump) || !strcmp(req_name, "dump"))
|
||||||
|
printf("%s\n", dump_buf);
|
||||||
|
else
|
||||||
|
format_info();
|
||||||
|
out:
|
||||||
|
if (close(fd))
|
||||||
|
log_error("failed to close dump socket %d", fd);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_able(const char *req_name)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
int result;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
reply = _lvmlockd_send(req_name,
|
||||||
|
"cmd = %s", "lvmlockctl",
|
||||||
|
"pid = %d", getpid(),
|
||||||
|
"vg_name = %s", arg_vg_name,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!_lvmlockd_result(reply, &result)) {
|
||||||
|
log_error("lvmlockd result %d", result);
|
||||||
|
rv = result;
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_stop_lockspaces(void)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
char opts[32];
|
||||||
|
int result;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(opts, 0, sizeof(opts));
|
||||||
|
|
||||||
|
if (wait_opt)
|
||||||
|
strcat(opts, "wait ");
|
||||||
|
if (force_opt)
|
||||||
|
strcat(opts, "force ");
|
||||||
|
|
||||||
|
reply = _lvmlockd_send("stop_all",
|
||||||
|
"cmd = %s", "lvmlockctl",
|
||||||
|
"pid = %d", getpid(),
|
||||||
|
"opts = %s", opts[0] ? opts : "none",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!_lvmlockd_result(reply, &result)) {
|
||||||
|
log_error("lvmlockd result %d", result);
|
||||||
|
rv = result;
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_kill(void)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
int result;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
|
||||||
|
/* These two lines explain the manual alternative to the FIXME below. */
|
||||||
|
syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
|
||||||
|
syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It may not be strictly necessary to notify lvmlockd of the kill, but
|
||||||
|
* lvmlockd can use this information to avoid attempting any new lock
|
||||||
|
* requests in the VG (which would fail anyway), and can return an
|
||||||
|
* error indicating that the VG has been killed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
reply = _lvmlockd_send("kill_vg",
|
||||||
|
"cmd = %s", "lvmlockctl",
|
||||||
|
"pid = %d", getpid(),
|
||||||
|
"vg_name = %s", arg_vg_name,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!_lvmlockd_result(reply, &result)) {
|
||||||
|
log_error("lvmlockd result %d", result);
|
||||||
|
rv = result;
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: here is where we should implement a strong form of
|
||||||
|
* blkdeactivate, and if it completes successfully, automatically call
|
||||||
|
* do_drop() afterward. (The drop step may not always be necessary
|
||||||
|
* if the lvm commands run while shutting things down release all the
|
||||||
|
* leases.)
|
||||||
|
*
|
||||||
|
* run_strong_blkdeactivate();
|
||||||
|
* do_drop();
|
||||||
|
*/
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_drop(void)
|
||||||
|
{
|
||||||
|
daemon_reply reply;
|
||||||
|
int result;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for misuse by looking for any active LVs in the VG
|
||||||
|
* and refusing this operation if found? One possible way
|
||||||
|
* to kill LVs (e.g. if fs cannot be unmounted) is to suspend
|
||||||
|
* them, or replace them with the error target. In that
|
||||||
|
* case the LV will still appear to be active, but it is
|
||||||
|
* safe to release the lock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
reply = _lvmlockd_send("drop_vg",
|
||||||
|
"cmd = %s", "lvmlockctl",
|
||||||
|
"pid = %d", getpid(),
|
||||||
|
"vg_name = %s", arg_vg_name,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!_lvmlockd_result(reply, &result)) {
|
||||||
|
log_error("lvmlockd result %d", result);
|
||||||
|
rv = result;
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_usage(void)
|
||||||
|
{
|
||||||
|
printf("lvmlockctl options\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
printf("--help | -h\n");
|
||||||
|
printf(" Show this help information.\n");
|
||||||
|
printf("--quit | -q\n");
|
||||||
|
printf(" Tell lvmlockd to quit.\n");
|
||||||
|
printf("--info | -i\n");
|
||||||
|
printf(" Print lock state information from lvmlockd.\n");
|
||||||
|
printf("--dump | -d\n");
|
||||||
|
printf(" Print log buffer from lvmlockd.\n");
|
||||||
|
printf("--wait | -w 0|1\n");
|
||||||
|
printf(" Wait option for other commands.\n");
|
||||||
|
printf("--force | -f 0|1>\n");
|
||||||
|
printf(" Force option for other commands.\n");
|
||||||
|
printf("--kill | -k <vgname>\n");
|
||||||
|
printf(" Kill access to the VG when sanlock cannot renew lease.\n");
|
||||||
|
printf("--drop | -r <vgname>\n");
|
||||||
|
printf(" Clear locks for the VG when it is unused after kill (-k).\n");
|
||||||
|
printf("--gl-enable | -E <vgname>\n");
|
||||||
|
printf(" Tell lvmlockd to enable the global lock in a sanlock VG.\n");
|
||||||
|
printf("--gl-disable | -D <vgname>\n");
|
||||||
|
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
|
||||||
|
printf("--stop-lockspaces | -S\n");
|
||||||
|
printf(" Stop all lockspaces.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_options(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int option_index = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"help", no_argument, 0, 'h' },
|
||||||
|
{"quit", no_argument, 0, 'q' },
|
||||||
|
{"info", no_argument, 0, 'i' },
|
||||||
|
{"dump", no_argument, 0, 'd' },
|
||||||
|
{"wait", required_argument, 0, 'w' },
|
||||||
|
{"force", required_argument, 0, 'f' },
|
||||||
|
{"kill", required_argument, 0, 'k' },
|
||||||
|
{"drop", required_argument, 0, 'r' },
|
||||||
|
{"gl-enable", required_argument, 0, 'E' },
|
||||||
|
{"gl-disable", required_argument, 0, 'D' },
|
||||||
|
{"stop-lockspaces", no_argument, 0, 'S' },
|
||||||
|
{0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
print_usage();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
/* --help */
|
||||||
|
print_usage();
|
||||||
|
exit(0);
|
||||||
|
case 'q':
|
||||||
|
/* --quit */
|
||||||
|
quit = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
/* --info */
|
||||||
|
info = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
/* --dump */
|
||||||
|
dump = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
wait_opt = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
kill_vg = 1;
|
||||||
|
arg_vg_name = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
drop_vg = 1;
|
||||||
|
arg_vg_name = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
gl_enable = 1;
|
||||||
|
arg_vg_name = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
gl_disable = 1;
|
||||||
|
arg_vg_name = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
stop_lockspaces = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
rv = read_options(argc, argv);
|
||||||
|
if (rv < 0)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
_lvmlockd = lvmlockd_open(NULL);
|
||||||
|
|
||||||
|
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
||||||
|
log_error("Cannot connect to lvmlockd.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quit) {
|
||||||
|
rv = do_quit();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
rv = do_dump("info");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dump) {
|
||||||
|
rv = do_dump("dump");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kill_vg) {
|
||||||
|
rv = do_kill();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drop_vg) {
|
||||||
|
rv = do_drop();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gl_enable) {
|
||||||
|
syslog(LOG_INFO, "Enabling global lock in VG %s.", arg_vg_name);
|
||||||
|
rv = do_able("enable_gl");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gl_disable) {
|
||||||
|
syslog(LOG_INFO, "Disabling global lock in VG %s.", arg_vg_name);
|
||||||
|
rv = do_able("disable_gl");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop_lockspaces) {
|
||||||
|
rv = do_stop_lockspaces();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
lvmlockd_close(_lvmlockd);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
52
daemons/lvmlockd/lvmlockd-client.h
Normal file
52
daemons/lvmlockd/lvmlockd-client.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_LVMLOCKD_CLIENT_H
|
||||||
|
#define _LVM_LVMLOCKD_CLIENT_H
|
||||||
|
|
||||||
|
#include "daemon-client.h"
|
||||||
|
|
||||||
|
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
||||||
|
|
||||||
|
/* Wrappers to open/close connection */
|
||||||
|
|
||||||
|
static inline daemon_handle lvmlockd_open(const char *sock)
|
||||||
|
{
|
||||||
|
daemon_info lvmlockd_info = {
|
||||||
|
.path = "lvmlockd",
|
||||||
|
.socket = sock ?: LVMLOCKD_SOCKET,
|
||||||
|
.protocol = "lvmlockd",
|
||||||
|
.protocol_version = 1,
|
||||||
|
.autostart = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return daemon_open(lvmlockd_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lvmlockd_close(daemon_handle h)
|
||||||
|
{
|
||||||
|
return daemon_close(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Errors returned as the lvmlockd result value.
|
||||||
|
*/
|
||||||
|
#define ENOLS 210 /* lockspace not found */
|
||||||
|
#define ESTARTING 211 /* lockspace is starting */
|
||||||
|
#define EARGS 212
|
||||||
|
#define EHOSTID 213
|
||||||
|
#define EMANAGER 214
|
||||||
|
#define EPREPARE 215
|
||||||
|
#define ELOCKD 216
|
||||||
|
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
|
||||||
|
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
|
||||||
|
#define EREMOVED 219
|
||||||
|
|
||||||
|
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||||
6037
daemons/lvmlockd/lvmlockd-core.c
Normal file
6037
daemons/lvmlockd/lvmlockd-core.c
Normal file
File diff suppressed because it is too large
Load Diff
767
daemons/lvmlockd/lvmlockd-dlm.c
Normal file
767
daemons/lvmlockd/lvmlockd-dlm.c
Normal file
@@ -0,0 +1,767 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 500 /* pthread */
|
||||||
|
#define _ISOC99_SOURCE
|
||||||
|
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
|
#include "daemon-server.h"
|
||||||
|
#include "daemon-log.h"
|
||||||
|
#include "xlate.h"
|
||||||
|
|
||||||
|
#include "lvmlockd-internal.h"
|
||||||
|
#include "lvmlockd-client.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using synchronous _wait dlm apis so do not define _REENTRANT and
|
||||||
|
* link with non-threaded version of library, libdlm_lt.
|
||||||
|
*/
|
||||||
|
#include "libdlm.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <byteswap.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
struct lm_dlm {
|
||||||
|
dlm_lshandle_t *dh;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rd_dlm {
|
||||||
|
struct dlm_lksb lksb;
|
||||||
|
struct val_blk *vb;
|
||||||
|
};
|
||||||
|
|
||||||
|
int lm_data_size_dlm(void)
|
||||||
|
{
|
||||||
|
return sizeof(struct rd_dlm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lock_args format
|
||||||
|
*
|
||||||
|
* vg_lock_args format for dlm is
|
||||||
|
* vg_version_string:undefined:cluster_name
|
||||||
|
*
|
||||||
|
* lv_lock_args are not used for dlm
|
||||||
|
*
|
||||||
|
* version_string is MAJOR.MINOR.PATCH
|
||||||
|
* undefined may contain ":"
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VG_LOCK_ARGS_MAJOR 1
|
||||||
|
#define VG_LOCK_ARGS_MINOR 0
|
||||||
|
#define VG_LOCK_ARGS_PATCH 0
|
||||||
|
|
||||||
|
static int dlm_has_lvb_bug;
|
||||||
|
|
||||||
|
static int cluster_name_from_args(char *vg_args, char *clustername)
|
||||||
|
{
|
||||||
|
return last_string_from_args(vg_args, clustername);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_args_version(char *vg_args)
|
||||||
|
{
|
||||||
|
unsigned int major = 0;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
rv = version_from_args(vg_args, &major, NULL, NULL);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("check_args_version %s error %d", vg_args, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (major > VG_LOCK_ARGS_MAJOR) {
|
||||||
|
log_error("check_args_version %s major %d %d", vg_args, major, VG_LOCK_ARGS_MAJOR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will be set after dlm_controld is started. */
|
||||||
|
#define DLM_CLUSTER_NAME_PATH "/sys/kernel/config/dlm/cluster/cluster_name"
|
||||||
|
|
||||||
|
static int read_cluster_name(char *clustername)
|
||||||
|
{
|
||||||
|
static const char close_error_msg[] = "read_cluster_name: close_error %d";
|
||||||
|
char *n;
|
||||||
|
int fd;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (daemon_test) {
|
||||||
|
sprintf(clustername, "%s", "test");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(DLM_CLUSTER_NAME_PATH, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_debug("read_cluster_name: open error %d, check dlm_controld", fd);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = read(fd, clustername, MAX_ARGS);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
|
||||||
|
if (close(fd))
|
||||||
|
log_error(close_error_msg, fd);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = strstr(clustername, "\n");
|
||||||
|
if (n)
|
||||||
|
*n = '\0';
|
||||||
|
if (close(fd))
|
||||||
|
log_error(close_error_msg, fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
|
{
|
||||||
|
char clustername[MAX_ARGS+1];
|
||||||
|
char lock_args_version[MAX_ARGS+1];
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(clustername, 0, sizeof(clustername));
|
||||||
|
memset(lock_args_version, 0, sizeof(lock_args_version));
|
||||||
|
|
||||||
|
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||||
|
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||||
|
|
||||||
|
rv = read_cluster_name(clustername);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EMANAGER;
|
||||||
|
|
||||||
|
if (strlen(clustername) + strlen(lock_args_version) + 2 > MAX_ARGS) {
|
||||||
|
log_error("init_vg_dlm args too long");
|
||||||
|
return -EARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||||
|
{
|
||||||
|
char sys_clustername[MAX_ARGS+1];
|
||||||
|
char arg_clustername[MAX_ARGS+1];
|
||||||
|
uint32_t major = 0, minor = 0, patch = 0;
|
||||||
|
struct lm_dlm *lmd;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(sys_clustername, 0, sizeof(sys_clustername));
|
||||||
|
memset(arg_clustername, 0, sizeof(arg_clustername));
|
||||||
|
|
||||||
|
rv = read_cluster_name(sys_clustername);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EMANAGER;
|
||||||
|
|
||||||
|
rv = dlm_kernel_version(&major, &minor, &patch);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("prepare_lockspace_dlm kernel_version not detected %d", rv);
|
||||||
|
dlm_has_lvb_bug = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((major == 6) && (minor == 0) && (patch == 1)) {
|
||||||
|
log_debug("dlm kernel version %u.%u.%u has lvb bug", major, minor, patch);
|
||||||
|
dlm_has_lvb_bug = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ls->vg_args[0]) {
|
||||||
|
/* global lockspace has no vg args */
|
||||||
|
goto skip_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = check_args_version(ls->vg_args);
|
||||||
|
if (rv < 0)
|
||||||
|
return -EARGS;
|
||||||
|
|
||||||
|
rv = cluster_name_from_args(ls->vg_args, arg_clustername);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("prepare_lockspace_dlm %s no cluster name from args %s", ls->name, ls->vg_args);
|
||||||
|
return -EARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(sys_clustername, arg_clustername)) {
|
||||||
|
log_error("prepare_lockspace_dlm %s mismatching cluster names sys %s arg %s",
|
||||||
|
ls->name, sys_clustername, arg_clustername);
|
||||||
|
return -EARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_args:
|
||||||
|
lmd = malloc(sizeof(struct lm_dlm));
|
||||||
|
if (!lmd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ls->lm_data = lmd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (adopt)
|
||||||
|
lmd->dh = dlm_open_lockspace(ls->name);
|
||||||
|
else
|
||||||
|
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
|
||||||
|
|
||||||
|
if (!lmd->dh) {
|
||||||
|
log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
|
||||||
|
free(lmd);
|
||||||
|
ls->lm_data = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If free_vg is set, it means we are doing vgremove, and we may want
|
||||||
|
* to tell any other nodes to leave the lockspace. This is not really
|
||||||
|
* necessary since there should be no harm in having an unused
|
||||||
|
* lockspace sitting around. A new "notification lock" would need to
|
||||||
|
* be added with a callback to signal this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rv = dlm_release_lockspace(ls->name, lmd->dh, 1);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("rem_lockspace_dlm error %d", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
free(lmd);
|
||||||
|
ls->lm_data = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
char *buf;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||||
|
buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||||
|
|
||||||
|
rdd->vb = (struct val_blk *)buf;
|
||||||
|
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
|
||||||
|
|
||||||
|
flags |= LKF_VALBLK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!with_lock_nl)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* because this is a new NL lock request */
|
||||||
|
flags |= LKF_EXPEDITE;
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rv = dlm_ls_lock_wait(lmd->dh, LKM_NLMODE, &rdd->lksb, flags,
|
||||||
|
r->name, strlen(r->name),
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
|
struct dlm_lksb *lksb;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
lksb = &rdd->lksb;
|
||||||
|
|
||||||
|
if (!lksb->sb_lkid)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if (rdd->vb)
|
||||||
|
free(rdd->vb);
|
||||||
|
|
||||||
|
memset(rdd, 0, sizeof(struct rd_dlm));
|
||||||
|
r->lm_init = 0;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int to_dlm_mode(int ld_mode)
|
||||||
|
{
|
||||||
|
switch (ld_mode) {
|
||||||
|
case LD_LK_EX:
|
||||||
|
return LKM_EXMODE;
|
||||||
|
case LD_LK_SH:
|
||||||
|
return LKM_PRMODE;
|
||||||
|
};
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
|
struct val_blk *vb_out)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
|
struct dlm_lksb *lksb;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
int mode;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(vb_out, 0, sizeof(struct val_blk));
|
||||||
|
|
||||||
|
if (!r->lm_init) {
|
||||||
|
rv = lm_add_resource_dlm(ls, r, 0);
|
||||||
|
if (rv < 0)
|
||||||
|
return rv;
|
||||||
|
r->lm_init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lksb = &rdd->lksb;
|
||||||
|
|
||||||
|
flags |= LKF_PERSISTENT;
|
||||||
|
flags |= LKF_ORPHAN;
|
||||||
|
|
||||||
|
if (rdd->vb)
|
||||||
|
flags |= LKF_VALBLK;
|
||||||
|
|
||||||
|
mode = to_dlm_mode(ld_mode);
|
||||||
|
if (mode < 0) {
|
||||||
|
log_error("adopt_dlm invalid mode %d", ld_mode);
|
||||||
|
rv = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("S %s R %s adopt_dlm", ls->name, r->name);
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dlm returns 0 for success, -EAGAIN if an orphan is
|
||||||
|
* found with another mode, and -ENOENT if no orphan.
|
||||||
|
*
|
||||||
|
* cast/bast/param are (void *)1 because the kernel
|
||||||
|
* returns errors if some are null.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
|
||||||
|
r->name, strlen(r->name), 0,
|
||||||
|
(void *)1, (void *)1, (void *)1,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
if (rv == -1 && errno == -EAGAIN) {
|
||||||
|
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
||||||
|
ls->name, r->name, ld_mode);
|
||||||
|
rv = -EUCLEAN;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
|
||||||
|
ls->name, r->name, mode, flags, rv, errno);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: For GL/VG locks we probably want to read the lvb,
|
||||||
|
* especially if adopting an ex lock, because when we
|
||||||
|
* release this adopted ex lock we may want to write new
|
||||||
|
* lvb values based on the current lvb values (at lease
|
||||||
|
* in the GL case where we increment the current values.)
|
||||||
|
*
|
||||||
|
* It should be possible to read the lvb by requesting
|
||||||
|
* this lock in the same mode it's already in.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
lm_rem_resource_dlm(ls, r);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use PERSISTENT so that if lvmlockd exits while holding locks,
|
||||||
|
* the locks will remain orphaned in the dlm, still protecting what
|
||||||
|
* they were acquired to protect.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
|
struct val_blk *vb_out, int adopt)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
|
struct dlm_lksb *lksb;
|
||||||
|
struct val_blk vb;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
int mode;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (adopt) {
|
||||||
|
/* When adopting, we don't follow the normal method
|
||||||
|
of acquiring a NL lock then converting it to the
|
||||||
|
desired mode. */
|
||||||
|
return lm_adopt_dlm(ls, r, ld_mode, vb_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!r->lm_init) {
|
||||||
|
rv = lm_add_resource_dlm(ls, r, 1);
|
||||||
|
if (rv < 0)
|
||||||
|
return rv;
|
||||||
|
r->lm_init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lksb = &rdd->lksb;
|
||||||
|
|
||||||
|
flags |= LKF_CONVERT;
|
||||||
|
flags |= LKF_NOQUEUE;
|
||||||
|
flags |= LKF_PERSISTENT;
|
||||||
|
|
||||||
|
if (rdd->vb)
|
||||||
|
flags |= LKF_VALBLK;
|
||||||
|
|
||||||
|
mode = to_dlm_mode(ld_mode);
|
||||||
|
if (mode < 0) {
|
||||||
|
log_error("lock_dlm invalid mode %d", ld_mode);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("S %s R %s lock_dlm", ls->name, r->name);
|
||||||
|
|
||||||
|
if (daemon_test) {
|
||||||
|
memset(vb_out, 0, sizeof(struct val_blk));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dlm lvb bug means that converting NL->EX will not return
|
||||||
|
* the latest lvb, so we have to convert NL->PR->EX to reread it.
|
||||||
|
*/
|
||||||
|
if (dlm_has_lvb_bug && (ld_mode == LD_LK_EX)) {
|
||||||
|
rv = dlm_ls_lock_wait(lmd->dh, LKM_PRMODE, lksb, flags,
|
||||||
|
r->name, strlen(r->name),
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
if (rv == -1) {
|
||||||
|
log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
|
||||||
|
ls->name, r->name, mode, rv);
|
||||||
|
goto lockrv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fall through to request EX. */
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
||||||
|
r->name, strlen(r->name),
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
lockrv:
|
||||||
|
if (rv == -1 && errno == EAGAIN) {
|
||||||
|
log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdd->vb) {
|
||||||
|
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
||||||
|
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
||||||
|
memset(rdd->vb, 0, sizeof(struct val_blk));
|
||||||
|
memset(vb_out, 0, sizeof(struct val_blk));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'vb' contains disk endian values, not host endian.
|
||||||
|
* It is copied directly to rdd->vb which is also kept
|
||||||
|
* in disk endian form.
|
||||||
|
* vb_out is returned to the caller in host endian form.
|
||||||
|
*/
|
||||||
|
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
|
||||||
|
memcpy(rdd->vb, &vb, sizeof(vb));
|
||||||
|
|
||||||
|
vb_out->version = le16_to_cpu(vb.version);
|
||||||
|
vb_out->flags = le16_to_cpu(vb.flags);
|
||||||
|
vb_out->r_version = le32_to_cpu(vb.r_version);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
|
int ld_mode, uint32_t r_version)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
|
struct dlm_lksb *lksb = &rdd->lksb;
|
||||||
|
uint32_t mode;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
log_debug("S %s R %s convert_dlm", ls->name, r->name);
|
||||||
|
|
||||||
|
flags |= LKF_CONVERT;
|
||||||
|
flags |= LKF_NOQUEUE;
|
||||||
|
flags |= LKF_PERSISTENT;
|
||||||
|
|
||||||
|
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||||
|
if (!rdd->vb->version) {
|
||||||
|
/* first time vb has been written */
|
||||||
|
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
|
||||||
|
}
|
||||||
|
rdd->vb->r_version = cpu_to_le32(r_version);
|
||||||
|
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
||||||
|
|
||||||
|
log_debug("S %s R %s convert_dlm set r_version %u",
|
||||||
|
ls->name, r->name, r_version);
|
||||||
|
|
||||||
|
flags |= LKF_VALBLK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode = to_dlm_mode(ld_mode);
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
||||||
|
r->name, strlen(r->name),
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
if (rv == -1 && errno == EAGAIN) {
|
||||||
|
/* FIXME: When does this happen? Should something different be done? */
|
||||||
|
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
|
uint32_t r_version, uint32_t lmu_flags)
|
||||||
|
{
|
||||||
|
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||||
|
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||||
|
struct dlm_lksb *lksb = &rdd->lksb;
|
||||||
|
struct val_blk vb_prev;
|
||||||
|
struct val_blk vb_next;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
int new_vb = 0;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not set PERSISTENT, because we don't need an orphan
|
||||||
|
* NL lock to protect anything.
|
||||||
|
*/
|
||||||
|
|
||||||
|
flags |= LKF_CONVERT;
|
||||||
|
|
||||||
|
if (rdd->vb && (r->mode == LD_LK_EX)) {
|
||||||
|
|
||||||
|
/* vb_prev and vb_next are in disk endian form */
|
||||||
|
memcpy(&vb_prev, rdd->vb, sizeof(struct val_blk));
|
||||||
|
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
|
||||||
|
|
||||||
|
if (!vb_prev.version) {
|
||||||
|
vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
|
||||||
|
new_vb = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
|
||||||
|
vb_next.flags = cpu_to_le16(VBF_REMOVED);
|
||||||
|
new_vb = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r_version) {
|
||||||
|
vb_next.r_version = cpu_to_le32(r_version);
|
||||||
|
new_vb = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_vb) {
|
||||||
|
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
||||||
|
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
||||||
|
|
||||||
|
log_debug("S %s R %s unlock_dlm vb old %x %x %u new %x %x %u",
|
||||||
|
ls->name, r->name,
|
||||||
|
le16_to_cpu(vb_prev.version),
|
||||||
|
le16_to_cpu(vb_prev.flags),
|
||||||
|
le32_to_cpu(vb_prev.r_version),
|
||||||
|
le16_to_cpu(vb_next.version),
|
||||||
|
le16_to_cpu(vb_next.flags),
|
||||||
|
le32_to_cpu(vb_next.r_version));
|
||||||
|
} else {
|
||||||
|
log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= LKF_VALBLK;
|
||||||
|
} else {
|
||||||
|
log_debug("S %s R %s unlock_dlm", ls->name, r->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon_test)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rv = dlm_ls_lock_wait(lmd->dh, LKM_NLMODE, lksb, flags,
|
||||||
|
r->name, strlen(r->name),
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
if (rv < 0) {
|
||||||
|
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This list could be read from dlm_controld via libdlmcontrol,
|
||||||
|
* but it's simpler to get it from sysfs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DLM_LOCKSPACES_PATH "/sys/kernel/config/dlm/cluster/spaces"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: this should be implemented differently.
|
||||||
|
* It's not nice to use an aspect of the dlm clustering
|
||||||
|
* implementation, which could change. It would be
|
||||||
|
* better to do something like use a special lock in the
|
||||||
|
* lockspace that was held PR by all nodes, and then an
|
||||||
|
* EX request on it could check if it's started (and
|
||||||
|
* possibly also notify others to stop it automatically).
|
||||||
|
* Or, possibly an enhancement to libdlm that would give
|
||||||
|
* info about lockspace members.
|
||||||
|
*
|
||||||
|
* (We could let the VG be removed while others still
|
||||||
|
* have the lockspace running, which largely works, but
|
||||||
|
* introduces problems if another VG with the same name is
|
||||||
|
* recreated while others still have the lockspace running
|
||||||
|
* for the previous VG. We'd also want a way to clean up
|
||||||
|
* the stale lockspaces on the others eventually.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||||
|
{
|
||||||
|
static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
|
||||||
|
char ls_nodes_path[PATH_MAX];
|
||||||
|
struct dirent *de;
|
||||||
|
DIR *ls_dir;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
memset(ls_nodes_path, 0, sizeof(ls_nodes_path));
|
||||||
|
snprintf(ls_nodes_path, PATH_MAX-1, "%s/%s/nodes",
|
||||||
|
DLM_LOCKSPACES_PATH, ls->name);
|
||||||
|
|
||||||
|
if (!(ls_dir = opendir(ls_nodes_path)))
|
||||||
|
return -ECONNREFUSED;
|
||||||
|
|
||||||
|
while ((de = readdir(ls_dir))) {
|
||||||
|
if (de->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedir(ls_dir))
|
||||||
|
log_error(closedir_err_msg);
|
||||||
|
|
||||||
|
if (!count) {
|
||||||
|
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume that a count of one node represents ourself,
|
||||||
|
* and any value over one represents other nodes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||||
|
{
|
||||||
|
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||||
|
struct lockspace *ls;
|
||||||
|
struct dirent *de;
|
||||||
|
DIR *ls_dir;
|
||||||
|
|
||||||
|
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
|
||||||
|
return -ECONNREFUSED;
|
||||||
|
|
||||||
|
while ((de = readdir(ls_dir))) {
|
||||||
|
if (de->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp(de->d_name, LVM_LS_PREFIX, strlen(LVM_LS_PREFIX)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(ls = alloc_lockspace())) {
|
||||||
|
if (closedir(ls_dir))
|
||||||
|
log_error(closedir_err_msg);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ls->lm_type = LD_LM_DLM;
|
||||||
|
strncpy(ls->name, de->d_name, MAX_NAME);
|
||||||
|
strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
|
||||||
|
list_add_tail(&ls->list, ls_rejoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedir(ls_dir))
|
||||||
|
log_error(closedir_err_msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm_is_running_dlm(void)
|
||||||
|
{
|
||||||
|
char sys_clustername[MAX_ARGS+1];
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
memset(sys_clustername, 0, sizeof(sys_clustername));
|
||||||
|
|
||||||
|
rv = read_cluster_name(sys_clustername);
|
||||||
|
if (rv < 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
587
daemons/lvmlockd/lvmlockd-internal.h
Normal file
587
daemons/lvmlockd/lvmlockd-internal.h
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_LVMLOCKD_INTERNAL_H
|
||||||
|
#define _LVM_LVMLOCKD_INTERNAL_H
|
||||||
|
|
||||||
|
#define MAX_NAME 64
|
||||||
|
#define MAX_ARGS 64
|
||||||
|
|
||||||
|
#define R_NAME_GL_DISABLED "_GLLK_disabled"
|
||||||
|
#define R_NAME_GL "GLLK"
|
||||||
|
#define R_NAME_VG "VGLK"
|
||||||
|
#define S_NAME_GL_DLM "lvm_global"
|
||||||
|
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
|
||||||
|
/* global lockspace name for sanlock is a vg name */
|
||||||
|
|
||||||
|
/* lock manager types */
|
||||||
|
enum {
|
||||||
|
LD_LM_NONE = 0,
|
||||||
|
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
|
||||||
|
LD_LM_DLM = 2,
|
||||||
|
LD_LM_SANLOCK = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* operation types */
|
||||||
|
enum {
|
||||||
|
LD_OP_HELLO = 1,
|
||||||
|
LD_OP_QUIT,
|
||||||
|
LD_OP_INIT,
|
||||||
|
LD_OP_FREE,
|
||||||
|
LD_OP_START,
|
||||||
|
LD_OP_STOP,
|
||||||
|
LD_OP_LOCK,
|
||||||
|
LD_OP_UPDATE,
|
||||||
|
LD_OP_CLOSE,
|
||||||
|
LD_OP_ENABLE,
|
||||||
|
LD_OP_DISABLE,
|
||||||
|
LD_OP_START_WAIT,
|
||||||
|
LD_OP_STOP_ALL,
|
||||||
|
LD_OP_DUMP_INFO,
|
||||||
|
LD_OP_DUMP_LOG,
|
||||||
|
LD_OP_RENAME_BEFORE,
|
||||||
|
LD_OP_RENAME_FINAL,
|
||||||
|
LD_OP_RUNNING_LM,
|
||||||
|
LD_OP_FIND_FREE_LOCK,
|
||||||
|
LD_OP_KILL_VG,
|
||||||
|
LD_OP_DROP_VG,
|
||||||
|
LD_OP_BUSY,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* resource types */
|
||||||
|
enum {
|
||||||
|
LD_RT_GL = 1,
|
||||||
|
LD_RT_VG,
|
||||||
|
LD_RT_LV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* lock modes, more restrictive must be larger value */
|
||||||
|
enum {
|
||||||
|
LD_LK_IV = -1,
|
||||||
|
LD_LK_UN = 0,
|
||||||
|
LD_LK_NL = 1,
|
||||||
|
LD_LK_SH = 2,
|
||||||
|
LD_LK_EX = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list_head {
|
||||||
|
struct list_head *next, *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct client {
|
||||||
|
struct list_head list;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
int pid;
|
||||||
|
int fd;
|
||||||
|
int pi;
|
||||||
|
uint32_t id;
|
||||||
|
unsigned int recv : 1;
|
||||||
|
unsigned int dead : 1;
|
||||||
|
unsigned int poll_ignore : 1;
|
||||||
|
unsigned int lock_ops : 1;
|
||||||
|
char name[MAX_NAME+1];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LD_AF_PERSISTENT 0x00000001
|
||||||
|
#define LD_AF_NO_CLIENT 0x00000002
|
||||||
|
#define LD_AF_UNLOCK_CANCEL 0x00000004
|
||||||
|
#define LD_AF_NEXT_VERSION 0x00000008
|
||||||
|
#define LD_AF_WAIT 0x00000010
|
||||||
|
#define LD_AF_FORCE 0x00000020
|
||||||
|
#define LD_AF_EX_DISABLE 0x00000040
|
||||||
|
#define LD_AF_ENABLE 0x00000080
|
||||||
|
#define LD_AF_DISABLE 0x00000100
|
||||||
|
#define LD_AF_SEARCH_LS 0x00000200
|
||||||
|
#define LD_AF_WAIT_STARTING 0x00001000
|
||||||
|
#define LD_AF_DUP_GL_LS 0x00002000
|
||||||
|
#define LD_AF_ADOPT 0x00010000
|
||||||
|
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||||
|
#define LD_AF_LV_LOCK 0x00040000
|
||||||
|
#define LD_AF_LV_UNLOCK 0x00080000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of times to repeat a lock request after
|
||||||
|
* a lock conflict (-EAGAIN) if unspecified in the
|
||||||
|
* request.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_MAX_RETRIES 4
|
||||||
|
|
||||||
|
struct action {
|
||||||
|
struct list_head list;
|
||||||
|
uint32_t client_id;
|
||||||
|
uint32_t flags; /* LD_AF_ */
|
||||||
|
uint32_t version;
|
||||||
|
uint64_t host_id;
|
||||||
|
int8_t op; /* operation type LD_OP_ */
|
||||||
|
int8_t rt; /* resource type LD_RT_ */
|
||||||
|
int8_t mode; /* lock mode LD_LK_ */
|
||||||
|
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
||||||
|
int retries;
|
||||||
|
int max_retries;
|
||||||
|
int result;
|
||||||
|
int lm_rv; /* return value from lm_ function */
|
||||||
|
char vg_uuid[64];
|
||||||
|
char vg_name[MAX_NAME+1];
|
||||||
|
char lv_name[MAX_NAME+1];
|
||||||
|
char lv_uuid[MAX_NAME+1];
|
||||||
|
char vg_args[MAX_ARGS+1];
|
||||||
|
char lv_args[MAX_ARGS+1];
|
||||||
|
char vg_sysid[MAX_NAME+1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct resource {
|
||||||
|
struct list_head list; /* lockspace.resources */
|
||||||
|
char name[MAX_NAME+1]; /* vg name or lv name */
|
||||||
|
int8_t type; /* resource type LD_RT_ */
|
||||||
|
int8_t mode;
|
||||||
|
unsigned int sh_count; /* number of sh locks on locks list */
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
||||||
|
unsigned int lm_init : 1; /* lm_data is initialized */
|
||||||
|
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
||||||
|
unsigned int version_zero_valid : 1;
|
||||||
|
unsigned int use_vb : 1;
|
||||||
|
struct list_head locks;
|
||||||
|
struct list_head actions;
|
||||||
|
char lv_args[MAX_ARGS+1];
|
||||||
|
char lm_data[0]; /* lock manager specific data */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LD_LF_PERSISTENT 0x00000001
|
||||||
|
|
||||||
|
struct lock {
|
||||||
|
struct list_head list; /* resource.locks */
|
||||||
|
int8_t mode; /* lock mode LD_LK_ */
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t flags; /* LD_LF_ */
|
||||||
|
uint32_t client_id; /* may be 0 for persistent or internal locks */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lockspace {
|
||||||
|
struct list_head list; /* lockspaces */
|
||||||
|
char name[MAX_NAME+1];
|
||||||
|
char vg_name[MAX_NAME+1];
|
||||||
|
char vg_uuid[64];
|
||||||
|
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
|
||||||
|
char vg_sysid[MAX_NAME+1];
|
||||||
|
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
||||||
|
void *lm_data;
|
||||||
|
uint64_t host_id;
|
||||||
|
uint64_t free_lock_offset; /* start search for free lock here */
|
||||||
|
|
||||||
|
uint32_t start_client_id; /* client_id that started the lockspace */
|
||||||
|
pthread_t thread; /* makes synchronous lock requests */
|
||||||
|
pthread_cond_t cond;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
unsigned int create_fail : 1;
|
||||||
|
unsigned int create_done : 1;
|
||||||
|
unsigned int thread_work : 1;
|
||||||
|
unsigned int thread_stop : 1;
|
||||||
|
unsigned int thread_done : 1;
|
||||||
|
unsigned int sanlock_gl_enabled: 1;
|
||||||
|
unsigned int sanlock_gl_dup: 1;
|
||||||
|
unsigned int free_vg: 1;
|
||||||
|
unsigned int kill_vg: 1;
|
||||||
|
unsigned int drop_vg: 1;
|
||||||
|
|
||||||
|
struct list_head actions; /* new client actions */
|
||||||
|
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* val_blk version */
|
||||||
|
#define VAL_BLK_VERSION 0x0101
|
||||||
|
|
||||||
|
/* val_blk flags */
|
||||||
|
#define VBF_REMOVED 0x0001
|
||||||
|
|
||||||
|
struct val_blk {
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t flags;
|
||||||
|
uint32_t r_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* lm_unlock flags */
|
||||||
|
#define LMUF_FREE_VG 0x00000001
|
||||||
|
|
||||||
|
#define container_of(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||||
|
|
||||||
|
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||||
|
{
|
||||||
|
list->next = list;
|
||||||
|
list->prev = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_add(struct list_head *new,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = new;
|
||||||
|
new->next = next;
|
||||||
|
new->prev = prev;
|
||||||
|
prev->next = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = prev;
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_del(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int list_empty(const struct list_head *head)
|
||||||
|
{
|
||||||
|
return head->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define list_entry(ptr, type, member) \
|
||||||
|
container_of(ptr, type, member)
|
||||||
|
|
||||||
|
#define list_first_entry(ptr, type, member) \
|
||||||
|
list_entry((ptr)->next, type, member)
|
||||||
|
|
||||||
|
#define list_for_each_entry(pos, head, member) \
|
||||||
|
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||||
|
|
||||||
|
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||||
|
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||||
|
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||||
|
|
||||||
|
|
||||||
|
/* to improve readability */
|
||||||
|
#define WAIT 1
|
||||||
|
#define NO_WAIT 0
|
||||||
|
#define FORCE 1
|
||||||
|
#define NO_FORCE 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* global variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXTERN
|
||||||
|
#define EXTERN extern
|
||||||
|
#define INIT(X)
|
||||||
|
#else
|
||||||
|
#undef EXTERN
|
||||||
|
#define EXTERN
|
||||||
|
#define INIT(X) =X
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gl_type_static and gl_use_ are set by command line or config file
|
||||||
|
* to specify whether the global lock comes from dlm or sanlock.
|
||||||
|
* Without a static setting, lvmlockd will figure out where the
|
||||||
|
* global lock should be (but it could get mixed up in cases where
|
||||||
|
* both sanlock and dlm vgs exist.)
|
||||||
|
*
|
||||||
|
* gl_use_dlm means that the gl should come from lockspace gl_lsname_dlm
|
||||||
|
* gl_use_sanlock means that the gl should come from lockspace gl_lsname_sanlock
|
||||||
|
*
|
||||||
|
* gl_use_dlm has precedence over gl_use_sanlock, so if a node sees both
|
||||||
|
* dlm and sanlock vgs, it will use the dlm gl.
|
||||||
|
*
|
||||||
|
* gl_use_ is set when the first evidence of that lm_type is seen
|
||||||
|
* in any command.
|
||||||
|
*
|
||||||
|
* gl_lsname_sanlock is set when the first vg is seen in which an
|
||||||
|
* enabled gl is exists, or when init_vg creates a vg with gl enabled,
|
||||||
|
* or when enable_gl is used.
|
||||||
|
*
|
||||||
|
* gl_lsname_sanlock is cleared when free_vg deletes a vg with gl enabled
|
||||||
|
* or when disable_gl matches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
EXTERN int gl_type_static;
|
||||||
|
EXTERN int gl_use_dlm;
|
||||||
|
EXTERN int gl_use_sanlock;
|
||||||
|
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||||
|
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||||
|
EXTERN int global_dlm_lockspace_exists;
|
||||||
|
|
||||||
|
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||||
|
EXTERN int daemon_debug;
|
||||||
|
EXTERN int daemon_host_id;
|
||||||
|
EXTERN const char *daemon_host_id_file;
|
||||||
|
EXTERN int sanlock_io_timeout;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This flag is set to 1 if we see multiple vgs with the global
|
||||||
|
* lock enabled. While this is set, we return a special flag
|
||||||
|
* with the vg lock result indicating to the lvm command that
|
||||||
|
* there is a duplicate gl in the vg which should be resolved.
|
||||||
|
* While this is set, find_lockspace_name has the side job of
|
||||||
|
* counting the number of lockspaces with enabled gl's so that
|
||||||
|
* this can be set back to zero when the duplicates are disabled.
|
||||||
|
*/
|
||||||
|
EXTERN int sanlock_gl_dup;
|
||||||
|
|
||||||
|
void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||||
|
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
|
||||||
|
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
|
||||||
|
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
|
||||||
|
|
||||||
|
struct lockspace *alloc_lockspace(void);
|
||||||
|
int lockspaces_empty(void);
|
||||||
|
int last_string_from_args(char *args_in, char *last);
|
||||||
|
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LOCKDDLM_SUPPORT
|
||||||
|
|
||||||
|
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
|
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||||
|
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||||
|
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||||
|
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
|
struct val_blk *vb_out, int adopt);
|
||||||
|
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
|
int ld_mode, uint32_t r_version);
|
||||||
|
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
|
uint32_t r_version, uint32_t lmu_flags);
|
||||||
|
int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r);
|
||||||
|
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
||||||
|
int lm_data_size_dlm(void);
|
||||||
|
int lm_is_running_dlm(void);
|
||||||
|
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
||||||
|
|
||||||
|
static inline int lm_support_dlm(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
|
struct val_blk *vb_out, int adopt)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||||
|
int ld_mode, uint32_t r_version)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||||
|
uint32_t r_version, uint32_t lmu_flags)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_data_size_dlm(void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_is_running_dlm(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_support_dlm(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* dlm support */
|
||||||
|
|
||||||
|
#ifdef LOCKDSANLOCK_SUPPORT
|
||||||
|
|
||||||
|
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
|
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
|
||||||
|
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
||||||
|
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
|
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||||
|
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
||||||
|
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||||
|
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
|
struct val_blk *vb_out, int *retry, int adopt);
|
||||||
|
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
|
int ld_mode, uint32_t r_version);
|
||||||
|
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
|
uint32_t r_version, uint32_t lmu_flags);
|
||||||
|
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
|
||||||
|
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
|
||||||
|
int lm_hosts_sanlock(struct lockspace *ls, int notify);
|
||||||
|
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
|
||||||
|
int lm_gl_is_enabled(struct lockspace *ls);
|
||||||
|
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
||||||
|
int lm_data_size_sanlock(void);
|
||||||
|
int lm_is_running_sanlock(void);
|
||||||
|
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
|
||||||
|
|
||||||
|
static inline int lm_support_sanlock(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||||
|
struct val_blk *vb_out, int *retry, int adopt)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
|
int ld_mode, uint32_t r_version)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||||
|
uint32_t r_version, uint32_t lmu_flags)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_gl_is_enabled(struct lockspace *ls)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_data_size_sanlock(void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_is_running_sanlock(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lm_support_sanlock(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* sanlock support */
|
||||||
|
|
||||||
|
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
||||||
1825
daemons/lvmlockd/lvmlockd-sanlock.c
Normal file
1825
daemons/lvmlockd/lvmlockd-sanlock.c
Normal file
File diff suppressed because it is too large
Load Diff
1
daemons/lvmpolld/.gitignore
vendored
Normal file
1
daemons/lvmpolld/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
lvmpolld
|
||||||
48
daemons/lvmpolld/Makefile.in
Normal file
48
daemons/lvmpolld/Makefile.in
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of LVM2.
|
||||||
|
#
|
||||||
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
# of the GNU Lesser General Public License v.2.1.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
|
||||||
|
|
||||||
|
TARGETS = lvmpolld
|
||||||
|
|
||||||
|
.PHONY: install_lvmpolld
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
CFLOW_TARGET = lvmpolld
|
||||||
|
|
||||||
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||||
|
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
|
||||||
|
|
||||||
|
LIBS += $(PTHREAD_LIBS)
|
||||||
|
|
||||||
|
LDFLAGS += -L$(top_builddir)/libdaemon/server $(DAEMON_LDFLAGS)
|
||||||
|
CLDFLAGS += -L$(top_builddir)/libdaemon/server
|
||||||
|
CFLAGS += $(DAEMON_CFLAGS)
|
||||||
|
|
||||||
|
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||||
|
|
||||||
|
install_lvmpolld: lvmpolld
|
||||||
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
|
|
||||||
|
install_lvm2: install_lvmpolld
|
||||||
|
|
||||||
|
install: install_lvm2
|
||||||
144
daemons/lvmpolld/lvmpolld-cmd-utils.c
Normal file
144
daemons/lvmpolld/lvmpolld-cmd-utils.c
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lvmpolld-common.h"
|
||||||
|
|
||||||
|
/* extract this info from autoconf/automake files */
|
||||||
|
#define LVPOLL_CMD "lvpoll"
|
||||||
|
|
||||||
|
#define MIN_ARGV_SIZE 8
|
||||||
|
|
||||||
|
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
|
||||||
|
[CONVERT] = LVMPD_REQ_CONVERT,
|
||||||
|
[MERGE] = LVMPD_REQ_MERGE,
|
||||||
|
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN };
|
||||||
|
|
||||||
|
const char *polling_op(enum poll_type type)
|
||||||
|
{
|
||||||
|
return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||||
|
{
|
||||||
|
const char **newargv = *cmdargv;
|
||||||
|
|
||||||
|
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
|
||||||
|
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||||
|
if (!newargv)
|
||||||
|
return 0;
|
||||||
|
*cmdargv = newargv;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(*cmdargv + (*ind)++) = str;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||||
|
|
||||||
|
if (!cmd_argv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* path to lvm2 binary */
|
||||||
|
if (!add_to_cmd_arr(&cmd_argv, lvm_binary, &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* cmd to execute */
|
||||||
|
if (!add_to_cmd_arr(&cmd_argv, LVPOLL_CMD, &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* transfer internal polling interval */
|
||||||
|
if (pdlv->sinterval &&
|
||||||
|
(!add_to_cmd_arr(&cmd_argv, "--interval", &i) ||
|
||||||
|
!add_to_cmd_arr(&cmd_argv, pdlv->sinterval, &i)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* pass abort param */
|
||||||
|
if (abort_polling &&
|
||||||
|
!add_to_cmd_arr(&cmd_argv, "--abort", &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* pass handle-missing-pvs. used by mirror polling operation */
|
||||||
|
if (handle_missing_pvs &&
|
||||||
|
!add_to_cmd_arr(&cmd_argv, "--handlemissingpvs", &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* one of: "convert", "pvmove", "merge", "merge_thin" */
|
||||||
|
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
|
||||||
|
!add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* vg/lv name */
|
||||||
|
if (!add_to_cmd_arr(&cmd_argv, pdlv->lvname, &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* disable metadata backup */
|
||||||
|
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* terminating NULL */
|
||||||
|
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return cmd_argv;
|
||||||
|
err:
|
||||||
|
dm_free(cmd_argv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: in fact exclude should be va list */
|
||||||
|
static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
|
||||||
|
{
|
||||||
|
const char * const* tmp = (const char * const*) environ;
|
||||||
|
|
||||||
|
if (!tmp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (*tmp) {
|
||||||
|
if (strncmp(*tmp, exclude, strlen(exclude)) && !add_to_cmd_arr(cmd_envp, *tmp, i))
|
||||||
|
return 0;
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||||
|
|
||||||
|
if (!cmd_envp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* copy whole environment from lvmpolld, exclude LVM_SYSTEM_DIR if set */
|
||||||
|
if (!copy_env(&cmd_envp, &i, "LVM_SYSTEM_DIR="))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* Add per client LVM_SYSTEM_DIR variable if set */
|
||||||
|
if (*pdlv->lvm_system_dir_env && !add_to_cmd_arr(&cmd_envp, pdlv->lvm_system_dir_env, &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* terminating NULL */
|
||||||
|
if (!add_to_cmd_arr(&cmd_envp, NULL, &i))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return cmd_envp;
|
||||||
|
err:
|
||||||
|
dm_free(cmd_envp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
25
daemons/lvmpolld/lvmpolld-cmd-utils.h
Normal file
25
daemons/lvmpolld/lvmpolld-cmd-utils.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_LVMPOLLD_CMD_UTILS_H
|
||||||
|
#define _LVM_LVMPOLLD_CMD_UTILS_H
|
||||||
|
|
||||||
|
#include "lvmpolld-data-utils.h"
|
||||||
|
|
||||||
|
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort, unsigned handle_missing_pvs);
|
||||||
|
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv);
|
||||||
|
|
||||||
|
const char *polling_op(enum poll_type);
|
||||||
|
|
||||||
|
#endif /* _LVM_LVMPOLLD_CMD_UTILS_H */
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2006 Rackable Systems All rights reserved.
|
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -12,22 +12,20 @@
|
|||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_TIMESTAMP_H
|
/*
|
||||||
#define _LVM_TIMESTAMP_H
|
* This file must be included first by every lvmpolld source file.
|
||||||
|
|
||||||
struct timestamp;
|
|
||||||
|
|
||||||
struct timestamp *get_timestamp(void);
|
|
||||||
|
|
||||||
/* cmp_timestamp: Compare two timestamps
|
|
||||||
*
|
|
||||||
* Return: -1 if t1 is less than t2
|
|
||||||
* 0 if t1 is equal to t2
|
|
||||||
* 1 if t1 is greater than t2
|
|
||||||
*/
|
*/
|
||||||
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2);
|
#ifndef _LVM_LVMPOLLD_COMMON_H
|
||||||
|
#define _LVM_LVMPOLLD_COMMON_H
|
||||||
|
|
||||||
void destroy_timestamp(struct timestamp *t);
|
#define _REENTRANT
|
||||||
|
|
||||||
#endif /* _LVM_TIMESTAMP_H */
|
#include "tool.h"
|
||||||
|
|
||||||
|
#include "lvmpolld-cmd-utils.h"
|
||||||
|
#include "lvmpolld-protocol.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#endif /* _LVM_LVMPOLLD_COMMON_H */
|
||||||
999
daemons/lvmpolld/lvmpolld-core.c
Normal file
999
daemons/lvmpolld/lvmpolld-core.c
Normal file
@@ -0,0 +1,999 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lvmpolld-common.h"
|
||||||
|
|
||||||
|
#include "lvm-version.h"
|
||||||
|
#include "daemon-server.h"
|
||||||
|
#include "daemon-log.h"
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <wait.h>
|
||||||
|
|
||||||
|
#define LVMPOLLD_SOCKET DEFAULT_RUN_DIR "/lvmpolld.socket"
|
||||||
|
|
||||||
|
#define PD_LOG_PREFIX "LVMPOLLD"
|
||||||
|
#define LVM2_LOG_PREFIX "\tLVPOLL"
|
||||||
|
|
||||||
|
/* predefined reason for response = "failed" case */
|
||||||
|
#define REASON_REQ_NOT_IMPLEMENTED "request not implemented"
|
||||||
|
#define REASON_MISSING_LVID "request requires lvid set"
|
||||||
|
#define REASON_MISSING_LVNAME "request requires lvname set"
|
||||||
|
#define REASON_MISSING_VGNAME "request requires vgname set"
|
||||||
|
#define REASON_POLLING_FAILED "polling of lvm command failed"
|
||||||
|
#define REASON_ILLEGAL_ABORT_REQUEST "abort only supported with PVMOVE polling operation"
|
||||||
|
#define REASON_DIFFERENT_OPERATION_IN_PROGRESS "Different operation on LV already in progress"
|
||||||
|
#define REASON_INVALID_INTERVAL "request requires interval set"
|
||||||
|
#define REASON_ENOMEM "not enough memory"
|
||||||
|
|
||||||
|
struct lvmpolld_state {
|
||||||
|
daemon_idle *idle;
|
||||||
|
log_state *log;
|
||||||
|
const char *log_config;
|
||||||
|
const char *lvm_binary;
|
||||||
|
|
||||||
|
struct lvmpolld_store *id_to_pdlv_abort;
|
||||||
|
struct lvmpolld_store *id_to_pdlv_poll;
|
||||||
|
};
|
||||||
|
|
||||||
|
static pthread_key_t key;
|
||||||
|
|
||||||
|
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
||||||
|
{
|
||||||
|
#ifdef _GNU_SOURCE
|
||||||
|
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
||||||
|
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
||||||
|
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
||||||
|
#else
|
||||||
|
# warning "Can't decide proper strerror_r implementation. lvmpolld will not issue specific system error messages"
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _usage(const char *prog, FILE *file)
|
||||||
|
{
|
||||||
|
fprintf(file, "Usage:\n"
|
||||||
|
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path] [-B path] [-p path] [-t secs]\n"
|
||||||
|
"%s --dump [-s path]\n"
|
||||||
|
" -V|--version Show version info\n"
|
||||||
|
" -h|--help Show this help information\n"
|
||||||
|
" -f|--foreground Don't fork, run in the foreground\n"
|
||||||
|
" --dump Dump full lvmpolld state\n"
|
||||||
|
" -l|--log Logging message level (-l {all|wire|debug})\n"
|
||||||
|
" -p|--pidfile Set path to the pidfile\n"
|
||||||
|
" -s|--socket Set path to the communication socket\n"
|
||||||
|
" -B|--binary Path to lvm2 binary\n"
|
||||||
|
" -t|--timeout Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog, prog);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init(struct daemon_state *s)
|
||||||
|
{
|
||||||
|
struct lvmpolld_state *ls = s->private;
|
||||||
|
ls->log = s->log;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* log warnings to stderr by default. Otherwise we would miss any lvpoll
|
||||||
|
* error messages in default configuration
|
||||||
|
*/
|
||||||
|
daemon_log_enable(ls->log, DAEMON_LOG_OUTLET_STDERR, DAEMON_LOG_WARN, 1);
|
||||||
|
|
||||||
|
if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pthread_key_create(&key, lvmpolld_thread_data_destroy)) {
|
||||||
|
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to create pthread key");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ls->id_to_pdlv_poll = pdst_init("polling");
|
||||||
|
ls->id_to_pdlv_abort = pdst_init("abort");
|
||||||
|
|
||||||
|
if (!ls->id_to_pdlv_poll || !ls->id_to_pdlv_abort) {
|
||||||
|
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to allocate internal data structures");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ls->lvm_binary = ls->lvm_binary ?: LVM_PATH;
|
||||||
|
|
||||||
|
if (access(ls->lvm_binary, X_OK)) {
|
||||||
|
FATAL(ls, "%s: %s %s", PD_LOG_PREFIX, "Execute access rights denied on", ls->lvm_binary);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ls->idle)
|
||||||
|
ls->idle->is_idle = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmpolld_stores_lock(struct lvmpolld_state *ls)
|
||||||
|
{
|
||||||
|
pdst_lock(ls->id_to_pdlv_poll);
|
||||||
|
pdst_lock(ls->id_to_pdlv_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmpolld_stores_unlock(struct lvmpolld_state *ls)
|
||||||
|
{
|
||||||
|
pdst_unlock(ls->id_to_pdlv_abort);
|
||||||
|
pdst_unlock(ls->id_to_pdlv_poll);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmpolld_global_lock(struct lvmpolld_state *ls)
|
||||||
|
{
|
||||||
|
_lvmpolld_stores_lock(ls);
|
||||||
|
|
||||||
|
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_poll);
|
||||||
|
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
||||||
|
{
|
||||||
|
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_abort);
|
||||||
|
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_poll);
|
||||||
|
|
||||||
|
_lvmpolld_stores_unlock(ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fini(struct daemon_state *s)
|
||||||
|
{
|
||||||
|
int done;
|
||||||
|
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
|
||||||
|
struct lvmpolld_state *ls = s->private;
|
||||||
|
|
||||||
|
DEBUGLOG(s, "fini");
|
||||||
|
|
||||||
|
DEBUGLOG(s, "sending cancel requests");
|
||||||
|
|
||||||
|
_lvmpolld_global_lock(ls);
|
||||||
|
pdst_locked_send_cancel(ls->id_to_pdlv_poll);
|
||||||
|
pdst_locked_send_cancel(ls->id_to_pdlv_abort);
|
||||||
|
_lvmpolld_global_unlock(ls);
|
||||||
|
|
||||||
|
DEBUGLOG(s, "waiting for background threads to finish");
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
_lvmpolld_stores_lock(ls);
|
||||||
|
done = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
|
||||||
|
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
|
||||||
|
_lvmpolld_stores_unlock(ls);
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
|
nanosleep(&t, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGLOG(s, "destroying internal data structures");
|
||||||
|
|
||||||
|
_lvmpolld_stores_lock(ls);
|
||||||
|
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_poll);
|
||||||
|
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_abort);
|
||||||
|
_lvmpolld_stores_unlock(ls);
|
||||||
|
|
||||||
|
pdst_destroy(ls->id_to_pdlv_poll);
|
||||||
|
pdst_destroy(ls->id_to_pdlv_abort);
|
||||||
|
|
||||||
|
pthread_key_delete(key);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static response reply(const char *res, const char *reason)
|
||||||
|
{
|
||||||
|
return daemon_reply_simple(res, "reason = %s", reason, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_single_line(struct lvmpolld_thread_data *data, int err)
|
||||||
|
{
|
||||||
|
ssize_t r = getline(&data->line, &data->line_size, err ? data->ferr : data->fout);
|
||||||
|
|
||||||
|
if (r > 0 && *(data->line + r - 1) == '\n')
|
||||||
|
*(data->line + r - 1) = '\0';
|
||||||
|
|
||||||
|
return (r > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_idle_state(struct lvmpolld_state *ls)
|
||||||
|
{
|
||||||
|
if (!ls->idle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_lvmpolld_stores_lock(ls);
|
||||||
|
|
||||||
|
ls->idle->is_idle = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
|
||||||
|
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
|
||||||
|
|
||||||
|
_lvmpolld_stores_unlock(ls);
|
||||||
|
|
||||||
|
DEBUGLOG(ls, "%s: %s %s%s", PD_LOG_PREFIX, "daemon is", ls->idle->is_idle ? "" : "not ", "idle");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make this configurable */
|
||||||
|
#define MAX_TIMEOUT 2
|
||||||
|
|
||||||
|
static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data *data)
|
||||||
|
{
|
||||||
|
int ch_stat, r, err = 1, fds_count = 2, timeout = 0;
|
||||||
|
pid_t pid;
|
||||||
|
struct lvmpolld_cmd_stat cmd_state = { .retcode = -1, .signal = 0 };
|
||||||
|
struct pollfd fds[] = { { .fd = data->outpipe[0], .events = POLLIN },
|
||||||
|
{ .fd = data->errpipe[0], .events = POLLIN } };
|
||||||
|
|
||||||
|
if (!(data->fout = fdopen(data->outpipe[0], "r")) || !(data->ferr = fdopen(data->errpipe[0], "r"))) {
|
||||||
|
ERROR(pdlv->ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to open file stream",
|
||||||
|
errno, _strerror_r(errno, data));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
do {
|
||||||
|
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
||||||
|
} while (r < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
||||||
|
if (r < 0) {
|
||||||
|
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
|
||||||
|
PD_LOG_PREFIX, "poll() for LVM2 cmd", pdlv->cmd_pid,
|
||||||
|
errno, _strerror_r(errno, data));
|
||||||
|
goto out;
|
||||||
|
} else if (!r) {
|
||||||
|
timeout++;
|
||||||
|
|
||||||
|
WARN(pdlv->ls, "%s: %s (PID %d) %s", PD_LOG_PREFIX,
|
||||||
|
"polling for output of the lvm cmd", pdlv->cmd_pid,
|
||||||
|
"has timed out");
|
||||||
|
|
||||||
|
if (timeout > MAX_TIMEOUT) {
|
||||||
|
ERROR(pdlv->ls, "%s: %s (PID %d) (no output for %d seconds)",
|
||||||
|
PD_LOG_PREFIX,
|
||||||
|
"LVM2 cmd is unresponsive too long",
|
||||||
|
pdlv->cmd_pid,
|
||||||
|
timeout * pdlv_get_timeout(pdlv));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue; /* while(1) */
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = 0;
|
||||||
|
|
||||||
|
/* handle the command's STDOUT */
|
||||||
|
if (fds[0].revents & POLLIN) {
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught input data in STDOUT");
|
||||||
|
|
||||||
|
assert(read_single_line(data, 0)); /* may block indef. anyway */
|
||||||
|
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||||
|
pdlv->cmd_pid, "STDOUT", data->line);
|
||||||
|
} else if (fds[0].revents) {
|
||||||
|
if (fds[0].revents & POLLHUP)
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught POLLHUP");
|
||||||
|
else
|
||||||
|
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
|
||||||
|
|
||||||
|
fds[0].fd = -1;
|
||||||
|
fds_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle the command's STDERR */
|
||||||
|
if (fds[1].revents & POLLIN) {
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
|
||||||
|
"caught input data in STDERR");
|
||||||
|
|
||||||
|
assert(read_single_line(data, 1)); /* may block indef. anyway */
|
||||||
|
WARN(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||||
|
pdlv->cmd_pid, "STDERR", data->line);
|
||||||
|
} else if (fds[1].revents) {
|
||||||
|
if (fds[1].revents & POLLHUP)
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught err POLLHUP");
|
||||||
|
else
|
||||||
|
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
|
||||||
|
|
||||||
|
fds[1].fd = -1;
|
||||||
|
fds_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* fds_count == 0 means polling reached EOF
|
||||||
|
* or received error on both descriptors.
|
||||||
|
* In such case, just wait for command to finish
|
||||||
|
*/
|
||||||
|
pid = waitpid(pdlv->cmd_pid, &ch_stat, fds_count ? WNOHANG : 0);
|
||||||
|
} while (pid < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (pid) {
|
||||||
|
if (pid < 0) {
|
||||||
|
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
|
||||||
|
PD_LOG_PREFIX, "waitpid() for lvm2 cmd",
|
||||||
|
pdlv->cmd_pid, errno,
|
||||||
|
_strerror_r(errno, data));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "child exited");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} /* while(1) */
|
||||||
|
|
||||||
|
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "about to collect remaining lines");
|
||||||
|
if (fds[0].fd >= 0)
|
||||||
|
while (read_single_line(data, 0)) {
|
||||||
|
assert(r > 0);
|
||||||
|
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDOUT", data->line);
|
||||||
|
}
|
||||||
|
if (fds[1].fd >= 0)
|
||||||
|
while (read_single_line(data, 1)) {
|
||||||
|
assert(r > 0);
|
||||||
|
WARN(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDERR", data->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFEXITED(ch_stat)) {
|
||||||
|
cmd_state.retcode = WEXITSTATUS(ch_stat);
|
||||||
|
if (cmd_state.retcode)
|
||||||
|
ERROR(pdlv->ls, "%s: %s (PID %d) %s (retcode: %d)", PD_LOG_PREFIX,
|
||||||
|
"lvm2 cmd", pdlv->cmd_pid, "failed", cmd_state.retcode);
|
||||||
|
else
|
||||||
|
INFO(pdlv->ls, "%s: %s (PID %d) %s", PD_LOG_PREFIX,
|
||||||
|
"lvm2 cmd", pdlv->cmd_pid, "finished successfully");
|
||||||
|
} else if (WIFSIGNALED(ch_stat)) {
|
||||||
|
ERROR(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
|
||||||
|
"lvm2 cmd", pdlv->cmd_pid, "got terminated by signal",
|
||||||
|
WTERMSIG(ch_stat));
|
||||||
|
cmd_state.signal = WTERMSIG(ch_stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
out:
|
||||||
|
if (!err)
|
||||||
|
pdlv_set_cmd_state(pdlv, &cmd_state);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
|
||||||
|
{
|
||||||
|
const char * const* tmp = ptr;
|
||||||
|
|
||||||
|
if (!tmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (*tmp) {
|
||||||
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, *tmp);
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *fork_and_poll(void *args)
|
||||||
|
{
|
||||||
|
int outfd, errfd, state;
|
||||||
|
struct lvmpolld_thread_data *data;
|
||||||
|
pid_t r;
|
||||||
|
|
||||||
|
int error = 1;
|
||||||
|
struct lvmpolld_lv *pdlv = (struct lvmpolld_lv *) args;
|
||||||
|
struct lvmpolld_state *ls = pdlv->ls;
|
||||||
|
|
||||||
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
||||||
|
data = lvmpolld_thread_data_constructor(pdlv);
|
||||||
|
pthread_setspecific(key, data);
|
||||||
|
pthread_setcancelstate(state, &state);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Failed to initialize per-thread data");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
|
||||||
|
debug_print(ls, pdlv->cmdargv);
|
||||||
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
|
||||||
|
|
||||||
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd environment variables:");
|
||||||
|
debug_print(ls, pdlv->cmdenvp);
|
||||||
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
|
||||||
|
|
||||||
|
outfd = data->outpipe[1];
|
||||||
|
errfd = data->errpipe[1];
|
||||||
|
|
||||||
|
r = fork();
|
||||||
|
if (!r) {
|
||||||
|
/* child */
|
||||||
|
/* !!! Do not touch any posix thread primitives !!! */
|
||||||
|
|
||||||
|
if ((dup2(outfd, STDOUT_FILENO ) != STDOUT_FILENO) ||
|
||||||
|
(dup2(errfd, STDERR_FILENO ) != STDERR_FILENO))
|
||||||
|
_exit(LVMPD_RET_DUP_FAILED);
|
||||||
|
|
||||||
|
execve(*(pdlv->cmdargv), (char *const *)pdlv->cmdargv, (char *const *)pdlv->cmdenvp);
|
||||||
|
|
||||||
|
_exit(LVMPD_RET_EXC_FAILED);
|
||||||
|
} else {
|
||||||
|
/* parent */
|
||||||
|
if (r == -1) {
|
||||||
|
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "fork failed",
|
||||||
|
errno, _strerror_r(errno, data));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO(ls, "%s: LVM2 cmd \"%s\" (PID: %d)", PD_LOG_PREFIX, *(pdlv->cmdargv), r);
|
||||||
|
|
||||||
|
pdlv->cmd_pid = r;
|
||||||
|
|
||||||
|
/* failure to close write end of any pipe will result in broken polling */
|
||||||
|
if (close(data->outpipe[1])) {
|
||||||
|
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of pipe",
|
||||||
|
errno, _strerror_r(errno, data));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
data->outpipe[1] = -1;
|
||||||
|
|
||||||
|
if (close(data->errpipe[1])) {
|
||||||
|
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of err pipe",
|
||||||
|
errno, _strerror_r(errno, data));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
data->errpipe[1] = -1;
|
||||||
|
|
||||||
|
error = poll_for_output(pdlv, data);
|
||||||
|
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "polling for lvpoll output has finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
pdst_lock(pdlv->pdst);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
/* last reader is responsible for pdlv cleanup */
|
||||||
|
r = pdlv->cmd_pid;
|
||||||
|
pdlv_set_error(pdlv, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdlv_set_polling_finished(pdlv, 1);
|
||||||
|
if (data)
|
||||||
|
data->pdlv = NULL;
|
||||||
|
|
||||||
|
pdst_locked_dec(pdlv->pdst);
|
||||||
|
|
||||||
|
pdst_unlock(pdlv->pdst);
|
||||||
|
|
||||||
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
||||||
|
lvmpolld_thread_data_destroy(data);
|
||||||
|
pthread_setspecific(key, NULL);
|
||||||
|
pthread_setcancelstate(state, &state);
|
||||||
|
|
||||||
|
update_idle_state(ls);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is unfortunate case where we
|
||||||
|
* know nothing about state of lvm cmd and
|
||||||
|
* (eventually) ongoing progress.
|
||||||
|
*
|
||||||
|
* harvest zombies
|
||||||
|
*/
|
||||||
|
if (r)
|
||||||
|
while(waitpid(r, NULL, 0) < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static response progress_info(client_handle h, struct lvmpolld_state *ls, request req)
|
||||||
|
{
|
||||||
|
char *id;
|
||||||
|
struct lvmpolld_lv *pdlv;
|
||||||
|
struct lvmpolld_store *pdst;
|
||||||
|
struct lvmpolld_lv_state st;
|
||||||
|
response r;
|
||||||
|
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
|
||||||
|
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||||
|
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||||
|
|
||||||
|
if (!lvid)
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
|
||||||
|
|
||||||
|
id = construct_id(sysdir, lvid);
|
||||||
|
if (!id) {
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "progress_info request failed to construct ID.");
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGLOG(ls, "%s: %s: %s", PD_LOG_PREFIX, "ID", id);
|
||||||
|
|
||||||
|
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
|
||||||
|
|
||||||
|
pdst_lock(pdst);
|
||||||
|
|
||||||
|
pdlv = pdst_locked_lookup(pdst, id);
|
||||||
|
if (pdlv) {
|
||||||
|
/*
|
||||||
|
* with store lock held, I'm the only reader accessing the pdlv
|
||||||
|
*/
|
||||||
|
st = pdlv_get_status(pdlv);
|
||||||
|
|
||||||
|
if (st.error || st.polling_finished) {
|
||||||
|
INFO(ls, "%s: %s %s", PD_LOG_PREFIX,
|
||||||
|
"Polling finished. Removing related data structure for LV",
|
||||||
|
lvid);
|
||||||
|
pdst_locked_remove(pdst, id);
|
||||||
|
pdlv_destroy(pdlv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* pdlv must not be dereferenced from now on */
|
||||||
|
|
||||||
|
pdst_unlock(pdst);
|
||||||
|
|
||||||
|
dm_free(id);
|
||||||
|
|
||||||
|
if (pdlv) {
|
||||||
|
if (st.error)
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_POLLING_FAILED);
|
||||||
|
|
||||||
|
if (st.polling_finished)
|
||||||
|
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
|
||||||
|
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
|
||||||
|
LVMPD_PARM_VALUE " = %d", (int64_t)(st.cmd_state.signal ?: st.cmd_state.retcode),
|
||||||
|
NULL);
|
||||||
|
else
|
||||||
|
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = daemon_reply_simple(LVMPD_RESP_NOT_FOUND, NULL);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls,
|
||||||
|
struct lvmpolld_store *pdst,
|
||||||
|
const char *interval, const char *id,
|
||||||
|
const char *vgname, const char *lvname,
|
||||||
|
const char *sysdir, enum poll_type type,
|
||||||
|
unsigned abort_polling, unsigned uinterval)
|
||||||
|
{
|
||||||
|
const char **cmdargv, **cmdenvp;
|
||||||
|
struct lvmpolld_lv *pdlv;
|
||||||
|
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
||||||
|
|
||||||
|
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
||||||
|
interval, uinterval, pdst);
|
||||||
|
|
||||||
|
if (!pdlv) {
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdargv = cmdargv_ctr(pdlv, pdlv->ls->lvm_binary, abort_polling, handle_missing_pvs);
|
||||||
|
if (!cmdargv) {
|
||||||
|
pdlv_destroy(pdlv);
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd arguments for lvpoll command");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdlv->cmdargv = cmdargv;
|
||||||
|
|
||||||
|
cmdenvp = cmdenvp_ctr(pdlv);
|
||||||
|
if (!cmdenvp) {
|
||||||
|
pdlv_destroy(pdlv);
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd environment for lvpoll command");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdlv->cmdenvp = cmdenvp;
|
||||||
|
|
||||||
|
return pdlv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spawn_detached_thread(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
|
||||||
|
if (pthread_attr_init(&attr) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = pthread_create(&pdlv->tid, &attr, fork_and_poll, (void *)pdlv);
|
||||||
|
|
||||||
|
if (pthread_attr_destroy(&attr) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return !r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static response poll_init(client_handle h, struct lvmpolld_state *ls, request req, enum poll_type type)
|
||||||
|
{
|
||||||
|
char *id;
|
||||||
|
struct lvmpolld_lv *pdlv;
|
||||||
|
struct lvmpolld_store *pdst;
|
||||||
|
unsigned uinterval;
|
||||||
|
|
||||||
|
const char *interval = daemon_request_str(req, LVMPD_PARM_INTERVAL, NULL);
|
||||||
|
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
|
||||||
|
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
||||||
|
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
||||||
|
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||||
|
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||||
|
|
||||||
|
assert(type < POLL_TYPE_MAX);
|
||||||
|
|
||||||
|
if (abort_polling && type != PVMOVE)
|
||||||
|
return reply(LVMPD_RESP_EINVAL, REASON_ILLEGAL_ABORT_REQUEST);
|
||||||
|
|
||||||
|
if (!interval || strpbrk(interval, "-") || sscanf(interval, "%u", &uinterval) != 1)
|
||||||
|
return reply(LVMPD_RESP_EINVAL, REASON_INVALID_INTERVAL);
|
||||||
|
|
||||||
|
if (!lvname)
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVNAME);
|
||||||
|
|
||||||
|
if (!lvid)
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
|
||||||
|
|
||||||
|
if (!vgname)
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_MISSING_VGNAME);
|
||||||
|
|
||||||
|
id = construct_id(sysdir, lvid);
|
||||||
|
if (!id) {
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "poll_init request failed to construct ID.");
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGLOG(ls, "%s: %s=%s", PD_LOG_PREFIX, "ID", id);
|
||||||
|
|
||||||
|
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
|
||||||
|
|
||||||
|
pdst_lock(pdst);
|
||||||
|
|
||||||
|
pdlv = pdst_locked_lookup(pdst, id);
|
||||||
|
if (pdlv && pdlv_get_polling_finished(pdlv)) {
|
||||||
|
WARN(ls, "%s: %s %s", PD_LOG_PREFIX, "Force removal of uncollected info for LV",
|
||||||
|
lvid);
|
||||||
|
/*
|
||||||
|
* lvmpolld has to remove uncollected results in this case.
|
||||||
|
* otherwise it would have to refuse request for new polling
|
||||||
|
* lv with same id.
|
||||||
|
*/
|
||||||
|
pdst_locked_remove(pdst, id);
|
||||||
|
pdlv_destroy(pdlv);
|
||||||
|
pdlv = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdlv) {
|
||||||
|
if (!pdlv_is_type(pdlv, type)) {
|
||||||
|
pdst_unlock(pdst);
|
||||||
|
ERROR(ls, "%s: %s '%s': expected: %s, requested: %s",
|
||||||
|
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
|
||||||
|
id,
|
||||||
|
polling_op(pdlv_get_type(pdlv)), polling_op(type));
|
||||||
|
dm_free(id);
|
||||||
|
return reply(LVMPD_RESP_EINVAL,
|
||||||
|
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
|
||||||
|
}
|
||||||
|
pdlv->init_rq_count++; /* safe. protected by store lock */
|
||||||
|
} else {
|
||||||
|
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
||||||
|
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||||
|
if (!pdlv) {
|
||||||
|
pdst_unlock(pdst);
|
||||||
|
dm_free(id);
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
|
}
|
||||||
|
if (!pdst_locked_insert(pdst, id, pdlv)) {
|
||||||
|
pdlv_destroy(pdlv);
|
||||||
|
pdst_unlock(pdst);
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
|
||||||
|
dm_free(id);
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
|
}
|
||||||
|
if (!spawn_detached_thread(pdlv)) {
|
||||||
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to spawn detached monitoring thread");
|
||||||
|
pdst_locked_remove(pdst, id);
|
||||||
|
pdlv_destroy(pdlv);
|
||||||
|
pdst_unlock(pdst);
|
||||||
|
dm_free(id);
|
||||||
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdst_locked_inc(pdst);
|
||||||
|
if (ls->idle)
|
||||||
|
ls->idle->is_idle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdst_unlock(pdst);
|
||||||
|
|
||||||
|
dm_free(id);
|
||||||
|
|
||||||
|
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static response dump_state(client_handle h, struct lvmpolld_state *ls, request r)
|
||||||
|
{
|
||||||
|
response res = { 0 };
|
||||||
|
struct buffer *b = &res.buffer;
|
||||||
|
|
||||||
|
buffer_init(b);
|
||||||
|
|
||||||
|
_lvmpolld_global_lock(ls);
|
||||||
|
|
||||||
|
buffer_append(b, "# Registered polling operations\n\n");
|
||||||
|
buffer_append(b, "poll {\n");
|
||||||
|
pdst_locked_dump(ls->id_to_pdlv_poll, b);
|
||||||
|
buffer_append(b, "}\n\n");
|
||||||
|
|
||||||
|
buffer_append(b, "# Registered abort operations\n\n");
|
||||||
|
buffer_append(b, "abort {\n");
|
||||||
|
pdst_locked_dump(ls->id_to_pdlv_abort, b);
|
||||||
|
buffer_append(b, "}");
|
||||||
|
|
||||||
|
_lvmpolld_global_unlock(ls);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static response _handler(struct daemon_state s, client_handle h, request r)
|
||||||
|
{
|
||||||
|
struct lvmpolld_state *ls = s.private;
|
||||||
|
const char *rq = daemon_request_str(r, "request", "NONE");
|
||||||
|
|
||||||
|
if (!strcmp(rq, LVMPD_REQ_PVMOVE))
|
||||||
|
return poll_init(h, ls, r, PVMOVE);
|
||||||
|
else if (!strcmp(rq, LVMPD_REQ_CONVERT))
|
||||||
|
return poll_init(h, ls, r, CONVERT);
|
||||||
|
else if (!strcmp(rq, LVMPD_REQ_MERGE))
|
||||||
|
return poll_init(h, ls, r, MERGE);
|
||||||
|
else if (!strcmp(rq, LVMPD_REQ_MERGE_THIN))
|
||||||
|
return poll_init(h, ls, r, MERGE_THIN);
|
||||||
|
else if (!strcmp(rq, LVMPD_REQ_PROGRESS))
|
||||||
|
return progress_info(h, ls, r);
|
||||||
|
else if (!strcmp(rq, LVMPD_REQ_DUMP))
|
||||||
|
return dump_state(h, ls, r);
|
||||||
|
else
|
||||||
|
return reply(LVMPD_RESP_EINVAL, REASON_REQ_NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
unsigned long l;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
l = strtoul(str, &endptr, 10);
|
||||||
|
if (errno || *endptr || l >= UINT_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*max_timeouts = (unsigned) l;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Client functionality */
|
||||||
|
typedef int (*action_fn_t) (void *args);
|
||||||
|
|
||||||
|
struct log_line_baton {
|
||||||
|
const char *prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
daemon_handle _lvmpolld = { .error = 0 };
|
||||||
|
|
||||||
|
static daemon_handle _lvmpolld_open(const char *socket)
|
||||||
|
{
|
||||||
|
daemon_info lvmpolld_info = {
|
||||||
|
.path = "lvmpolld",
|
||||||
|
.socket = socket ?: DEFAULT_RUN_DIR "/lvmpolld.socket",
|
||||||
|
.protocol = LVMPOLLD_PROTOCOL,
|
||||||
|
.protocol_version = LVMPOLLD_PROTOCOL_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
|
return daemon_open(lvmpolld_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _log_line(const char *line, void *baton) {
|
||||||
|
struct log_line_baton *b = baton;
|
||||||
|
fprintf(stdout, "%s%s\n", b->prefix, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int printout_raw_response(const char *prefix, const char *msg)
|
||||||
|
{
|
||||||
|
struct log_line_baton b = { .prefix = prefix };
|
||||||
|
char *buf;
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
buf = dm_strdup(msg);
|
||||||
|
pos = buf;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (pos) {
|
||||||
|
char *next = strchr(pos, '\n');
|
||||||
|
if (next)
|
||||||
|
*next = 0;
|
||||||
|
_log_line(pos, &b);
|
||||||
|
pos = next ? next + 1 : 0;
|
||||||
|
}
|
||||||
|
dm_free(buf);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* place all action implementations below */
|
||||||
|
|
||||||
|
static int action_dump(void *args __attribute__((unused)))
|
||||||
|
{
|
||||||
|
daemon_request req;
|
||||||
|
daemon_reply repl;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
req = daemon_request_make(LVMPD_REQ_DUMP);
|
||||||
|
if (!req.cft) {
|
||||||
|
fprintf(stderr, "Failed to create lvmpolld " LVMPD_REQ_DUMP " request.\n");
|
||||||
|
goto out_req;
|
||||||
|
}
|
||||||
|
|
||||||
|
repl = daemon_send(_lvmpolld, req);
|
||||||
|
if (repl.error) {
|
||||||
|
fprintf(stderr, "Failed to send a request or receive response.\n");
|
||||||
|
goto out_rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is dumb copy & paste from libdaemon log routines.
|
||||||
|
*/
|
||||||
|
if (!printout_raw_response(" ", repl.buffer.mem)) {
|
||||||
|
fprintf(stderr, "Failed to print out the response.\n");
|
||||||
|
goto out_rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 1;
|
||||||
|
|
||||||
|
out_rep:
|
||||||
|
daemon_reply_destroy(repl);
|
||||||
|
out_req:
|
||||||
|
daemon_request_destroy(req);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum action_index {
|
||||||
|
ACTION_DUMP = 0,
|
||||||
|
ACTION_MAX /* keep at the end */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
||||||
|
|
||||||
|
static int _make_action(enum action_index idx, void *args)
|
||||||
|
{
|
||||||
|
return idx < ACTION_MAX ? actions[idx](args) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvmpolld_client(const char *socket, unsigned action)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_lvmpolld = _lvmpolld_open(socket);
|
||||||
|
|
||||||
|
if (_lvmpolld.error || _lvmpolld.socket_fd < 0) {
|
||||||
|
fprintf(stderr, "Failed to establish connection with lvmpolld.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = _make_action(action, NULL);
|
||||||
|
|
||||||
|
daemon_close(_lvmpolld);
|
||||||
|
|
||||||
|
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int action_idx = ACTION_MAX;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
/* Have actions always at the beginning of the array. */
|
||||||
|
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
|
||||||
|
|
||||||
|
/* other options */
|
||||||
|
{"binary", required_argument, 0, 'B' },
|
||||||
|
{"foreground", no_argument, 0, 'f' },
|
||||||
|
{"help", no_argument, 0, 'h' },
|
||||||
|
{"log", required_argument, 0, 'l' },
|
||||||
|
{"pidfile", required_argument, 0, 'p' },
|
||||||
|
{"socket", required_argument, 0, 's' },
|
||||||
|
{"timeout", required_argument, 0, 't' },
|
||||||
|
{"version", no_argument, 0, 'V' },
|
||||||
|
{0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
int option_index = 0;
|
||||||
|
int client = 0, server = 0;
|
||||||
|
unsigned action = ACTION_MAX;
|
||||||
|
struct timeval timeout;
|
||||||
|
daemon_idle di = { .ptimeout = &timeout };
|
||||||
|
struct lvmpolld_state ls = { .log_config = "" };
|
||||||
|
daemon_state s = {
|
||||||
|
.daemon_fini = _fini,
|
||||||
|
.daemon_init = _init,
|
||||||
|
.handler = _handler,
|
||||||
|
.name = "lvmpolld",
|
||||||
|
.pidfile = getenv("LVM_LVMPOLLD_PIDFILE") ?: LVMPOLLD_PIDFILE,
|
||||||
|
.private = &ls,
|
||||||
|
.protocol = LVMPOLLD_PROTOCOL,
|
||||||
|
.protocol_version = LVMPOLLD_PROTOCOL_VERSION,
|
||||||
|
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 0 :
|
||||||
|
if (action < ACTION_MAX) {
|
||||||
|
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
||||||
|
long_options[action].name);
|
||||||
|
_usage(argv[0], stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
action = action_idx;
|
||||||
|
client = 1;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
_usage(argv[0], stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
case 'B': /* --binary */
|
||||||
|
ls.lvm_binary = optarg;
|
||||||
|
server = 1;
|
||||||
|
break;
|
||||||
|
case 'V': /* --version */
|
||||||
|
printf("lvmpolld version: " LVM_VERSION "\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'f': /* --foreground */
|
||||||
|
s.foreground = 1;
|
||||||
|
server = 1;
|
||||||
|
break;
|
||||||
|
case 'h': /* --help */
|
||||||
|
_usage(argv[0], stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'l': /* --log */
|
||||||
|
ls.log_config = optarg;
|
||||||
|
server = 1;
|
||||||
|
break;
|
||||||
|
case 'p': /* --pidfile */
|
||||||
|
s.pidfile = optarg;
|
||||||
|
server = 1;
|
||||||
|
break;
|
||||||
|
case 's': /* --socket */
|
||||||
|
s.socket_path = optarg;
|
||||||
|
break;
|
||||||
|
case 't': /* --timeout in seconds */
|
||||||
|
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||||
|
fprintf(stderr, "Invalid value of timeout parameter.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
/* 0 equals to wait indefinitely */
|
||||||
|
if (di.max_timeouts)
|
||||||
|
s.idle = ls.idle = &di;
|
||||||
|
server = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client && server) {
|
||||||
|
fprintf(stderr, "Invalid combination of client and server parameters.\n\n");
|
||||||
|
_usage(argv[0], stdout);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client)
|
||||||
|
return _lvmpolld_client(s.socket_path, action);
|
||||||
|
|
||||||
|
/* Server */
|
||||||
|
daemon_start(s);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
391
daemons/lvmpolld/lvmpolld-data-utils.c
Normal file
391
daemons/lvmpolld/lvmpolld-data-utils.c
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lvmpolld-common.h"
|
||||||
|
|
||||||
|
#include "config-util.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
static char *_construct_full_lvname(const char *vgname, const char *lvname)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
l = strlen(vgname) + strlen(lvname) + 2; /* vg/lv and \0 */
|
||||||
|
name = (char *) dm_malloc(l * sizeof(char));
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (dm_snprintf(name, l, "%s/%s", vgname, lvname) < 0) {
|
||||||
|
dm_free(name);
|
||||||
|
name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_construct_lvm_system_dir_env(const char *sysdir)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Store either "LVM_SYSTEM_DIR=/path/to..."
|
||||||
|
* - or -
|
||||||
|
* just single char to store NULL byte
|
||||||
|
*/
|
||||||
|
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
|
||||||
|
char *env = (char *) dm_malloc(l * sizeof(char));
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*env = '\0';
|
||||||
|
|
||||||
|
if (sysdir && dm_snprintf(env, l, "LVM_SYSTEM_DIR=%s", sysdir) < 0) {
|
||||||
|
dm_free(env);
|
||||||
|
env = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *_get_lvid(const char *lvmpolld_id, const char *sysdir)
|
||||||
|
{
|
||||||
|
return lvmpolld_id ? (lvmpolld_id + (sysdir ? strlen(sysdir) : 0)) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *construct_id(const char *sysdir, const char *uuid)
|
||||||
|
{
|
||||||
|
char *id;
|
||||||
|
int r;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
l = strlen(uuid) + (sysdir ? strlen(sysdir) : 0) + 1;
|
||||||
|
id = (char *) dm_malloc(l * sizeof(char));
|
||||||
|
if (!id)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
r = sysdir ? dm_snprintf(id, l, "%s%s", sysdir, uuid) :
|
||||||
|
dm_snprintf(id, l, "%s", uuid);
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
dm_free(id);
|
||||||
|
id = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||||
|
const char *vgname, const char *lvname,
|
||||||
|
const char *sysdir, enum poll_type type,
|
||||||
|
const char *sinterval, unsigned pdtimeout,
|
||||||
|
struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
char *lvmpolld_id = dm_strdup(id), /* copy */
|
||||||
|
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
|
||||||
|
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
|
||||||
|
|
||||||
|
struct lvmpolld_lv tmp = {
|
||||||
|
.ls = ls,
|
||||||
|
.type = type,
|
||||||
|
.lvmpolld_id = lvmpolld_id,
|
||||||
|
.lvid = _get_lvid(lvmpolld_id, sysdir),
|
||||||
|
.lvname = full_lvname,
|
||||||
|
.lvm_system_dir_env = lvm_system_dir_env,
|
||||||
|
.sinterval = dm_strdup(sinterval), /* copy */
|
||||||
|
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
||||||
|
.cmd_state = { .retcode = -1, .signal = 0 },
|
||||||
|
.pdst = pdst,
|
||||||
|
.init_rq_count = 1
|
||||||
|
}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
|
||||||
|
|
||||||
|
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
memcpy(pdlv, &tmp, sizeof(*pdlv));
|
||||||
|
|
||||||
|
if (pthread_mutex_init(&pdlv->lock, NULL))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return pdlv;
|
||||||
|
|
||||||
|
err:
|
||||||
|
dm_free((void *)full_lvname);
|
||||||
|
dm_free((void *)lvmpolld_id);
|
||||||
|
dm_free((void *)lvm_system_dir_env);
|
||||||
|
dm_free((void *)tmp.sinterval);
|
||||||
|
dm_free((void *)pdlv);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
dm_free((void *)pdlv->lvmpolld_id);
|
||||||
|
dm_free((void *)pdlv->lvname);
|
||||||
|
dm_free((void *)pdlv->sinterval);
|
||||||
|
dm_free((void *)pdlv->lvm_system_dir_env);
|
||||||
|
dm_free((void *)pdlv->cmdargv);
|
||||||
|
dm_free((void *)pdlv->cmdenvp);
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&pdlv->lock);
|
||||||
|
|
||||||
|
dm_free((void *)pdlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
unsigned ret;
|
||||||
|
|
||||||
|
pdlv_lock(pdlv);
|
||||||
|
ret = pdlv->polling_finished;
|
||||||
|
pdlv_unlock(pdlv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
struct lvmpolld_lv_state r;
|
||||||
|
|
||||||
|
pdlv_lock(pdlv);
|
||||||
|
r.error = pdlv_locked_error(pdlv);
|
||||||
|
r.polling_finished = pdlv_locked_polling_finished(pdlv);
|
||||||
|
r.cmd_state = pdlv_locked_cmd_state(pdlv);
|
||||||
|
pdlv_unlock(pdlv);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state)
|
||||||
|
{
|
||||||
|
pdlv_lock(pdlv);
|
||||||
|
pdlv->cmd_state = *cmd_state;
|
||||||
|
pdlv_unlock(pdlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error)
|
||||||
|
{
|
||||||
|
pdlv_lock(pdlv);
|
||||||
|
pdlv->error = error;
|
||||||
|
pdlv_unlock(pdlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
|
||||||
|
{
|
||||||
|
pdlv_lock(pdlv);
|
||||||
|
pdlv->polling_finished = finished;
|
||||||
|
pdlv_unlock(pdlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmpolld_store *pdst_init(const char *name)
|
||||||
|
{
|
||||||
|
struct lvmpolld_store *pdst = (struct lvmpolld_store *) dm_malloc(sizeof(struct lvmpolld_store));
|
||||||
|
if (!pdst)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pdst->store = dm_hash_create(32);
|
||||||
|
if (!pdst->store)
|
||||||
|
goto err_hash;
|
||||||
|
if (pthread_mutex_init(&pdst->lock, NULL))
|
||||||
|
goto err_mutex;
|
||||||
|
|
||||||
|
pdst->name = name;
|
||||||
|
pdst->active_polling_count = 0;
|
||||||
|
|
||||||
|
return pdst;
|
||||||
|
|
||||||
|
err_mutex:
|
||||||
|
dm_hash_destroy(pdst->store);
|
||||||
|
err_hash:
|
||||||
|
dm_free(pdst);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdst_destroy(struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
if (!pdst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dm_hash_destroy(pdst->store);
|
||||||
|
pthread_mutex_destroy(&pdst->lock);
|
||||||
|
dm_free(pdst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
struct dm_hash_node *n;
|
||||||
|
|
||||||
|
dm_hash_iterate(n, pdst->store)
|
||||||
|
pdlv_lock(dm_hash_get_data(pdst->store, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
struct dm_hash_node *n;
|
||||||
|
|
||||||
|
dm_hash_iterate(n, pdst->store)
|
||||||
|
pdlv_unlock(dm_hash_get_data(pdst->store, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
char tmp[1024];
|
||||||
|
const struct lvmpolld_cmd_stat *cmd_state = &pdlv->cmd_state;
|
||||||
|
|
||||||
|
/* pdlv-section { */
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t%s {\n", pdlv->lvmpolld_id) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvid=\"%s\"\n", pdlv->lvid) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\ttype=\"%s\"\n", polling_op(pdlv->type)) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvname=\"%s\"\n", pdlv->lvname) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvmpolld_internal_timeout=%d\n", pdlv->pdtimeout) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_interval=\"%s\"\n", pdlv->sinterval ?: "<undefined>") > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tLVM_SYSTEM_DIR=\"%s\"\n",
|
||||||
|
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + strlen("LVM_SYSTEM_DIR=")) : "<undefined>")) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_pid=%d\n", pdlv->cmd_pid) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
|
||||||
|
/* lvm_commmand-section { */
|
||||||
|
buffer_append(buff, "\t\tlvm_command {\n");
|
||||||
|
if (cmd_state->retcode == -1 && !cmd_state->signal)
|
||||||
|
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
|
||||||
|
else {
|
||||||
|
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_FINISHED "\"\n");
|
||||||
|
if (dm_snprintf(tmp, sizeof(tmp), "\t\t\treason=\"%s\"\n\t\t\tvalue=%d\n",
|
||||||
|
(cmd_state->signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE),
|
||||||
|
(cmd_state->signal ?: cmd_state->retcode)) > 0)
|
||||||
|
buffer_append(buff, tmp);
|
||||||
|
}
|
||||||
|
buffer_append(buff, "\t\t}\n");
|
||||||
|
/* } lvm_commmand-section */
|
||||||
|
|
||||||
|
buffer_append(buff, "\t}\n");
|
||||||
|
/* } pdlv-section */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff)
|
||||||
|
{
|
||||||
|
struct dm_hash_node *n;
|
||||||
|
|
||||||
|
dm_hash_iterate(n, pdst->store)
|
||||||
|
_pdlv_locked_dump(buff, dm_hash_get_data(pdst->store, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
struct lvmpolld_lv *pdlv;
|
||||||
|
struct dm_hash_node *n;
|
||||||
|
|
||||||
|
dm_hash_iterate(n, pdst->store) {
|
||||||
|
pdlv = dm_hash_get_data(pdst->store, n);
|
||||||
|
if (!pdlv_locked_polling_finished(pdlv))
|
||||||
|
pthread_cancel(pdlv->tid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
struct dm_hash_node *n;
|
||||||
|
|
||||||
|
dm_hash_iterate(n, pdst->store)
|
||||||
|
pdlv_destroy(dm_hash_get_data(pdst->store, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) dm_malloc(sizeof(struct lvmpolld_thread_data));
|
||||||
|
if (!data)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data->pdlv = NULL;
|
||||||
|
data->line = NULL;
|
||||||
|
data->line_size = 0;
|
||||||
|
data->fout = data->ferr = NULL;
|
||||||
|
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
|
||||||
|
|
||||||
|
if (pipe(data->outpipe) || pipe(data->errpipe)) {
|
||||||
|
lvmpolld_thread_data_destroy(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(data->outpipe[0], F_SETFD, FD_CLOEXEC) ||
|
||||||
|
fcntl(data->outpipe[1], F_SETFD, FD_CLOEXEC) ||
|
||||||
|
fcntl(data->errpipe[0], F_SETFD, FD_CLOEXEC) ||
|
||||||
|
fcntl(data->errpipe[1], F_SETFD, FD_CLOEXEC)) {
|
||||||
|
lvmpolld_thread_data_destroy(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->pdlv = pdlv;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvmpolld_thread_data_destroy(void *thread_private)
|
||||||
|
{
|
||||||
|
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) thread_private;
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (data->pdlv) {
|
||||||
|
pdst_lock(data->pdlv->pdst);
|
||||||
|
/*
|
||||||
|
* FIXME: skip this step if lvmpolld is activated
|
||||||
|
* by systemd.
|
||||||
|
*/
|
||||||
|
if (!pdlv_get_polling_finished(data->pdlv))
|
||||||
|
kill(data->pdlv->cmd_pid, SIGTERM);
|
||||||
|
pdlv_set_polling_finished(data->pdlv, 1);
|
||||||
|
pdst_locked_dec(data->pdlv->pdst);
|
||||||
|
pdst_unlock(data->pdlv->pdst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* may get reallocated in getline(). dm_free must not be used */
|
||||||
|
free(data->line);
|
||||||
|
|
||||||
|
if (data->fout && !fclose(data->fout))
|
||||||
|
data->outpipe[0] = -1;
|
||||||
|
|
||||||
|
if (data->ferr && !fclose(data->ferr))
|
||||||
|
data->errpipe[0] = -1;
|
||||||
|
|
||||||
|
if (data->outpipe[0] >= 0)
|
||||||
|
(void) close(data->outpipe[0]);
|
||||||
|
|
||||||
|
if (data->outpipe[1] >= 0)
|
||||||
|
(void) close(data->outpipe[1]);
|
||||||
|
|
||||||
|
if (data->errpipe[0] >= 0)
|
||||||
|
(void) close(data->errpipe[0]);
|
||||||
|
|
||||||
|
if (data->errpipe[1] >= 0)
|
||||||
|
(void) close(data->errpipe[1]);
|
||||||
|
|
||||||
|
dm_free(data);
|
||||||
|
}
|
||||||
215
daemons/lvmpolld/lvmpolld-data-utils.h
Normal file
215
daemons/lvmpolld/lvmpolld-data-utils.h
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
|
||||||
|
#define _LVM_LVMPOLLD_DATA_UTILS_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
struct buffer;
|
||||||
|
struct lvmpolld_state;
|
||||||
|
|
||||||
|
enum poll_type {
|
||||||
|
PVMOVE = 0,
|
||||||
|
CONVERT,
|
||||||
|
MERGE,
|
||||||
|
MERGE_THIN,
|
||||||
|
POLL_TYPE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lvmpolld_cmd_stat {
|
||||||
|
int retcode;
|
||||||
|
int signal;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lvmpolld_store {
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
void *store;
|
||||||
|
const char *name;
|
||||||
|
unsigned active_polling_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lvmpolld_lv {
|
||||||
|
/*
|
||||||
|
* accessing following vars doesn't
|
||||||
|
* require struct lvmpolld_lv lock
|
||||||
|
*/
|
||||||
|
struct lvmpolld_state *const ls;
|
||||||
|
const enum poll_type type;
|
||||||
|
const char *const lvid;
|
||||||
|
const char *const lvmpolld_id;
|
||||||
|
const char *const lvname; /* full vg/lv name */
|
||||||
|
const unsigned pdtimeout; /* in seconds */
|
||||||
|
const char *const sinterval;
|
||||||
|
const char *const lvm_system_dir_env;
|
||||||
|
struct lvmpolld_store *const pdst;
|
||||||
|
const char *const *cmdargv;
|
||||||
|
const char *const *cmdenvp;
|
||||||
|
|
||||||
|
/* only used by write */
|
||||||
|
pid_t cmd_pid;
|
||||||
|
pthread_t tid;
|
||||||
|
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
|
||||||
|
/* block of shared variables protected by lock */
|
||||||
|
struct lvmpolld_cmd_stat cmd_state;
|
||||||
|
unsigned init_rq_count; /* for debuging purposes only */
|
||||||
|
unsigned polling_finished:1; /* no more updates */
|
||||||
|
unsigned error:1; /* unrecoverable error occured in lvmpolld */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
|
||||||
|
|
||||||
|
/* TODO: replace with configuration option */
|
||||||
|
#define MIN_POLLING_TIMEOUT 60
|
||||||
|
|
||||||
|
struct lvmpolld_lv_state {
|
||||||
|
unsigned error:1;
|
||||||
|
unsigned polling_finished:1;
|
||||||
|
struct lvmpolld_cmd_stat cmd_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lvmpolld_thread_data {
|
||||||
|
char *line;
|
||||||
|
size_t line_size;
|
||||||
|
int outpipe[2];
|
||||||
|
int errpipe[2];
|
||||||
|
FILE *fout;
|
||||||
|
FILE *ferr;
|
||||||
|
char buf[1024];
|
||||||
|
struct lvmpolld_lv *pdlv;
|
||||||
|
};
|
||||||
|
|
||||||
|
char *construct_id(const char *sysdir, const char *lvid);
|
||||||
|
|
||||||
|
/* LVMPOLLD_LV_T section */
|
||||||
|
|
||||||
|
/* only call with appropriate struct lvmpolld_store lock held */
|
||||||
|
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||||
|
const char *vgname, const char *lvname,
|
||||||
|
const char *sysdir, enum poll_type type,
|
||||||
|
const char *sinterval, unsigned pdtimeout,
|
||||||
|
struct lvmpolld_store *pdst);
|
||||||
|
|
||||||
|
/* only call with appropriate struct lvmpolld_store lock held */
|
||||||
|
void pdlv_destroy(struct lvmpolld_lv *pdlv);
|
||||||
|
|
||||||
|
static inline void pdlv_lock(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&pdlv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pdlv_unlock(struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&pdlv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* no struct lvmpolld_lv lock required section
|
||||||
|
*/
|
||||||
|
static inline int pdlv_is_type(const struct lvmpolld_lv *pdlv, enum poll_type type)
|
||||||
|
{
|
||||||
|
return pdlv->type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned pdlv_get_timeout(const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
return pdlv->pdtimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline enum poll_type pdlv_get_type(const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
return pdlv->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv);
|
||||||
|
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv);
|
||||||
|
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state);
|
||||||
|
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error);
|
||||||
|
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct lvmpolld_lv lock required section
|
||||||
|
*/
|
||||||
|
static inline struct lvmpolld_cmd_stat pdlv_locked_cmd_state(const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
return pdlv->cmd_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pdlv_locked_polling_finished(const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
return pdlv->polling_finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned pdlv_locked_error(const struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
return pdlv->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* struct lvmpolld_store manipulation routines */
|
||||||
|
|
||||||
|
struct lvmpolld_store *pdst_init(const char *name);
|
||||||
|
void pdst_destroy(struct lvmpolld_store *pdst);
|
||||||
|
|
||||||
|
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff);
|
||||||
|
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst);
|
||||||
|
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst);
|
||||||
|
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst);
|
||||||
|
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst);
|
||||||
|
|
||||||
|
static inline void pdst_lock(struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&pdst->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pdst_unlock(struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&pdst->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pdst_locked_inc(struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
pdst->active_polling_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pdst_locked_dec(struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
pdst->active_polling_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned pdst_locked_get_active_count(const struct lvmpolld_store *pdst)
|
||||||
|
{
|
||||||
|
return pdst->active_polling_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int pdst_locked_insert(struct lvmpolld_store *pdst, const char *key, struct lvmpolld_lv *pdlv)
|
||||||
|
{
|
||||||
|
return dm_hash_insert(pdst->store, key, pdlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct lvmpolld_lv *pdst_locked_lookup(struct lvmpolld_store *pdst, const char *key)
|
||||||
|
{
|
||||||
|
return dm_hash_lookup(pdst->store, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pdst_locked_remove(struct lvmpolld_store *pdst, const char *key)
|
||||||
|
{
|
||||||
|
dm_hash_remove(pdst->store, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv);
|
||||||
|
void lvmpolld_thread_data_destroy(void *thread_private);
|
||||||
|
|
||||||
|
#endif /* _LVM_LVMPOLLD_DATA_UTILS_H */
|
||||||
52
daemons/lvmpolld/lvmpolld-protocol.h
Normal file
52
daemons/lvmpolld/lvmpolld-protocol.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_LVMPOLLD_PROTOCOL_H
|
||||||
|
#define _LVM_LVMPOLLD_PROTOCOL_H
|
||||||
|
|
||||||
|
#include "polling_ops.h"
|
||||||
|
|
||||||
|
#define LVMPOLLD_PROTOCOL "lvmpolld"
|
||||||
|
#define LVMPOLLD_PROTOCOL_VERSION 1
|
||||||
|
|
||||||
|
#define LVMPD_REQ_CONVERT CONVERT_POLL
|
||||||
|
#define LVMPD_REQ_DUMP "dump"
|
||||||
|
#define LVMPD_REQ_MERGE MERGE_POLL
|
||||||
|
#define LVMPD_REQ_MERGE_THIN MERGE_THIN_POLL
|
||||||
|
#define LVMPD_REQ_PROGRESS "progress_info"
|
||||||
|
#define LVMPD_REQ_PVMOVE PVMOVE_POLL
|
||||||
|
|
||||||
|
#define LVMPD_PARM_ABORT "abort"
|
||||||
|
#define LVMPD_PARM_HANDLE_MISSING_PVS "handle_missing_pvs"
|
||||||
|
#define LVMPD_PARM_INTERVAL "interval"
|
||||||
|
#define LVMPD_PARM_LVID "lvid"
|
||||||
|
#define LVMPD_PARM_LVNAME "lvname"
|
||||||
|
#define LVMPD_PARM_SYSDIR "sysdir"
|
||||||
|
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
|
||||||
|
#define LVMPD_PARM_VGNAME "vgname"
|
||||||
|
|
||||||
|
#define LVMPD_RESP_FAILED "failed"
|
||||||
|
#define LVMPD_RESP_FINISHED "finished"
|
||||||
|
#define LVMPD_RESP_IN_PROGRESS "in_progress"
|
||||||
|
#define LVMPD_RESP_EINVAL "invalid"
|
||||||
|
#define LVMPD_RESP_NOT_FOUND "not_found"
|
||||||
|
#define LVMPD_RESP_OK "OK"
|
||||||
|
|
||||||
|
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
|
||||||
|
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating singal */
|
||||||
|
|
||||||
|
#define LVMPD_RET_DUP_FAILED 100
|
||||||
|
#define LVMPD_RET_EXC_FAILED 101
|
||||||
|
|
||||||
|
#endif /* _LVM_LVMPOLLD_PROTOCOL_H */
|
||||||
25
daemons/lvmpolld/polling_ops.h
Normal file
25
daemons/lvmpolld/polling_ops.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_TOOL_POLLING_OPS_H
|
||||||
|
#define _LVM_TOOL_POLLING_OPS_H
|
||||||
|
|
||||||
|
/* this file is also part of lvmpolld protocol */
|
||||||
|
|
||||||
|
#define PVMOVE_POLL "pvmove"
|
||||||
|
#define CONVERT_POLL "convert"
|
||||||
|
#define MERGE_POLL "merge"
|
||||||
|
#define MERGE_THIN_POLL "merge_thin"
|
||||||
|
|
||||||
|
#endif /* _LVM_TOOL_POLLING_OPS_H */
|
||||||
86
doc/caching_foreign_vgs.txt
Normal file
86
doc/caching_foreign_vgs.txt
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
Q: Why should lvmetad cache foreign VGs?
|
||||||
|
A: It's the most useful behavior in the "steady state".
|
||||||
|
|
||||||
|
How to arrive at that conclusion.
|
||||||
|
Four code configurations to consider, each in two different circumstances.
|
||||||
|
|
||||||
|
configurations:
|
||||||
|
|
||||||
|
1. lvm not using lvmetad
|
||||||
|
2. lvm using lvmetad and lvmlockd
|
||||||
|
3. lvm using lvmetad, and lvmetad does not cache foreign VGs
|
||||||
|
(Not currently implemented.)
|
||||||
|
4. lvm using lvmetad, and lvmetad caches foreign VGs
|
||||||
|
|
||||||
|
circumstances:
|
||||||
|
|
||||||
|
A. steady state: PVs are not added or removed to/from foreign VGs
|
||||||
|
B. transient state: PVs are added or removed to/from foreign VGs
|
||||||
|
|
||||||
|
combinations:
|
||||||
|
|
||||||
|
1.A. A PV is correctly shown in the foreign VG.
|
||||||
|
1.B. A PV is correctly shown in the foreign VG.
|
||||||
|
|
||||||
|
The most accurate representation, at the cost of always scanning disks.
|
||||||
|
|
||||||
|
|
||||||
|
2.A. A PV is correctly shown in the foreign VG.
|
||||||
|
2.B. A PV is correctly shown in the foreign VG.
|
||||||
|
|
||||||
|
The most accurate representation, at the cost of using lvmlockd.
|
||||||
|
|
||||||
|
|
||||||
|
3.A. A PV in a foreign VG is shown as unused.
|
||||||
|
3.B. A PV in a foreign VG is shown as unused.
|
||||||
|
|
||||||
|
If lvmetad ignores foreign VGs and does not cache them, the PVs in the
|
||||||
|
foreign VGs appear to be unused. This largely defeats the purpose of
|
||||||
|
system_id, which is meant to treat VGs/PVs as foreign instead of free
|
||||||
|
(albeit imperfectly, see below.)
|
||||||
|
|
||||||
|
|
||||||
|
4.A. A PV is correctly shown in the foreign VG.
|
||||||
|
4.B. A PV is not correctly shown in the foreign VG.
|
||||||
|
|
||||||
|
This avoids the cost of always scanning disks, and avoids the cost of
|
||||||
|
using lvmlockd. The steady state 4.A. is an improvement over the steady
|
||||||
|
state 3.A. When the steady state is the common case, this is a big
|
||||||
|
advantage. When the steady state is *not* the common case, the foreign VG
|
||||||
|
concept is not as useful (if shared devices are this dynamic, lvmlockd
|
||||||
|
should be considered.)
|
||||||
|
|
||||||
|
The limitations related to the transient state 4.B. are explained in
|
||||||
|
lvmsystemid(7), along with how to handle it. The specific inaccuracies
|
||||||
|
possible in 4.B. are:
|
||||||
|
|
||||||
|
. PV is shown as belonging to a foreign VG, but is actually unused.
|
||||||
|
. PV is shown as unused, but actually belongs to a foreign VG.
|
||||||
|
|
||||||
|
To resolve the inaccuracies in the transient state (4.B.), and return the
|
||||||
|
system to an accurate steady state (4.A.), the disks need to be scanned,
|
||||||
|
which updates lvmetad. The scanning/updating is a manual step, i.e.
|
||||||
|
running 'pvscan --cache', which by definition scans disks and updates
|
||||||
|
lvmetad.
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
The --foreign command line option for report/display commands
|
||||||
|
(vgs/lvs/pvs/vgdisplay/lvdisplay/pvdisplay) is not directly related to
|
||||||
|
whether or not lvmetad caches foreign VGs.
|
||||||
|
|
||||||
|
By default, foreign VGs are silently ignored and not printed by these
|
||||||
|
commands. However, when the --foreign option is used, these commands do
|
||||||
|
produce output about foreign VGs.
|
||||||
|
|
||||||
|
(When --foreign is not used, and the command specifically requests a
|
||||||
|
foreign VG by name, an error is produced about not accessing foreign VGs,
|
||||||
|
and the foreign VG is not displayed.)
|
||||||
|
|
||||||
|
The decision to report/display foreign VGs or not is independent of
|
||||||
|
whether lvmetad is caching those VGs. When lvmetad is caching the foreign
|
||||||
|
VG, a report/display command run with --foreign will scan disks to read
|
||||||
|
the foreign VG and give the most up to date version of it (the copy of the
|
||||||
|
foreign VG in lvmetad may be out of date due to changes to the VG by the
|
||||||
|
foreign host.)
|
||||||
|
|
||||||
@@ -30,28 +30,48 @@ multiqueue
|
|||||||
|
|
||||||
This policy is the default.
|
This policy is the default.
|
||||||
|
|
||||||
The multiqueue policy has two sets of 16 queues: one set for entries
|
The multiqueue policy has three sets of 16 queues: one set for entries
|
||||||
waiting for the cache and another one for those in the cache.
|
waiting for the cache and another two for those in the cache (a set for
|
||||||
|
clean entries and a set for dirty entries).
|
||||||
|
|
||||||
Cache entries in the queues are aged based on logical time. Entry into
|
Cache entries in the queues are aged based on logical time. Entry into
|
||||||
the cache is based on variable thresholds and queue selection is based
|
the cache is based on variable thresholds and queue selection is based
|
||||||
on hit count on entry. The policy aims to take different cache miss
|
on hit count on entry. The policy aims to take different cache miss
|
||||||
costs into account and to adjust to varying load patterns automatically.
|
costs into account and to adjust to varying load patterns automatically.
|
||||||
|
|
||||||
Message and constructor argument pairs are:
|
Message and constructor argument pairs are:
|
||||||
'sequential_threshold <#nr_sequential_ios>' and
|
'sequential_threshold <#nr_sequential_ios>'
|
||||||
'random_threshold <#nr_random_ios>'.
|
'random_threshold <#nr_random_ios>'
|
||||||
|
'read_promote_adjustment <value>'
|
||||||
|
'write_promote_adjustment <value>'
|
||||||
|
'discard_promote_adjustment <value>'
|
||||||
|
|
||||||
The sequential threshold indicates the number of contiguous I/Os
|
The sequential threshold indicates the number of contiguous I/Os
|
||||||
required before a stream is treated as sequential. The random threshold
|
required before a stream is treated as sequential. Once a stream is
|
||||||
|
considered sequential it will bypass the cache. The random threshold
|
||||||
is the number of intervening non-contiguous I/Os that must be seen
|
is the number of intervening non-contiguous I/Os that must be seen
|
||||||
before the stream is treated as random again.
|
before the stream is treated as random again.
|
||||||
|
|
||||||
The sequential and random thresholds default to 512 and 4 respectively.
|
The sequential and random thresholds default to 512 and 4 respectively.
|
||||||
|
|
||||||
Large, sequential ios are probably better left on the origin device
|
Large, sequential I/Os are probably better left on the origin device
|
||||||
since spindles tend to have good bandwidth. The io_tracker counts
|
since spindles tend to have good sequential I/O bandwidth. The
|
||||||
contiguous I/Os to try to spot when the io is in one of these sequential
|
io_tracker counts contiguous I/Os to try to spot when the I/O is in one
|
||||||
modes.
|
of these sequential modes. But there are use-cases for wanting to
|
||||||
|
promote sequential blocks to the cache (e.g. fast application startup).
|
||||||
|
If sequential threshold is set to 0 the sequential I/O detection is
|
||||||
|
disabled and sequential I/O will no longer implicitly bypass the cache.
|
||||||
|
Setting the random threshold to 0 does _not_ disable the random I/O
|
||||||
|
stream detection.
|
||||||
|
|
||||||
|
Internally the mq policy determines a promotion threshold. If the hit
|
||||||
|
count of a block not in the cache goes above this threshold it gets
|
||||||
|
promoted to the cache. The read, write and discard promote adjustment
|
||||||
|
tunables allow you to tweak the promotion threshold by adding a small
|
||||||
|
value based on the io type. They default to 4, 8 and 1 respectively.
|
||||||
|
If you're trying to quickly warm a new cache device you may wish to
|
||||||
|
reduce these to encourage promotion. Remember to switch them back to
|
||||||
|
their defaults after the cache fills though.
|
||||||
|
|
||||||
cleaner
|
cleaner
|
||||||
-------
|
-------
|
||||||
|
|||||||
@@ -50,14 +50,16 @@ other parameters detailed later):
|
|||||||
which are dirty, and extra hints for use by the policy object.
|
which are dirty, and extra hints for use by the policy object.
|
||||||
This information could be put on the cache device, but having it
|
This information could be put on the cache device, but having it
|
||||||
separate allows the volume manager to configure it differently,
|
separate allows the volume manager to configure it differently,
|
||||||
e.g. as a mirror for extra robustness.
|
e.g. as a mirror for extra robustness. This metadata device may only
|
||||||
|
be used by a single cache device.
|
||||||
|
|
||||||
Fixed block size
|
Fixed block size
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
The origin is divided up into blocks of a fixed size. This block size
|
The origin is divided up into blocks of a fixed size. This block size
|
||||||
is configurable when you first create the cache. Typically we've been
|
is configurable when you first create the cache. Typically we've been
|
||||||
using block sizes of 256k - 1024k.
|
using block sizes of 256KB - 1024KB. The block size must be between 64
|
||||||
|
(32KB) and 2097152 (1GB) and a multiple of 64 (32KB).
|
||||||
|
|
||||||
Having a fixed block size simplifies the target a lot. But it is
|
Having a fixed block size simplifies the target a lot. But it is
|
||||||
something of a compromise. For instance, a small part of a block may be
|
something of a compromise. For instance, a small part of a block may be
|
||||||
@@ -66,10 +68,11 @@ So large block sizes are bad because they waste cache space. And small
|
|||||||
block sizes are bad because they increase the amount of metadata (both
|
block sizes are bad because they increase the amount of metadata (both
|
||||||
in core and on disk).
|
in core and on disk).
|
||||||
|
|
||||||
Writeback/writethrough
|
Cache operating modes
|
||||||
----------------------
|
---------------------
|
||||||
|
|
||||||
The cache has two modes, writeback and writethrough.
|
The cache has three operating modes: writeback, writethrough and
|
||||||
|
passthrough.
|
||||||
|
|
||||||
If writeback, the default, is selected then a write to a block that is
|
If writeback, the default, is selected then a write to a block that is
|
||||||
cached will go only to the cache and the block will be marked dirty in
|
cached will go only to the cache and the block will be marked dirty in
|
||||||
@@ -79,15 +82,38 @@ If writethrough is selected then a write to a cached block will not
|
|||||||
complete until it has hit both the origin and cache devices. Clean
|
complete until it has hit both the origin and cache devices. Clean
|
||||||
blocks should remain clean.
|
blocks should remain clean.
|
||||||
|
|
||||||
|
If passthrough is selected, useful when the cache contents are not known
|
||||||
|
to be coherent with the origin device, then all reads are served from
|
||||||
|
the origin device (all reads miss the cache) and all writes are
|
||||||
|
forwarded to the origin device; additionally, write hits cause cache
|
||||||
|
block invalidates. To enable passthrough mode the cache must be clean.
|
||||||
|
Passthrough mode allows a cache device to be activated without having to
|
||||||
|
worry about coherency. Coherency that exists is maintained, although
|
||||||
|
the cache will gradually cool as writes take place. If the coherency of
|
||||||
|
the cache can later be verified, or established through use of the
|
||||||
|
"invalidate_cblocks" message, the cache device can be transitioned to
|
||||||
|
writethrough or writeback mode while still warm. Otherwise, the cache
|
||||||
|
contents can be discarded prior to transitioning to the desired
|
||||||
|
operating mode.
|
||||||
|
|
||||||
A simple cleaner policy is provided, which will clean (write back) all
|
A simple cleaner policy is provided, which will clean (write back) all
|
||||||
dirty blocks in a cache. Useful for decommissioning a cache.
|
dirty blocks in a cache. Useful for decommissioning a cache or when
|
||||||
|
shrinking a cache. Shrinking the cache's fast device requires all cache
|
||||||
|
blocks, in the area of the cache being removed, to be clean. If the
|
||||||
|
area being removed from the cache still contains dirty blocks the resize
|
||||||
|
will fail. Care must be taken to never reduce the volume used for the
|
||||||
|
cache's fast device until the cache is clean. This is of particular
|
||||||
|
importance if writeback mode is used. Writethrough and passthrough
|
||||||
|
modes already maintain a clean cache. Future support to partially clean
|
||||||
|
the cache, above a specified threshold, will allow for keeping the cache
|
||||||
|
warm and in writeback mode during resize.
|
||||||
|
|
||||||
Migration throttling
|
Migration throttling
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Migrating data between the origin and cache device uses bandwidth.
|
Migrating data between the origin and cache device uses bandwidth.
|
||||||
The user can set a throttle to prevent more than a certain amount of
|
The user can set a throttle to prevent more than a certain amount of
|
||||||
migration occuring at any one time. Currently we're not taking any
|
migration occurring at any one time. Currently we're not taking any
|
||||||
account of normal io traffic going to the devices. More work needs
|
account of normal io traffic going to the devices. More work needs
|
||||||
doing here to avoid migrating during those peak io moments.
|
doing here to avoid migrating during those peak io moments.
|
||||||
|
|
||||||
@@ -98,12 +124,11 @@ the default being 204800 sectors (or 100MB).
|
|||||||
Updating on-disk metadata
|
Updating on-disk metadata
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
|
On-disk metadata is committed every time a FLUSH or FUA bio is written.
|
||||||
written. If no such requests are made then commits will occur every
|
If no such requests are made then commits will occur every second. This
|
||||||
second. This means the cache behaves like a physical disk that has a
|
means the cache behaves like a physical disk that has a volatile write
|
||||||
write cache (the same is true of the thin-provisioning target). If
|
cache. If power is lost you may lose some recent writes. The metadata
|
||||||
power is lost you may lose some recent writes. The metadata should
|
should always be consistent in spite of any crash.
|
||||||
always be consistent in spite of any crash.
|
|
||||||
|
|
||||||
The 'dirty' state for a cache block changes far too frequently for us
|
The 'dirty' state for a cache block changes far too frequently for us
|
||||||
to keep updating it on the fly. So we treat it as a hint. In normal
|
to keep updating it on the fly. So we treat it as a hint. In normal
|
||||||
@@ -159,7 +184,7 @@ Constructor
|
|||||||
block size : cache unit size in sectors
|
block size : cache unit size in sectors
|
||||||
|
|
||||||
#feature args : number of feature arguments passed
|
#feature args : number of feature arguments passed
|
||||||
feature args : writethrough. (The default is writeback.)
|
feature args : writethrough or passthrough (The default is writeback.)
|
||||||
|
|
||||||
policy : the replacement policy to use
|
policy : the replacement policy to use
|
||||||
#policy args : an even number of arguments corresponding to
|
#policy args : an even number of arguments corresponding to
|
||||||
@@ -175,6 +200,13 @@ Optional feature arguments are:
|
|||||||
back cache block contents later for performance reasons,
|
back cache block contents later for performance reasons,
|
||||||
so they may differ from the corresponding origin blocks.
|
so they may differ from the corresponding origin blocks.
|
||||||
|
|
||||||
|
passthrough : a degraded mode useful for various cache coherency
|
||||||
|
situations (e.g., rolling back snapshots of
|
||||||
|
underlying storage). Reads and writes always go to
|
||||||
|
the origin. If a write goes to a cached origin
|
||||||
|
block, then the cache block is invalidated.
|
||||||
|
To enable passthrough mode the cache must be clean.
|
||||||
|
|
||||||
A policy called 'default' is always registered. This is an alias for
|
A policy called 'default' is always registered. This is an alias for
|
||||||
the policy we currently think is giving best all round performance.
|
the policy we currently think is giving best all round performance.
|
||||||
|
|
||||||
@@ -184,36 +216,43 @@ the characteristics of a specific policy, always request it by name.
|
|||||||
Status
|
Status
|
||||||
------
|
------
|
||||||
|
|
||||||
<#used metadata blocks>/<#total metadata blocks> <#read hits> <#read misses>
|
<metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||||
<#write hits> <#write misses> <#demotions> <#promotions> <#blocks in cache>
|
<cache block size> <#used cache blocks>/<#total cache blocks>
|
||||||
<#dirty> <#features> <features>* <#core args> <core args>* <#policy args>
|
<#read hits> <#read misses> <#write hits> <#write misses>
|
||||||
<policy args>*
|
<#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||||
|
<#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||||
|
|
||||||
#used metadata blocks : Number of metadata blocks used
|
metadata block size : Fixed block size for each metadata block in
|
||||||
#total metadata blocks : Total number of metadata blocks
|
sectors
|
||||||
#read hits : Number of times a READ bio has been mapped
|
#used metadata blocks : Number of metadata blocks used
|
||||||
|
#total metadata blocks : Total number of metadata blocks
|
||||||
|
cache block size : Configurable block size for the cache device
|
||||||
|
in sectors
|
||||||
|
#used cache blocks : Number of blocks resident in the cache
|
||||||
|
#total cache blocks : Total number of cache blocks
|
||||||
|
#read hits : Number of times a READ bio has been mapped
|
||||||
to the cache
|
to the cache
|
||||||
#read misses : Number of times a READ bio has been mapped
|
#read misses : Number of times a READ bio has been mapped
|
||||||
to the origin
|
to the origin
|
||||||
#write hits : Number of times a WRITE bio has been mapped
|
#write hits : Number of times a WRITE bio has been mapped
|
||||||
to the cache
|
to the cache
|
||||||
#write misses : Number of times a WRITE bio has been
|
#write misses : Number of times a WRITE bio has been
|
||||||
mapped to the origin
|
mapped to the origin
|
||||||
#demotions : Number of times a block has been removed
|
#demotions : Number of times a block has been removed
|
||||||
from the cache
|
from the cache
|
||||||
#promotions : Number of times a block has been moved to
|
#promotions : Number of times a block has been moved to
|
||||||
the cache
|
the cache
|
||||||
#blocks in cache : Number of blocks resident in the cache
|
#dirty : Number of blocks in the cache that differ
|
||||||
#dirty : Number of blocks in the cache that differ
|
|
||||||
from the origin
|
from the origin
|
||||||
#feature args : Number of feature args to follow
|
#feature args : Number of feature args to follow
|
||||||
feature args : 'writethrough' (optional)
|
feature args : 'writethrough' (optional)
|
||||||
#core args : Number of core arguments (must be even)
|
#core args : Number of core arguments (must be even)
|
||||||
core args : Key/value pairs for tuning the core
|
core args : Key/value pairs for tuning the core
|
||||||
e.g. migration_threshold
|
e.g. migration_threshold
|
||||||
#policy args : Number of policy arguments to follow (must be even)
|
policy name : Name of the policy
|
||||||
policy args : Key/value pairs
|
#policy args : Number of policy arguments to follow (must be even)
|
||||||
e.g. 'sequential_threshold 1024
|
policy args : Key/value pairs
|
||||||
|
e.g. sequential_threshold
|
||||||
|
|
||||||
Messages
|
Messages
|
||||||
--------
|
--------
|
||||||
@@ -229,12 +268,28 @@ The message format is:
|
|||||||
E.g.
|
E.g.
|
||||||
dmsetup message my_cache 0 sequential_threshold 1024
|
dmsetup message my_cache 0 sequential_threshold 1024
|
||||||
|
|
||||||
|
|
||||||
|
Invalidation is removing an entry from the cache without writing it
|
||||||
|
back. Cache blocks can be invalidated via the invalidate_cblocks
|
||||||
|
message, which takes an arbitrary number of cblock ranges. Each cblock
|
||||||
|
range's end value is "one past the end", meaning 5-10 expresses a range
|
||||||
|
of values from 5 to 9. Each cblock must be expressed as a decimal
|
||||||
|
value, in the future a variant message that takes cblock ranges
|
||||||
|
expressed in hexidecimal may be needed to better support efficient
|
||||||
|
invalidation of larger caches. The cache must be in passthrough mode
|
||||||
|
when invalidate_cblocks is used.
|
||||||
|
|
||||||
|
invalidate_cblocks [<cblock>|<cblock begin>-<cblock end>]*
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
dmsetup message my_cache 0 invalidate_cblocks 2345 3456-4567 5678-6789
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
|
|
||||||
The test suite can be found here:
|
The test suite can be found here:
|
||||||
|
|
||||||
https://github.com/jthornber/thinp-test-suite
|
https://github.com/jthornber/device-mapper-test-suite
|
||||||
|
|
||||||
dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \
|
dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \
|
||||||
/dev/mapper/ssd /dev/mapper/origin 512 1 writeback default 0'
|
/dev/mapper/ssd /dev/mapper/origin 512 1 writeback default 0'
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ dm-crypt
|
|||||||
Device-Mapper's "crypt" target provides transparent encryption of block devices
|
Device-Mapper's "crypt" target provides transparent encryption of block devices
|
||||||
using the kernel crypto API.
|
using the kernel crypto API.
|
||||||
|
|
||||||
|
For a more detailed description of supported parameters see:
|
||||||
|
https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
|
||||||
|
|
||||||
Parameters: <cipher> <key> <iv_offset> <device path> \
|
Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||||
<offset> [<#opt_params> <opt_params>]
|
<offset> [<#opt_params> <opt_params>]
|
||||||
|
|
||||||
<cipher>
|
<cipher>
|
||||||
Encryption cipher and an optional IV generation mode.
|
Encryption cipher and an optional IV generation mode.
|
||||||
(In format cipher[:keycount]-chainmode-ivopts:ivmode).
|
(In format cipher[:keycount]-chainmode-ivmode[:ivopts]).
|
||||||
Examples:
|
Examples:
|
||||||
des
|
des
|
||||||
aes-cbc-essiv:sha256
|
aes-cbc-essiv:sha256
|
||||||
@@ -19,7 +22,11 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
|||||||
|
|
||||||
<key>
|
<key>
|
||||||
Key used for encryption. It is encoded as a hexadecimal number.
|
Key used for encryption. It is encoded as a hexadecimal number.
|
||||||
You can only use key sizes that are valid for the selected cipher.
|
You can only use key sizes that are valid for the selected cipher
|
||||||
|
in combination with the selected iv mode.
|
||||||
|
Note that for some iv modes the key string can contain additional
|
||||||
|
keys (for example IV seed) so the key contains more parts concatenated
|
||||||
|
into a single string.
|
||||||
|
|
||||||
<keycount>
|
<keycount>
|
||||||
Multi-key compatibility mode. You can define <keycount> keys and
|
Multi-key compatibility mode. You can define <keycount> keys and
|
||||||
@@ -44,7 +51,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
|||||||
Otherwise #opt_params is the number of following arguments.
|
Otherwise #opt_params is the number of following arguments.
|
||||||
|
|
||||||
Example of optional parameters section:
|
Example of optional parameters section:
|
||||||
1 allow_discards
|
3 allow_discards same_cpu_crypt submit_from_crypt_cpus
|
||||||
|
|
||||||
allow_discards
|
allow_discards
|
||||||
Block discard requests (a.k.a. TRIM) are passed through the crypt device.
|
Block discard requests (a.k.a. TRIM) are passed through the crypt device.
|
||||||
@@ -56,11 +63,24 @@ allow_discards
|
|||||||
used space etc.) if the discarded blocks can be located easily on the
|
used space etc.) if the discarded blocks can be located easily on the
|
||||||
device later.
|
device later.
|
||||||
|
|
||||||
|
same_cpu_crypt
|
||||||
|
Perform encryption using the same cpu that IO was submitted on.
|
||||||
|
The default is to use an unbound workqueue so that encryption work
|
||||||
|
is automatically balanced between available CPUs.
|
||||||
|
|
||||||
|
submit_from_crypt_cpus
|
||||||
|
Disable offloading writes to a separate thread after encryption.
|
||||||
|
There are some situations where offloading write bios from the
|
||||||
|
encryption threads to a single thread degrades performance
|
||||||
|
significantly. The default is to offload write bios to the same
|
||||||
|
thread because it benefits CFQ to have writes submitted using the
|
||||||
|
same context.
|
||||||
|
|
||||||
Example scripts
|
Example scripts
|
||||||
===============
|
===============
|
||||||
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
|
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
|
||||||
encryption with dm-crypt using the 'cryptsetup' utility, see
|
encryption with dm-crypt using the 'cryptsetup' utility, see
|
||||||
http://code.google.com/p/cryptsetup/
|
https://gitlab.com/cryptsetup/cryptsetup
|
||||||
|
|
||||||
[[
|
[[
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|||||||
108
doc/kernel/era.txt
Normal file
108
doc/kernel/era.txt
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
dm-era is a target that behaves similar to the linear target. In
|
||||||
|
addition it keeps track of which blocks were written within a user
|
||||||
|
defined period of time called an 'era'. Each era target instance
|
||||||
|
maintains the current era as a monotonically increasing 32-bit
|
||||||
|
counter.
|
||||||
|
|
||||||
|
Use cases include tracking changed blocks for backup software, and
|
||||||
|
partially invalidating the contents of a cache to restore cache
|
||||||
|
coherency after rolling back a vendor snapshot.
|
||||||
|
|
||||||
|
Constructor
|
||||||
|
===========
|
||||||
|
|
||||||
|
era <metadata dev> <origin dev> <block size>
|
||||||
|
|
||||||
|
metadata dev : fast device holding the persistent metadata
|
||||||
|
origin dev : device holding data blocks that may change
|
||||||
|
block size : block size of origin data device, granularity that is
|
||||||
|
tracked by the target
|
||||||
|
|
||||||
|
Messages
|
||||||
|
========
|
||||||
|
|
||||||
|
None of the dm messages take any arguments.
|
||||||
|
|
||||||
|
checkpoint
|
||||||
|
----------
|
||||||
|
|
||||||
|
Possibly move to a new era. You shouldn't assume the era has
|
||||||
|
incremented. After sending this message, you should check the
|
||||||
|
current era via the status line.
|
||||||
|
|
||||||
|
take_metadata_snap
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Create a clone of the metadata, to allow a userland process to read it.
|
||||||
|
|
||||||
|
drop_metadata_snap
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Drop the metadata snapshot.
|
||||||
|
|
||||||
|
Status
|
||||||
|
======
|
||||||
|
|
||||||
|
<metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||||
|
<current era> <held metadata root | '-'>
|
||||||
|
|
||||||
|
metadata block size : Fixed block size for each metadata block in
|
||||||
|
sectors
|
||||||
|
#used metadata blocks : Number of metadata blocks used
|
||||||
|
#total metadata blocks : Total number of metadata blocks
|
||||||
|
current era : The current era
|
||||||
|
held metadata root : The location, in blocks, of the metadata root
|
||||||
|
that has been 'held' for userspace read
|
||||||
|
access. '-' indicates there is no held root
|
||||||
|
|
||||||
|
Detailed use case
|
||||||
|
=================
|
||||||
|
|
||||||
|
The scenario of invalidating a cache when rolling back a vendor
|
||||||
|
snapshot was the primary use case when developing this target:
|
||||||
|
|
||||||
|
Taking a vendor snapshot
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- Send a checkpoint message to the era target
|
||||||
|
- Make a note of the current era in its status line
|
||||||
|
- Take vendor snapshot (the era and snapshot should be forever
|
||||||
|
associated now).
|
||||||
|
|
||||||
|
Rolling back to an vendor snapshot
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
- Cache enters passthrough mode (see: dm-cache's docs in cache.txt)
|
||||||
|
- Rollback vendor storage
|
||||||
|
- Take metadata snapshot
|
||||||
|
- Ascertain which blocks have been written since the snapshot was taken
|
||||||
|
by checking each block's era
|
||||||
|
- Invalidate those blocks in the caching software
|
||||||
|
- Cache returns to writeback/writethrough mode
|
||||||
|
|
||||||
|
Memory usage
|
||||||
|
============
|
||||||
|
|
||||||
|
The target uses a bitset to record writes in the current era. It also
|
||||||
|
has a spare bitset ready for switching over to a new era. Other than
|
||||||
|
that it uses a few 4k blocks for updating metadata.
|
||||||
|
|
||||||
|
(4 * nr_blocks) bytes + buffers
|
||||||
|
|
||||||
|
Resilience
|
||||||
|
==========
|
||||||
|
|
||||||
|
Metadata is updated on disk before a write to a previously unwritten
|
||||||
|
block is performed. As such dm-era should not be effected by a hard
|
||||||
|
crash such as power failure.
|
||||||
|
|
||||||
|
Userland tools
|
||||||
|
==============
|
||||||
|
|
||||||
|
Userland tools are found in the increasingly poorly named
|
||||||
|
thin-provisioning-tools project:
|
||||||
|
|
||||||
|
https://github.com/jthornber/thin-provisioning-tools
|
||||||
140
doc/kernel/log-writes.txt
Normal file
140
doc/kernel/log-writes.txt
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
dm-log-writes
|
||||||
|
=============
|
||||||
|
|
||||||
|
This target takes 2 devices, one to pass all IO to normally, and one to log all
|
||||||
|
of the write operations to. This is intended for file system developers wishing
|
||||||
|
to verify the integrity of metadata or data as the file system is written to.
|
||||||
|
There is a log_write_entry written for every WRITE request and the target is
|
||||||
|
able to take arbitrary data from userspace to insert into the log. The data
|
||||||
|
that is in the WRITE requests is copied into the log to make the replay happen
|
||||||
|
exactly as it happened originally.
|
||||||
|
|
||||||
|
Log Ordering
|
||||||
|
============
|
||||||
|
|
||||||
|
We log things in order of completion once we are sure the write is no longer in
|
||||||
|
cache. This means that normal WRITE requests are not actually logged until the
|
||||||
|
next REQ_FLUSH request. This is to make it easier for userspace to replay the
|
||||||
|
log in a way that correlates to what is on disk and not what is in cache, to
|
||||||
|
make it easier to detect improper waiting/flushing.
|
||||||
|
|
||||||
|
This works by attaching all WRITE requests to a list once the write completes.
|
||||||
|
Once we see a REQ_FLUSH request we splice this list onto the request and once
|
||||||
|
the FLUSH request completes we log all of the WRITEs and then the FLUSH. Only
|
||||||
|
completed WRITEs, at the time the REQ_FLUSH is issued, are added in order to
|
||||||
|
simulate the worst case scenario with regard to power failures. Consider the
|
||||||
|
following example (W means write, C means complete):
|
||||||
|
|
||||||
|
W1,W2,W3,C3,C2,Wflush,C1,Cflush
|
||||||
|
|
||||||
|
The log would show the following
|
||||||
|
|
||||||
|
W3,W2,flush,W1....
|
||||||
|
|
||||||
|
Again this is to simulate what is actually on disk, this allows us to detect
|
||||||
|
cases where a power failure at a particular point in time would create an
|
||||||
|
inconsistent file system.
|
||||||
|
|
||||||
|
Any REQ_FUA requests bypass this flushing mechanism and are logged as soon as
|
||||||
|
they complete as those requests will obviously bypass the device cache.
|
||||||
|
|
||||||
|
Any REQ_DISCARD requests are treated like WRITE requests. Otherwise we would
|
||||||
|
have all the DISCARD requests, and then the WRITE requests and then the FLUSH
|
||||||
|
request. Consider the following example:
|
||||||
|
|
||||||
|
WRITE block 1, DISCARD block 1, FLUSH
|
||||||
|
|
||||||
|
If we logged DISCARD when it completed, the replay would look like this
|
||||||
|
|
||||||
|
DISCARD 1, WRITE 1, FLUSH
|
||||||
|
|
||||||
|
which isn't quite what happened and wouldn't be caught during the log replay.
|
||||||
|
|
||||||
|
Target interface
|
||||||
|
================
|
||||||
|
|
||||||
|
i) Constructor
|
||||||
|
|
||||||
|
log-writes <dev_path> <log_dev_path>
|
||||||
|
|
||||||
|
dev_path : Device that all of the IO will go to normally.
|
||||||
|
log_dev_path : Device where the log entries are written to.
|
||||||
|
|
||||||
|
ii) Status
|
||||||
|
|
||||||
|
<#logged entries> <highest allocated sector>
|
||||||
|
|
||||||
|
#logged entries : Number of logged entries
|
||||||
|
highest allocated sector : Highest allocated sector
|
||||||
|
|
||||||
|
iii) Messages
|
||||||
|
|
||||||
|
mark <description>
|
||||||
|
|
||||||
|
You can use a dmsetup message to set an arbitrary mark in a log.
|
||||||
|
For example say you want to fsck a file system after every
|
||||||
|
write, but first you need to replay up to the mkfs to make sure
|
||||||
|
we're fsck'ing something reasonable, you would do something like
|
||||||
|
this:
|
||||||
|
|
||||||
|
mkfs.btrfs -f /dev/mapper/log
|
||||||
|
dmsetup message log 0 mark mkfs
|
||||||
|
<run test>
|
||||||
|
|
||||||
|
This would allow you to replay the log up to the mkfs mark and
|
||||||
|
then replay from that point on doing the fsck check in the
|
||||||
|
interval that you want.
|
||||||
|
|
||||||
|
Every log has a mark at the end labeled "dm-log-writes-end".
|
||||||
|
|
||||||
|
Userspace component
|
||||||
|
===================
|
||||||
|
|
||||||
|
There is a userspace tool that will replay the log for you in various ways.
|
||||||
|
It can be found here: https://github.com/josefbacik/log-writes
|
||||||
|
|
||||||
|
Example usage
|
||||||
|
=============
|
||||||
|
|
||||||
|
Say you want to test fsync on your file system. You would do something like
|
||||||
|
this:
|
||||||
|
|
||||||
|
TABLE="0 $(blockdev --getsz /dev/sdb) log-writes /dev/sdb /dev/sdc"
|
||||||
|
dmsetup create log --table "$TABLE"
|
||||||
|
mkfs.btrfs -f /dev/mapper/log
|
||||||
|
dmsetup message log 0 mark mkfs
|
||||||
|
|
||||||
|
mount /dev/mapper/log /mnt/btrfs-test
|
||||||
|
<some test that does fsync at the end>
|
||||||
|
dmsetup message log 0 mark fsync
|
||||||
|
md5sum /mnt/btrfs-test/foo
|
||||||
|
umount /mnt/btrfs-test
|
||||||
|
|
||||||
|
dmsetup remove log
|
||||||
|
replay-log --log /dev/sdc --replay /dev/sdb --end-mark fsync
|
||||||
|
mount /dev/sdb /mnt/btrfs-test
|
||||||
|
md5sum /mnt/btrfs-test/foo
|
||||||
|
<verify md5sum's are correct>
|
||||||
|
|
||||||
|
Another option is to do a complicated file system operation and verify the file
|
||||||
|
system is consistent during the entire operation. You could do this with:
|
||||||
|
|
||||||
|
TABLE="0 $(blockdev --getsz /dev/sdb) log-writes /dev/sdb /dev/sdc"
|
||||||
|
dmsetup create log --table "$TABLE"
|
||||||
|
mkfs.btrfs -f /dev/mapper/log
|
||||||
|
dmsetup message log 0 mark mkfs
|
||||||
|
|
||||||
|
mount /dev/mapper/log /mnt/btrfs-test
|
||||||
|
<fsstress to dirty the fs>
|
||||||
|
btrfs filesystem balance /mnt/btrfs-test
|
||||||
|
umount /mnt/btrfs-test
|
||||||
|
dmsetup remove log
|
||||||
|
|
||||||
|
replay-log --log /dev/sdc --replay /dev/sdb --end-mark mkfs
|
||||||
|
btrfsck /dev/sdb
|
||||||
|
replay-log --log /dev/sdc --replay /dev/sdb --start-mark mkfs \
|
||||||
|
--fsck "btrfsck /dev/sdb" --check fua
|
||||||
|
|
||||||
|
And that will replay the log until it sees a FUA request, run the fsck command
|
||||||
|
and if the fsck passes it will replay to the next FUA, until it is completed or
|
||||||
|
the fsck command exists abnormally.
|
||||||
@@ -222,3 +222,5 @@ Version History
|
|||||||
1.4.2 Add RAID10 "far" and "offset" algorithm support.
|
1.4.2 Add RAID10 "far" and "offset" algorithm support.
|
||||||
1.5.0 Add message interface to allow manipulation of the sync_action.
|
1.5.0 Add message interface to allow manipulation of the sync_action.
|
||||||
New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
|
New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
|
||||||
|
1.5.1 Add ability to restore transiently failed devices on resume.
|
||||||
|
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
|
||||||
|
|||||||
186
doc/kernel/statistics.txt
Normal file
186
doc/kernel/statistics.txt
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
DM statistics
|
||||||
|
=============
|
||||||
|
|
||||||
|
Device Mapper supports the collection of I/O statistics on user-defined
|
||||||
|
regions of a DM device. If no regions are defined no statistics are
|
||||||
|
collected so there isn't any performance impact. Only bio-based DM
|
||||||
|
devices are currently supported.
|
||||||
|
|
||||||
|
Each user-defined region specifies a starting sector, length and step.
|
||||||
|
Individual statistics will be collected for each step-sized area within
|
||||||
|
the range specified.
|
||||||
|
|
||||||
|
The I/O statistics counters for each step-sized area of a region are
|
||||||
|
in the same format as /sys/block/*/stat or /proc/diskstats (see:
|
||||||
|
Documentation/iostats.txt). But two extra counters (12 and 13) are
|
||||||
|
provided: total time spent reading and writing in milliseconds. All
|
||||||
|
these counters may be accessed by sending the @stats_print message to
|
||||||
|
the appropriate DM device via dmsetup.
|
||||||
|
|
||||||
|
Each region has a corresponding unique identifier, which we call a
|
||||||
|
region_id, that is assigned when the region is created. The region_id
|
||||||
|
must be supplied when querying statistics about the region, deleting the
|
||||||
|
region, etc. Unique region_ids enable multiple userspace programs to
|
||||||
|
request and process statistics for the same DM device without stepping
|
||||||
|
on each other's data.
|
||||||
|
|
||||||
|
The creation of DM statistics will allocate memory via kmalloc or
|
||||||
|
fallback to using vmalloc space. At most, 1/4 of the overall system
|
||||||
|
memory may be allocated by DM statistics. The admin can see how much
|
||||||
|
memory is used by reading
|
||||||
|
/sys/module/dm_mod/parameters/stats_current_allocated_bytes
|
||||||
|
|
||||||
|
Messages
|
||||||
|
========
|
||||||
|
|
||||||
|
@stats_create <range> <step> [<program_id> [<aux_data>]]
|
||||||
|
|
||||||
|
Create a new region and return the region_id.
|
||||||
|
|
||||||
|
<range>
|
||||||
|
"-" - whole device
|
||||||
|
"<start_sector>+<length>" - a range of <length> 512-byte sectors
|
||||||
|
starting with <start_sector>.
|
||||||
|
|
||||||
|
<step>
|
||||||
|
"<area_size>" - the range is subdivided into areas each containing
|
||||||
|
<area_size> sectors.
|
||||||
|
"/<number_of_areas>" - the range is subdivided into the specified
|
||||||
|
number of areas.
|
||||||
|
|
||||||
|
<program_id>
|
||||||
|
An optional parameter. A name that uniquely identifies
|
||||||
|
the userspace owner of the range. This groups ranges together
|
||||||
|
so that userspace programs can identify the ranges they
|
||||||
|
created and ignore those created by others.
|
||||||
|
The kernel returns this string back in the output of
|
||||||
|
@stats_list message, but it doesn't use it for anything else.
|
||||||
|
|
||||||
|
<aux_data>
|
||||||
|
An optional parameter. A word that provides auxiliary data
|
||||||
|
that is useful to the client program that created the range.
|
||||||
|
The kernel returns this string back in the output of
|
||||||
|
@stats_list message, but it doesn't use this value for anything.
|
||||||
|
|
||||||
|
@stats_delete <region_id>
|
||||||
|
|
||||||
|
Delete the region with the specified id.
|
||||||
|
|
||||||
|
<region_id>
|
||||||
|
region_id returned from @stats_create
|
||||||
|
|
||||||
|
@stats_clear <region_id>
|
||||||
|
|
||||||
|
Clear all the counters except the in-flight i/o counters.
|
||||||
|
|
||||||
|
<region_id>
|
||||||
|
region_id returned from @stats_create
|
||||||
|
|
||||||
|
@stats_list [<program_id>]
|
||||||
|
|
||||||
|
List all regions registered with @stats_create.
|
||||||
|
|
||||||
|
<program_id>
|
||||||
|
An optional parameter.
|
||||||
|
If this parameter is specified, only matching regions
|
||||||
|
are returned.
|
||||||
|
If it is not specified, all regions are returned.
|
||||||
|
|
||||||
|
Output format:
|
||||||
|
<region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
|
||||||
|
|
||||||
|
@stats_print <region_id> [<starting_line> <number_of_lines>]
|
||||||
|
|
||||||
|
Print counters for each step-sized area of a region.
|
||||||
|
|
||||||
|
<region_id>
|
||||||
|
region_id returned from @stats_create
|
||||||
|
|
||||||
|
<starting_line>
|
||||||
|
The index of the starting line in the output.
|
||||||
|
If omitted, all lines are returned.
|
||||||
|
|
||||||
|
<number_of_lines>
|
||||||
|
The number of lines to include in the output.
|
||||||
|
If omitted, all lines are returned.
|
||||||
|
|
||||||
|
Output format for each step-sized area of a region:
|
||||||
|
|
||||||
|
<start_sector>+<length> counters
|
||||||
|
|
||||||
|
The first 11 counters have the same meaning as
|
||||||
|
/sys/block/*/stat or /proc/diskstats.
|
||||||
|
|
||||||
|
Please refer to Documentation/iostats.txt for details.
|
||||||
|
|
||||||
|
1. the number of reads completed
|
||||||
|
2. the number of reads merged
|
||||||
|
3. the number of sectors read
|
||||||
|
4. the number of milliseconds spent reading
|
||||||
|
5. the number of writes completed
|
||||||
|
6. the number of writes merged
|
||||||
|
7. the number of sectors written
|
||||||
|
8. the number of milliseconds spent writing
|
||||||
|
9. the number of I/Os currently in progress
|
||||||
|
10. the number of milliseconds spent doing I/Os
|
||||||
|
11. the weighted number of milliseconds spent doing I/Os
|
||||||
|
|
||||||
|
Additional counters:
|
||||||
|
12. the total time spent reading in milliseconds
|
||||||
|
13. the total time spent writing in milliseconds
|
||||||
|
|
||||||
|
@stats_print_clear <region_id> [<starting_line> <number_of_lines>]
|
||||||
|
|
||||||
|
Atomically print and then clear all the counters except the
|
||||||
|
in-flight i/o counters. Useful when the client consuming the
|
||||||
|
statistics does not want to lose any statistics (those updated
|
||||||
|
between printing and clearing).
|
||||||
|
|
||||||
|
<region_id>
|
||||||
|
region_id returned from @stats_create
|
||||||
|
|
||||||
|
<starting_line>
|
||||||
|
The index of the starting line in the output.
|
||||||
|
If omitted, all lines are printed and then cleared.
|
||||||
|
|
||||||
|
<number_of_lines>
|
||||||
|
The number of lines to process.
|
||||||
|
If omitted, all lines are printed and then cleared.
|
||||||
|
|
||||||
|
@stats_set_aux <region_id> <aux_data>
|
||||||
|
|
||||||
|
Store auxiliary data aux_data for the specified region.
|
||||||
|
|
||||||
|
<region_id>
|
||||||
|
region_id returned from @stats_create
|
||||||
|
|
||||||
|
<aux_data>
|
||||||
|
The string that identifies data which is useful to the client
|
||||||
|
program that created the range. The kernel returns this
|
||||||
|
string back in the output of @stats_list message, but it
|
||||||
|
doesn't use this value for anything.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
Subdivide the DM device 'vol' into 100 pieces and start collecting
|
||||||
|
statistics on them:
|
||||||
|
|
||||||
|
dmsetup message vol 0 @stats_create - /100
|
||||||
|
|
||||||
|
Set the auxillary data string to "foo bar baz" (the escape for each
|
||||||
|
space must also be escaped, otherwise the shell will consume them):
|
||||||
|
|
||||||
|
dmsetup message vol 0 @stats_set_aux 0 foo\\ bar\\ baz
|
||||||
|
|
||||||
|
List the statistics:
|
||||||
|
|
||||||
|
dmsetup message vol 0 @stats_list
|
||||||
|
|
||||||
|
Print the statistics:
|
||||||
|
|
||||||
|
dmsetup message vol 0 @stats_print 0
|
||||||
|
|
||||||
|
Delete the statistics:
|
||||||
|
|
||||||
|
dmsetup message vol 0 @stats_delete 0
|
||||||
138
doc/kernel/switch.txt
Normal file
138
doc/kernel/switch.txt
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
dm-switch
|
||||||
|
=========
|
||||||
|
|
||||||
|
The device-mapper switch target creates a device that supports an
|
||||||
|
arbitrary mapping of fixed-size regions of I/O across a fixed set of
|
||||||
|
paths. The path used for any specific region can be switched
|
||||||
|
dynamically by sending the target a message.
|
||||||
|
|
||||||
|
It maps I/O to underlying block devices efficiently when there is a large
|
||||||
|
number of fixed-sized address regions but there is no simple pattern
|
||||||
|
that would allow for a compact representation of the mapping such as
|
||||||
|
dm-stripe.
|
||||||
|
|
||||||
|
Background
|
||||||
|
----------
|
||||||
|
|
||||||
|
Dell EqualLogic and some other iSCSI storage arrays use a distributed
|
||||||
|
frameless architecture. In this architecture, the storage group
|
||||||
|
consists of a number of distinct storage arrays ("members") each having
|
||||||
|
independent controllers, disk storage and network adapters. When a LUN
|
||||||
|
is created it is spread across multiple members. The details of the
|
||||||
|
spreading are hidden from initiators connected to this storage system.
|
||||||
|
The storage group exposes a single target discovery portal, no matter
|
||||||
|
how many members are being used. When iSCSI sessions are created, each
|
||||||
|
session is connected to an eth port on a single member. Data to a LUN
|
||||||
|
can be sent on any iSCSI session, and if the blocks being accessed are
|
||||||
|
stored on another member the I/O will be forwarded as required. This
|
||||||
|
forwarding is invisible to the initiator. The storage layout is also
|
||||||
|
dynamic, and the blocks stored on disk may be moved from member to
|
||||||
|
member as needed to balance the load.
|
||||||
|
|
||||||
|
This architecture simplifies the management and configuration of both
|
||||||
|
the storage group and initiators. In a multipathing configuration, it
|
||||||
|
is possible to set up multiple iSCSI sessions to use multiple network
|
||||||
|
interfaces on both the host and target to take advantage of the
|
||||||
|
increased network bandwidth. An initiator could use a simple round
|
||||||
|
robin algorithm to send I/O across all paths and let the storage array
|
||||||
|
members forward it as necessary, but there is a performance advantage to
|
||||||
|
sending data directly to the correct member.
|
||||||
|
|
||||||
|
A device-mapper table already lets you map different regions of a
|
||||||
|
device onto different targets. However in this architecture the LUN is
|
||||||
|
spread with an address region size on the order of 10s of MBs, which
|
||||||
|
means the resulting table could have more than a million entries and
|
||||||
|
consume far too much memory.
|
||||||
|
|
||||||
|
Using this device-mapper switch target we can now build a two-layer
|
||||||
|
device hierarchy:
|
||||||
|
|
||||||
|
Upper Tier - Determine which array member the I/O should be sent to.
|
||||||
|
Lower Tier - Load balance amongst paths to a particular member.
|
||||||
|
|
||||||
|
The lower tier consists of a single dm multipath device for each member.
|
||||||
|
Each of these multipath devices contains the set of paths directly to
|
||||||
|
the array member in one priority group, and leverages existing path
|
||||||
|
selectors to load balance amongst these paths. We also build a
|
||||||
|
non-preferred priority group containing paths to other array members for
|
||||||
|
failover reasons.
|
||||||
|
|
||||||
|
The upper tier consists of a single dm-switch device. This device uses
|
||||||
|
a bitmap to look up the location of the I/O and choose the appropriate
|
||||||
|
lower tier device to route the I/O. By using a bitmap we are able to
|
||||||
|
use 4 bits for each address range in a 16 member group (which is very
|
||||||
|
large for us). This is a much denser representation than the dm table
|
||||||
|
b-tree can achieve.
|
||||||
|
|
||||||
|
Construction Parameters
|
||||||
|
=======================
|
||||||
|
|
||||||
|
<num_paths> <region_size> <num_optional_args> [<optional_args>...]
|
||||||
|
[<dev_path> <offset>]+
|
||||||
|
|
||||||
|
<num_paths>
|
||||||
|
The number of paths across which to distribute the I/O.
|
||||||
|
|
||||||
|
<region_size>
|
||||||
|
The number of 512-byte sectors in a region. Each region can be redirected
|
||||||
|
to any of the available paths.
|
||||||
|
|
||||||
|
<num_optional_args>
|
||||||
|
The number of optional arguments. Currently, no optional arguments
|
||||||
|
are supported and so this must be zero.
|
||||||
|
|
||||||
|
<dev_path>
|
||||||
|
The block device that represents a specific path to the device.
|
||||||
|
|
||||||
|
<offset>
|
||||||
|
The offset of the start of data on the specific <dev_path> (in units
|
||||||
|
of 512-byte sectors). This number is added to the sector number when
|
||||||
|
forwarding the request to the specific path. Typically it is zero.
|
||||||
|
|
||||||
|
Messages
|
||||||
|
========
|
||||||
|
|
||||||
|
set_region_mappings <index>:<path_nr> [<index>]:<path_nr> [<index>]:<path_nr>...
|
||||||
|
|
||||||
|
Modify the region table by specifying which regions are redirected to
|
||||||
|
which paths.
|
||||||
|
|
||||||
|
<index>
|
||||||
|
The region number (region size was specified in constructor parameters).
|
||||||
|
If index is omitted, the next region (previous index + 1) is used.
|
||||||
|
Expressed in hexadecimal (WITHOUT any prefix like 0x).
|
||||||
|
|
||||||
|
<path_nr>
|
||||||
|
The path number in the range 0 ... (<num_paths> - 1).
|
||||||
|
Expressed in hexadecimal (WITHOUT any prefix like 0x).
|
||||||
|
|
||||||
|
R<n>,<m>
|
||||||
|
This parameter allows repetitive patterns to be loaded quickly. <n> and <m>
|
||||||
|
are hexadecimal numbers. The last <n> mappings are repeated in the next <m>
|
||||||
|
slots.
|
||||||
|
|
||||||
|
Status
|
||||||
|
======
|
||||||
|
|
||||||
|
No status line is reported.
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
Assume that you have volumes vg1/switch0 vg1/switch1 vg1/switch2 with
|
||||||
|
the same size.
|
||||||
|
|
||||||
|
Create a switch device with 64kB region size:
|
||||||
|
dmsetup create switch --table "0 `blockdev --getsize /dev/vg1/switch0`
|
||||||
|
switch 3 128 0 /dev/vg1/switch0 0 /dev/vg1/switch1 0 /dev/vg1/switch2 0"
|
||||||
|
|
||||||
|
Set mappings for the first 7 entries to point to devices switch0, switch1,
|
||||||
|
switch2, switch0, switch1, switch2, switch1:
|
||||||
|
dmsetup message switch 0 set_region_mappings 0:0 :1 :2 :0 :1 :2 :1
|
||||||
|
|
||||||
|
Set repetitive mapping. This command:
|
||||||
|
dmsetup message switch 0 set_region_mappings 1000:1 :2 R2,10
|
||||||
|
is equivalent to:
|
||||||
|
dmsetup message switch 0 set_region_mappings 1000:1 :2 :1 :2 :1 :2 :1 :2 \
|
||||||
|
:1 :2 :1 :2 :1 :2 :1 :2 :1 :2
|
||||||
|
|
||||||
@@ -99,13 +99,14 @@ Using an existing pool device
|
|||||||
$data_block_size $low_water_mark"
|
$data_block_size $low_water_mark"
|
||||||
|
|
||||||
$data_block_size gives the smallest unit of disk space that can be
|
$data_block_size gives the smallest unit of disk space that can be
|
||||||
allocated at a time expressed in units of 512-byte sectors. People
|
allocated at a time expressed in units of 512-byte sectors.
|
||||||
primarily interested in thin provisioning may want to use a value such
|
$data_block_size must be between 128 (64KB) and 2097152 (1GB) and a
|
||||||
as 1024 (512KB). People doing lots of snapshotting may want a smaller value
|
multiple of 128 (64KB). $data_block_size cannot be changed after the
|
||||||
such as 128 (64KB). If you are not zeroing newly-allocated data,
|
thin-pool is created. People primarily interested in thin provisioning
|
||||||
a larger $data_block_size in the region of 256000 (128MB) is suggested.
|
may want to use a value such as 1024 (512KB). People doing lots of
|
||||||
$data_block_size must be the same for the lifetime of the
|
snapshotting may want a smaller value such as 128 (64KB). If you are
|
||||||
metadata device.
|
not zeroing newly-allocated data, a larger $data_block_size in the
|
||||||
|
region of 256000 (128MB) is suggested.
|
||||||
|
|
||||||
$low_water_mark is expressed in blocks of size $data_block_size. If
|
$low_water_mark is expressed in blocks of size $data_block_size. If
|
||||||
free space on the data device drops below this level then a dm event
|
free space on the data device drops below this level then a dm event
|
||||||
@@ -115,6 +116,35 @@ Resuming a device with a new table itself triggers an event so the
|
|||||||
userspace daemon can use this to detect a situation where a new table
|
userspace daemon can use this to detect a situation where a new table
|
||||||
already exceeds the threshold.
|
already exceeds the threshold.
|
||||||
|
|
||||||
|
A low water mark for the metadata device is maintained in the kernel and
|
||||||
|
will trigger a dm event if free space on the metadata device drops below
|
||||||
|
it.
|
||||||
|
|
||||||
|
Updating on-disk metadata
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
On-disk metadata is committed every time a FLUSH or FUA bio is written.
|
||||||
|
If no such requests are made then commits will occur every second. This
|
||||||
|
means the thin-provisioning target behaves like a physical disk that has
|
||||||
|
a volatile write cache. If power is lost you may lose some recent
|
||||||
|
writes. The metadata should always be consistent in spite of any crash.
|
||||||
|
|
||||||
|
If data space is exhausted the pool will either error or queue IO
|
||||||
|
according to the configuration (see: error_if_no_space). If metadata
|
||||||
|
space is exhausted or a metadata operation fails: the pool will error IO
|
||||||
|
until the pool is taken offline and repair is performed to 1) fix any
|
||||||
|
potential inconsistencies and 2) clear the flag that imposes repair.
|
||||||
|
Once the pool's metadata device is repaired it may be resized, which
|
||||||
|
will allow the pool to return to normal operation. Note that if a pool
|
||||||
|
is flagged as needing repair, the pool's data and metadata devices
|
||||||
|
cannot be resized until repair is performed. It should also be noted
|
||||||
|
that when the pool's metadata space is exhausted the current metadata
|
||||||
|
transaction is aborted. Given that the pool will cache IO whose
|
||||||
|
completion may have already been acknowledged to upper IO layers
|
||||||
|
(e.g. filesystem) it is strongly suggested that consistency checks
|
||||||
|
(e.g. fsck) be performed on those layers when repair of the pool is
|
||||||
|
required.
|
||||||
|
|
||||||
Thin provisioning
|
Thin provisioning
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@@ -234,6 +264,8 @@ i) Constructor
|
|||||||
read_only: Don't allow any changes to be made to the pool
|
read_only: Don't allow any changes to be made to the pool
|
||||||
metadata.
|
metadata.
|
||||||
|
|
||||||
|
error_if_no_space: Error IOs, instead of queueing, if no space.
|
||||||
|
|
||||||
Data block size must be between 64KB (128 sectors) and 1GB
|
Data block size must be between 64KB (128 sectors) and 1GB
|
||||||
(2097152 sectors) inclusive.
|
(2097152 sectors) inclusive.
|
||||||
|
|
||||||
@@ -255,10 +287,9 @@ ii) Status
|
|||||||
should register for the event and then check the target's status.
|
should register for the event and then check the target's status.
|
||||||
|
|
||||||
held metadata root:
|
held metadata root:
|
||||||
The location, in sectors, of the metadata root that has been
|
The location, in blocks, of the metadata root that has been
|
||||||
'held' for userspace read access. '-' indicates there is no
|
'held' for userspace read access. '-' indicates there is no
|
||||||
held root. This feature is not yet implemented so '-' is
|
held root.
|
||||||
always returned.
|
|
||||||
|
|
||||||
discard_passdown|no_discard_passdown
|
discard_passdown|no_discard_passdown
|
||||||
Whether or not discards are actually being passed down to the
|
Whether or not discards are actually being passed down to the
|
||||||
@@ -275,6 +306,14 @@ ii) Status
|
|||||||
contain the string 'Fail'. The userspace recovery tools
|
contain the string 'Fail'. The userspace recovery tools
|
||||||
should then be used.
|
should then be used.
|
||||||
|
|
||||||
|
error_if_no_space|queue_if_no_space
|
||||||
|
If the pool runs out of data or metadata space, the pool will
|
||||||
|
either queue or error the IO destined to the data device. The
|
||||||
|
default is to queue the IO until more space is added or the
|
||||||
|
'no_space_timeout' expires. The 'no_space_timeout' dm-thin-pool
|
||||||
|
module parameter can be used to change this timeout -- it
|
||||||
|
defaults to 60 seconds but may be disabled using a value of 0.
|
||||||
|
|
||||||
iii) Messages
|
iii) Messages
|
||||||
|
|
||||||
create_thin <dev id>
|
create_thin <dev id>
|
||||||
@@ -341,9 +380,6 @@ then you'll have no access to blocks mapped beyond the end. If you
|
|||||||
load a target that is bigger than before, then extra blocks will be
|
load a target that is bigger than before, then extra blocks will be
|
||||||
provisioned as and when needed.
|
provisioned as and when needed.
|
||||||
|
|
||||||
If you wish to reduce the size of your thin device and potentially
|
|
||||||
regain some space then send the 'trim' message to the pool.
|
|
||||||
|
|
||||||
ii) Status
|
ii) Status
|
||||||
|
|
||||||
<nr mapped sectors> <highest mapped sector>
|
<nr mapped sectors> <highest mapped sector>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Construction Parameters
|
|||||||
<data_block_size> <hash_block_size>
|
<data_block_size> <hash_block_size>
|
||||||
<num_data_blocks> <hash_start_block>
|
<num_data_blocks> <hash_start_block>
|
||||||
<algorithm> <digest> <salt>
|
<algorithm> <digest> <salt>
|
||||||
|
[<#opt_params> <opt_params>]
|
||||||
|
|
||||||
<version>
|
<version>
|
||||||
This is the type of the on-disk hash format.
|
This is the type of the on-disk hash format.
|
||||||
@@ -62,6 +63,22 @@ Construction Parameters
|
|||||||
<salt>
|
<salt>
|
||||||
The hexadecimal encoding of the salt value.
|
The hexadecimal encoding of the salt value.
|
||||||
|
|
||||||
|
<#opt_params>
|
||||||
|
Number of optional parameters. If there are no optional parameters,
|
||||||
|
the optional paramaters section can be skipped or #opt_params can be zero.
|
||||||
|
Otherwise #opt_params is the number of following arguments.
|
||||||
|
|
||||||
|
Example of optional parameters section:
|
||||||
|
1 ignore_corruption
|
||||||
|
|
||||||
|
ignore_corruption
|
||||||
|
Log corrupted blocks, but allow read operations to proceed normally.
|
||||||
|
|
||||||
|
restart_on_corruption
|
||||||
|
Restart the system when a corrupted block is discovered. This option is
|
||||||
|
not compatible with ignore_corruption and requires user space support to
|
||||||
|
avoid restart loops.
|
||||||
|
|
||||||
Theory of operation
|
Theory of operation
|
||||||
===================
|
===================
|
||||||
|
|
||||||
@@ -125,7 +142,7 @@ block boundary) are the hash blocks which are stored a depth at a time
|
|||||||
|
|
||||||
The full specification of kernel parameters and on-disk metadata format
|
The full specification of kernel parameters and on-disk metadata format
|
||||||
is available at the cryptsetup project's wiki page
|
is available at the cryptsetup project's wiki page
|
||||||
http://code.google.com/p/cryptsetup/wiki/DMVerity
|
https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
|
||||||
|
|
||||||
Status
|
Status
|
||||||
======
|
======
|
||||||
@@ -142,7 +159,7 @@ Set up a device:
|
|||||||
|
|
||||||
A command line tool veritysetup is available to compute or verify
|
A command line tool veritysetup is available to compute or verify
|
||||||
the hash tree or activate the kernel device. This is available from
|
the hash tree or activate the kernel device. This is available from
|
||||||
the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
|
the cryptsetup upstream repository https://gitlab.com/cryptsetup/cryptsetup/
|
||||||
(as a libcryptsetup extension).
|
(as a libcryptsetup extension).
|
||||||
|
|
||||||
Create hash on the device:
|
Create hash on the device:
|
||||||
|
|||||||
@@ -137,6 +137,17 @@ hosts. Overall, this is not hard, but the devil is in the details. I would
|
|||||||
possibly disable lvmetad for clustered volume groups in the first phase and
|
possibly disable lvmetad for clustered volume groups in the first phase and
|
||||||
only proceed when the local mode is robust and well tested.
|
only proceed when the local mode is robust and well tested.
|
||||||
|
|
||||||
|
With lvmlockd, lvmetad state is kept up to date by flagging either an
|
||||||
|
individual VG as "invalid", or the global state as "invalid". When either
|
||||||
|
the VG or the global state are read, this invalid flag is returned along
|
||||||
|
with the data. The client command can check for this invalid state and
|
||||||
|
decide to read the information from disk rather than use the stale cached
|
||||||
|
data. After the latest data is read from disk, the command may choose to
|
||||||
|
send it to lvmetad to update the cache. lvmlockd uses version numbers
|
||||||
|
embedded in its VG and global locks to detect when cached data becomes
|
||||||
|
invalid, and it then tells lvmetad to set the related invalid flag.
|
||||||
|
dct, 2015-06-23
|
||||||
|
|
||||||
Protocol & co.
|
Protocol & co.
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|||||||
81
doc/lvmpolld_overview.txt
Normal file
81
doc/lvmpolld_overview.txt
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
LVM poll daemon overview
|
||||||
|
========================
|
||||||
|
|
||||||
|
(last updated: 2015-05-09)
|
||||||
|
|
||||||
|
LVM poll daemon (lvmpolld) is the alternative for lvm2 classical polling
|
||||||
|
mechanisms. The motivation behind new lvmpolld was to create persistent
|
||||||
|
system service that would be more durable and transparent. It's suited
|
||||||
|
particularly for any systemd enabled distribution.
|
||||||
|
|
||||||
|
Before lvmpolld any background polling process originating in a lvm2 command
|
||||||
|
initiated inside cgroup of a systemd service could get killed if the main
|
||||||
|
process (service) exited in such cgroup. That could lead to premature termination
|
||||||
|
of such lvm2 polling process.
|
||||||
|
|
||||||
|
Also without lvmpolld there were no means to detect a particular polling process
|
||||||
|
suited for monitoring of specific operation is already in-progress and therefore
|
||||||
|
it's not desirable to start next one with exactly same task. lvmpolld is able to
|
||||||
|
detect such duplicate requests and not spawn such redundant process.
|
||||||
|
|
||||||
|
lvmpolld is primarily targeted for systems with systemd as init process. For systems
|
||||||
|
without systemd there's no need to install lvmpolld because there is no issue
|
||||||
|
with observation described in second paragraph. You can still benefit from
|
||||||
|
avoiding duplicate polling process being spawned, but without systemd lvmpolld
|
||||||
|
can't easily be run on-demand (activated by a socket maintained by systemd).
|
||||||
|
|
||||||
|
lvmpolld implement shutdown on idle and can shutdown automatically when idle
|
||||||
|
for requested time. 60 second is recommended default here. This behaviour can be
|
||||||
|
turned off if found useless.
|
||||||
|
|
||||||
|
Data structures
|
||||||
|
---------------
|
||||||
|
|
||||||
|
a) Logical Volume (struct lvmpolld_lv)
|
||||||
|
|
||||||
|
Each operation is identified by LV. Internal identifier within lvmpolld
|
||||||
|
is full LV uuid (vg_uuid+lv_uuid) prefixed with LVM_SYSTEM_DIR if set by client.
|
||||||
|
|
||||||
|
such full identifier may look like:
|
||||||
|
|
||||||
|
"/etc/lvm/lvm.confWFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
|
||||||
|
|
||||||
|
or without LVM_SYSTEM_DIR being set explicitly:
|
||||||
|
|
||||||
|
"WFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
|
||||||
|
|
||||||
|
|
||||||
|
LV carries various metadata about polling operation. The most significant are:
|
||||||
|
|
||||||
|
VG name
|
||||||
|
LV name
|
||||||
|
polling interval (usually --interval passed to lvm2 command or default from lvm2
|
||||||
|
configuration)
|
||||||
|
operation type (one of: pvmove, convert, merge, thin_merge)
|
||||||
|
LVM_SYSTEM_DIR (if set, this is also passed among environment variables of lvpoll
|
||||||
|
command spawned by lvmpolld)
|
||||||
|
|
||||||
|
b) LV stores (struct lvmpolld_store)
|
||||||
|
|
||||||
|
lvmpolld uses two stores for Logical volumes (struct lvmpolld_lv). One store for polling
|
||||||
|
operations in-progress. These operations are as of now: PV move, mirror up-conversion,
|
||||||
|
classical snapshot merge, thin snapshot merge.
|
||||||
|
|
||||||
|
The second store is suited only for pvmove --abort operations in-progress. Both
|
||||||
|
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
|
||||||
|
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
|
||||||
|
guaranteed by lvm2 locking mechanism).
|
||||||
|
|
||||||
|
Locking order
|
||||||
|
-------------
|
||||||
|
|
||||||
|
There are two types of locks in lvmpolld. Each store has own store lock and each LV has
|
||||||
|
own lv lock.
|
||||||
|
|
||||||
|
Locking order is:
|
||||||
|
1) store lock
|
||||||
|
2) LV lock
|
||||||
|
|
||||||
|
Each LV has to be inside a store. When daemon requires to take both locks it has
|
||||||
|
to take a store lock first and LV lock has to be taken afterwards (after the
|
||||||
|
appropriate store lock where the LV is being stored :))
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
@top_srcdir@/daemons/clvmd/clvm.h
|
@top_srcdir@/daemons/clvmd/clvm.h
|
||||||
@top_srcdir@/daemons/dmeventd/libdevmapper-event.h
|
@top_srcdir@/daemons/dmeventd/libdevmapper-event.h
|
||||||
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
|
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
|
||||||
|
@top_srcdir@/daemons/lvmpolld/lvmpolld-protocol.h
|
||||||
|
@top_srcdir@/daemons/lvmpolld/polling_ops.h
|
||||||
|
@top_srcdir@/daemons/lvmlockd/lvmlockd-client.h
|
||||||
@top_srcdir@/liblvm/lvm2app.h
|
@top_srcdir@/liblvm/lvm2app.h
|
||||||
@top_srcdir@/lib/activate/activate.h
|
@top_srcdir@/lib/activate/activate.h
|
||||||
@top_srcdir@/lib/activate/targets.h
|
@top_srcdir@/lib/activate/targets.h
|
||||||
@top_srcdir@/lib/cache/lvmcache.h
|
@top_srcdir@/lib/cache/lvmcache.h
|
||||||
@top_srcdir@/lib/cache/lvmetad.h
|
@top_srcdir@/lib/cache/lvmetad.h
|
||||||
|
@top_srcdir@/lib/locking/lvmlockd.h
|
||||||
@top_srcdir@/lib/commands/toolcontext.h
|
@top_srcdir@/lib/commands/toolcontext.h
|
||||||
@top_srcdir@/lib/config/config.h
|
@top_srcdir@/lib/config/config.h
|
||||||
@top_srcdir@/lib/config/config_settings.h
|
@top_srcdir@/lib/config/config_settings.h
|
||||||
@@ -13,6 +17,7 @@
|
|||||||
@top_srcdir@/lib/datastruct/btree.h
|
@top_srcdir@/lib/datastruct/btree.h
|
||||||
@top_srcdir@/lib/datastruct/str_list.h
|
@top_srcdir@/lib/datastruct/str_list.h
|
||||||
@top_srcdir@/lib/device/dev-cache.h
|
@top_srcdir@/lib/device/dev-cache.h
|
||||||
|
@top_srcdir@/lib/device/dev-ext-udev-constants.h
|
||||||
@top_srcdir@/lib/device/dev-type.h
|
@top_srcdir@/lib/device/dev-type.h
|
||||||
@top_srcdir@/lib/device/device.h
|
@top_srcdir@/lib/device/device.h
|
||||||
@top_srcdir@/lib/device/device-types.h
|
@top_srcdir@/lib/device/device-types.h
|
||||||
@@ -28,6 +33,8 @@
|
|||||||
@top_srcdir@/lib/locking/locking.h
|
@top_srcdir@/lib/locking/locking.h
|
||||||
@top_srcdir@/lib/log/log.h
|
@top_srcdir@/lib/log/log.h
|
||||||
@top_srcdir@/lib/log/lvm-logging.h
|
@top_srcdir@/lib/log/lvm-logging.h
|
||||||
|
@top_srcdir@/lib/lvmpolld/lvmpolld-client.h
|
||||||
|
@top_srcdir@/lib/lvmpolld/polldaemon.h
|
||||||
@top_srcdir@/lib/metadata/lv.h
|
@top_srcdir@/lib/metadata/lv.h
|
||||||
@top_srcdir@/lib/metadata/lv_alloc.h
|
@top_srcdir@/lib/metadata/lv_alloc.h
|
||||||
@top_srcdir@/lib/metadata/metadata.h
|
@top_srcdir@/lib/metadata/metadata.h
|
||||||
@@ -38,7 +45,6 @@
|
|||||||
@top_srcdir@/lib/metadata/vg.h
|
@top_srcdir@/lib/metadata/vg.h
|
||||||
@top_srcdir@/lib/mm/memlock.h
|
@top_srcdir@/lib/mm/memlock.h
|
||||||
@top_srcdir@/lib/mm/xlate.h
|
@top_srcdir@/lib/mm/xlate.h
|
||||||
@top_builddir@/lib/misc/configure.h
|
|
||||||
@top_srcdir@/lib/misc/crc.h
|
@top_srcdir@/lib/misc/crc.h
|
||||||
@top_srcdir@/lib/misc/intl.h
|
@top_srcdir@/lib/misc/intl.h
|
||||||
@top_srcdir@/lib/misc/last-path-component.h
|
@top_srcdir@/lib/misc/last-path-component.h
|
||||||
@@ -49,7 +55,6 @@
|
|||||||
@top_srcdir@/lib/misc/lvm-globals.h
|
@top_srcdir@/lib/misc/lvm-globals.h
|
||||||
@top_srcdir@/lib/misc/lvm-signal.h
|
@top_srcdir@/lib/misc/lvm-signal.h
|
||||||
@top_srcdir@/lib/misc/lvm-string.h
|
@top_srcdir@/lib/misc/lvm-string.h
|
||||||
@top_builddir@/lib/misc/lvm-version.h
|
|
||||||
@top_srcdir@/lib/misc/lvm-percent.h
|
@top_srcdir@/lib/misc/lvm-percent.h
|
||||||
@top_srcdir@/lib/misc/lvm-wrappers.h
|
@top_srcdir@/lib/misc/lvm-wrappers.h
|
||||||
@top_srcdir@/lib/misc/sharedlib.h
|
@top_srcdir@/lib/misc/sharedlib.h
|
||||||
@@ -69,3 +74,4 @@
|
|||||||
@top_srcdir@/libdm/misc/kdev_t.h
|
@top_srcdir@/libdm/misc/kdev_t.h
|
||||||
@top_srcdir@/po/pogen.h
|
@top_srcdir@/po/pogen.h
|
||||||
@top_srcdir@/tools/lvm2cmd.h
|
@top_srcdir@/tools/lvm2cmd.h
|
||||||
|
@top_srcdir@/tools/tool.h
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of LVM2.
|
# This file is part of LVM2.
|
||||||
#
|
#
|
||||||
@@ -20,8 +20,12 @@ include $(top_builddir)/make.tmpl
|
|||||||
|
|
||||||
all: .symlinks_created
|
all: .symlinks_created
|
||||||
|
|
||||||
.symlinks_created: .symlinks
|
LINKS := $(shell find . -maxdepth 1 -type l)
|
||||||
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
|
|
||||||
|
.symlinks_created: .symlinks
|
||||||
|
ifneq (,$(firstword $(LINKS)))
|
||||||
|
$(RM) $(LINKS)
|
||||||
|
endif
|
||||||
for i in `cat $<`; do $(LN_S) $$i ; done
|
for i in `cat $<`; do $(LN_S) $$i ; done
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
@@ -31,5 +35,5 @@ device-mapper: all
|
|||||||
|
|
||||||
cflow: all
|
cflow: all
|
||||||
|
|
||||||
DISTCLEAN_TARGETS += $(shell find . -maxdepth 1 -type l)
|
DISTCLEAN_TARGETS += .symlinks configure.h lvm-version.h
|
||||||
DISTCLEAN_TARGETS += .include_symlinks .symlinks_created .symlinks
|
CLEAN_TARGETS += $(LINKS) .include_symlinks .symlinks_created
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* lib/misc/configure.h.in. Generated from configure.in by autoheader. */
|
/* include/configure.h.in. Generated from configure.in by autoheader. */
|
||||||
|
|
||||||
/* Define to 1 to use libblkid detection of signatures when wiping. */
|
/* Define to 1 to use libblkid detection of signatures when wiping. */
|
||||||
#undef BLKID_WIPING_SUPPORT
|
#undef BLKID_WIPING_SUPPORT
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
/* The path to 'cache_check', if available. */
|
/* The path to 'cache_check', if available. */
|
||||||
#undef CACHE_CHECK_CMD
|
#undef CACHE_CHECK_CMD
|
||||||
|
|
||||||
|
/* Define to 1 if the external 'cache_check' tool requires the
|
||||||
|
--clear-needs-check-flag option */
|
||||||
|
#undef CACHE_CHECK_NEEDS_CHECK
|
||||||
|
|
||||||
/* The path to 'cache_dump', if available. */
|
/* The path to 'cache_dump', if available. */
|
||||||
#undef CACHE_DUMP_CMD
|
#undef CACHE_DUMP_CMD
|
||||||
|
|
||||||
@@ -65,6 +69,13 @@
|
|||||||
/* Default DM run directory. */
|
/* Default DM run directory. */
|
||||||
#undef DEFAULT_DM_RUN_DIR
|
#undef DEFAULT_DM_RUN_DIR
|
||||||
|
|
||||||
|
/* Default system configuration directory. */
|
||||||
|
#undef DEFAULT_ETC_DIR
|
||||||
|
|
||||||
|
/* Fall back to LVM1 by default if device-mapper is missing from the kernel.
|
||||||
|
*/
|
||||||
|
#undef DEFAULT_FALLBACK_TO_LVM1
|
||||||
|
|
||||||
/* Name of default locking directory. */
|
/* Name of default locking directory. */
|
||||||
#undef DEFAULT_LOCK_DIR
|
#undef DEFAULT_LOCK_DIR
|
||||||
|
|
||||||
@@ -92,6 +103,18 @@
|
|||||||
/* Path to LVM system directory. */
|
/* Path to LVM system directory. */
|
||||||
#undef DEFAULT_SYS_DIR
|
#undef DEFAULT_SYS_DIR
|
||||||
|
|
||||||
|
/* Use blkid wiping by default. */
|
||||||
|
#undef DEFAULT_USE_BLKID_WIPING
|
||||||
|
|
||||||
|
/* Use lvmetad by default. */
|
||||||
|
#undef DEFAULT_USE_LVMETAD
|
||||||
|
|
||||||
|
/* Use lvmlockd by default. */
|
||||||
|
#undef DEFAULT_USE_LVMLOCKD
|
||||||
|
|
||||||
|
/* Use lvmpolld by default. */
|
||||||
|
#undef DEFAULT_USE_LVMPOLLD
|
||||||
|
|
||||||
/* Define to 1 to enable LVM2 device-mapper interaction. */
|
/* Define to 1 to enable LVM2 device-mapper interaction. */
|
||||||
#undef DEVMAPPER_SUPPORT
|
#undef DEVMAPPER_SUPPORT
|
||||||
|
|
||||||
@@ -104,9 +127,27 @@
|
|||||||
/* Path to dmeventd pidfile. */
|
/* Path to dmeventd pidfile. */
|
||||||
#undef DMEVENTD_PIDFILE
|
#undef DMEVENTD_PIDFILE
|
||||||
|
|
||||||
|
/* Define to enable compat protocol */
|
||||||
|
#undef DM_COMPAT
|
||||||
|
|
||||||
|
/* Define default group for device node */
|
||||||
|
#undef DM_DEVICE_GID
|
||||||
|
|
||||||
|
/* Define default mode for device node */
|
||||||
|
#undef DM_DEVICE_MODE
|
||||||
|
|
||||||
|
/* Define default owner for device node */
|
||||||
|
#undef DM_DEVICE_UID
|
||||||
|
|
||||||
|
/* Define to enable ioctls calls to kernel */
|
||||||
|
#undef DM_IOCTLS
|
||||||
|
|
||||||
/* Library version */
|
/* Library version */
|
||||||
#undef DM_LIB_VERSION
|
#undef DM_LIB_VERSION
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `alarm' function. */
|
||||||
|
#undef HAVE_ALARM
|
||||||
|
|
||||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||||
#undef HAVE_ALLOCA
|
#undef HAVE_ALLOCA
|
||||||
|
|
||||||
@@ -123,12 +164,18 @@
|
|||||||
/* Define to 1 if you have the <assert.h> header file. */
|
/* Define to 1 if you have the <assert.h> header file. */
|
||||||
#undef HAVE_ASSERT_H
|
#undef HAVE_ASSERT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `atexit' function. */
|
||||||
|
#undef HAVE_ATEXIT
|
||||||
|
|
||||||
/* Define to 1 if canonicalize_file_name is available. */
|
/* Define to 1 if canonicalize_file_name is available. */
|
||||||
#undef HAVE_CANONICALIZE_FILE_NAME
|
#undef HAVE_CANONICALIZE_FILE_NAME
|
||||||
|
|
||||||
/* Define to 1 if your system has a working `chown' function. */
|
/* Define to 1 if your system has a working `chown' function. */
|
||||||
#undef HAVE_CHOWN
|
#undef HAVE_CHOWN
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `clock_gettime' function. */
|
||||||
|
#undef HAVE_CLOCK_GETTIME
|
||||||
|
|
||||||
/* Define to 1 if you have the <corosync/cmap.h> header file. */
|
/* Define to 1 if you have the <corosync/cmap.h> header file. */
|
||||||
#undef HAVE_COROSYNC_CMAP_H
|
#undef HAVE_COROSYNC_CMAP_H
|
||||||
|
|
||||||
@@ -138,6 +185,10 @@
|
|||||||
/* Define to 1 if you have the <ctype.h> header file. */
|
/* Define to 1 if you have the <ctype.h> header file. */
|
||||||
#undef HAVE_CTYPE_H
|
#undef HAVE_CTYPE_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
|
||||||
|
don't. */
|
||||||
|
#undef HAVE_DECL_STRERROR_R
|
||||||
|
|
||||||
/* Define to 1 if you have the <dirent.h> header file. */
|
/* Define to 1 if you have the <dirent.h> header file. */
|
||||||
#undef HAVE_DIRENT_H
|
#undef HAVE_DIRENT_H
|
||||||
|
|
||||||
@@ -156,6 +207,9 @@
|
|||||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||||
#undef HAVE_FCNTL_H
|
#undef HAVE_FCNTL_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <float.h> header file. */
|
||||||
|
#undef HAVE_FLOAT_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `fork' function. */
|
/* Define to 1 if you have the `fork' function. */
|
||||||
#undef HAVE_FORK
|
#undef HAVE_FORK
|
||||||
|
|
||||||
@@ -213,6 +267,9 @@
|
|||||||
/* Define to 1 if you have the <locale.h> header file. */
|
/* Define to 1 if you have the <locale.h> header file. */
|
||||||
#undef HAVE_LOCALE_H
|
#undef HAVE_LOCALE_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `localtime_r' function. */
|
||||||
|
#undef HAVE_LOCALTIME_R
|
||||||
|
|
||||||
/* Define to 1 if `lstat' has the bug that it succeeds when given the
|
/* Define to 1 if `lstat' has the bug that it succeeds when given the
|
||||||
zero-length file name argument. */
|
zero-length file name argument. */
|
||||||
#undef HAVE_LSTAT_EMPTY_STRING_BUG
|
#undef HAVE_LSTAT_EMPTY_STRING_BUG
|
||||||
@@ -227,6 +284,9 @@
|
|||||||
/* Define to 1 if you have the <malloc.h> header file. */
|
/* Define to 1 if you have the <malloc.h> header file. */
|
||||||
#undef HAVE_MALLOC_H
|
#undef HAVE_MALLOC_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `memchr' function. */
|
||||||
|
#undef HAVE_MEMCHR
|
||||||
|
|
||||||
/* Define to 1 if you have the `memmove' function. */
|
/* Define to 1 if you have the `memmove' function. */
|
||||||
#undef HAVE_MEMMOVE
|
#undef HAVE_MEMMOVE
|
||||||
|
|
||||||
@@ -263,9 +323,15 @@
|
|||||||
/* Define to 1 if you have the `nl_langinfo' function. */
|
/* Define to 1 if you have the `nl_langinfo' function. */
|
||||||
#undef HAVE_NL_LANGINFO
|
#undef HAVE_NL_LANGINFO
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <paths.h> header file. */
|
||||||
|
#undef HAVE_PATHS_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <pthread.h> header file. */
|
/* Define to 1 if you have the <pthread.h> header file. */
|
||||||
#undef HAVE_PTHREAD_H
|
#undef HAVE_PTHREAD_H
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||||
|
#undef HAVE_PTRDIFF_T
|
||||||
|
|
||||||
/* Define to 1 if you have the <readline/history.h> header file. */
|
/* Define to 1 if you have the <readline/history.h> header file. */
|
||||||
#undef HAVE_READLINE_HISTORY_H
|
#undef HAVE_READLINE_HISTORY_H
|
||||||
|
|
||||||
@@ -276,6 +342,9 @@
|
|||||||
and to 0 otherwise. */
|
and to 0 otherwise. */
|
||||||
#undef HAVE_REALLOC
|
#undef HAVE_REALLOC
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `realpath' function. */
|
||||||
|
#undef HAVE_REALPATH
|
||||||
|
|
||||||
/* Define to 1 to include support for realtime clock. */
|
/* Define to 1 to include support for realtime clock. */
|
||||||
#undef HAVE_REALTIME
|
#undef HAVE_REALTIME
|
||||||
|
|
||||||
@@ -319,9 +388,15 @@
|
|||||||
zero-length file name argument. */
|
zero-length file name argument. */
|
||||||
#undef HAVE_STAT_EMPTY_STRING_BUG
|
#undef HAVE_STAT_EMPTY_STRING_BUG
|
||||||
|
|
||||||
|
/* Define if struct stat has a field st_ctim with timespec for ctime */
|
||||||
|
#undef HAVE_STAT_ST_CTIM
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||||
#undef HAVE_STDARG_H
|
#undef HAVE_STDARG_H
|
||||||
|
|
||||||
|
/* Define to 1 if stdbool.h conforms to C99. */
|
||||||
|
#undef HAVE_STDBOOL_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <stddef.h> header file. */
|
/* Define to 1 if you have the <stddef.h> header file. */
|
||||||
#undef HAVE_STDDEF_H
|
#undef HAVE_STDDEF_H
|
||||||
|
|
||||||
@@ -349,6 +424,9 @@
|
|||||||
/* Define to 1 if you have the `strerror' function. */
|
/* Define to 1 if you have the `strerror' function. */
|
||||||
#undef HAVE_STRERROR
|
#undef HAVE_STRERROR
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strerror_r' function. */
|
||||||
|
#undef HAVE_STRERROR_R
|
||||||
|
|
||||||
/* Define to 1 if you have the <strings.h> header file. */
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
#undef HAVE_STRINGS_H
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
@@ -358,6 +436,12 @@
|
|||||||
/* Define to 1 if you have the `strncasecmp' function. */
|
/* Define to 1 if you have the `strncasecmp' function. */
|
||||||
#undef HAVE_STRNCASECMP
|
#undef HAVE_STRNCASECMP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strndup' function. */
|
||||||
|
#undef HAVE_STRNDUP
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strpbrk' function. */
|
||||||
|
#undef HAVE_STRPBRK
|
||||||
|
|
||||||
/* Define to 1 if you have the `strrchr' function. */
|
/* Define to 1 if you have the `strrchr' function. */
|
||||||
#undef HAVE_STRRCHR
|
#undef HAVE_STRRCHR
|
||||||
|
|
||||||
@@ -373,6 +457,9 @@
|
|||||||
/* Define to 1 if you have the `strtoul' function. */
|
/* Define to 1 if you have the `strtoul' function. */
|
||||||
#undef HAVE_STRTOUL
|
#undef HAVE_STRTOUL
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `strtoull' function. */
|
||||||
|
#undef HAVE_STRTOULL
|
||||||
|
|
||||||
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
||||||
#undef HAVE_STRUCT_STAT_ST_RDEV
|
#undef HAVE_STRUCT_STAT_ST_RDEV
|
||||||
|
|
||||||
@@ -426,6 +513,9 @@
|
|||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
#undef HAVE_SYS_STAT_H
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/timerfd.h> header file. */
|
||||||
|
#undef HAVE_SYS_TIMERFD_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||||
#undef HAVE_SYS_TIME_H
|
#undef HAVE_SYS_TIME_H
|
||||||
|
|
||||||
@@ -459,6 +549,9 @@
|
|||||||
/* Define to 1 if you have the <utmpx.h> header file. */
|
/* Define to 1 if you have the <utmpx.h> header file. */
|
||||||
#undef HAVE_UTMPX_H
|
#undef HAVE_UTMPX_H
|
||||||
|
|
||||||
|
/* valgrind.h found */
|
||||||
|
#undef HAVE_VALGRIND
|
||||||
|
|
||||||
/* Define to 1 if you have the `vfork' function. */
|
/* Define to 1 if you have the `vfork' function. */
|
||||||
#undef HAVE_VFORK
|
#undef HAVE_VFORK
|
||||||
|
|
||||||
@@ -474,6 +567,21 @@
|
|||||||
/* Define to 1 if `vfork' works. */
|
/* Define to 1 if `vfork' works. */
|
||||||
#undef HAVE_WORKING_VFORK
|
#undef HAVE_WORKING_VFORK
|
||||||
|
|
||||||
|
/* Define to 1 if the system has the type `_Bool'. */
|
||||||
|
#undef HAVE__BOOL
|
||||||
|
|
||||||
|
/* Internalization package */
|
||||||
|
#undef INTL_PACKAGE
|
||||||
|
|
||||||
|
/* Locale-dependent data */
|
||||||
|
#undef LOCALEDIR
|
||||||
|
|
||||||
|
/* Define to 1 to include code that uses lvmlockd dlm option. */
|
||||||
|
#undef LOCKDDLM_SUPPORT
|
||||||
|
|
||||||
|
/* Define to 1 to include code that uses lvmlockd sanlock option. */
|
||||||
|
#undef LOCKDSANLOCK_SUPPORT
|
||||||
|
|
||||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||||
slash. */
|
slash. */
|
||||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||||
@@ -491,6 +599,18 @@
|
|||||||
/* Define to 1 to include code that uses lvmetad. */
|
/* Define to 1 to include code that uses lvmetad. */
|
||||||
#undef LVMETAD_SUPPORT
|
#undef LVMETAD_SUPPORT
|
||||||
|
|
||||||
|
/* Path to lvmlockd pidfile. */
|
||||||
|
#undef LVMLOCKD_PIDFILE
|
||||||
|
|
||||||
|
/* Define to 1 to include code that uses lvmlockd. */
|
||||||
|
#undef LVMLOCKD_SUPPORT
|
||||||
|
|
||||||
|
/* Path to lvmpolld pidfile. */
|
||||||
|
#undef LVMPOLLD_PIDFILE
|
||||||
|
|
||||||
|
/* Define to 1 to include code that uses lvmpolld. */
|
||||||
|
#undef LVMPOLLD_SUPPORT
|
||||||
|
|
||||||
/* Path to lvm binary. */
|
/* Path to lvm binary. */
|
||||||
#undef LVM_PATH
|
#undef LVM_PATH
|
||||||
|
|
||||||
@@ -567,6 +687,12 @@
|
|||||||
/* Define to 1 if you have the ANSI C header files. */
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
#undef STDC_HEADERS
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Define to 1 if strerror_r returns char *. */
|
||||||
|
#undef STRERROR_R_CHAR_P
|
||||||
|
|
||||||
|
/* Path to testsuite data */
|
||||||
|
#undef TESTSUITE_DATA
|
||||||
|
|
||||||
/* The path to 'thin_check', if available. */
|
/* The path to 'thin_check', if available. */
|
||||||
#undef THIN_CHECK_CMD
|
#undef THIN_CHECK_CMD
|
||||||
|
|
||||||
@@ -56,11 +56,13 @@ SOURCES =\
|
|||||||
datastruct/btree.c \
|
datastruct/btree.c \
|
||||||
datastruct/str_list.c \
|
datastruct/str_list.c \
|
||||||
device/dev-cache.c \
|
device/dev-cache.c \
|
||||||
|
device/dev-ext.c \
|
||||||
device/dev-io.c \
|
device/dev-io.c \
|
||||||
device/dev-md.c \
|
device/dev-md.c \
|
||||||
device/dev-swap.c \
|
device/dev-swap.c \
|
||||||
device/dev-type.c \
|
device/dev-type.c \
|
||||||
device/dev-luks.c \
|
device/dev-luks.c \
|
||||||
|
device/dev-dasd.c \
|
||||||
display/display.c \
|
display/display.c \
|
||||||
error/errseg.c \
|
error/errseg.c \
|
||||||
unknown/unknown.c \
|
unknown/unknown.c \
|
||||||
@@ -69,6 +71,7 @@ SOURCES =\
|
|||||||
filters/filter-regex.c \
|
filters/filter-regex.c \
|
||||||
filters/filter-sysfs.c \
|
filters/filter-sysfs.c \
|
||||||
filters/filter-md.c \
|
filters/filter-md.c \
|
||||||
|
filters/filter-fwraid.c \
|
||||||
filters/filter-mpath.c \
|
filters/filter-mpath.c \
|
||||||
filters/filter-partitioned.c \
|
filters/filter-partitioned.c \
|
||||||
filters/filter-type.c \
|
filters/filter-type.c \
|
||||||
@@ -80,7 +83,6 @@ SOURCES =\
|
|||||||
format_text/format-text.c \
|
format_text/format-text.c \
|
||||||
format_text/import.c \
|
format_text/import.c \
|
||||||
format_text/import_vsn1.c \
|
format_text/import_vsn1.c \
|
||||||
format_text/tags.c \
|
|
||||||
format_text/text_label.c \
|
format_text/text_label.c \
|
||||||
freeseg/freeseg.c \
|
freeseg/freeseg.c \
|
||||||
label/label.c \
|
label/label.c \
|
||||||
@@ -121,11 +123,6 @@ SOURCES =\
|
|||||||
uuid/uuid.c \
|
uuid/uuid.c \
|
||||||
zero/zero.c
|
zero/zero.c
|
||||||
|
|
||||||
ifeq ("@HAVE_REALTIME@", "yes")
|
|
||||||
SOURCES +=\
|
|
||||||
misc/timestamp.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ("@LVM1@", "internal")
|
ifeq ("@LVM1@", "internal")
|
||||||
SOURCES +=\
|
SOURCES +=\
|
||||||
format1/disk-rep.c \
|
format1/disk-rep.c \
|
||||||
@@ -194,6 +191,16 @@ ifeq ("@BUILD_LVMETAD@", "yes")
|
|||||||
cache/lvmetad.c
|
cache/lvmetad.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||||
|
SOURCES +=\
|
||||||
|
lvmpolld/lvmpolld-client.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LVMLOCKD@", "yes")
|
||||||
|
SOURCES +=\
|
||||||
|
locking/lvmlockd.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ("@DMEVENTD@", "yes")
|
ifeq ("@DMEVENTD@", "yes")
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
|
||||||
LIBS += -ldevmapper-event
|
LIBS += -ldevmapper-event
|
||||||
@@ -220,8 +227,8 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
|||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS)
|
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
|
||||||
|
|
||||||
$(SUBDIRS): $(LIB_STATIC)
|
$(SUBDIRS): $(LIB_STATIC)
|
||||||
|
|
||||||
DISTCLEAN_TARGETS += misc/configure.h misc/lvm-version.h
|
CLEAN_TARGETS += misc/configure.h misc/lvm-version.h
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_vol
|
|||||||
{
|
{
|
||||||
const struct dm_config_node *cn;
|
const struct dm_config_node *cn;
|
||||||
|
|
||||||
if (!(cn = find_config_tree_node(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
|
if (!(cn = find_config_tree_array(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
|
||||||
log_verbose("activation/auto_activation_volume_list configuration setting "
|
log_verbose("activation/auto_activation_volume_list configuration setting "
|
||||||
"not defined: All logical volumes will be auto-activated.");
|
"not defined: All logical volumes will be auto-activated.");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -238,6 +238,22 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||||
|
const struct lv_segment *lv_seg, int use_layer,
|
||||||
|
struct lv_with_info_and_seg_status *status,
|
||||||
|
int with_open_count, int with_read_ahead)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
|
||||||
|
int use_layer, struct lv_seg_status *lv_seg_status)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_cache_status(const struct logical_volume *cache_lv,
|
||||||
|
struct lv_status_cache **status)
|
||||||
|
{
|
||||||
|
}
|
||||||
int lv_check_not_in_use(const struct logical_volume *lv)
|
int lv_check_not_in_use(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -451,7 +467,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
|||||||
{
|
{
|
||||||
const struct dm_config_node *cn;
|
const struct dm_config_node *cn;
|
||||||
|
|
||||||
if (!(cn = find_config_tree_node(cmd, activation_volume_list_CFG, NULL))) {
|
if (!(cn = find_config_tree_array(cmd, activation_volume_list_CFG, NULL))) {
|
||||||
log_verbose("activation/volume_list configuration setting "
|
log_verbose("activation/volume_list configuration setting "
|
||||||
"not defined: Checking only host tags for %s/%s",
|
"not defined: Checking only host tags for %s/%s",
|
||||||
lv->vg->name, lv->name);
|
lv->vg->name, lv->name);
|
||||||
@@ -480,7 +496,7 @@ static int _passes_readonly_filter(struct cmd_context *cmd,
|
|||||||
{
|
{
|
||||||
const struct dm_config_node *cn;
|
const struct dm_config_node *cn;
|
||||||
|
|
||||||
if (!(cn = find_config_tree_node(cmd, activation_read_only_volume_list_CFG, NULL)))
|
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
|
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
|
||||||
@@ -618,7 +634,9 @@ int target_present(struct cmd_context *cmd, const char *target_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||||
int use_layer, struct lvinfo *info, struct lv_seg_status *seg_status,
|
int use_layer, struct lvinfo *info,
|
||||||
|
const struct lv_segment *seg,
|
||||||
|
struct lv_seg_status *seg_status,
|
||||||
int with_open_count, int with_read_ahead)
|
int with_open_count, int with_read_ahead)
|
||||||
{
|
{
|
||||||
struct dm_info dminfo;
|
struct dm_info dminfo;
|
||||||
@@ -630,15 +648,23 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
|||||||
* in progress - as only those could lead to opened files
|
* in progress - as only those could lead to opened files
|
||||||
*/
|
*/
|
||||||
if (with_open_count) {
|
if (with_open_count) {
|
||||||
if (locking_is_clustered())
|
if (locking_is_clustered() && !sync_local_dev_names(cmd)) /* Wait to have udev in sync */
|
||||||
sync_local_dev_names(cmd); /* Wait to have udev in sync */
|
return_0;
|
||||||
else if (fs_has_non_delete_ops())
|
else if (fs_has_non_delete_ops())
|
||||||
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
|
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* New thin-pool has no layer, but -tpool suffix needs to be queried */
|
/* New thin-pool has no layer, but -tpool suffix needs to be queried */
|
||||||
if (!use_layer && lv_is_new_thin_pool(lv))
|
if (!use_layer && lv_is_new_thin_pool(lv)) {
|
||||||
use_layer = 1;
|
/* Check if there isn't existing old thin pool mapping in the table */
|
||||||
|
if (!dev_manager_info(cmd->mem, lv, NULL, 0, 0, &dminfo, NULL, NULL))
|
||||||
|
return_0;
|
||||||
|
if (!dminfo.exists)
|
||||||
|
use_layer = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seg_status)
|
||||||
|
seg_status->seg = seg;
|
||||||
|
|
||||||
if (!dev_manager_info(cmd->mem, lv,
|
if (!dev_manager_info(cmd->mem, lv,
|
||||||
(use_layer) ? lv_layer(lv) : NULL,
|
(use_layer) ? lv_layer(lv) : NULL,
|
||||||
@@ -672,7 +698,7 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_la
|
|||||||
if (!activation())
|
if (!activation())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return _lv_info(cmd, lv, use_layer, info, NULL, with_open_count, with_read_ahead);
|
return _lv_info(cmd, lv, use_layer, info, NULL, NULL, with_open_count, with_read_ahead);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||||
@@ -690,19 +716,45 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
/*
|
||||||
const struct lv_segment *lv_seg, int use_layer,
|
* Returns 1 if lv_seg_status structure populated,
|
||||||
struct lv_with_info_and_seg_status *lvdm,
|
* else 0 on failure or if device not active locally.
|
||||||
int with_open_count, int with_read_ahead)
|
*/
|
||||||
|
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
|
||||||
|
int use_layer, struct lv_seg_status *lv_seg_status)
|
||||||
{
|
{
|
||||||
if (!activation())
|
if (!activation())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!_lv_info(cmd, lv, use_layer, lvdm->info, lvdm->seg_status,
|
return _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, lv_seg_status, 0, 0);
|
||||||
with_open_count, with_read_ahead))
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if lv_with_info_and_seg_status structure populated,
|
||||||
|
* else 0 on failure or if device not active locally.
|
||||||
|
*
|
||||||
|
* This is the same as calling lv_info and lv_status,
|
||||||
|
* but* it's done in one go with one ioctl if possible! ]
|
||||||
|
*/
|
||||||
|
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||||
|
const struct lv_segment *lv_seg, int use_layer,
|
||||||
|
struct lv_with_info_and_seg_status *status,
|
||||||
|
int with_open_count, int with_read_ahead)
|
||||||
|
{
|
||||||
|
if (!activation())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
if (lv == lv_seg->lv)
|
||||||
|
return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
|
||||||
|
with_open_count, with_read_ahead);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the info is requested for an LV and segment
|
||||||
|
* status for segment that belong to another LV,
|
||||||
|
* we need to acquire info and status separately!
|
||||||
|
*/
|
||||||
|
return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
|
||||||
|
_lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OPEN_COUNT_CHECK_RETRIES 25
|
#define OPEN_COUNT_CHECK_RETRIES 25
|
||||||
@@ -1713,6 +1765,19 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data)
|
|||||||
struct detached_lv_data *detached = data;
|
struct detached_lv_data *detached = data;
|
||||||
struct lv_list *lvl_pre;
|
struct lv_list *lvl_pre;
|
||||||
|
|
||||||
|
/* Check and preload removed raid image leg or metadata */
|
||||||
|
if (lv_is_raid_image(lv)) {
|
||||||
|
if ((lvl_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) &&
|
||||||
|
!lv_is_raid_image(lvl_pre->lv) && lv_is_active(lv) &&
|
||||||
|
!_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required))
|
||||||
|
return_0;
|
||||||
|
} else if (lv_is_raid_metadata(lv)) {
|
||||||
|
if ((lvl_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) &&
|
||||||
|
!lv_is_raid_metadata(lvl_pre->lv) && lv_is_active(lv) &&
|
||||||
|
!_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required))
|
||||||
|
return_0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((lvl_pre = find_lv_in_vg(detached->lv_pre->vg, lv->name))) {
|
if ((lvl_pre = find_lv_in_vg(detached->lv_pre->vg, lv->name))) {
|
||||||
if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) &&
|
if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) &&
|
||||||
(!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) &&
|
(!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) &&
|
||||||
@@ -1748,7 +1813,9 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
|||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
/* Ignore origin_only unless LV is origin in both old and new metadata */
|
/* Ignore origin_only unless LV is origin in both old and new metadata */
|
||||||
if (!lv_is_thin_volume(ondisk_lv) && !(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
|
/* or LV is thin or thin pool volume */
|
||||||
|
if (!lv_is_thin_volume(ondisk_lv) && !lv_is_thin_pool(ondisk_lv) &&
|
||||||
|
!(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
|
||||||
laopts->origin_only = 0;
|
laopts->origin_only = 0;
|
||||||
|
|
||||||
if (test_mode()) {
|
if (test_mode()) {
|
||||||
@@ -1922,7 +1989,6 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
|||||||
const struct logical_volume *lv_to_free = NULL;
|
const struct logical_volume *lv_to_free = NULL;
|
||||||
struct lvinfo info;
|
struct lvinfo info;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int messages_only = 0;
|
|
||||||
|
|
||||||
if (!activation())
|
if (!activation())
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1930,10 +1996,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
|||||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (lv_is_thin_pool(lv) && laopts->origin_only)
|
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
|
||||||
messages_only = 1;
|
|
||||||
|
|
||||||
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv))
|
|
||||||
laopts->origin_only = 0;
|
laopts->origin_only = 0;
|
||||||
|
|
||||||
if (test_mode()) {
|
if (test_mode()) {
|
||||||
@@ -1945,13 +2008,15 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
|||||||
|
|
||||||
log_debug_activation("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
|
log_debug_activation("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
|
||||||
error_if_not_active ? "" : " if active",
|
error_if_not_active ? "" : " if active",
|
||||||
laopts->origin_only ? " without snapshots" : "",
|
laopts->origin_only ?
|
||||||
|
(lv_is_thin_pool(lv) ? " pool only" :
|
||||||
|
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
|
||||||
laopts->revert ? " (reverting)" : "");
|
laopts->revert ? " (reverting)" : "");
|
||||||
|
|
||||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (!info.exists || !(info.suspended || messages_only)) {
|
if (!info.exists || !info.suspended) {
|
||||||
if (error_if_not_active)
|
if (error_if_not_active)
|
||||||
goto_out;
|
goto_out;
|
||||||
r = 1;
|
r = 1;
|
||||||
@@ -2173,6 +2238,16 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if cmirrord is running for clustered mirrors.
|
||||||
|
*/
|
||||||
|
if (!laopts->exclusive && vg_is_clustered(lv->vg) &&
|
||||||
|
lv_is_mirror(lv) && !lv_is_raid(lv) &&
|
||||||
|
!cluster_mirror_is_available(lv->vg->cmd)) {
|
||||||
|
log_error("Shared cluster mirrors are not available.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (test_mode()) {
|
if (test_mode()) {
|
||||||
_skip("Activating '%s'.", lv->name);
|
_skip("Activating '%s'.", lv->name);
|
||||||
r = 1;
|
r = 1;
|
||||||
@@ -2197,6 +2272,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
|||||||
if (info.exists && !info.suspended && info.live_table &&
|
if (info.exists && !info.suspended && info.live_table &&
|
||||||
(info.read_only == read_only_lv(lv, laopts))) {
|
(info.read_only == read_only_lv(lv, laopts))) {
|
||||||
r = 1;
|
r = 1;
|
||||||
|
log_debug_activation("Volume is already active.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,21 +36,29 @@ typedef enum {
|
|||||||
SEG_STATUS_RAID,
|
SEG_STATUS_RAID,
|
||||||
SEG_STATUS_SNAPSHOT,
|
SEG_STATUS_SNAPSHOT,
|
||||||
SEG_STATUS_THIN,
|
SEG_STATUS_THIN,
|
||||||
SEG_STATUS_THIN_POOL
|
SEG_STATUS_THIN_POOL,
|
||||||
|
SEG_STATUS_UNKNOWN
|
||||||
} lv_seg_status_type_t;
|
} lv_seg_status_type_t;
|
||||||
|
|
||||||
struct lv_seg_status {
|
struct lv_seg_status {
|
||||||
struct dm_pool *mem; /* input */
|
struct dm_pool *mem; /* input */
|
||||||
struct lv_segment *seg; /* input */
|
const struct lv_segment *seg; /* input */
|
||||||
lv_seg_status_type_t type; /* output */
|
lv_seg_status_type_t type; /* output */
|
||||||
void *status; /* struct dm_status_* */ /* output */
|
union {
|
||||||
|
struct dm_status_cache *cache;
|
||||||
|
struct dm_status_raid *raid;
|
||||||
|
struct dm_status_snapshot *snapshot;
|
||||||
|
struct dm_status_thin *thin;
|
||||||
|
struct dm_status_thin_pool *thin_pool;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lv_with_info_and_seg_status {
|
struct lv_with_info_and_seg_status {
|
||||||
struct logical_volume *lv; /* input */
|
const struct logical_volume *lv; /* input */
|
||||||
struct lvinfo *info; /* output */
|
int info_ok;
|
||||||
|
struct lvinfo info; /* output */
|
||||||
int seg_part_of_lv; /* output */
|
int seg_part_of_lv; /* output */
|
||||||
struct lv_seg_status *seg_status; /* input/output, see lv_seg_status */
|
struct lv_seg_status seg_status; /* input/output, see lv_seg_status */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lv_activate_opts {
|
struct lv_activate_opts {
|
||||||
@@ -111,16 +119,31 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
|||||||
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
|
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if info structure has been populated, else 0.
|
* Returns 1 if info structure has been populated, else 0 on failure.
|
||||||
|
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
|
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
|
||||||
struct lvinfo *info, int with_open_count, int with_read_ahead);
|
struct lvinfo *info, int with_open_count, int with_read_ahead);
|
||||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||||
struct lvinfo *info, int with_open_count, int with_read_ahead);
|
struct lvinfo *info, int with_open_count, int with_read_ahead);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if lv_seg_status structure has been populated,
|
||||||
|
* else 0 on failure or if device not active locally.
|
||||||
|
*/
|
||||||
|
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
|
||||||
|
int use_layer, struct lv_seg_status *lv_seg_status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if lv_info_and_seg_status structure has been populated,
|
||||||
|
* else 0 on failure or if device not active locally.
|
||||||
|
*
|
||||||
|
* lv_info_with_seg_status is the same as calling lv_info and then lv_status,
|
||||||
|
* but this fn tries to do that with one ioctl if possible.
|
||||||
|
*/
|
||||||
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||||
const struct lv_segment *lv_seg, int use_layer,
|
const struct lv_segment *lv_seg, int use_layer,
|
||||||
struct lv_with_info_and_seg_status *lvdm,
|
struct lv_with_info_and_seg_status *status,
|
||||||
int with_open_count, int with_read_ahead);
|
int with_open_count, int with_read_ahead);
|
||||||
|
|
||||||
int lv_check_not_in_use(const struct logical_volume *lv);
|
int lv_check_not_in_use(const struct logical_volume *lv);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "activate.h"
|
#include "activate.h"
|
||||||
#include "lvm-exec.h"
|
#include "lvm-exec.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@@ -44,6 +45,12 @@ typedef enum {
|
|||||||
/* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
|
/* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
|
||||||
const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "tdata", "tmeta", NULL};
|
const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "tdata", "tmeta", NULL};
|
||||||
|
|
||||||
|
struct dlid_list {
|
||||||
|
struct dm_list list;
|
||||||
|
const char *dlid;
|
||||||
|
const struct logical_volume *lv;
|
||||||
|
};
|
||||||
|
|
||||||
struct dev_manager {
|
struct dev_manager {
|
||||||
struct dm_pool *mem;
|
struct dm_pool *mem;
|
||||||
|
|
||||||
@@ -53,7 +60,10 @@ struct dev_manager {
|
|||||||
uint32_t pvmove_mirror_count;
|
uint32_t pvmove_mirror_count;
|
||||||
int flush_required;
|
int flush_required;
|
||||||
int activation; /* building activation tree */
|
int activation; /* building activation tree */
|
||||||
|
int suspend; /* building suspend tree */
|
||||||
int skip_external_lv;
|
int skip_external_lv;
|
||||||
|
struct dm_list pending_delete; /* str_list of dlid(s) with pending delete */
|
||||||
|
unsigned track_pending_delete;
|
||||||
unsigned track_pvmove_deps;
|
unsigned track_pvmove_deps;
|
||||||
|
|
||||||
char *vg_name;
|
char *vg_name;
|
||||||
@@ -112,6 +122,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
|||||||
{
|
{
|
||||||
struct segment_type *segtype;
|
struct segment_type *segtype;
|
||||||
|
|
||||||
|
seg_status->type = SEG_STATUS_UNKNOWN;
|
||||||
/*
|
/*
|
||||||
* TODO: Add support for other segment types too!
|
* TODO: Add support for other segment types too!
|
||||||
* The segment to report status for must be properly
|
* The segment to report status for must be properly
|
||||||
@@ -119,10 +130,11 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
|||||||
* linear/striped, old snapshots and raids have proper
|
* linear/striped, old snapshots and raids have proper
|
||||||
* segment selected for status!
|
* segment selected for status!
|
||||||
*/
|
*/
|
||||||
if (strcmp(target_name, "cache"))
|
if (strcmp(target_name, "cache") && strcmp(target_name, "thin-pool"))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, target_name);
|
if (!(segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, target_name)))
|
||||||
|
return_0;
|
||||||
|
|
||||||
if (segtype != seg_status->seg->segtype) {
|
if (segtype != seg_status->seg->segtype) {
|
||||||
log_error(INTERNAL_ERROR "_get_segment_status_from_target_params: "
|
log_error(INTERNAL_ERROR "_get_segment_status_from_target_params: "
|
||||||
@@ -131,31 +143,29 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(segtype->name, "cache")) {
|
if (segtype_is_cache(segtype)) {
|
||||||
if (!dm_get_status_cache(seg_status->mem, params,
|
if (!dm_get_status_cache(seg_status->mem, params, &(seg_status->cache)))
|
||||||
(struct dm_status_cache **) &seg_status->status))
|
return_0;
|
||||||
return_0;
|
seg_status->type = SEG_STATUS_CACHE;
|
||||||
seg_status->type = SEG_STATUS_CACHE;
|
} else if (segtype_is_raid(segtype)) {
|
||||||
} else if (!strcmp(segtype->name, "raid")) {
|
if (!dm_get_status_raid(seg_status->mem, params, &seg_status->raid))
|
||||||
if (!dm_get_status_raid(seg_status->mem, params,
|
return_0;
|
||||||
(struct dm_status_raid **) &seg_status->status))
|
seg_status->type = SEG_STATUS_RAID;
|
||||||
return_0;
|
} else if (segtype_is_thin_volume(segtype)) {
|
||||||
seg_status->type = SEG_STATUS_RAID;
|
if (!dm_get_status_thin(seg_status->mem, params, &seg_status->thin))
|
||||||
} else if (!strcmp(segtype->name, "thin")) {
|
return_0;
|
||||||
if (!dm_get_status_thin(seg_status->mem, params,
|
seg_status->type = SEG_STATUS_THIN;
|
||||||
(struct dm_status_thin **) &seg_status->status))
|
} else if (segtype_is_thin_pool(segtype)) {
|
||||||
return_0;
|
if (!dm_get_status_thin_pool(seg_status->mem, params, &seg_status->thin_pool))
|
||||||
seg_status->type = SEG_STATUS_THIN;
|
return_0;
|
||||||
} else if (!strcmp(segtype->name, "thin-pool")) {
|
seg_status->type = SEG_STATUS_THIN_POOL;
|
||||||
if (!dm_get_status_thin_pool(seg_status->mem, params,
|
} else if (segtype_is_snapshot(segtype)) {
|
||||||
(struct dm_status_thin_pool **) &seg_status->status))
|
if (!dm_get_status_snapshot(seg_status->mem, params, &seg_status->snapshot))
|
||||||
return_0;
|
return_0;
|
||||||
seg_status->type = SEG_STATUS_THIN_POOL;
|
|
||||||
} else if (!strcmp(segtype->name, "snapshot")) {
|
|
||||||
if (!dm_get_status_snapshot(seg_status->mem, params,
|
|
||||||
(struct dm_status_snapshot **) &seg_status->status))
|
|
||||||
return_0;
|
|
||||||
seg_status->type = SEG_STATUS_SNAPSHOT;
|
seg_status->type = SEG_STATUS_SNAPSHOT;
|
||||||
|
} else {
|
||||||
|
log_error(INTERNAL_ERROR "Unsupported segment type %s.", segtype->name);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -191,9 +201,12 @@ static int _info_run(info_type_t type, const char *name, const char *dlid,
|
|||||||
case MKNODES:
|
case MKNODES:
|
||||||
dmtask = DM_DEVICE_MKNODES;
|
dmtask = DM_DEVICE_MKNODES;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
log_error(INTERNAL_ERROR "_info_run: unhandled info type");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(dmt = _setup_task(type != MKNODES ? name : NULL, dlid, 0, dmtask,
|
if (!(dmt = _setup_task((type == MKNODES) ? name : NULL, dlid, 0, dmtask,
|
||||||
major, minor, with_open_count)))
|
major, minor, with_open_count)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
@@ -214,8 +227,8 @@ static int _info_run(info_type_t type, const char *name, const char *dlid,
|
|||||||
do {
|
do {
|
||||||
target = dm_get_next_target(dmt, target, &target_start,
|
target = dm_get_next_target(dmt, target, &target_start,
|
||||||
&target_length, &target_name, &target_params);
|
&target_length, &target_name, &target_params);
|
||||||
if ((seg_status->seg->le * extent_size == target_start) &&
|
if (((uint64_t) seg_status->seg->le * extent_size == target_start) &&
|
||||||
(seg_status->seg->len * extent_size == target_length)) {
|
((uint64_t) seg_status->seg->len * extent_size == target_length)) {
|
||||||
params_to_process = target_params;
|
params_to_process = target_params;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -433,6 +446,145 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _device_is_suspended(int major, int minor)
|
||||||
|
{
|
||||||
|
struct dm_task *dmt;
|
||||||
|
struct dm_info info;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!dm_task_set_major_minor(dmt, major, minor, 1))
|
||||||
|
goto_out;
|
||||||
|
|
||||||
|
if (activation_checks() && !dm_task_enable_checks(dmt))
|
||||||
|
goto_out;
|
||||||
|
|
||||||
|
if (!dm_task_run(dmt) ||
|
||||||
|
!dm_task_get_info(dmt, &info)) {
|
||||||
|
log_error("Failed to get info for device %d:%d", major, minor);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = info.exists && info.suspended;
|
||||||
|
out:
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _ignore_suspended_snapshot_component(struct device *dev)
|
||||||
|
{
|
||||||
|
struct dm_task *dmt;
|
||||||
|
void *next = NULL;
|
||||||
|
char *params, *target_type = NULL;
|
||||||
|
uint64_t start, length;
|
||||||
|
int major1, minor1, major2, minor2;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
|
||||||
|
goto_out;
|
||||||
|
|
||||||
|
if (activation_checks() && !dm_task_enable_checks(dmt))
|
||||||
|
goto_out;
|
||||||
|
|
||||||
|
if (!dm_task_run(dmt)) {
|
||||||
|
log_error("Failed to get state of snapshot or snapshot origin device");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
|
if (!strcmp(target_type, "snapshot")) {
|
||||||
|
if (sscanf(params, "%d:%d %d:%d", &major1, &minor1, &major2, &minor2) != 4) {
|
||||||
|
log_error("Incorrect snapshot table found");
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
r = r || _device_is_suspended(major1, minor1) || _device_is_suspended(major2, minor2);
|
||||||
|
} else if (!strcmp(target_type, "snapshot-origin")) {
|
||||||
|
if (sscanf(params, "%d:%d", &major1, &minor1) != 2) {
|
||||||
|
log_error("Incorrect snapshot-origin table found");
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
r = r || _device_is_suspended(major1, minor1);
|
||||||
|
}
|
||||||
|
} while (next);
|
||||||
|
|
||||||
|
out:
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _ignore_unusable_thins(struct device *dev)
|
||||||
|
{
|
||||||
|
/* TODO make function for thin testing */
|
||||||
|
struct dm_pool *mem;
|
||||||
|
struct dm_status_thin_pool *status;
|
||||||
|
struct dm_task *dmt = NULL;
|
||||||
|
void *next = NULL;
|
||||||
|
uint64_t start, length;
|
||||||
|
char *target_type = NULL;
|
||||||
|
char *params;
|
||||||
|
int minor, major;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (!(mem = dm_pool_create("unusable_thins", 128)))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
|
||||||
|
goto_out;
|
||||||
|
if (!dm_task_no_open_count(dmt))
|
||||||
|
goto_out;
|
||||||
|
if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
|
||||||
|
goto_out;
|
||||||
|
if (!dm_task_run(dmt)) {
|
||||||
|
log_error("Failed to get state of mapped device.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
|
if (sscanf(params, "%d:%d", &minor, &major) != 2) {
|
||||||
|
log_error("Failed to get thin-pool major:minor for thin device %d:%d.",
|
||||||
|
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
|
||||||
|
if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
|
||||||
|
goto_out;
|
||||||
|
if (!dm_task_no_flush(dmt))
|
||||||
|
log_warn("Can't set no_flush.");
|
||||||
|
if (!dm_task_no_open_count(dmt))
|
||||||
|
goto_out;
|
||||||
|
if (!dm_task_set_major_minor(dmt, minor, major, 1))
|
||||||
|
goto_out;
|
||||||
|
if (!dm_task_run(dmt)) {
|
||||||
|
log_error("Failed to get state of mapped device.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
|
if (!dm_get_status_thin_pool(mem, params, &status))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (status->read_only || status->out_of_data_space) {
|
||||||
|
log_warn("WARNING: %s: Thin's thin-pool needs inspection.",
|
||||||
|
dev_name(dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 1;
|
||||||
|
out:
|
||||||
|
if (dmt)
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
|
||||||
|
dm_pool_destroy(mem);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* device_is_usable
|
* device_is_usable
|
||||||
* @dev
|
* @dev
|
||||||
@@ -534,16 +686,37 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Snapshot origin could be sitting on top of a mirror which
|
* FIXME: Snapshot origin could be sitting on top of a mirror
|
||||||
* could be blocking I/O. Skip snapshot origins entirely for
|
* which could be blocking I/O. We should add a check for the
|
||||||
* now.
|
* stack here and see if there's blocked mirror underneath.
|
||||||
|
* Currently, mirrors used as origin or snapshot is not
|
||||||
|
* supported anymore and in general using mirrors in a stack
|
||||||
|
* is disabled by default (with a warning that if enabled,
|
||||||
|
* it could cause various deadlocks).
|
||||||
|
* Similar situation can happen with RAID devices where
|
||||||
|
* a RAID device can be snapshotted.
|
||||||
|
* If one of the RAID legs are down and we're doing
|
||||||
|
* lvconvert --repair, there's a time period in which
|
||||||
|
* snapshot components are (besides other devs) suspended.
|
||||||
|
* See also https://bugzilla.redhat.com/show_bug.cgi?id=1219222
|
||||||
|
* for an example where this causes problems.
|
||||||
*
|
*
|
||||||
* FIXME: rather than skipping origin, check if mirror is
|
* This is a quick check for now, but replace it with more
|
||||||
* underneath and if the mirror is blocking I/O.
|
* robust and better check that would check the stack
|
||||||
|
* correctly, not just snapshots but any cobimnation possible
|
||||||
|
* in a stack - use proper dm tree to check this instead.
|
||||||
*/
|
*/
|
||||||
if (check.check_suspended && target_type && !strcmp(target_type, "snapshot-origin")) {
|
if (check.check_suspended && target_type &&
|
||||||
log_debug_activation("%s: Snapshot-origin device %s not usable.",
|
(!strcmp(target_type, "snapshot") || !strcmp(target_type, "snapshot-origin")) &&
|
||||||
dev_name(dev), name);
|
_ignore_suspended_snapshot_component(dev)) {
|
||||||
|
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: extend check struct ? */
|
||||||
|
if (target_type && !strcmp(target_type, "thin") &&
|
||||||
|
!_ignore_unusable_thins(dev)) {
|
||||||
|
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,6 +1045,11 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
|||||||
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0, 0)))
|
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0, 0)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
|
/* No freeze on overfilled thin-pool, read existing slightly outdated data */
|
||||||
|
if (lv && lv_is_thin_pool(lv) &&
|
||||||
|
!dm_task_no_flush(dmt))
|
||||||
|
log_warn("Can't set no_flush flag."); /* Non fatal */
|
||||||
|
|
||||||
if (!dm_task_run(dmt))
|
if (!dm_task_run(dmt))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
@@ -939,7 +1117,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
|||||||
goto_out;
|
goto_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug_activation("LV percent: %f", dm_percent_to_float(*overall_percent));
|
log_debug_activation("LV percent: %.2f", dm_percent_to_float(*overall_percent));
|
||||||
r = 1;
|
r = 1;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1066,6 +1244,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
|||||||
|
|
||||||
dm_udev_set_sync_support(cmd->current_settings.udev_sync);
|
dm_udev_set_sync_support(cmd->current_settings.udev_sync);
|
||||||
|
|
||||||
|
dm_list_init(&dm->pending_delete);
|
||||||
|
|
||||||
return dm;
|
return dm;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
@@ -1723,6 +1903,12 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.exists && dm->track_pending_delete) {
|
||||||
|
log_debug_activation("Tracking pending delete for %s (%s).", lv->name, dlid);
|
||||||
|
if (!str_list_add(dm->mem, &dm->pending_delete, dlid))
|
||||||
|
return_0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1811,7 +1997,6 @@ struct pool_cb_data {
|
|||||||
int skip_zero; /* to skip zeroed device header (check first 64B) */
|
int skip_zero; /* to skip zeroed device header (check first 64B) */
|
||||||
int exec; /* which binary to call */
|
int exec; /* which binary to call */
|
||||||
int opts;
|
int opts;
|
||||||
const char *defaults;
|
|
||||||
const char *global;
|
const char *global;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1819,7 +2004,6 @@ static int _pool_callback(struct dm_tree_node *node,
|
|||||||
dm_node_callback_t type, void *cb_data)
|
dm_node_callback_t type, void *cb_data)
|
||||||
{
|
{
|
||||||
int ret, status, fd;
|
int ret, status, fd;
|
||||||
char *split;
|
|
||||||
const struct dm_config_node *cn;
|
const struct dm_config_node *cn;
|
||||||
const struct dm_config_value *cv;
|
const struct dm_config_value *cv;
|
||||||
const struct pool_cb_data *data = cb_data;
|
const struct pool_cb_data *data = cb_data;
|
||||||
@@ -1834,23 +2018,19 @@ static int _pool_callback(struct dm_tree_node *node,
|
|||||||
if (!*argv[0])
|
if (!*argv[0])
|
||||||
return 1; /* Checking disabled */
|
return 1; /* Checking disabled */
|
||||||
|
|
||||||
if ((cn = find_config_tree_node(mlv->vg->cmd, data->opts, NULL))) {
|
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
|
||||||
for (cv = cn->v; cv && args < 16; cv = cv->next) {
|
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
|
||||||
if (cv->type != DM_CFG_STRING) {
|
return 0;
|
||||||
log_error("Invalid string in config file: "
|
}
|
||||||
"global/%s_check_options",
|
|
||||||
data->global);
|
for (cv = cn->v; cv && args < 16; cv = cv->next) {
|
||||||
return 0;
|
if (cv->type != DM_CFG_STRING) {
|
||||||
}
|
log_error("Invalid string in config file: "
|
||||||
argv[++args] = cv->v.str;
|
"global/%s_check_options",
|
||||||
}
|
data->global);
|
||||||
} else {
|
|
||||||
/* Use default options (no support for options with spaces) */
|
|
||||||
if (!(split = dm_pool_strdup(data->dm->mem, data->defaults))) {
|
|
||||||
log_error("Failed to duplicate defaults.");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
args = dm_split_words(split, 16, 0, (char**) argv + 1);
|
argv[++args] = cv->v.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args == 16) {
|
if (args == 16) {
|
||||||
@@ -1871,6 +2051,8 @@ static int _pool_callback(struct dm_tree_node *node,
|
|||||||
/* let's assume there is no problem to read 64 bytes */
|
/* let's assume there is no problem to read 64 bytes */
|
||||||
if (read(fd, buf, sizeof(buf)) < sizeof(buf)) {
|
if (read(fd, buf, sizeof(buf)) < sizeof(buf)) {
|
||||||
log_sys_error("read", argv[args]);
|
log_sys_error("read", argv[args]);
|
||||||
|
if (close(fd))
|
||||||
|
log_sys_error("close", argv[args]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (ret = 0; ret < DM_ARRAY_SIZE(buf); ++ret)
|
for (ret = 0; ret < DM_ARRAY_SIZE(buf); ++ret)
|
||||||
@@ -1939,14 +2121,12 @@ static int _pool_register_callback(struct dev_manager *dm,
|
|||||||
data->skip_zero = 1;
|
data->skip_zero = 1;
|
||||||
data->exec = global_thin_check_executable_CFG;
|
data->exec = global_thin_check_executable_CFG;
|
||||||
data->opts = global_thin_check_options_CFG;
|
data->opts = global_thin_check_options_CFG;
|
||||||
data->defaults = DEFAULT_THIN_CHECK_OPTIONS;
|
|
||||||
data->global = "thin";
|
data->global = "thin";
|
||||||
} else if (lv_is_cache(lv)) { /* cache pool */
|
} else if (lv_is_cache(lv)) { /* cache pool */
|
||||||
data->pool_lv = first_seg(lv)->pool_lv;
|
data->pool_lv = first_seg(lv)->pool_lv;
|
||||||
data->skip_zero = dm->activation;
|
data->skip_zero = dm->activation;
|
||||||
data->exec = global_cache_check_executable_CFG;
|
data->exec = global_cache_check_executable_CFG;
|
||||||
data->opts = global_cache_check_options_CFG;
|
data->opts = global_cache_check_options_CFG;
|
||||||
data->defaults = DEFAULT_CACHE_CHECK_OPTIONS;
|
|
||||||
data->global = "cache";
|
data->global = "cache";
|
||||||
} else {
|
} else {
|
||||||
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
|
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
|
||||||
@@ -1958,6 +2138,11 @@ static int _pool_register_callback(struct dev_manager *dm,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Declaration to resolve suspend tree and message passing for thin-pool */
|
||||||
|
static int _add_target_to_dtree(struct dev_manager *dm,
|
||||||
|
struct dm_tree_node *dnode,
|
||||||
|
struct lv_segment *seg,
|
||||||
|
struct lv_activate_opts *laopts);
|
||||||
/*
|
/*
|
||||||
* Add LV and any known dependencies
|
* Add LV and any known dependencies
|
||||||
*/
|
*/
|
||||||
@@ -2026,26 +2211,48 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
*/
|
*/
|
||||||
if (!_add_dev_to_dtree(dm, dtree, lv, lv_layer(lv)))
|
if (!_add_dev_to_dtree(dm, dtree, lv, lv_layer(lv)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: change API and move this code
|
||||||
|
* Could be easier to handle this in _add_dev_to_dtree()
|
||||||
|
* and base this according to info.exists ?
|
||||||
|
*/
|
||||||
if (!dm->activation) {
|
if (!dm->activation) {
|
||||||
/* Setup callback for non-activation partial tree */
|
|
||||||
/* Activation gets own callback when needed */
|
|
||||||
/* TODO: extend _cached_dm_info() to return dnode */
|
|
||||||
if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||||
return_0;
|
return_0;
|
||||||
if ((node = dm_tree_find_node_by_uuid(dtree, uuid)) &&
|
if ((node = dm_tree_find_node_by_uuid(dtree, uuid))) {
|
||||||
!_pool_register_callback(dm, node, lv))
|
if (origin_only) {
|
||||||
return_0;
|
struct lv_activate_opts laopts = {
|
||||||
|
.origin_only = 1,
|
||||||
|
.send_messages = 1 /* Node with messages */
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* Add some messsages if right node exist in the table only
|
||||||
|
* when building SUSPEND tree for origin-only thin-pool.
|
||||||
|
*
|
||||||
|
* TODO: Fix call of '_add_target_to_dtree()' to add message
|
||||||
|
* to thin-pool node as we already know the pool node exists
|
||||||
|
* in the table. Any better/cleaner API way ?
|
||||||
|
*
|
||||||
|
* Probably some 'new' target method to add messages for any node?
|
||||||
|
*/
|
||||||
|
if (dm->suspend &&
|
||||||
|
!dm_list_empty(&(first_seg(lv)->thin_messages)) &&
|
||||||
|
!_add_target_to_dtree(dm, node, first_seg(lv), &laopts))
|
||||||
|
return_0;
|
||||||
|
} else {
|
||||||
|
/* Setup callback for non-activation partial tree */
|
||||||
|
/* Activation gets own callback when needed */
|
||||||
|
/* TODO: extend _cached_dm_info() to return dnode */
|
||||||
|
if (!_pool_register_callback(dm, node, lv))
|
||||||
|
return_0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lv_is_cache(lv)) {
|
if (lv_is_cache(lv)) {
|
||||||
if (lv_is_pending_delete(lv)) {
|
if (!origin_only && !dm->activation && !dm->track_pending_delete) {
|
||||||
if (!_add_lv_to_dtree(dm, dtree, first_seg(lv)->pool_lv, 1)) /* stack */
|
|
||||||
return_0;
|
|
||||||
/* Orhan cache LV exits here */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!origin_only && !dm->activation) {
|
|
||||||
/* Setup callback for non-activation partial tree */
|
/* Setup callback for non-activation partial tree */
|
||||||
/* Activation gets own callback when needed */
|
/* Activation gets own callback when needed */
|
||||||
/* TODO: extend _cached_dm_info() to return dnode */
|
/* TODO: extend _cached_dm_info() to return dnode */
|
||||||
@@ -2075,13 +2282,16 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
dm->track_pvmove_deps = 1;
|
dm->track_pvmove_deps = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
if (!dm->track_pending_delete)
|
||||||
if (lv_is_pending_delete(sl->seg->lv) && lv_is_cache(sl->seg->lv)) {
|
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||||
if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
|
if (lv_is_pending_delete(sl->seg->lv)) {
|
||||||
return_0;
|
/* LV is referenced by 'cache pending delete LV */
|
||||||
break;
|
dm->track_pending_delete = 1;
|
||||||
|
if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
|
||||||
|
return_0;
|
||||||
|
dm->track_pending_delete = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Adding LV head of replicator adds all other related devs */
|
/* Adding LV head of replicator adds all other related devs */
|
||||||
if (lv_is_replicator_dev(lv) &&
|
if (lv_is_replicator_dev(lv) &&
|
||||||
@@ -2106,6 +2316,8 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s) &&
|
if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s) &&
|
||||||
|
/* origin only for cache without pending delete */
|
||||||
|
(!dm->track_pending_delete || !lv_is_cache(lv)) &&
|
||||||
!_add_lv_to_dtree(dm, dtree, seg_lv(seg, s), 0))
|
!_add_lv_to_dtree(dm, dtree, seg_lv(seg, s), 0))
|
||||||
return_0;
|
return_0;
|
||||||
if (seg_is_raid(seg) &&
|
if (seg_is_raid(seg) &&
|
||||||
@@ -2133,7 +2345,7 @@ static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, const struc
|
|||||||
|
|
||||||
dm_tree_set_optional_uuid_suffixes(dtree, &uuid_suffix_list[0]);
|
dm_tree_set_optional_uuid_suffixes(dtree, &uuid_suffix_list[0]);
|
||||||
|
|
||||||
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv)) ? origin_only : 0))
|
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv) || lv_is_thin_pool(lv)) ? origin_only : 0))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
return dtree;
|
return dtree;
|
||||||
@@ -2270,7 +2482,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
|||||||
* is used in the CTR table.
|
* is used in the CTR table.
|
||||||
*/
|
*/
|
||||||
if ((seg_type(seg, s) == AREA_UNASSIGNED) ||
|
if ((seg_type(seg, s) == AREA_UNASSIGNED) ||
|
||||||
((seg_lv(seg, s)->status & VISIBLE_LV) &&
|
(lv_is_visible(seg_lv(seg, s)) &&
|
||||||
!(seg_lv(seg, s)->status & LVM_WRITE))) {
|
!(seg_lv(seg, s)->status & LVM_WRITE))) {
|
||||||
/* One each for metadata area and data area */
|
/* One each for metadata area and data area */
|
||||||
if (!dm_tree_node_add_null_area(node, 0) ||
|
if (!dm_tree_node_add_null_area(node, 0) ||
|
||||||
@@ -2549,21 +2761,24 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
|||||||
{
|
{
|
||||||
uint32_t s;
|
uint32_t s;
|
||||||
struct lv_segment *seg_present;
|
struct lv_segment *seg_present;
|
||||||
|
const struct segment_type *segtype;
|
||||||
const char *target_name;
|
const char *target_name;
|
||||||
|
|
||||||
/* Ensure required device-mapper targets are loaded */
|
/* Ensure required device-mapper targets are loaded */
|
||||||
seg_present = find_snapshot(seg->lv) ? : seg;
|
seg_present = find_snapshot(seg->lv) ? : seg;
|
||||||
target_name = (seg_present->segtype->ops->target_name ?
|
segtype = seg_present->segtype;
|
||||||
seg_present->segtype->ops->target_name(seg_present, laopts) :
|
|
||||||
seg_present->segtype->name);
|
target_name = (segtype->ops->target_name ?
|
||||||
|
segtype->ops->target_name(seg_present, laopts) :
|
||||||
|
segtype->name);
|
||||||
|
|
||||||
log_debug_activation("Checking kernel supports %s segment type for %s%s%s",
|
log_debug_activation("Checking kernel supports %s segment type for %s%s%s",
|
||||||
target_name, seg->lv->name,
|
target_name, seg->lv->name,
|
||||||
layer ? "-" : "", layer ? : "");
|
layer ? "-" : "", layer ? : "");
|
||||||
|
|
||||||
if (seg_present->segtype->ops->target_present &&
|
if (segtype->ops->target_present &&
|
||||||
!seg_present->segtype->ops->target_present(seg_present->lv->vg->cmd,
|
!segtype->ops->target_present(seg_present->lv->vg->cmd,
|
||||||
seg_present, NULL)) {
|
seg_present, NULL)) {
|
||||||
log_error("Can't process LV %s: %s target support missing "
|
log_error("Can't process LV %s: %s target support missing "
|
||||||
"from kernel?", seg->lv->name, target_name);
|
"from kernel?", seg->lv->name, target_name);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2585,7 +2800,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
|||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
/* Add pool layer */
|
/* Add pool layer */
|
||||||
if (seg->pool_lv &&
|
if (seg->pool_lv && !laopts->origin_only &&
|
||||||
!_add_new_lv_to_dtree(dm, dtree, seg->pool_lv, laopts,
|
!_add_new_lv_to_dtree(dm, dtree, seg->pool_lv, laopts,
|
||||||
lv_layer(seg->pool_lv)))
|
lv_layer(seg->pool_lv)))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -2598,8 +2813,10 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
|||||||
/* Add any LVs used by this segment */
|
/* Add any LVs used by this segment */
|
||||||
for (s = 0; s < seg->area_count; ++s) {
|
for (s = 0; s < seg->area_count; ++s) {
|
||||||
if ((seg_type(seg, s) == AREA_LV) &&
|
if ((seg_type(seg, s) == AREA_LV) &&
|
||||||
(!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s),
|
/* origin only for cache without pending delete */
|
||||||
laopts, NULL)))
|
(!dm->track_pending_delete || !seg_is_cache(seg)) &&
|
||||||
|
!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s),
|
||||||
|
laopts, NULL))
|
||||||
return_0;
|
return_0;
|
||||||
if (seg_is_raid(seg) &&
|
if (seg_is_raid(seg) &&
|
||||||
!_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s),
|
!_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s),
|
||||||
@@ -2607,7 +2824,13 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
|||||||
return_0;
|
return_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_add_target_to_dtree(dm, dnode, seg, laopts))
|
if (dm->track_pending_delete) {
|
||||||
|
/* Replace target and all its used devs with error mapping */
|
||||||
|
log_debug_activation("Using error for pending delete %s.",
|
||||||
|
seg->lv->name);
|
||||||
|
if (!dm_tree_node_add_error_target(dnode, (uint64_t)seg->lv->vg->extent_size * seg->len))
|
||||||
|
return_0;
|
||||||
|
} else if (!_add_target_to_dtree(dm, dnode, seg, laopts))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -2680,6 +2903,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
uint32_t max_stripe_size = UINT32_C(0);
|
uint32_t max_stripe_size = UINT32_C(0);
|
||||||
uint32_t read_ahead = lv->read_ahead;
|
uint32_t read_ahead = lv->read_ahead;
|
||||||
uint32_t read_ahead_flags = UINT32_C(0);
|
uint32_t read_ahead_flags = UINT32_C(0);
|
||||||
|
int save_pending_delete = dm->track_pending_delete;
|
||||||
|
|
||||||
/* LV with pending delete is never put new into a table */
|
/* LV with pending delete is never put new into a table */
|
||||||
if (lv_is_pending_delete(lv) && !_cached_dm_info(dm->mem, dtree, lv, NULL))
|
if (lv_is_pending_delete(lv) && !_cached_dm_info(dm->mem, dtree, lv, NULL))
|
||||||
@@ -2767,29 +2991,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
/* Create table */
|
/* Create table */
|
||||||
dm->pvmove_mirror_count = 0u;
|
dm->pvmove_mirror_count = 0u;
|
||||||
|
|
||||||
if (lv_is_pending_delete(lv)) {
|
if (lv_is_pending_delete(lv))
|
||||||
/* Handle LVs with pending delete */
|
/* Handle LVs with pending delete */
|
||||||
if (lv_is_cache(lv)) {
|
/* Fow now used only by cache segtype, TODO snapshots */
|
||||||
/* Use 'error' for cache, metadata and data volumes */
|
dm->track_pending_delete = 1;
|
||||||
seg = first_seg(lv);
|
|
||||||
if (!dm_tree_node_add_error_target(dnode, seg_lv(seg, 0)->size))
|
|
||||||
return_0;
|
|
||||||
seg = first_seg(seg->pool_lv);
|
|
||||||
if (!(dlid = build_dm_uuid(dm->mem, seg->metadata_lv, NULL)))
|
|
||||||
return_0;
|
|
||||||
if ((dnode = dm_tree_find_node_by_uuid(dtree, dlid)) &&
|
|
||||||
!dm_tree_node_get_context(dnode) &&
|
|
||||||
!dm_tree_node_add_error_target(dnode, seg->metadata_lv->size))
|
|
||||||
return_0;
|
|
||||||
if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, 0), NULL)))
|
|
||||||
return_0;
|
|
||||||
if ((dnode = dm_tree_find_node_by_uuid(dtree, dlid)) &&
|
|
||||||
!dm_tree_node_get_context(dnode) &&
|
|
||||||
!dm_tree_node_add_error_target(dnode, seg_lv(seg, 0)->size))
|
|
||||||
return_0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is unused cache-pool - make metadata accessible */
|
/* This is unused cache-pool - make metadata accessible */
|
||||||
if (lv_is_cache_pool(lv))
|
if (lv_is_cache_pool(lv))
|
||||||
@@ -2875,6 +3080,8 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
|||||||
return_0;
|
return_0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
dm->track_pending_delete = save_pending_delete; /* restore */
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2967,12 +3174,20 @@ static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *non_toplevel_tree_dlid)
|
static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, const char *non_toplevel_tree_dlid)
|
||||||
{
|
{
|
||||||
void *handle = NULL;
|
void *handle = NULL;
|
||||||
struct dm_tree_node *child;
|
struct dm_tree_node *child;
|
||||||
char *vgname, *lvname, *layer;
|
char *vgname, *lvname, *layer;
|
||||||
const char *name, *uuid;
|
const char *name, *uuid;
|
||||||
|
struct dm_str_list *dl;
|
||||||
|
|
||||||
|
/* Deactivate any tracked pending delete nodes */
|
||||||
|
dm_list_iterate_items(dl, &dm->pending_delete) {
|
||||||
|
log_debug_activation("Deleting tracked UUID %s.", dl->str);
|
||||||
|
if (!dm_tree_deactivate_children(root, dl->str, strlen(dl->str)))
|
||||||
|
return_0;
|
||||||
|
}
|
||||||
|
|
||||||
while ((child = dm_tree_next_child(&handle, root, 0))) {
|
while ((child = dm_tree_next_child(&handle, root, 0))) {
|
||||||
if (!(name = dm_tree_node_get_name(child)))
|
if (!(name = dm_tree_node_get_name(child)))
|
||||||
@@ -2987,23 +3202,14 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not meant to be top level? */
|
/* Not meant to be top level? */
|
||||||
if (!*layer && (!(layer = strchr(uuid + 4, '-')) || strstr(layer, "-pool") || strstr(layer, "-tpool")))
|
if (!*layer)
|
||||||
continue;
|
|
||||||
|
|
||||||
/* FIXME: we still occasionally need to activate these at top-level */
|
|
||||||
if (((name = strstr(lvname, "_tmeta")) && !name[6]) ||
|
|
||||||
((name = strstr(lvname, "_tdata")) && !name[6]))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* If operation was performed on a partial tree, don't remove it */
|
/* If operation was performed on a partial tree, don't remove it */
|
||||||
if (non_toplevel_tree_dlid && !strcmp(non_toplevel_tree_dlid, uuid))
|
if (non_toplevel_tree_dlid && !strcmp(non_toplevel_tree_dlid, uuid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((name = strstr(lvname, "_corig")) && !name[6]) {
|
if (!dm_tree_deactivate_children(root, uuid, strlen(uuid)))
|
||||||
/* FIXME: for now just for _corig deactivate LVM subtree, should be generic */
|
|
||||||
if (!dm_tree_deactivate_children(root, "LVM-", 4))
|
|
||||||
return_0;
|
|
||||||
} else if (!dm_tree_deactivate_children(root, uuid, strlen(uuid)))
|
|
||||||
return_0;
|
return_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3013,7 +3219,7 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
|
|||||||
static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||||
struct lv_activate_opts *laopts, action_t action)
|
struct lv_activate_opts *laopts, action_t action)
|
||||||
{
|
{
|
||||||
static const char const _action_names[][24] = {
|
static const char _action_names[][24] = {
|
||||||
"PRELOAD", "ACTIVATE", "DEACTIVATE", "SUSPEND", "SUSPEND_WITH_LOCKFS", "CLEAN"
|
"PRELOAD", "ACTIVATE", "DEACTIVATE", "SUSPEND", "SUSPEND_WITH_LOCKFS", "CLEAN"
|
||||||
};
|
};
|
||||||
const size_t DLID_SIZE = ID_LEN + sizeof(UUID_PREFIX) - 1;
|
const size_t DLID_SIZE = ID_LEN + sizeof(UUID_PREFIX) - 1;
|
||||||
@@ -3023,7 +3229,10 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (action < DM_ARRAY_SIZE(_action_names))
|
if (action < DM_ARRAY_SIZE(_action_names))
|
||||||
log_debug_activation("Creating %s tree for %s.", _action_names[action], lv->name);
|
log_debug_activation("Creating %s%s tree for %s.",
|
||||||
|
_action_names[action],
|
||||||
|
(laopts->origin_only) ? " origin-only" : "",
|
||||||
|
display_lvname(lv));
|
||||||
|
|
||||||
/* Some LV can be used for top level tree */
|
/* Some LV can be used for top level tree */
|
||||||
/* TODO: add more.... */
|
/* TODO: add more.... */
|
||||||
@@ -3033,6 +3242,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
|||||||
}
|
}
|
||||||
/* Some targets may build bigger tree for activation */
|
/* Some targets may build bigger tree for activation */
|
||||||
dm->activation = ((action == PRELOAD) || (action == ACTIVATE));
|
dm->activation = ((action == PRELOAD) || (action == ACTIVATE));
|
||||||
|
dm->suspend = (action == SUSPEND_WITH_LOCKFS) || (action == SUSPEND);
|
||||||
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
|
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
@@ -3067,7 +3277,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
|||||||
break;
|
break;
|
||||||
case SUSPEND:
|
case SUSPEND:
|
||||||
dm_tree_skip_lockfs(root);
|
dm_tree_skip_lockfs(root);
|
||||||
if (!dm->flush_required && lv_is_mirror(lv) && !lv_is_pvmove(lv))
|
if (!dm->flush_required && !lv_is_pvmove(lv))
|
||||||
dm_tree_use_no_flush_suspend(root);
|
dm_tree_use_no_flush_suspend(root);
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
case SUSPEND_WITH_LOCKFS:
|
case SUSPEND_WITH_LOCKFS:
|
||||||
@@ -3077,14 +3287,23 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
|||||||
case PRELOAD:
|
case PRELOAD:
|
||||||
case ACTIVATE:
|
case ACTIVATE:
|
||||||
/* Add all required new devices to tree */
|
/* Add all required new devices to tree */
|
||||||
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL))
|
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts,
|
||||||
|
(lv_is_origin(lv) && laopts->origin_only) ? "real" :
|
||||||
|
(lv_is_thin_pool(lv) && laopts->origin_only) ? "tpool" : NULL))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
/* Preload any devices required before any suspensions */
|
/* Preload any devices required before any suspensions */
|
||||||
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
|
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (dm_tree_node_size_changed(root))
|
if ((dm_tree_node_size_changed(root) < 0))
|
||||||
|
dm->flush_required = 1;
|
||||||
|
|
||||||
|
/* Currently keep the code require flush for any
|
||||||
|
* non 'thin pool/volume, mirror' or with any size change */
|
||||||
|
if (!lv_is_thin_volume(lv) &&
|
||||||
|
!lv_is_thin_pool(lv) &&
|
||||||
|
(!lv_is_mirror(lv) || dm_tree_node_size_changed(root)))
|
||||||
dm->flush_required = 1;
|
dm->flush_required = 1;
|
||||||
|
|
||||||
if (action == ACTIVATE) {
|
if (action == ACTIVATE) {
|
||||||
@@ -3115,7 +3334,6 @@ out_no_root:
|
|||||||
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
|
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
|
||||||
struct lv_activate_opts *laopts)
|
struct lv_activate_opts *laopts)
|
||||||
{
|
{
|
||||||
laopts->send_messages = 1;
|
|
||||||
if (!_tree_action(dm, lv, laopts, ACTIVATE))
|
if (!_tree_action(dm, lv, laopts, ACTIVATE))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
|
|||||||
512
lib/cache/lvmcache.c
vendored
512
lib/cache/lvmcache.c
vendored
@@ -56,6 +56,9 @@ struct lvmcache_vginfo {
|
|||||||
char _padding[7];
|
char _padding[7];
|
||||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||||
char *creation_host;
|
char *creation_host;
|
||||||
|
char *lock_type;
|
||||||
|
uint32_t mda_checksum;
|
||||||
|
size_t mda_size;
|
||||||
size_t vgmetadata_size;
|
size_t vgmetadata_size;
|
||||||
char *vgmetadata; /* Copy of VG metadata as format_text string */
|
char *vgmetadata; /* Copy of VG metadata as format_text string */
|
||||||
struct dm_config_tree *cft; /* Config tree created from vgmetadata */
|
struct dm_config_tree *cft; /* Config tree created from vgmetadata */
|
||||||
@@ -65,6 +68,7 @@ struct lvmcache_vginfo {
|
|||||||
unsigned vg_use_count; /* Counter of vg reusage */
|
unsigned vg_use_count; /* Counter of vg reusage */
|
||||||
unsigned precommitted; /* Is vgmetadata live or precommitted? */
|
unsigned precommitted; /* Is vgmetadata live or precommitted? */
|
||||||
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
|
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
|
||||||
|
unsigned preferred_duplicates; /* preferred duplicate pvs have been set */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dm_hash_table *_pvid_hash = NULL;
|
static struct dm_hash_table *_pvid_hash = NULL;
|
||||||
@@ -76,6 +80,7 @@ static int _scanning_in_progress = 0;
|
|||||||
static int _has_scanned = 0;
|
static int _has_scanned = 0;
|
||||||
static int _vgs_locked = 0;
|
static int _vgs_locked = 0;
|
||||||
static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */
|
static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */
|
||||||
|
static int _found_duplicate_pvs = 0; /* If we never see a duplicate PV we can skip checking for them later. */
|
||||||
|
|
||||||
int lvmcache_init(void)
|
int lvmcache_init(void)
|
||||||
{
|
{
|
||||||
@@ -112,6 +117,47 @@ int lvmcache_init(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once PV info has been populated in lvmcache and
|
||||||
|
* lvmcache has chosen preferred duplicate devices,
|
||||||
|
* set this flag so that lvmcache will not try to
|
||||||
|
* compare and choose preferred duplicate devices
|
||||||
|
* again (which may result in different preferred
|
||||||
|
* devices.) PV info can be populated in lvmcache
|
||||||
|
* multiple times, each time causing lvmcache to
|
||||||
|
* compare the duplicate devices, so we need to
|
||||||
|
* record that the comparison/preferences have
|
||||||
|
* already been done, so the preferrences from the
|
||||||
|
* first time through are not changed.
|
||||||
|
*
|
||||||
|
* This is something of a hack to work around the
|
||||||
|
* fact that the code isn't really designed to
|
||||||
|
* handle duplicate PVs, and the fact that lvmetad
|
||||||
|
* has its own way of picking a preferred duplicate
|
||||||
|
* and lvmcache has another way based on having
|
||||||
|
* more information than lvmetad does.
|
||||||
|
*
|
||||||
|
* If we come up with a better overall method to
|
||||||
|
* handle duplicate PVs, then this can probably be
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* FIXME: if we want to make lvmetad work with clvmd,
|
||||||
|
* then this may need to be changed to set
|
||||||
|
* preferred_duplicates back to 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void lvmcache_set_preferred_duplicates(const char *vgid)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) {
|
||||||
|
stack;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vginfo->preferred_duplicates = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
|
void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
if (!lvmetad_active() || _has_scanned)
|
if (!lvmetad_active() || _has_scanned)
|
||||||
@@ -284,6 +330,9 @@ void lvmcache_commit_metadata(const char *vgname)
|
|||||||
|
|
||||||
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
||||||
{
|
{
|
||||||
|
if (lvmcache_vgname_is_locked(VG_GLOBAL) && !vg_write_lock_held())
|
||||||
|
return;
|
||||||
|
|
||||||
/* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
|
/* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
|
||||||
if (!strcmp(vgname, VG_ORPHANS)) {
|
if (!strcmp(vgname, VG_ORPHANS)) {
|
||||||
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
|
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
|
||||||
@@ -292,7 +341,7 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
|||||||
|
|
||||||
/* Indicate that PVs could now be missing from the cache */
|
/* Indicate that PVs could now be missing from the cache */
|
||||||
init_full_scan_done(0);
|
init_full_scan_done(0);
|
||||||
} else if (!lvmcache_vgname_is_locked(VG_GLOBAL))
|
} else
|
||||||
_drop_metadata(vgname, drop_precommitted);
|
_drop_metadata(vgname, drop_precommitted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,6 +451,16 @@ int lvmcache_vgs_locked(void)
|
|||||||
return _vgs_locked;
|
return _vgs_locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When lvmcache sees a duplicate PV, this is set.
|
||||||
|
* process_each_pv() can avoid searching for duplicates
|
||||||
|
* by checking this and seeing that no duplicate PVs exist.
|
||||||
|
*/
|
||||||
|
int lvmcache_found_duplicate_pvs(void)
|
||||||
|
{
|
||||||
|
return _found_duplicate_pvs;
|
||||||
|
}
|
||||||
|
|
||||||
static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
|
static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
|
||||||
struct lvmcache_info *info)
|
struct lvmcache_info *info)
|
||||||
{
|
{
|
||||||
@@ -847,6 +906,37 @@ int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo
|
|||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
|
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
|
||||||
|
struct dm_list *vgnameids)
|
||||||
|
{
|
||||||
|
struct vgnameid_list *vgnl;
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
lvmcache_label_scan(cmd, 0);
|
||||||
|
|
||||||
|
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||||
|
if (!include_internal && is_orphan_vg(vginfo->vgname))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {
|
||||||
|
log_error("vgnameid_list allocation failed.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgnl->vgid = dm_pool_strdup(cmd->mem, vginfo->vgid);
|
||||||
|
vgnl->vg_name = dm_pool_strdup(cmd->mem, vginfo->vgname);
|
||||||
|
|
||||||
|
if (!vgnl->vgid || !vgnl->vg_name) {
|
||||||
|
log_error("vgnameid_list member allocation failed.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_list_add(vgnameids, &vgnl->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
|
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
|
||||||
int include_internal)
|
int include_internal)
|
||||||
{
|
{
|
||||||
@@ -1358,7 +1448,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
|
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
|
||||||
const char *creation_host)
|
const char *creation_host, const char *lock_type)
|
||||||
{
|
{
|
||||||
if (!info || !info->vginfo)
|
if (!info || !info->vginfo)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1371,11 +1461,11 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
|||||||
info->vginfo->status = vgstatus;
|
info->vginfo->status = vgstatus;
|
||||||
|
|
||||||
if (!creation_host)
|
if (!creation_host)
|
||||||
return 1;
|
goto set_lock_type;
|
||||||
|
|
||||||
if (info->vginfo->creation_host && !strcmp(creation_host,
|
if (info->vginfo->creation_host && !strcmp(creation_host,
|
||||||
info->vginfo->creation_host))
|
info->vginfo->creation_host))
|
||||||
return 1;
|
goto set_lock_type;
|
||||||
|
|
||||||
if (info->vginfo->creation_host)
|
if (info->vginfo->creation_host)
|
||||||
dm_free(info->vginfo->creation_host);
|
dm_free(info->vginfo->creation_host);
|
||||||
@@ -1389,6 +1479,44 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
|||||||
log_debug_cache("lvmcache: %s: VG %s: Set creation host to %s.",
|
log_debug_cache("lvmcache: %s: VG %s: Set creation host to %s.",
|
||||||
dev_name(info->dev), info->vginfo->vgname, creation_host);
|
dev_name(info->dev), info->vginfo->vgname, creation_host);
|
||||||
|
|
||||||
|
set_lock_type:
|
||||||
|
|
||||||
|
if (!lock_type)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (info->vginfo->lock_type && !strcmp(lock_type, info->vginfo->lock_type))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (info->vginfo->lock_type)
|
||||||
|
dm_free(info->vginfo->lock_type);
|
||||||
|
|
||||||
|
if (!(info->vginfo->lock_type = dm_strdup(lock_type))) {
|
||||||
|
log_error("cache creation host alloc failed for %s",
|
||||||
|
lock_type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvmcache_update_vg_mda_info(struct lvmcache_info *info, uint32_t mda_checksum,
|
||||||
|
size_t mda_size)
|
||||||
|
{
|
||||||
|
if (!info || !info->vginfo || !mda_size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (info->vginfo->mda_checksum == mda_checksum || info->vginfo->mda_size == mda_size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
info->vginfo->mda_checksum = mda_checksum;
|
||||||
|
info->vginfo->mda_size = mda_size;
|
||||||
|
|
||||||
|
/* FIXME Add checksum index */
|
||||||
|
|
||||||
|
log_debug_cache("lvmcache: %s: VG %s: Stored metadata checksum %" PRIu32 " with size %" PRIsize_t ".",
|
||||||
|
dev_name(info->dev), info->vginfo->vgname, mda_checksum, mda_size);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1402,10 +1530,11 @@ int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
|
|||||||
return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
|
return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary)
|
||||||
const char *vgname, const char *vgid,
|
|
||||||
uint32_t vgstatus, const char *creation_host)
|
|
||||||
{
|
{
|
||||||
|
const char *vgname = vgsummary->vgname;
|
||||||
|
const char *vgid = (char *)&vgsummary->vgid;
|
||||||
|
|
||||||
if (!vgname && !info->vginfo) {
|
if (!vgname && !info->vginfo) {
|
||||||
log_error(INTERNAL_ERROR "NULL vgname handed to cache");
|
log_error(INTERNAL_ERROR "NULL vgname handed to cache");
|
||||||
/* FIXME Remove this */
|
/* FIXME Remove this */
|
||||||
@@ -1413,10 +1542,6 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
|||||||
vgid = vgname;
|
vgid = vgname;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When using lvmetad, the PV could not have become orphaned. */
|
|
||||||
if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* If PV without mdas is already in a real VG, don't make it orphan */
|
/* If PV without mdas is already in a real VG, don't make it orphan */
|
||||||
if (is_orphan_vg(vgname) && info->vginfo &&
|
if (is_orphan_vg(vgname) && info->vginfo &&
|
||||||
mdas_empty_or_ignored(&info->mdas) &&
|
mdas_empty_or_ignored(&info->mdas) &&
|
||||||
@@ -1433,10 +1558,11 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
|||||||
if (!is_orphan_vg(vgname))
|
if (!is_orphan_vg(vgname))
|
||||||
info->status &= ~CACHE_INVALID;
|
info->status &= ~CACHE_INVALID;
|
||||||
|
|
||||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
|
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
|
||||||
creation_host, info->fmt) ||
|
vgsummary->creation_host, info->fmt) ||
|
||||||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
|
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
|
||||||
!_lvmcache_update_vgstatus(info, vgstatus, creation_host))
|
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type) ||
|
||||||
|
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1447,6 +1573,12 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
|||||||
struct pv_list *pvl;
|
struct pv_list *pvl;
|
||||||
struct lvmcache_info *info;
|
struct lvmcache_info *info;
|
||||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||||
|
struct lvmcache_vgsummary vgsummary = {
|
||||||
|
.vgname = vg->name,
|
||||||
|
.vgstatus = vg->status,
|
||||||
|
.vgid = vg->id,
|
||||||
|
.lock_type = vg->lock_type
|
||||||
|
};
|
||||||
|
|
||||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||||
|
|
||||||
@@ -1454,9 +1586,7 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
|||||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||||
if ((info = lvmcache_info_from_pvid(pvid_s, 0)) &&
|
if ((info = lvmcache_info_from_pvid(pvid_s, 0)) &&
|
||||||
!lvmcache_update_vgname_and_id(info, vg->name,
|
!lvmcache_update_vgname_and_id(info, &vgsummary))
|
||||||
(char *) &vg->id,
|
|
||||||
vg->status, NULL))
|
|
||||||
return_0;
|
return_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1467,6 +1597,85 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Replace pv->dev with dev so that dev will appear for reporting.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
|
||||||
|
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||||
|
|
||||||
|
if (!(info = lvmcache_info_from_pvid(pvid_s, 0)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
info->dev = dev;
|
||||||
|
info->label->dev = dev;
|
||||||
|
pv->dev = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can see multiple different devices with the
|
||||||
|
* same pvid, i.e. duplicates.
|
||||||
|
*
|
||||||
|
* There may be different reasons for seeing two
|
||||||
|
* devices with the same pvid:
|
||||||
|
* - multipath showing two paths to the same thing
|
||||||
|
* - one device copied to another, e.g. with dd,
|
||||||
|
* also referred to as cloned devices.
|
||||||
|
* - a "subsystem" taking a device and creating
|
||||||
|
* another device of its own that represents the
|
||||||
|
* underlying device it is using, e.g. using dm
|
||||||
|
* to create an identity mapping of a PV.
|
||||||
|
*
|
||||||
|
* Given duplicate devices, we have to choose one
|
||||||
|
* of them to be the "preferred" dev, i.e. the one
|
||||||
|
* that will be referenced in lvmcache, by pv->dev.
|
||||||
|
* We can keep the existing dev, that's currently
|
||||||
|
* used in lvmcache, or we can replace the existing
|
||||||
|
* dev with the new duplicate.
|
||||||
|
*
|
||||||
|
* Regardless of which device is preferred, we need
|
||||||
|
* to print messages explaining which devices were
|
||||||
|
* found so that a user can sort out for themselves
|
||||||
|
* what has happened if the preferred device is not
|
||||||
|
* the one they are interested in.
|
||||||
|
*
|
||||||
|
* If a user wants to use the non-preferred device,
|
||||||
|
* they will need to filter out the device that
|
||||||
|
* lvm is preferring.
|
||||||
|
*
|
||||||
|
* The dev_subsystem calls check if the major number
|
||||||
|
* of the dev is part of a subsystem like DM/MD/DRBD.
|
||||||
|
* A dev that's part of a subsystem is preferred over a
|
||||||
|
* duplicate of that dev that is not part of a
|
||||||
|
* subsystem.
|
||||||
|
*
|
||||||
|
* The has_holders calls check if the device is being
|
||||||
|
* used by another, and prefers one that's being used.
|
||||||
|
*
|
||||||
|
* FIXME: why do we prefer a device without holders
|
||||||
|
* over a device with holders? We should understand
|
||||||
|
* the reason for that choice.
|
||||||
|
*
|
||||||
|
* FIXME: there may be other reasons to prefer one
|
||||||
|
* device over another:
|
||||||
|
*
|
||||||
|
* . are there other use/open counts we could check
|
||||||
|
* beyond the holders?
|
||||||
|
*
|
||||||
|
* . check if either is bad/usable and prefer
|
||||||
|
* the good one?
|
||||||
|
*
|
||||||
|
* . prefer the one with smaller minor number?
|
||||||
|
* Might avoid disturbing things due to a new
|
||||||
|
* transient duplicate?
|
||||||
|
*/
|
||||||
|
|
||||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
const char *vgname, const char *vgid,
|
const char *vgname, const char *vgid,
|
||||||
@@ -1477,6 +1686,14 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
|||||||
struct label *label;
|
struct label *label;
|
||||||
struct lvmcache_info *existing, *info;
|
struct lvmcache_info *existing, *info;
|
||||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||||
|
struct lvmcache_vgsummary vgsummary = {
|
||||||
|
.vgname = vgname,
|
||||||
|
.vgstatus = vgstatus,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* N.B. vgid is not NUL-terminated when called from _text_pv_write */
|
||||||
|
if (vgid)
|
||||||
|
strncpy((char *)&vgsummary.vgid, vgid, sizeof(vgsummary.vgid));
|
||||||
|
|
||||||
if (!_vgname_hash && !lvmcache_init()) {
|
if (!_vgname_hash && !lvmcache_init()) {
|
||||||
log_error("Internal cache initialisation failed");
|
log_error("Internal cache initialisation failed");
|
||||||
@@ -1506,49 +1723,166 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
|||||||
lvmcache_del_bas(info);
|
lvmcache_del_bas(info);
|
||||||
} else {
|
} else {
|
||||||
if (existing->dev != dev) {
|
if (existing->dev != dev) {
|
||||||
/* Is the existing entry a duplicate pvid e.g. md ? */
|
int old_in_subsystem = 0;
|
||||||
if (dev_subsystem_part_major(dt, existing->dev) &&
|
int new_in_subsystem = 0;
|
||||||
!dev_subsystem_part_major(dt, dev)) {
|
int old_is_dm = 0;
|
||||||
log_very_verbose("Ignoring duplicate PV %s on "
|
int new_is_dm = 0;
|
||||||
"%s - using %s %s",
|
int old_has_holders = 0;
|
||||||
pvid, dev_name(dev),
|
int new_has_holders = 0;
|
||||||
dev_subsystem_name(dt, existing->dev),
|
|
||||||
dev_name(existing->dev));
|
/*
|
||||||
|
* Here are different devices with the same pvid:
|
||||||
|
* duplicates. See comment above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This flag tells the process_each_pv code to search
|
||||||
|
* the devices list for duplicates, so that devices
|
||||||
|
* can be processed together with their duplicates
|
||||||
|
* (while processing the VG, rather than reporting
|
||||||
|
* pv->dev under the VG, and its duplicate outside
|
||||||
|
* the VG context.)
|
||||||
|
*/
|
||||||
|
_found_duplicate_pvs = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The new dev may not have pvid set.
|
||||||
|
* The process_each_pv code needs to have the pvid
|
||||||
|
* set in each device to detect that the devices
|
||||||
|
* are duplicates.
|
||||||
|
*/
|
||||||
|
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now decide if we are going to ignore the new
|
||||||
|
* device, or replace the existing/old device in
|
||||||
|
* lvmcache with the new one.
|
||||||
|
*/
|
||||||
|
old_in_subsystem = dev_subsystem_part_major(dt, existing->dev);
|
||||||
|
new_in_subsystem = dev_subsystem_part_major(dt, dev);
|
||||||
|
|
||||||
|
old_is_dm = dm_is_dm_major(MAJOR(existing->dev->dev));
|
||||||
|
new_is_dm = dm_is_dm_major(MAJOR(dev->dev));
|
||||||
|
|
||||||
|
old_has_holders = dm_device_has_holders(MAJOR(existing->dev->dev), MINOR(existing->dev->dev));
|
||||||
|
new_has_holders = dm_device_has_holders(MAJOR(dev->dev), MINOR(dev->dev));
|
||||||
|
|
||||||
|
if (old_has_holders && new_has_holders) {
|
||||||
|
/*
|
||||||
|
* This is not a selection of old or new, but
|
||||||
|
* just a warning to be aware of.
|
||||||
|
*/
|
||||||
|
log_warn("WARNING: duplicate PV %s is being used from both devices %s and %s",
|
||||||
|
pvid_s,
|
||||||
|
dev_name(existing->dev),
|
||||||
|
dev_name(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing->vginfo->preferred_duplicates) {
|
||||||
|
/*
|
||||||
|
* The preferred duplicate devs have already
|
||||||
|
* been chosen during a previous populating of
|
||||||
|
* lvmcache, so just use the existing preferences.
|
||||||
|
*/
|
||||||
|
log_verbose("Found duplicate PV %s: using existing dev %s",
|
||||||
|
pvid_s,
|
||||||
|
dev_name(existing->dev));
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
}
|
||||||
!dm_is_dm_major(MAJOR(dev->dev))) {
|
|
||||||
log_very_verbose("Ignoring duplicate PV %s on "
|
if (old_in_subsystem && !new_in_subsystem) {
|
||||||
"%s - using dm %s",
|
/* Use old, ignore new. */
|
||||||
pvid, dev_name(dev),
|
log_warn("Found duplicate PV %s: using %s not %s",
|
||||||
dev_name(existing->dev));
|
pvid_s,
|
||||||
|
dev_name(existing->dev),
|
||||||
|
dev_name(dev));
|
||||||
|
log_warn("Using duplicate PV %s from subsystem %s, ignoring %s",
|
||||||
|
dev_name(existing->dev),
|
||||||
|
dev_subsystem_name(dt, existing->dev),
|
||||||
|
dev_name(dev));
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (!dev_subsystem_part_major(dt, existing->dev) &&
|
|
||||||
dev_subsystem_part_major(dt, dev))
|
} else if (!old_in_subsystem && new_in_subsystem) {
|
||||||
log_very_verbose("Duplicate PV %s on %s - "
|
/* Use new, replace old. */
|
||||||
"using %s %s", pvid,
|
log_warn("Found duplicate PV %s: using %s not %s",
|
||||||
dev_name(existing->dev),
|
pvid_s,
|
||||||
dev_subsystem_name(dt, existing->dev),
|
dev_name(dev),
|
||||||
dev_name(dev));
|
dev_name(existing->dev));
|
||||||
else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
log_warn("Using duplicate PV %s from subsystem %s, replacing %s",
|
||||||
dm_is_dm_major(MAJOR(dev->dev)))
|
dev_name(dev),
|
||||||
log_very_verbose("Duplicate PV %s on %s - "
|
dev_subsystem_name(dt, dev),
|
||||||
"using dm %s", pvid,
|
dev_name(existing->dev));
|
||||||
dev_name(existing->dev),
|
|
||||||
dev_name(dev));
|
} else if (old_has_holders && !new_has_holders) {
|
||||||
/* FIXME If both dm, check dependencies */
|
/* Use new, replace old. */
|
||||||
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
/* FIXME: why choose the one without olders? */
|
||||||
//dm_is_dm_major(MAJOR(dev->dev)))
|
log_warn("Found duplicate PV %s: using %s not %s",
|
||||||
//
|
pvid_s,
|
||||||
else if (!strcmp(pvid_s, existing->dev->pvid))
|
dev_name(dev),
|
||||||
log_error("Found duplicate PV %s: using %s not "
|
dev_name(existing->dev));
|
||||||
"%s", pvid, dev_name(dev),
|
log_warn("Using duplicate PV %s without holders, replacing %s",
|
||||||
dev_name(existing->dev));
|
dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
|
||||||
|
} else if (!old_has_holders && new_has_holders) {
|
||||||
|
/* Use old, ignore new. */
|
||||||
|
log_warn("Found duplicate PV %s: using %s not %s",
|
||||||
|
pvid_s,
|
||||||
|
dev_name(existing->dev),
|
||||||
|
dev_name(dev));
|
||||||
|
log_warn("Using duplicate PV %s without holders, ignoring %s",
|
||||||
|
dev_name(existing->dev),
|
||||||
|
dev_name(dev));
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
} else if (old_is_dm && new_is_dm) {
|
||||||
|
/* Use new, replace old. */
|
||||||
|
/* FIXME: why choose the new instead of the old? */
|
||||||
|
log_warn("Found duplicate PV %s: using %s not %s",
|
||||||
|
pvid_s,
|
||||||
|
dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
log_warn("Using duplicate PV %s which is last seen, replacing %s",
|
||||||
|
dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
|
||||||
|
} else if (!strcmp(pvid_s, existing->dev->pvid)) {
|
||||||
|
/* No criteria to use for preferring old or new. */
|
||||||
|
/* FIXME: why choose the new instead of the old? */
|
||||||
|
/* FIXME: a transient duplicate would be a reason
|
||||||
|
* to select the old instead of the new. */
|
||||||
|
log_warn("Found duplicate PV %s: using %s not %s",
|
||||||
|
pvid_s,
|
||||||
|
dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
log_warn("Using duplicate PV %s which is last seen, replacing %s",
|
||||||
|
dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The new dev is the same as the existing dev.
|
||||||
|
*
|
||||||
|
* FIXME: Why can't we just return NULL here if the
|
||||||
|
* device already exists? Things don't seem to work
|
||||||
|
* if we do that for some reason.
|
||||||
|
*/
|
||||||
|
log_debug_cache("Found same device %s with same pvid %s",
|
||||||
|
dev_name(existing->dev), pvid_s);
|
||||||
}
|
}
|
||||||
if (strcmp(pvid_s, existing->dev->pvid))
|
|
||||||
log_debug_cache("Updating pvid cache to %s (%s) from %s (%s)",
|
/*
|
||||||
pvid_s, dev_name(dev),
|
* This happens when running pvcreate on an existing PV.
|
||||||
existing->dev->pvid, dev_name(existing->dev));
|
*/
|
||||||
/* Switch over to new preferred device */
|
if (strcmp(pvid_s, existing->dev->pvid)) {
|
||||||
|
log_verbose("Replacing dev %s pvid %s with dev %s pvid %s",
|
||||||
|
dev_name(existing->dev), existing->dev->pvid,
|
||||||
|
dev_name(dev), pvid_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch over to new preferred device.
|
||||||
|
*/
|
||||||
existing->dev = dev;
|
existing->dev = dev;
|
||||||
info = existing;
|
info = existing;
|
||||||
/* Has labeller changed? */
|
/* Has labeller changed? */
|
||||||
@@ -1573,7 +1907,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
|
if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
dm_hash_remove(_pvid_hash, pvid_s);
|
dm_hash_remove(_pvid_hash, pvid_s);
|
||||||
strcpy(info->dev->pvid, "");
|
strcpy(info->dev->pvid, "");
|
||||||
@@ -1982,3 +2316,65 @@ uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info)
|
|||||||
const struct format_type *lvmcache_fmt(struct lvmcache_info *info) {
|
const struct format_type *lvmcache_fmt(struct lvmcache_info *info) {
|
||||||
return info->fmt;
|
return info->fmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
if (!vgsummary->mda_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* FIXME Index the checksums */
|
||||||
|
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||||
|
if (vgsummary->mda_checksum == vginfo->mda_checksum &&
|
||||||
|
vgsummary->mda_size == vginfo->mda_size &&
|
||||||
|
!is_orphan_vg(vginfo->vgname)) {
|
||||||
|
vgsummary->vgname = vginfo->vgname;
|
||||||
|
vgsummary->creation_host = vginfo->creation_host;
|
||||||
|
vgsummary->vgstatus = vginfo->status;
|
||||||
|
/* vginfo->vgid has 1 extra byte then vgsummary->vgid */
|
||||||
|
memcpy(&vgsummary->vgid, vginfo->vgid, sizeof(vgsummary->vgid));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||||
|
if (vginfo->lock_type && !strcmp(vginfo->lock_type, "sanlock"))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||||
|
unsigned *pv_max_name_len,
|
||||||
|
unsigned *vg_max_name_len)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
unsigned len;
|
||||||
|
|
||||||
|
*vg_max_name_len = 0;
|
||||||
|
*pv_max_name_len = 0;
|
||||||
|
|
||||||
|
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||||
|
len = strlen(vginfo->vgname);
|
||||||
|
if (*vg_max_name_len < len)
|
||||||
|
*vg_max_name_len = len;
|
||||||
|
|
||||||
|
dm_list_iterate_items(info, &vginfo->infos) {
|
||||||
|
len = strlen(dev_name(info->dev));
|
||||||
|
if (*pv_max_name_len < len)
|
||||||
|
*pv_max_name_len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
41
lib/cache/lvmcache.h
vendored
41
lib/cache/lvmcache.h
vendored
@@ -39,6 +39,27 @@ struct disk_locn;
|
|||||||
|
|
||||||
struct lvmcache_vginfo;
|
struct lvmcache_vginfo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vgsummary represents a summary of the VG that is read
|
||||||
|
* without a lock. The info does not come through vg_read(),
|
||||||
|
* but through reading mdas. It provides information about
|
||||||
|
* the VG that is needed to lock the VG and then read it fully
|
||||||
|
* with vg_read(), after which the VG summary should be checked
|
||||||
|
* against the full VG metadata to verify it was correct (since
|
||||||
|
* it was read without a lock.)
|
||||||
|
*
|
||||||
|
* Once read, vgsummary information is saved in lvmcache_vginfo.
|
||||||
|
*/
|
||||||
|
struct lvmcache_vgsummary {
|
||||||
|
const char *vgname;
|
||||||
|
struct id vgid;
|
||||||
|
uint64_t vgstatus;
|
||||||
|
char *creation_host;
|
||||||
|
const char *lock_type;
|
||||||
|
uint32_t mda_checksum;
|
||||||
|
size_t mda_size;
|
||||||
|
};
|
||||||
|
|
||||||
int lvmcache_init(void);
|
int lvmcache_init(void);
|
||||||
void lvmcache_allow_reads_with_lvmetad(void);
|
void lvmcache_allow_reads_with_lvmetad(void);
|
||||||
|
|
||||||
@@ -58,8 +79,7 @@ void lvmcache_del(struct lvmcache_info *info);
|
|||||||
|
|
||||||
/* Update things */
|
/* Update things */
|
||||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||||
const char *vgname, const char *vgid,
|
struct lvmcache_vgsummary *vgsummary);
|
||||||
uint32_t vgstatus, const char *hostname);
|
|
||||||
int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted);
|
int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted);
|
||||||
|
|
||||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||||
@@ -68,6 +88,7 @@ int lvmcache_verify_lock_order(const char *vgname);
|
|||||||
|
|
||||||
/* Queries */
|
/* Queries */
|
||||||
const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels);
|
const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels);
|
||||||
|
int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary);
|
||||||
|
|
||||||
/* Decrement and test if there are still vg holders in vginfo. */
|
/* Decrement and test if there are still vg holders in vginfo. */
|
||||||
int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo);
|
int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo);
|
||||||
@@ -98,6 +119,9 @@ struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd,
|
|||||||
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
|
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
|
||||||
int include_internal);
|
int include_internal);
|
||||||
|
|
||||||
|
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
|
||||||
|
struct dm_list *vgnameids);
|
||||||
|
|
||||||
/* Returns list of struct dm_str_list containing pool-allocated copy of pvids */
|
/* Returns list of struct dm_str_list containing pool-allocated copy of pvids */
|
||||||
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
||||||
const char *vgid);
|
const char *vgid);
|
||||||
@@ -157,4 +181,17 @@ unsigned lvmcache_mda_count(struct lvmcache_info *info);
|
|||||||
int lvmcache_vgid_is_cached(const char *vgid);
|
int lvmcache_vgid_is_cached(const char *vgid);
|
||||||
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
|
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
|
||||||
|
|
||||||
|
void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
|
||||||
|
struct device *dev);
|
||||||
|
|
||||||
|
int lvmcache_found_duplicate_pvs(void);
|
||||||
|
|
||||||
|
void lvmcache_set_preferred_duplicates(const char *vgid);
|
||||||
|
|
||||||
|
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
|
||||||
|
|
||||||
|
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||||
|
unsigned *pv_max_name_len, unsigned *vg_max_name_len);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
826
lib/cache/lvmetad.c
vendored
826
lib/cache/lvmetad.c
vendored
File diff suppressed because it is too large
Load Diff
30
lib/cache/lvmetad.h
vendored
30
lib/cache/lvmetad.h
vendored
@@ -29,8 +29,7 @@ typedef int (*activation_handler) (struct cmd_context *cmd,
|
|||||||
|
|
||||||
#ifdef LVMETAD_SUPPORT
|
#ifdef LVMETAD_SUPPORT
|
||||||
/*
|
/*
|
||||||
* Initialise the communication with lvmetad. Normally called by
|
* Sets up a global handle for our process.
|
||||||
* lvmcache_init. Sets up a global handle for our process.
|
|
||||||
*/
|
*/
|
||||||
void lvmetad_init(struct cmd_context *);
|
void lvmetad_init(struct cmd_context *);
|
||||||
|
|
||||||
@@ -59,7 +58,9 @@ int lvmetad_socket_present(void);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether lvmetad is active (where active means both that it is running
|
* Check whether lvmetad is active (where active means both that it is running
|
||||||
* and that we have a working connection with it).
|
* and that we have a working connection with it). It opens new connection
|
||||||
|
* with lvmetad in the process when lvmetad is supposed to be used and the
|
||||||
|
* connection is not open yet.
|
||||||
*/
|
*/
|
||||||
int lvmetad_active(void);
|
int lvmetad_active(void);
|
||||||
|
|
||||||
@@ -70,8 +71,9 @@ int lvmetad_active(void);
|
|||||||
void lvmetad_connect_or_warn(void);
|
void lvmetad_connect_or_warn(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish
|
* Drop connection to lvmetad. A subsequent lvmetad_connect_or_warn or
|
||||||
* the connection (possibly at a different socket path).
|
* lvmetad_active will re-establish the connection (possibly at a
|
||||||
|
* different socket path).
|
||||||
*/
|
*/
|
||||||
void lvmetad_disconnect(void);
|
void lvmetad_disconnect(void);
|
||||||
|
|
||||||
@@ -142,6 +144,12 @@ int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *f
|
|||||||
*/
|
*/
|
||||||
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd);
|
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request a list of vgid/vgname pairs for all VGs known to lvmetad.
|
||||||
|
* Does not do vg_lookup's on each VG, and does not populate lvmcache.
|
||||||
|
*/
|
||||||
|
int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a VG by its ID or its name in the lvmetad cache. Gives NULL if the VG is
|
* Find a VG by its ID or its name in the lvmetad cache. Gives NULL if the VG is
|
||||||
* not found.
|
* not found.
|
||||||
@@ -153,9 +161,13 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
|
|||||||
* Scan a single device and update lvmetad with the result(s).
|
* Scan a single device and update lvmetad with the result(s).
|
||||||
*/
|
*/
|
||||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||||
activation_handler handler);
|
activation_handler handler, int ignore_obsolete);
|
||||||
|
|
||||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
|
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
|
||||||
|
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
|
||||||
|
|
||||||
|
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
|
||||||
|
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
|
||||||
|
|
||||||
# else /* LVMETAD_SUPPORT */
|
# else /* LVMETAD_SUPPORT */
|
||||||
|
|
||||||
@@ -178,9 +190,13 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
|||||||
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
|
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
|
||||||
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
||||||
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
||||||
|
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
|
||||||
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
|
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
|
||||||
# define lvmetad_pvscan_single(cmd, dev, handler) (0)
|
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
|
||||||
# define lvmetad_pvscan_all_devs(cmd, handler) (0)
|
# define lvmetad_pvscan_all_devs(cmd, handler) (0)
|
||||||
|
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
|
||||||
|
# define lvmetad_vg_clear_outdated_pvs(vg) (1)
|
||||||
|
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
|
||||||
|
|
||||||
# endif /* LVMETAD_SUPPORT */
|
# endif /* LVMETAD_SUPPORT */
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,17 @@
|
|||||||
#include "text_export.h"
|
#include "text_export.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "str_list.h"
|
#include "str_list.h"
|
||||||
#include "targets.h"
|
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "activate.h"
|
#include "activate.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "lv_alloc.h"
|
#include "lv_alloc.h"
|
||||||
#include "defaults.h"
|
#include "defaults.h"
|
||||||
|
|
||||||
|
static const char _cache_module[] = "cache";
|
||||||
|
|
||||||
|
/* TODO: using static field here, maybe should be a part of segment_type */
|
||||||
|
static unsigned _feature_mask;
|
||||||
|
|
||||||
#define SEG_LOG_ERROR(t, p...) \
|
#define SEG_LOG_ERROR(t, p...) \
|
||||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||||
@@ -67,7 +71,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
|||||||
if (dm_config_has_node(sn, "cache_mode")) {
|
if (dm_config_has_node(sn, "cache_mode")) {
|
||||||
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
|
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
|
||||||
return SEG_LOG_ERROR("cache_mode must be a string in");
|
return SEG_LOG_ERROR("cache_mode must be a string in");
|
||||||
if (!set_cache_pool_feature(&seg->feature_flags, str))
|
if (!cache_set_mode(seg, str))
|
||||||
return SEG_LOG_ERROR("Unknown cache_mode in");
|
return SEG_LOG_ERROR("Unknown cache_mode in");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,9 +80,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
|||||||
return SEG_LOG_ERROR("policy must be a string in");
|
return SEG_LOG_ERROR("policy must be a string in");
|
||||||
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
|
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
|
||||||
return SEG_LOG_ERROR("Failed to duplicate policy in");
|
return SEG_LOG_ERROR("Failed to duplicate policy in");
|
||||||
} else
|
}
|
||||||
/* Cannot use 'just' default, so pick one */
|
|
||||||
seg->policy_name = DEFAULT_CACHE_POOL_POLICY; /* FIXME make configurable */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read in policy args:
|
* Read in policy args:
|
||||||
@@ -98,6 +100,9 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
|||||||
* If the policy is not present, default policy is used.
|
* If the policy is not present, default policy is used.
|
||||||
*/
|
*/
|
||||||
if ((sn = dm_config_find_node(sn, "policy_settings"))) {
|
if ((sn = dm_config_find_node(sn, "policy_settings"))) {
|
||||||
|
if (!seg->policy_name)
|
||||||
|
return SEG_LOG_ERROR("policy_settings must have a policy_name in");
|
||||||
|
|
||||||
if (sn->v)
|
if (sn->v)
|
||||||
return SEG_LOG_ERROR("policy_settings must be a section in");
|
return SEG_LOG_ERROR("policy_settings must be a section in");
|
||||||
|
|
||||||
@@ -126,24 +131,33 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
|
|||||||
{
|
{
|
||||||
const char *cache_mode;
|
const char *cache_mode;
|
||||||
|
|
||||||
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
|
|
||||||
return_0;
|
|
||||||
|
|
||||||
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
|
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
|
||||||
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
|
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
|
||||||
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
|
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
|
||||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
|
||||||
|
|
||||||
if (seg->policy_name)
|
/*
|
||||||
|
* Cache pool used by a cache LV holds data. Not ideal,
|
||||||
|
* but not worth to break backward compatibility, by shifting
|
||||||
|
* content to cache segment
|
||||||
|
*/
|
||||||
|
if (cache_mode_is_set(seg)) {
|
||||||
|
if (!(cache_mode = get_cache_mode_name(seg)))
|
||||||
|
return_0;
|
||||||
|
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seg->policy_name) {
|
||||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||||
|
|
||||||
if (seg->policy_settings) {
|
if (seg->policy_settings) {
|
||||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||||
seg->policy_settings->key);
|
seg->policy_settings->key);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
if (seg->policy_settings->child)
|
||||||
|
out_config_node(f, seg->policy_settings);
|
||||||
}
|
}
|
||||||
out_config_node(f, seg->policy_settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -156,12 +170,29 @@ static void _destroy(struct segment_type *segtype)
|
|||||||
|
|
||||||
#ifdef DEVMAPPER_SUPPORT
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
static int _target_present(struct cmd_context *cmd,
|
static int _target_present(struct cmd_context *cmd,
|
||||||
const struct lv_segment *seg __attribute__((unused)),
|
const struct lv_segment *seg __attribute__((unused)),
|
||||||
unsigned *attributes __attribute__((unused)))
|
unsigned *attributes __attribute__((unused)))
|
||||||
{
|
{
|
||||||
uint32_t maj, min, patchlevel;
|
/* List of features with their kernel target version */
|
||||||
|
static const struct feature {
|
||||||
|
uint32_t maj;
|
||||||
|
uint32_t min;
|
||||||
|
unsigned cache_feature;
|
||||||
|
const char feature[12];
|
||||||
|
const char module[12]; /* check dm-%s */
|
||||||
|
} _features[] = {
|
||||||
|
{ 1, 3, CACHE_FEATURE_POLICY_MQ, "policy_mq", "cache-mq" },
|
||||||
|
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, "policy_smq", "cache-smq" },
|
||||||
|
};
|
||||||
|
static const char _lvmconf[] = "global/cache_disabled_features";
|
||||||
|
static unsigned _attrs = 0;
|
||||||
static int _cache_checked = 0;
|
static int _cache_checked = 0;
|
||||||
static int _cache_present = 0;
|
static int _cache_present = 0;
|
||||||
|
uint32_t maj, min, patchlevel;
|
||||||
|
unsigned i;
|
||||||
|
const struct dm_config_node *cn;
|
||||||
|
const struct dm_config_value *cv;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
if (!_cache_checked) {
|
if (!_cache_checked) {
|
||||||
_cache_present = target_present(cmd, "cache", 1);
|
_cache_present = target_present(cmd, "cache", 1);
|
||||||
@@ -175,11 +206,53 @@ static int _target_present(struct cmd_context *cmd,
|
|||||||
|
|
||||||
if ((maj < 1) ||
|
if ((maj < 1) ||
|
||||||
((maj == 1) && (min < 3))) {
|
((maj == 1) && (min < 3))) {
|
||||||
log_error("The cache kernel module is version %u.%u.%u."
|
_cache_present = 0;
|
||||||
" Version 1.3.0+ is required.",
|
log_error("The cache kernel module is version %u.%u.%u. "
|
||||||
|
"Version 1.3.0+ is required.",
|
||||||
maj, min, patchlevel);
|
maj, min, patchlevel);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) {
|
||||||
|
if (((maj > _features[i].maj) ||
|
||||||
|
(maj == _features[i].maj && min >= _features[i].min)) &&
|
||||||
|
(!_features[i].module[0] || module_present(cmd, _features[i].module)))
|
||||||
|
_attrs |= _features[i].cache_feature;
|
||||||
|
else
|
||||||
|
log_very_verbose("Target %s does not support %s.",
|
||||||
|
_cache_module, _features[i].feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes) {
|
||||||
|
if (!_feature_mask) {
|
||||||
|
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
|
||||||
|
if ((cn = find_config_tree_array(cmd, global_cache_disabled_features_CFG, NULL))) {
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != DM_CFG_STRING) {
|
||||||
|
log_error("Ignoring invalid string in config file %s.",
|
||||||
|
_lvmconf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
str = cv->v.str;
|
||||||
|
if (!*str)
|
||||||
|
continue;
|
||||||
|
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||||
|
if (strcasecmp(str, _features[i].feature) == 0)
|
||||||
|
_feature_mask |= _features[i].cache_feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_feature_mask = ~_feature_mask;
|
||||||
|
|
||||||
|
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||||
|
if ((_attrs & _features[i].cache_feature) &&
|
||||||
|
!(_feature_mask & _features[i].cache_feature))
|
||||||
|
log_very_verbose("Target %s %s support disabled by %s",
|
||||||
|
_cache_module, _features[i].feature, _lvmconf);
|
||||||
|
}
|
||||||
|
*attributes = _attrs & _feature_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _cache_present;
|
return _cache_present;
|
||||||
@@ -281,9 +354,16 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
|||||||
struct dm_tree_node *node, uint64_t len,
|
struct dm_tree_node *node, uint64_t len,
|
||||||
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
||||||
{
|
{
|
||||||
struct lv_segment *cache_pool_seg = first_seg(seg->pool_lv);
|
struct lv_segment *cache_pool_seg;
|
||||||
char *metadata_uuid, *data_uuid, *origin_uuid;
|
char *metadata_uuid, *data_uuid, *origin_uuid;
|
||||||
|
|
||||||
|
if (!seg->pool_lv || !seg_is_cache(seg)) {
|
||||||
|
log_error(INTERNAL_ERROR "Passed segment is not cache.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_pool_seg = first_seg(seg->pool_lv);
|
||||||
|
|
||||||
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
|
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
@@ -298,7 +378,9 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
|||||||
metadata_uuid,
|
metadata_uuid,
|
||||||
data_uuid,
|
data_uuid,
|
||||||
origin_uuid,
|
origin_uuid,
|
||||||
seg->cleaner_policy ? "cleaner" : cache_pool_seg->policy_name,
|
seg->cleaner_policy ? "cleaner" :
|
||||||
|
/* undefined policy name -> likely an old "mq" */
|
||||||
|
cache_pool_seg->policy_name ? : "mq",
|
||||||
seg->cleaner_policy ? NULL : cache_pool_seg->policy_settings,
|
seg->cleaner_policy ? NULL : cache_pool_seg->policy_settings,
|
||||||
cache_pool_seg->chunk_size))
|
cache_pool_seg->chunk_size))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -338,7 +420,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
segtype->name = "cache-pool";
|
segtype->name = SEG_TYPE_NAME_CACHE_POOL;
|
||||||
segtype->flags = SEG_CACHE_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
segtype->flags = SEG_CACHE_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||||
segtype->ops = &_cache_pool_ops;
|
segtype->ops = &_cache_pool_ops;
|
||||||
|
|
||||||
@@ -352,7 +434,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
segtype->name = "cache";
|
segtype->name = SEG_TYPE_NAME_CACHE;
|
||||||
segtype->flags = SEG_CACHE | SEG_ONLY_EXCLUSIVE;
|
segtype->flags = SEG_CACHE | SEG_ONLY_EXCLUSIVE;
|
||||||
segtype->ops = &_cache_ops;
|
segtype->ops = &_cache_ops;
|
||||||
|
|
||||||
@@ -360,5 +442,8 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
|||||||
return_0;
|
return_0;
|
||||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||||
|
|
||||||
|
/* Reset mask for recalc */
|
||||||
|
_feature_mask = 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "lvmcache.h"
|
#include "lvmcache.h"
|
||||||
#include "lvmetad.h"
|
#include "lvmetad.h"
|
||||||
#include "archiver.h"
|
#include "archiver.h"
|
||||||
|
#include "lvmpolld-client.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
#include "sharedlib.h"
|
#include "sharedlib.h"
|
||||||
@@ -55,6 +56,128 @@
|
|||||||
|
|
||||||
static const size_t linebuffer_size = 4096;
|
static const size_t linebuffer_size = 4096;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the input string, removing invalid characters.
|
||||||
|
*/
|
||||||
|
const char *system_id_from_string(struct cmd_context *cmd, const char *str)
|
||||||
|
{
|
||||||
|
char *system_id;
|
||||||
|
|
||||||
|
if (!str || !*str) {
|
||||||
|
log_warn("WARNING: Empty system ID supplied.");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(system_id = dm_pool_zalloc(cmd->libmem, strlen(str) + 1))) {
|
||||||
|
log_warn("WARNING: Failed to allocate system ID.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_systemid_chars(str, system_id);
|
||||||
|
|
||||||
|
if (!*system_id) {
|
||||||
|
log_warn("WARNING: Invalid system ID format: %s", str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(system_id, "localhost", 9)) {
|
||||||
|
log_warn("WARNING: system ID may not begin with the string \"localhost\".");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return system_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *_read_system_id_from_file(struct cmd_context *cmd, const char *file)
|
||||||
|
{
|
||||||
|
char *line = NULL;
|
||||||
|
size_t line_size;
|
||||||
|
char *start, *end;
|
||||||
|
const char *system_id = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!file || !strlen(file) || !file[0])
|
||||||
|
return_NULL;
|
||||||
|
|
||||||
|
if (!(fp = fopen(file, "r"))) {
|
||||||
|
log_warn("WARNING: %s: fopen failed: %s", file, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (getline(&line, &line_size, fp) > 0) {
|
||||||
|
start = line;
|
||||||
|
|
||||||
|
/* Ignore leading whitespace */
|
||||||
|
while (*start && isspace(*start))
|
||||||
|
start++;
|
||||||
|
|
||||||
|
/* Ignore rest of line after # */
|
||||||
|
if (!*start || *start == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (system_id && *system_id) {
|
||||||
|
log_warn("WARNING: Ignoring extra line(s) in system ID file %s.", file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove any comments from end of line */
|
||||||
|
for (end = start; *end; end++)
|
||||||
|
if (*end == '#') {
|
||||||
|
*end = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
system_id = system_id_from_string(cmd, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
|
||||||
|
if (fclose(fp))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
return system_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *_system_id_from_source(struct cmd_context *cmd, const char *source)
|
||||||
|
{
|
||||||
|
char filebuf[PATH_MAX];
|
||||||
|
const char *file;
|
||||||
|
const char *etc_str;
|
||||||
|
const char *str;
|
||||||
|
const char *system_id = NULL;
|
||||||
|
|
||||||
|
if (!strcasecmp(source, "uname")) {
|
||||||
|
if (cmd->hostname)
|
||||||
|
system_id = system_id_from_string(cmd, cmd->hostname);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lvm.conf and lvmlocal.conf are merged into one config tree */
|
||||||
|
if (!strcasecmp(source, "lvmlocal")) {
|
||||||
|
if ((str = find_config_tree_str(cmd, local_system_id_CFG, NULL)))
|
||||||
|
system_id = system_id_from_string(cmd, str);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(source, "machineid") || !strcasecmp(source, "machine-id")) {
|
||||||
|
etc_str = find_config_tree_str(cmd, global_etc_CFG, NULL);
|
||||||
|
if (dm_snprintf(filebuf, sizeof(filebuf), "%s/machine-id", etc_str) != -1)
|
||||||
|
system_id = _read_system_id_from_file(cmd, filebuf);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(source, "file")) {
|
||||||
|
file = find_config_tree_str(cmd, global_system_id_file_CFG, NULL);
|
||||||
|
system_id = _read_system_id_from_file(cmd, file);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn("WARNING: Unrecognised system_id_source \"%s\".", source);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return system_id;
|
||||||
|
}
|
||||||
|
|
||||||
static int _get_env_vars(struct cmd_context *cmd)
|
static int _get_env_vars(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
const char *e;
|
const char *e;
|
||||||
@@ -122,8 +245,10 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
|||||||
const struct dm_config_value *cv;
|
const struct dm_config_value *cv;
|
||||||
int debug_classes = 0;
|
int debug_classes = 0;
|
||||||
|
|
||||||
if (!(cn = find_config_tree_node(cmd, log_debug_classes_CFG, NULL)))
|
if (!(cn = find_config_tree_array(cmd, log_debug_classes_CFG, NULL))) {
|
||||||
return DEFAULT_LOGGED_DEBUG_CLASSES;
|
log_error(INTERNAL_ERROR "Unable to find configuration for log/debug_classes.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (cv = cn->v; cv; cv = cv->next) {
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
if (cv->type != DM_CFG_STRING) {
|
if (cv->type != DM_CFG_STRING) {
|
||||||
@@ -151,6 +276,8 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
|||||||
debug_classes |= LOG_CLASS_CACHE;
|
debug_classes |= LOG_CLASS_CACHE;
|
||||||
else if (!strcasecmp(cv->v.str, "locking"))
|
else if (!strcasecmp(cv->v.str, "locking"))
|
||||||
debug_classes |= LOG_CLASS_LOCKING;
|
debug_classes |= LOG_CLASS_LOCKING;
|
||||||
|
else if (!strcasecmp(cv->v.str, "lvmpolld"))
|
||||||
|
debug_classes |= LOG_CLASS_LVMPOLLD;
|
||||||
else
|
else
|
||||||
log_verbose("Unrecognised value for log/debug_classes: %s", cv->v.str);
|
log_verbose("Unrecognised value for log/debug_classes: %s", cv->v.str);
|
||||||
}
|
}
|
||||||
@@ -235,7 +362,8 @@ static void _init_logging(struct cmd_context *cmd)
|
|||||||
|
|
||||||
/* Tell device-mapper about our logging */
|
/* Tell device-mapper about our logging */
|
||||||
#ifdef DEVMAPPER_SUPPORT
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
dm_log_with_errno_init(print_log);
|
if (!dm_log_is_non_default())
|
||||||
|
dm_log_with_errno_init(print_log);
|
||||||
#endif
|
#endif
|
||||||
reset_log_duplicated();
|
reset_log_duplicated();
|
||||||
reset_lvm_errno(1);
|
reset_lvm_errno(1);
|
||||||
@@ -288,7 +416,59 @@ static int _check_config(struct cmd_context *cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_profilable_config(struct cmd_context *cmd) {
|
static const char *_set_time_format(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
/* Compared to strftime, we do not allow "newline" character - the %n in format. */
|
||||||
|
static const char *allowed_format_chars = "aAbBcCdDeFGghHIjklmMpPrRsStTuUVwWxXyYzZ%";
|
||||||
|
static const char *allowed_alternative_format_chars_e = "cCxXyY";
|
||||||
|
static const char *allowed_alternative_format_chars_o = "deHImMSuUVwWy";
|
||||||
|
static const char *chars_to_check;
|
||||||
|
const char *tf = find_config_tree_str(cmd, report_time_format_CFG, NULL);
|
||||||
|
const char *p_fmt;
|
||||||
|
size_t i;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (!*tf) {
|
||||||
|
log_error("Configured time format is empty string.");
|
||||||
|
goto bad;
|
||||||
|
} else {
|
||||||
|
p_fmt = tf;
|
||||||
|
while ((c = *p_fmt)) {
|
||||||
|
if (c == '%') {
|
||||||
|
c = *++p_fmt;
|
||||||
|
if (c == 'E') {
|
||||||
|
c = *++p_fmt;
|
||||||
|
chars_to_check = allowed_alternative_format_chars_e;
|
||||||
|
} else if (c == 'O') {
|
||||||
|
c = *++p_fmt;
|
||||||
|
chars_to_check = allowed_alternative_format_chars_o;
|
||||||
|
} else
|
||||||
|
chars_to_check = allowed_format_chars;
|
||||||
|
|
||||||
|
for (i = 0; chars_to_check[i]; i++) {
|
||||||
|
if (c == chars_to_check[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!chars_to_check[i])
|
||||||
|
goto_bad;
|
||||||
|
}
|
||||||
|
else if (isprint(c))
|
||||||
|
p_fmt++;
|
||||||
|
else {
|
||||||
|
log_error("Configured time format contains non-printable characters.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tf;
|
||||||
|
bad:
|
||||||
|
log_error("Invalid time format \"%s\" supplied.", tf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_profilable_config(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
if (!(cmd->default_settings.unit_factor =
|
if (!(cmd->default_settings.unit_factor =
|
||||||
dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL),
|
dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL),
|
||||||
&cmd->default_settings.unit_type, 1, NULL))) {
|
&cmd->default_settings.unit_type, 1, NULL))) {
|
||||||
@@ -300,6 +480,46 @@ int process_profilable_config(struct cmd_context *cmd) {
|
|||||||
cmd->report_binary_values_as_numeric = find_config_tree_bool(cmd, report_binary_values_as_numeric_CFG, NULL);
|
cmd->report_binary_values_as_numeric = find_config_tree_bool(cmd, report_binary_values_as_numeric_CFG, NULL);
|
||||||
cmd->default_settings.suffix = find_config_tree_bool(cmd, global_suffix_CFG, NULL);
|
cmd->default_settings.suffix = find_config_tree_bool(cmd, global_suffix_CFG, NULL);
|
||||||
cmd->report_list_item_separator = find_config_tree_str(cmd, report_list_item_separator_CFG, NULL);
|
cmd->report_list_item_separator = find_config_tree_str(cmd, report_list_item_separator_CFG, NULL);
|
||||||
|
if (!(cmd->time_format = _set_time_format(cmd)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_system_id(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const char *source, *system_id;
|
||||||
|
int local_set = 0;
|
||||||
|
|
||||||
|
cmd->system_id = NULL;
|
||||||
|
cmd->unknown_system_id = 0;
|
||||||
|
|
||||||
|
system_id = find_config_tree_str_allow_empty(cmd, local_system_id_CFG, NULL);
|
||||||
|
if (system_id && *system_id)
|
||||||
|
local_set = 1;
|
||||||
|
|
||||||
|
source = find_config_tree_str(cmd, global_system_id_source_CFG, NULL);
|
||||||
|
if (!source)
|
||||||
|
source = "none";
|
||||||
|
|
||||||
|
/* Defining local system_id but not using it is probably a config mistake. */
|
||||||
|
if (local_set && strcmp(source, "lvmlocal"))
|
||||||
|
log_warn("WARNING: local/system_id is set, so should global/system_id_source be \"lvmlocal\" not \"%s\"?", source);
|
||||||
|
|
||||||
|
if (!strcmp(source, "none"))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if ((system_id = _system_id_from_source(cmd, source)) && *system_id) {
|
||||||
|
cmd->system_id = system_id;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The source failed to resolve a system_id. In this case allow
|
||||||
|
* VGs with no system_id to be accessed, but not VGs with a system_id.
|
||||||
|
*/
|
||||||
|
log_warn("WARNING: No system ID found from system_id_source %s.", source);
|
||||||
|
cmd->unknown_system_id = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -307,12 +527,12 @@ int process_profilable_config(struct cmd_context *cmd) {
|
|||||||
static int _process_config(struct cmd_context *cmd)
|
static int _process_config(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
mode_t old_umask;
|
mode_t old_umask;
|
||||||
|
const char *dev_ext_info_src;
|
||||||
const char *read_ahead;
|
const char *read_ahead;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
const struct dm_config_node *cn;
|
const struct dm_config_node *cn;
|
||||||
const struct dm_config_value *cv;
|
const struct dm_config_value *cv;
|
||||||
int64_t pv_min_kb;
|
int64_t pv_min_kb;
|
||||||
const char *lvmetad_socket;
|
|
||||||
int udev_disabled = 0;
|
int udev_disabled = 0;
|
||||||
char sysfs_dir[PATH_MAX];
|
char sysfs_dir[PATH_MAX];
|
||||||
|
|
||||||
@@ -340,6 +560,16 @@ static int _process_config(struct cmd_context *cmd)
|
|||||||
return_0;
|
return_0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
|
||||||
|
if (!strcmp(dev_ext_info_src, "none"))
|
||||||
|
init_external_device_info_source(DEV_EXT_NONE);
|
||||||
|
else if (!strcmp(dev_ext_info_src, "udev"))
|
||||||
|
init_external_device_info_source(DEV_EXT_UDEV);
|
||||||
|
else {
|
||||||
|
log_error("Invalid external device info source specification.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* proc dir */
|
/* proc dir */
|
||||||
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||||
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
|
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
|
||||||
@@ -423,7 +653,7 @@ static int _process_config(struct cmd_context *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cn = find_config_tree_node(cmd, activation_mlock_filter_CFG, NULL)))
|
if ((cn = find_config_tree_array(cmd, activation_mlock_filter_CFG, NULL)))
|
||||||
for (cv = cn->v; cv; cv = cv->next)
|
for (cv = cn->v; cv; cv = cv->next)
|
||||||
if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
|
if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
|
||||||
log_error("Ignoring invalid activation/mlock_filter entry in config file");
|
log_error("Ignoring invalid activation/mlock_filter entry in config file");
|
||||||
@@ -445,29 +675,8 @@ static int _process_config(struct cmd_context *cmd)
|
|||||||
init_detect_internal_vg_cache_corruption
|
init_detect_internal_vg_cache_corruption
|
||||||
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
|
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
|
||||||
|
|
||||||
lvmetad_disconnect();
|
if (!_init_system_id(cmd))
|
||||||
|
return_0;
|
||||||
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
|
|
||||||
if (!lvmetad_socket)
|
|
||||||
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
|
|
||||||
|
|
||||||
/* TODO?
|
|
||||||
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
|
|
||||||
DEFAULT_RUN_DIR "/lvmetad.socket");
|
|
||||||
*/
|
|
||||||
lvmetad_set_socket(lvmetad_socket);
|
|
||||||
cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL);
|
|
||||||
lvmetad_set_token(cn ? cn->v : NULL);
|
|
||||||
|
|
||||||
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
|
|
||||||
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
|
|
||||||
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
|
|
||||||
"Clustered environment not supported by lvmetad yet.");
|
|
||||||
lvmetad_set_active(NULL, 0);
|
|
||||||
} else
|
|
||||||
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
|
||||||
|
|
||||||
lvmetad_init(cmd);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -526,11 +735,12 @@ static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
|
|||||||
const char *tag;
|
const char *tag;
|
||||||
int passes;
|
int passes;
|
||||||
|
|
||||||
if (!(tn = find_config_tree_node(cmd, tags_CFG_SECTION, NULL)) || !tn->child)
|
/* Access tags section directly */
|
||||||
|
if (!(tn = find_config_node(cmd, cft, tags_CFG_SECTION)) || !tn->child)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* NB hosttags 0 when already 1 intentionally does not delete the tag */
|
/* NB hosttags 0 when already 1 intentionally does not delete the tag */
|
||||||
if (!cmd->hosttags && find_config_tree_bool(cmd, tags_hosttags_CFG, NULL)) {
|
if (!cmd->hosttags && find_config_bool(cmd, cft, tags_hosttags_CFG)) {
|
||||||
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
||||||
if (!_set_tag(cmd, cmd->hostname))
|
if (!_set_tag(cmd, cmd->hostname))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -561,7 +771,7 @@ static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
static int _load_config_file(struct cmd_context *cmd, const char *tag, int local)
|
||||||
{
|
{
|
||||||
static char config_file[PATH_MAX] = "";
|
static char config_file[PATH_MAX] = "";
|
||||||
const char *filler = "";
|
const char *filler = "";
|
||||||
@@ -569,6 +779,10 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
|||||||
|
|
||||||
if (*tag)
|
if (*tag)
|
||||||
filler = "_";
|
filler = "_";
|
||||||
|
else if (local) {
|
||||||
|
filler = "";
|
||||||
|
tag = "local";
|
||||||
|
}
|
||||||
|
|
||||||
if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||||
cmd->system_dir, filler, tag) < 0) {
|
cmd->system_dir, filler, tag) < 0) {
|
||||||
@@ -596,7 +810,9 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find and read first config file */
|
/*
|
||||||
|
* Find and read lvm.conf.
|
||||||
|
*/
|
||||||
static int _init_lvm_conf(struct cmd_context *cmd)
|
static int _init_lvm_conf(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||||
@@ -608,7 +824,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_load_config_file(cmd, ""))
|
if (!_load_config_file(cmd, "", 0))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -621,7 +837,7 @@ static int _init_tag_configs(struct cmd_context *cmd)
|
|||||||
|
|
||||||
/* Tag list may grow while inside this loop */
|
/* Tag list may grow while inside this loop */
|
||||||
dm_list_iterate_items(sl, &cmd->tags) {
|
dm_list_iterate_items(sl, &cmd->tags) {
|
||||||
if (!_load_config_file(cmd, sl->str))
|
if (!_load_config_file(cmd, sl->str, 0))
|
||||||
return_0;
|
return_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,15 +984,9 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
|||||||
|
|
||||||
init_obtain_device_list_from_udev(device_list_from_udev);
|
init_obtain_device_list_from_udev(device_list_from_udev);
|
||||||
|
|
||||||
if (!(cn = find_config_tree_node(cmd, devices_scan_CFG, NULL))) {
|
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
|
||||||
if (!dev_cache_add_dir("/dev")) {
|
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
|
||||||
log_error("Failed to add /dev to internal "
|
return_0;
|
||||||
"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) {
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
@@ -814,7 +1024,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(cn = find_config_tree_node(cmd, devices_loopfiles_CFG, NULL)))
|
if (!(cn = find_config_tree_array(cmd, devices_loopfiles_CFG, NULL)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (cv = cn->v; cv; cv = cv->next) {
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
@@ -835,7 +1045,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_FILTERS 7
|
#define MAX_FILTERS 8
|
||||||
|
|
||||||
static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
@@ -860,7 +1070,7 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
|||||||
nr_filt++;
|
nr_filt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* regex filter. Optional. */
|
/* global regex filter. Optional. */
|
||||||
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
|
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
|
||||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||||
log_error("Failed to create global regex device filter");
|
log_error("Failed to create global regex device filter");
|
||||||
@@ -869,6 +1079,17 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
|||||||
nr_filt++;
|
nr_filt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* regex filter. Optional. */
|
||||||
|
if (!lvmetad_used()) {
|
||||||
|
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||||
|
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||||
|
log_error("Failed to create regex device filter");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
nr_filt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* device type filter. Required. */
|
/* device type filter. Required. */
|
||||||
if (!(filters[nr_filt] = lvm_type_filter_create(cmd->dev_types))) {
|
if (!(filters[nr_filt] = lvm_type_filter_create(cmd->dev_types))) {
|
||||||
log_error("Failed to create lvm type filter");
|
log_error("Failed to create lvm type filter");
|
||||||
@@ -905,7 +1126,14 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
|||||||
nr_filt++;
|
nr_filt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(composite = composite_filter_create(nr_filt, filters)))
|
/* firmware raid filter. Optional, non-critical. */
|
||||||
|
if (find_config_tree_bool(cmd, devices_fw_raid_component_detection_CFG, NULL)) {
|
||||||
|
init_fwraid_filtering(1);
|
||||||
|
if ((filters[nr_filt] = fwraid_filter_create(cmd->dev_types)))
|
||||||
|
nr_filt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(composite = composite_filter_create(nr_filt, 1, filters)))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
return composite;
|
return composite;
|
||||||
@@ -926,31 +1154,35 @@ bad:
|
|||||||
* sysfs filter -> global regex filter -> type filter ->
|
* sysfs filter -> global regex filter -> type filter ->
|
||||||
* usable device filter(FILTER_MODE_PRE_LVMETAD) ->
|
* usable device filter(FILTER_MODE_PRE_LVMETAD) ->
|
||||||
* mpath component filter -> partitioned filter ->
|
* mpath component filter -> partitioned filter ->
|
||||||
* md component filter
|
* md component filter -> fw raid filter
|
||||||
*
|
*
|
||||||
* - cmd->filter - the filter chain used for lvmetad responses:
|
* - cmd->filter - the filter chain used for lvmetad responses:
|
||||||
* persistent filter -> usable device filter(FILTER_MODE_POST_LVMETAD) ->
|
* persistent filter -> regex_filter -> usable device filter(FILTER_MODE_POST_LVMETAD)
|
||||||
* regex filter
|
|
||||||
*
|
*
|
||||||
* - cmd->full_filter - the filter chain used for all the remaining situations:
|
* - cmd->full_filter - the filter chain used for all the remaining situations:
|
||||||
* lvmetad_filter -> filter
|
* cmd->lvmetad_filter -> cmd->filter
|
||||||
*
|
*
|
||||||
* If lvmetad isnot used, there's just one filter chain:
|
* If lvmetad is not used, there's just one filter chain:
|
||||||
*
|
*
|
||||||
* - cmd->filter == cmd->full_filter:
|
* - cmd->filter == cmd->full_filter:
|
||||||
* persistent filter -> regex filter -> sysfs filter ->
|
* persistent filter -> sysfs filter -> global regex filter ->
|
||||||
* global regex filter -> type filter ->
|
* regex_filter -> type filter -> usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||||
* usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
* mpath component filter -> partitioned filter -> md component filter -> fw raid filter
|
||||||
* mpath component filter -> partitioned filter ->
|
|
||||||
* md component filter
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||||
{
|
{
|
||||||
const char *dev_cache;
|
const char *dev_cache;
|
||||||
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
||||||
|
int nr_filt;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
const struct dm_config_node *cn;
|
const struct dm_config_node *cn;
|
||||||
|
struct timespec ts, cts;
|
||||||
|
|
||||||
|
if (!cmd->initialized.connections) {
|
||||||
|
log_error(INTERNAL_ERROR "connections must be initialized before filters");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cmd->dump_filter = 0;
|
cmd->dump_filter = 0;
|
||||||
|
|
||||||
@@ -971,26 +1203,26 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
|||||||
*/
|
*/
|
||||||
/* filter component 0 */
|
/* filter component 0 */
|
||||||
if (lvmetad_used()) {
|
if (lvmetad_used()) {
|
||||||
if (!(filter_components[0] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
nr_filt = 0;
|
||||||
|
if ((cn = find_config_tree_array(cmd, devices_filter_CFG, NULL))) {
|
||||||
|
if (!(filter_components[nr_filt] = regex_filter_create(cn->v))) {
|
||||||
|
log_verbose("Failed to create regex device filter.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
nr_filt++;
|
||||||
|
}
|
||||||
|
if (!(filter_components[nr_filt] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
||||||
log_verbose("Failed to create usable device filter.");
|
log_verbose("Failed to create usable device filter.");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
nr_filt++;
|
||||||
|
if (!(filter = composite_filter_create(nr_filt, 0, filter_components)))
|
||||||
|
goto_bad;
|
||||||
} else {
|
} else {
|
||||||
filter_components[0] = cmd->lvmetad_filter;
|
filter = cmd->lvmetad_filter;
|
||||||
cmd->lvmetad_filter = NULL;
|
cmd->lvmetad_filter = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* filter component 1 */
|
|
||||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
|
||||||
if (!(filter_components[1] = regex_filter_create(cn->v)))
|
|
||||||
goto_bad;
|
|
||||||
/* we have two filter components - create composite filter */
|
|
||||||
if (!(filter = composite_filter_create(2, filter_components)))
|
|
||||||
goto_bad;
|
|
||||||
} else
|
|
||||||
/* we have only one filter component - no need to create composite filter */
|
|
||||||
filter = filter_components[0];
|
|
||||||
|
|
||||||
if (!(dev_cache = find_config_tree_str(cmd, devices_cache_CFG, NULL)))
|
if (!(dev_cache = find_config_tree_str(cmd, devices_cache_CFG, NULL)))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
@@ -1002,9 +1234,12 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
|||||||
cmd->filter = filter;
|
cmd->filter = filter;
|
||||||
|
|
||||||
if (lvmetad_used()) {
|
if (lvmetad_used()) {
|
||||||
filter_components[0] = cmd->lvmetad_filter;
|
nr_filt = 0;
|
||||||
filter_components[1] = cmd->filter;
|
filter_components[nr_filt] = cmd->lvmetad_filter;
|
||||||
if (!(cmd->full_filter = composite_filter_create(2, filter_components)))
|
nr_filt++;
|
||||||
|
filter_components[nr_filt] = cmd->filter;
|
||||||
|
nr_filt++;
|
||||||
|
if (!(cmd->full_filter = composite_filter_create(nr_filt, 0, filter_components)))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
} else
|
} else
|
||||||
cmd->full_filter = filter;
|
cmd->full_filter = filter;
|
||||||
@@ -1023,12 +1258,16 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
|||||||
*/
|
*/
|
||||||
if (!find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL) &&
|
if (!find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL) &&
|
||||||
load_persistent_cache && !cmd->is_long_lived &&
|
load_persistent_cache && !cmd->is_long_lived &&
|
||||||
!stat(dev_cache, &st) &&
|
!stat(dev_cache, &st)) {
|
||||||
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
|
lvm_stat_ctim(&ts, &st);
|
||||||
!persistent_filter_load(cmd->filter, NULL))
|
cts = config_file_timestamp(cmd->cft);
|
||||||
log_verbose("Failed to load existing device cache from %s",
|
if (timespeccmp(&ts, &cts, >) &&
|
||||||
dev_cache);
|
!persistent_filter_load(cmd->filter, NULL))
|
||||||
|
log_verbose("Failed to load existing device cache from %s",
|
||||||
|
dev_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->initialized.filters = 1;
|
||||||
return 1;
|
return 1;
|
||||||
bad:
|
bad:
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
@@ -1052,6 +1291,7 @@ bad:
|
|||||||
if (cmd->lvmetad_filter)
|
if (cmd->lvmetad_filter)
|
||||||
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
|
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
|
||||||
|
|
||||||
|
cmd->initialized.filters = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1095,7 +1335,7 @@ static int _init_formats(struct cmd_context *cmd)
|
|||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
/* Load any formats in shared libs if not static */
|
/* Load any formats in shared libs if not static */
|
||||||
if (!is_static() &&
|
if (!is_static() &&
|
||||||
(cn = find_config_tree_node(cmd, global_format_libraries_CFG, NULL))) {
|
(cn = find_config_tree_array(cmd, global_format_libraries_CFG, NULL))) {
|
||||||
|
|
||||||
const struct dm_config_value *cv;
|
const struct dm_config_value *cv;
|
||||||
struct format_type *(*init_format_fn) (struct cmd_context *);
|
struct format_type *(*init_format_fn) (struct cmd_context *);
|
||||||
@@ -1261,7 +1501,7 @@ static int _init_segtypes(struct cmd_context *cmd)
|
|||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
/* Load any formats in shared libs unless static */
|
/* Load any formats in shared libs unless static */
|
||||||
if (!is_static() &&
|
if (!is_static() &&
|
||||||
(cn = find_config_tree_node(cmd, global_segment_libraries_CFG, NULL))) {
|
(cn = find_config_tree_array(cmd, global_segment_libraries_CFG, NULL))) {
|
||||||
|
|
||||||
const struct dm_config_value *cv;
|
const struct dm_config_value *cv;
|
||||||
int (*init_multiple_segtypes_fn) (struct cmd_context *,
|
int (*init_multiple_segtypes_fn) (struct cmd_context *,
|
||||||
@@ -1425,11 +1665,80 @@ static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *na
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _init_lvmetad(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const struct dm_config_node *cn;
|
||||||
|
const char *lvmetad_socket;
|
||||||
|
|
||||||
|
lvmetad_disconnect();
|
||||||
|
|
||||||
|
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
|
||||||
|
if (!lvmetad_socket)
|
||||||
|
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
|
||||||
|
|
||||||
|
/* TODO?
|
||||||
|
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
|
||||||
|
DEFAULT_RUN_DIR "/lvmetad.socket");
|
||||||
|
*/
|
||||||
|
|
||||||
|
lvmetad_set_socket(lvmetad_socket);
|
||||||
|
cn = find_config_tree_array(cmd, devices_global_filter_CFG, NULL);
|
||||||
|
lvmetad_set_token(cn ? cn->v : NULL);
|
||||||
|
|
||||||
|
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
|
||||||
|
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
|
||||||
|
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
|
||||||
|
"Clustered environment not supported by lvmetad yet.");
|
||||||
|
lvmetad_set_active(NULL, 0);
|
||||||
|
} else
|
||||||
|
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
||||||
|
|
||||||
|
lvmetad_init(cmd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_lvmpolld(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const char *lvmpolld_socket;
|
||||||
|
|
||||||
|
lvmpolld_disconnect();
|
||||||
|
|
||||||
|
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
|
||||||
|
if (!lvmpolld_socket)
|
||||||
|
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
|
||||||
|
lvmpolld_set_socket(lvmpolld_socket);
|
||||||
|
|
||||||
|
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_connections(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!_init_lvmetad(cmd)) {
|
||||||
|
log_error("Failed to initialize lvmetad connection.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_init_lvmpolld(cmd)) {
|
||||||
|
log_error("Failed to initialize lvmpolld connection.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->initialized.connections = 1;
|
||||||
|
return 1;
|
||||||
|
bad:
|
||||||
|
cmd->initialized.connections = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Entry point */
|
/* Entry point */
|
||||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||||
const char *system_dir,
|
const char *system_dir,
|
||||||
unsigned set_buffering,
|
unsigned set_buffering,
|
||||||
unsigned threaded)
|
unsigned threaded,
|
||||||
|
unsigned set_connections,
|
||||||
|
unsigned set_filters)
|
||||||
{
|
{
|
||||||
struct cmd_context *cmd;
|
struct cmd_context *cmd;
|
||||||
FILE *new_stream;
|
FILE *new_stream;
|
||||||
@@ -1550,6 +1859,10 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
|||||||
if (!_init_tags(cmd, cmd->cft))
|
if (!_init_tags(cmd, cmd->cft))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
|
/* Load lvmlocal.conf */
|
||||||
|
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
|
||||||
|
goto_out;
|
||||||
|
|
||||||
if (!_init_tag_configs(cmd))
|
if (!_init_tag_configs(cmd))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
@@ -1563,15 +1876,12 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
|||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||||
find_config_tree_node(cmd, devices_types_CFG, NULL))))
|
find_config_tree_array(cmd, devices_types_CFG, NULL))))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (!_init_dev_cache(cmd))
|
if (!_init_dev_cache(cmd))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (!_init_filters(cmd, 1))
|
|
||||||
goto_out;
|
|
||||||
|
|
||||||
memlock_init(cmd);
|
memlock_init(cmd);
|
||||||
|
|
||||||
if (!_init_formats(cmd))
|
if (!_init_formats(cmd))
|
||||||
@@ -1590,12 +1900,18 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
|||||||
|
|
||||||
_init_globals(cmd);
|
_init_globals(cmd);
|
||||||
|
|
||||||
|
if (set_connections && !init_connections(cmd))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (set_filters && !init_filters(cmd, 1))
|
||||||
|
goto_out;
|
||||||
|
|
||||||
cmd->default_settings.cache_vgmetadata = 1;
|
cmd->default_settings.cache_vgmetadata = 1;
|
||||||
cmd->current_settings = cmd->default_settings;
|
cmd->current_settings = cmd->default_settings;
|
||||||
|
|
||||||
cmd->config_initialized = 1;
|
cmd->initialized.config = 1;
|
||||||
out:
|
out:
|
||||||
if (!cmd->config_initialized) {
|
if (!cmd->initialized.config) {
|
||||||
destroy_toolcontext(cmd);
|
destroy_toolcontext(cmd);
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
}
|
}
|
||||||
@@ -1667,14 +1983,19 @@ static void _destroy_filters(struct cmd_context *cmd)
|
|||||||
cmd->full_filter->destroy(cmd->full_filter);
|
cmd->full_filter->destroy(cmd->full_filter);
|
||||||
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
|
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
|
||||||
}
|
}
|
||||||
|
cmd->initialized.filters = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int refresh_filters(struct cmd_context *cmd)
|
int refresh_filters(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
|
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
|
||||||
|
|
||||||
|
if (!cmd->initialized.filters)
|
||||||
|
/* if filters not initialized, there's nothing to refresh */
|
||||||
|
return 1;
|
||||||
|
|
||||||
_destroy_filters(cmd);
|
_destroy_filters(cmd);
|
||||||
if (!(r = _init_filters(cmd, 0)))
|
if (!(r = init_filters(cmd, 0)))
|
||||||
stack;
|
stack;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1703,7 +2024,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
label_exit();
|
label_exit();
|
||||||
_destroy_segtypes(&cmd->segtypes);
|
_destroy_segtypes(&cmd->segtypes);
|
||||||
_destroy_formats(cmd, &cmd->formats);
|
_destroy_formats(cmd, &cmd->formats);
|
||||||
_destroy_filters(cmd);
|
|
||||||
|
|
||||||
if (!dev_cache_exit())
|
if (!dev_cache_exit())
|
||||||
stack;
|
stack;
|
||||||
@@ -1721,7 +2041,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
|
|
||||||
_destroy_config(cmd);
|
_destroy_config(cmd);
|
||||||
|
|
||||||
cmd->config_initialized = 0;
|
cmd->initialized.config = 0;
|
||||||
|
|
||||||
cmd->hosttags = 0;
|
cmd->hosttags = 0;
|
||||||
|
|
||||||
@@ -1754,6 +2074,10 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
if (!_init_tags(cmd, cft_tmp))
|
if (!_init_tags(cmd, cft_tmp))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
|
/* Load lvmlocal.conf */
|
||||||
|
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
|
||||||
|
return_0;
|
||||||
|
|
||||||
/* Doesn't change cmd->cft */
|
/* Doesn't change cmd->cft */
|
||||||
if (!_init_tag_configs(cmd))
|
if (!_init_tag_configs(cmd))
|
||||||
return_0;
|
return_0;
|
||||||
@@ -1774,15 +2098,12 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||||
find_config_tree_node(cmd, devices_types_CFG, NULL))))
|
find_config_tree_array(cmd, devices_types_CFG, NULL))))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!_init_dev_cache(cmd))
|
if (!_init_dev_cache(cmd))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!_init_filters(cmd, 0))
|
|
||||||
return_0;
|
|
||||||
|
|
||||||
if (!_init_formats(cmd))
|
if (!_init_formats(cmd))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
@@ -1795,7 +2116,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
if (!_init_backup(cmd))
|
if (!_init_backup(cmd))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
cmd->config_initialized = 1;
|
cmd->initialized.config = 1;
|
||||||
|
|
||||||
|
if (cmd->initialized.connections && !init_connections(cmd))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (!refresh_filters(cmd))
|
||||||
|
return_0;
|
||||||
|
|
||||||
reset_lvm_errno(1);
|
reset_lvm_errno(1);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1864,6 +2191,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
|||||||
|
|
||||||
lvmetad_release_token();
|
lvmetad_release_token();
|
||||||
lvmetad_disconnect();
|
lvmetad_disconnect();
|
||||||
|
lvmpolld_disconnect();
|
||||||
|
|
||||||
release_log_memory();
|
release_log_memory();
|
||||||
activation_exit();
|
activation_exit();
|
||||||
|
|||||||
@@ -60,28 +60,59 @@ struct config_tree_list {
|
|||||||
struct dm_config_tree *cft;
|
struct dm_config_tree *cft;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cmd_context_initialized_parts {
|
||||||
|
unsigned config:1; /* used to reinitialize config if previous init was not successful */
|
||||||
|
unsigned filters:1;
|
||||||
|
unsigned connections:1;
|
||||||
|
};
|
||||||
|
|
||||||
/* FIXME Split into tool & library contexts */
|
/* FIXME Split into tool & library contexts */
|
||||||
/* command-instance-related variables needed by library */
|
/* command-instance-related variables needed by library */
|
||||||
struct cmd_context {
|
struct cmd_context {
|
||||||
struct dm_pool *libmem; /* For permanent config data */
|
/*
|
||||||
struct dm_pool *mem; /* Transient: Cleared between each command */
|
* Memory handlers.
|
||||||
|
*/
|
||||||
|
struct dm_pool *libmem; /* for permanent config data */
|
||||||
|
struct dm_pool *mem; /* transient: cleared between each command */
|
||||||
|
|
||||||
const struct format_type *fmt; /* Current format to use by default */
|
/*
|
||||||
struct format_type *fmt_backup; /* Format to use for backups */
|
* Command line and arguments.
|
||||||
|
*/
|
||||||
struct dm_list formats; /* Available formats */
|
|
||||||
struct dm_list segtypes; /* Available segment types */
|
|
||||||
const char *hostname;
|
|
||||||
const char *kernel_vsn;
|
|
||||||
|
|
||||||
unsigned rand_seed;
|
|
||||||
char *linebuffer;
|
|
||||||
const char *cmd_line;
|
const char *cmd_line;
|
||||||
struct command *command;
|
struct command *command;
|
||||||
char **argv;
|
char **argv;
|
||||||
struct arg_values *arg_values;
|
struct arg_values *arg_values;
|
||||||
struct dm_list arg_value_groups;
|
struct dm_list arg_value_groups;
|
||||||
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
|
|
||||||
|
/*
|
||||||
|
* Format handlers.
|
||||||
|
*/
|
||||||
|
const struct format_type *fmt; /* current format to use by default */
|
||||||
|
struct format_type *fmt_backup; /* format to use for backups */
|
||||||
|
struct dm_list formats; /* available formats */
|
||||||
|
struct dm_list segtypes; /* available segment types */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Machine and system identification.
|
||||||
|
*/
|
||||||
|
const char *system_id;
|
||||||
|
const char *hostname;
|
||||||
|
const char *kernel_vsn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device identification.
|
||||||
|
*/
|
||||||
|
struct dev_types *dev_types; /* recognized extra device types. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialization state.
|
||||||
|
*/
|
||||||
|
struct cmd_context_initialized_parts initialized;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switches.
|
||||||
|
*/
|
||||||
|
unsigned is_long_lived:1; /* optimises persistent_filter handling */
|
||||||
unsigned handles_missing_pvs:1;
|
unsigned handles_missing_pvs:1;
|
||||||
unsigned handles_unknown_segments:1;
|
unsigned handles_unknown_segments:1;
|
||||||
unsigned use_linear_target:1;
|
unsigned use_linear_target:1;
|
||||||
@@ -92,55 +123,73 @@ struct cmd_context {
|
|||||||
unsigned report_binary_values_as_numeric:1;
|
unsigned report_binary_values_as_numeric:1;
|
||||||
unsigned metadata_read_only:1;
|
unsigned metadata_read_only:1;
|
||||||
unsigned ignore_clustered_vgs:1;
|
unsigned ignore_clustered_vgs:1;
|
||||||
unsigned threaded:1; /* Set if running within a thread e.g. clvmd */
|
unsigned threaded:1; /* set if running within a thread e.g. clvmd */
|
||||||
|
unsigned independent_metadata_areas:1; /* active formats have MDAs outside PVs */
|
||||||
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
|
unsigned unknown_system_id:1;
|
||||||
|
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
|
||||||
struct dev_types *dev_types;
|
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
|
||||||
|
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
|
||||||
|
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
|
||||||
|
unsigned lockd_gl_disable:1;
|
||||||
|
unsigned lockd_vg_disable:1;
|
||||||
|
unsigned lockd_lv_disable:1;
|
||||||
|
unsigned lockd_gl_removed:1;
|
||||||
|
unsigned lockd_vg_rescan:1;
|
||||||
|
unsigned lockd_vg_default_sh:1;
|
||||||
|
unsigned lockd_vg_enforce_sh:1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use of filters depends on whether lvmetad is used or not:
|
* Filtering.
|
||||||
*
|
|
||||||
* - if lvmetad is used:
|
|
||||||
* - cmd->lvmetad_filter used when scanning devices for lvmetad
|
|
||||||
* - cmd->filter used when processing lvmetad responses
|
|
||||||
* - cmd->full_filter used for remaining situations
|
|
||||||
*
|
|
||||||
* - if lvmetad is not used:
|
|
||||||
* - cmd->lvmetad_filter is NULL
|
|
||||||
* - cmd->filter == cmd->full_filter used for all situations
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
struct dev_filter *lvmetad_filter;
|
struct dev_filter *lvmetad_filter; /* pre-lvmetad filter chain */
|
||||||
struct dev_filter *filter;
|
struct dev_filter *filter; /* post-lvmetad filter chain */
|
||||||
struct dev_filter *full_filter;
|
struct dev_filter *full_filter; /* lvmetad_filter + filter */
|
||||||
int dump_filter; /* Dump filter when exiting? */
|
int dump_filter; /* Dump filter when exiting? */
|
||||||
|
|
||||||
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
/*
|
||||||
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
|
* Configuration.
|
||||||
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
|
*/
|
||||||
int config_initialized; /* used to reinitialize config if previous init was not successful */
|
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
||||||
|
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
|
||||||
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
|
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||||
|
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
|
||||||
/* selected settings with original default/configured value which can be changed during cmd processing */
|
struct config_info default_settings; /* selected settings with original default/configured value which can be changed during cmd processing */
|
||||||
struct config_info default_settings;
|
struct config_info current_settings; /* may contain changed values compared to default_settings */
|
||||||
/* may contain changed values compared to default_settings */
|
|
||||||
struct config_info current_settings;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Archives and backups.
|
||||||
|
*/
|
||||||
struct archive_params *archive_params;
|
struct archive_params *archive_params;
|
||||||
struct backup_params *backup_params;
|
struct backup_params *backup_params;
|
||||||
const char *stripe_filler;
|
const char *stripe_filler;
|
||||||
|
|
||||||
/* List of defined tags */
|
/*
|
||||||
struct dm_list tags;
|
* Host tags.
|
||||||
const char *report_list_item_separator;
|
*/
|
||||||
|
struct dm_list tags; /* list of defined tags */
|
||||||
int hosttags;
|
int hosttags;
|
||||||
|
|
||||||
const char *lib_dir; /* Cache value global/library_dir */
|
/*
|
||||||
|
* Paths.
|
||||||
|
*/
|
||||||
|
const char *lib_dir; /* cache value global/library_dir */
|
||||||
char system_dir[PATH_MAX];
|
char system_dir[PATH_MAX];
|
||||||
char dev_dir[PATH_MAX];
|
char dev_dir[PATH_MAX];
|
||||||
char proc_dir[PATH_MAX];
|
char proc_dir[PATH_MAX];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buffers.
|
||||||
|
*/
|
||||||
|
char display_buffer[NAME_LEN * 10]; /* ring buffer for upto 10 longest vg/lv names */
|
||||||
|
unsigned display_lvname_idx; /* index to ring buffer */
|
||||||
|
char *linebuffer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Others - unsorted.
|
||||||
|
*/
|
||||||
|
const char *report_list_item_separator;
|
||||||
|
const char *time_format;
|
||||||
|
unsigned rand_seed;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -150,14 +199,20 @@ struct cmd_context {
|
|||||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||||
const char *system_dir,
|
const char *system_dir,
|
||||||
unsigned set_buffering,
|
unsigned set_buffering,
|
||||||
unsigned threaded);
|
unsigned threaded,
|
||||||
|
unsigned set_connections,
|
||||||
|
unsigned set_filters);
|
||||||
void destroy_toolcontext(struct cmd_context *cmd);
|
void destroy_toolcontext(struct cmd_context *cmd);
|
||||||
int refresh_toolcontext(struct cmd_context *cmd);
|
int refresh_toolcontext(struct cmd_context *cmd);
|
||||||
int refresh_filters(struct cmd_context *cmd);
|
int refresh_filters(struct cmd_context *cmd);
|
||||||
int process_profilable_config(struct cmd_context *cmd);
|
int process_profilable_config(struct cmd_context *cmd);
|
||||||
int config_files_changed(struct cmd_context *cmd);
|
int config_files_changed(struct cmd_context *cmd);
|
||||||
int init_lvmcache_orphans(struct cmd_context *cmd);
|
int init_lvmcache_orphans(struct cmd_context *cmd);
|
||||||
|
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
|
||||||
|
int init_connections(struct cmd_context *cmd);
|
||||||
|
|
||||||
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);
|
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);
|
||||||
|
|
||||||
|
const char *system_id_from_string(struct cmd_context *cmd, const char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ struct config_file {
|
|||||||
|
|
||||||
struct config_source {
|
struct config_source {
|
||||||
config_source_t type;
|
config_source_t type;
|
||||||
time_t timestamp;
|
struct timespec timestamp;
|
||||||
union {
|
union {
|
||||||
struct config_file *file;
|
struct config_file *file;
|
||||||
struct config_file *profile;
|
struct config_file *profile;
|
||||||
@@ -65,11 +65,11 @@ struct config_source {
|
|||||||
* Map each ID to respective definition of the configuration item.
|
* Map each ID to respective definition of the configuration item.
|
||||||
*/
|
*/
|
||||||
static struct cfg_def_item _cfg_def_items[CFG_COUNT + 1] = {
|
static struct cfg_def_item _cfg_def_items[CFG_COUNT + 1] = {
|
||||||
#define cfg_section(id, name, parent, flags, since_version, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, comment},
|
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, {0}, deprecated_since_version, deprecation_comment, comment},
|
||||||
#define cfg(id, name, parent, flags, type, default_value, since_version, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, comment},
|
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, {.v_UNCONFIGURED = unconfigured_value}, deprecated_since_version, deprecation_comment, comment},
|
||||||
#define cfg_runtime(id, name, parent, flags, type, since_version, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, comment},
|
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
|
||||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, comment},
|
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, {.v_UNCONFIGURED = unconfigured_value}, deprecated_since_version, deprecation_comment, comment},
|
||||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, comment},
|
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
|
||||||
#include "config_settings.h"
|
#include "config_settings.h"
|
||||||
#undef cfg_section
|
#undef cfg_section
|
||||||
#undef cfg
|
#undef cfg
|
||||||
@@ -173,7 +173,7 @@ int config_file_check(struct dm_config_tree *cft, const char **filename, struct
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cs->timestamp = info->st_ctime;
|
lvm_stat_ctim(&cs->timestamp, info);
|
||||||
cf->exists = 1;
|
cf->exists = 1;
|
||||||
cf->st_size = info->st_size;
|
cf->st_size = info->st_size;
|
||||||
|
|
||||||
@@ -193,6 +193,7 @@ int config_file_changed(struct dm_config_tree *cft)
|
|||||||
struct config_source *cs = dm_config_get_custom(cft);
|
struct config_source *cs = dm_config_get_custom(cft);
|
||||||
struct config_file *cf;
|
struct config_file *cf;
|
||||||
struct stat info;
|
struct stat info;
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
if (cs->type != CONFIG_FILE) {
|
if (cs->type != CONFIG_FILE) {
|
||||||
log_error(INTERNAL_ERROR "config_file_changed: expected file config source, "
|
log_error(INTERNAL_ERROR "config_file_changed: expected file config source, "
|
||||||
@@ -226,7 +227,9 @@ int config_file_changed(struct dm_config_tree *cft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Unchanged? */
|
/* Unchanged? */
|
||||||
if (cs->timestamp == info.st_ctime && cf->st_size == info.st_size)
|
lvm_stat_ctim(&ts, &info);
|
||||||
|
if ((timespeccmp(&cs->timestamp, &ts, ==)) &&
|
||||||
|
cf->st_size == info.st_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
reload:
|
reload:
|
||||||
@@ -478,9 +481,15 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When checksum_only is set, the checksum of buffer is only matched
|
||||||
|
* and function avoids parsing of mda into config tree which
|
||||||
|
* remains unmodified and should not be used.
|
||||||
|
*/
|
||||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||||
checksum_fn_t checksum_fn, uint32_t checksum)
|
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||||
|
int checksum_only)
|
||||||
{
|
{
|
||||||
char *fb, *fe;
|
char *fb, *fe;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
@@ -529,9 +538,11 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fe = fb + size + size2;
|
if (!checksum_only) {
|
||||||
if (!dm_config_parse(cft, fb, fe))
|
fe = fb + size + size2;
|
||||||
goto_out;
|
if (!dm_config_parse(cft, fb, fe))
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
|
||||||
r = 1;
|
r = 1;
|
||||||
|
|
||||||
@@ -570,12 +581,15 @@ int config_file_read(struct dm_config_tree *cft)
|
|||||||
if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
|
if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!dev_open_readonly_buffered(cf->dev))
|
if (!dev_open_readonly_buffered(cf->dev)) {
|
||||||
|
dev_destroy_file(cf->dev);
|
||||||
|
cf->dev = NULL;
|
||||||
return_0;
|
return_0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
|
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
|
||||||
(checksum_fn_t) NULL, 0);
|
(checksum_fn_t) NULL, 0, 0);
|
||||||
|
|
||||||
if (!cf->keep_open) {
|
if (!cf->keep_open) {
|
||||||
if (!dev_close(cf->dev))
|
if (!dev_close(cf->dev))
|
||||||
@@ -586,13 +600,14 @@ int config_file_read(struct dm_config_tree *cft)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t config_file_timestamp(struct dm_config_tree *cft)
|
struct timespec config_file_timestamp(struct dm_config_tree *cft)
|
||||||
{
|
{
|
||||||
struct config_source *cs = dm_config_get_custom(cft);
|
struct config_source *cs = dm_config_get_custom(cft);
|
||||||
return cs->timestamp;
|
return cs->timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define cfg_def_get_item_p(id) (&_cfg_def_items[id])
|
#define cfg_def_get_item_p(id) (&_cfg_def_items[id])
|
||||||
|
#define cfg_def_get_default_unconfigured_value_hint(cmd,item) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_unconfigured_value.fn_UNCONFIGURED(cmd) : item->default_unconfigured_value.v_UNCONFIGURED)
|
||||||
#define cfg_def_get_default_value_hint(cmd,item,type,profile) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_value.fn_##type(cmd,profile) : item->default_value.v_##type)
|
#define cfg_def_get_default_value_hint(cmd,item,type,profile) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_value.fn_##type(cmd,profile) : item->default_value.v_##type)
|
||||||
#define cfg_def_get_default_value(cmd,item,type,profile) (item->flags & CFG_DEFAULT_UNDEFINED ? 0 : cfg_def_get_default_value_hint(cmd,item,type,profile))
|
#define cfg_def_get_default_value(cmd,item,type,profile) (item->flags & CFG_DEFAULT_UNDEFINED ? 0 : cfg_def_get_default_value_hint(cmd,item,type,profile))
|
||||||
|
|
||||||
@@ -649,27 +664,33 @@ static void _log_type_error(const char *path, cfg_def_type_t actual,
|
|||||||
_get_type_name(actual_type_name, sizeof(actual_type_name), actual);
|
_get_type_name(actual_type_name, sizeof(actual_type_name), actual);
|
||||||
_get_type_name(expected_type_name, sizeof(expected_type_name), expected);
|
_get_type_name(expected_type_name, sizeof(expected_type_name), expected);
|
||||||
|
|
||||||
log_warn_suppress(suppress_messages, "Configuration setting \"%s\" has invalid type. "
|
log_warn_suppress(suppress_messages, "WARNING: Configuration setting \"%s\" has invalid type. "
|
||||||
"Found%s, expected%s.", path,
|
"Found%s but expected%s.", path,
|
||||||
actual_type_name, expected_type_name);
|
actual_type_name, expected_type_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
|
||||||
const cfg_def_item_t *def)
|
struct dm_config_tree *cft,
|
||||||
|
const cfg_def_item_t *def,
|
||||||
|
uint32_t format_flags)
|
||||||
{
|
{
|
||||||
|
const char *def_enc_value;
|
||||||
char *enc_value, *token, *p, *r;
|
char *enc_value, *token, *p, *r;
|
||||||
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
|
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
|
||||||
|
|
||||||
if (!def->default_value.v_CFG_TYPE_STRING) {
|
def_enc_value = cfg_def_get_default_value(cmd, def, CFG_TYPE_ARRAY, NULL);
|
||||||
|
|
||||||
|
if (!def_enc_value) {
|
||||||
if (!(array = dm_config_create_value(cft))) {
|
if (!(array = dm_config_create_value(cft))) {
|
||||||
log_error("Failed to create default empty array for %s.", def->name);
|
log_error("Failed to create default empty array for %s.", def->name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
array->type = DM_CFG_EMPTY_ARRAY;
|
array->type = DM_CFG_EMPTY_ARRAY;
|
||||||
|
dm_config_value_set_format_flags(array, format_flags);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(p = token = enc_value = dm_strdup(def->default_value.v_CFG_TYPE_STRING))) {
|
if (!(p = token = enc_value = dm_strdup(def_enc_value))) {
|
||||||
log_error("_get_def_array_values: dm_strdup failed");
|
log_error("_get_def_array_values: dm_strdup failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -698,6 +719,9 @@ static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
|||||||
dm_free(enc_value);
|
dm_free(enc_value);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dm_config_value_set_format_flags(v, format_flags);
|
||||||
|
|
||||||
if (oldv)
|
if (oldv)
|
||||||
oldv->next = v;
|
oldv->next = v;
|
||||||
if (!array)
|
if (!array)
|
||||||
@@ -790,6 +814,11 @@ static int _config_def_check_node_single_value(struct cft_check_handle *handle,
|
|||||||
} else if (!(def->type & CFG_TYPE_STRING)) {
|
} else if (!(def->type & CFG_TYPE_STRING)) {
|
||||||
_log_type_error(rp, CFG_TYPE_STRING, def->type, handle->suppress_messages);
|
_log_type_error(rp, CFG_TYPE_STRING, def->type, handle->suppress_messages);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (!(def->flags & CFG_ALLOW_EMPTY) && !*v->v.str) {
|
||||||
|
log_warn_suppress(handle->suppress_messages,
|
||||||
|
"Configuration setting \"%s\" invalid. "
|
||||||
|
"It cannot be set to an empty value.", rp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
@@ -809,6 +838,12 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
|
|||||||
float f;
|
float f;
|
||||||
const char *str;
|
const char *str;
|
||||||
|
|
||||||
|
if ((handle->ignoreunsupported && (def->flags & CFG_UNSUPPORTED)) ||
|
||||||
|
(handle->ignoreadvanced && (def->flags & CFG_ADVANCED))) {
|
||||||
|
diff = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* if default value is undefined, the value used differs from default */
|
/* if default value is undefined, the value used differs from default */
|
||||||
if (def->flags & CFG_DEFAULT_UNDEFINED) {
|
if (def->flags & CFG_DEFAULT_UNDEFINED) {
|
||||||
diff = 1;
|
diff = 1;
|
||||||
@@ -816,7 +851,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!v_def && (def->type & CFG_TYPE_ARRAY)) {
|
if (!v_def && (def->type & CFG_TYPE_ARRAY)) {
|
||||||
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cft, def)))
|
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cmd, handle->cft, def, 0)))
|
||||||
return_0;
|
return_0;
|
||||||
do {
|
do {
|
||||||
/* iterate over each element of the array and check its value */
|
/* iterate over each element of the array and check its value */
|
||||||
@@ -1008,9 +1043,14 @@ static int _config_def_check_tree(struct cft_check_handle *handle,
|
|||||||
size_t buf_size, struct dm_config_node *root)
|
size_t buf_size, struct dm_config_node *root)
|
||||||
{
|
{
|
||||||
struct dm_config_node *cn;
|
struct dm_config_node *cn;
|
||||||
|
cfg_def_item_t *def;
|
||||||
int valid, r = 1;
|
int valid, r = 1;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
def = cfg_def_get_item_p(root->id);
|
||||||
|
if (def->flags & CFG_SECTION_NO_CHECK)
|
||||||
|
return 1;
|
||||||
|
|
||||||
for (cn = root->child; cn; cn = cn->sib) {
|
for (cn = root->child; cn; cn = cn->sib) {
|
||||||
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
|
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
|
||||||
buf_size, cn)) && !cn->v) {
|
buf_size, cn)) && !cn->v) {
|
||||||
@@ -1140,6 +1180,29 @@ static int _apply_local_profile(struct cmd_context *cmd, struct profile *profile
|
|||||||
return override_config_tree_from_profile(cmd, profile);
|
return override_config_tree_from_profile(cmd, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _config_disabled(struct cmd_context *cmd, cfg_def_item_t *item, const char *path)
|
||||||
|
{
|
||||||
|
if ((item->flags & CFG_DISABLED) && dm_config_tree_find_node(cmd->cft, path)) {
|
||||||
|
log_warn("WARNING: Configuration setting %s is disabled. Using default value.", path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct dm_config_node *find_config_node(struct cmd_context *cmd, struct dm_config_tree *cft, int id)
|
||||||
|
{
|
||||||
|
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||||
|
char path[CFG_PATH_MAX_LEN];
|
||||||
|
const struct dm_config_node *cn;
|
||||||
|
|
||||||
|
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||||
|
|
||||||
|
cn = dm_config_tree_find_node(cft, path);
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
|
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
{
|
{
|
||||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||||
@@ -1171,7 +1234,8 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
|
|||||||
if (item->type != CFG_TYPE_STRING)
|
if (item->type != CFG_TYPE_STRING)
|
||||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as string.", path);
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as string.", path);
|
||||||
|
|
||||||
str = dm_config_tree_find_str(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
str = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile)
|
||||||
|
: dm_config_tree_find_str(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
||||||
|
|
||||||
if (profile_applied)
|
if (profile_applied)
|
||||||
remove_config_tree_by_source(cmd, profile->source);
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
@@ -1194,7 +1258,8 @@ const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, st
|
|||||||
if (!(item->flags & CFG_ALLOW_EMPTY))
|
if (!(item->flags & CFG_ALLOW_EMPTY))
|
||||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared to allow empty values.", path);
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared to allow empty values.", path);
|
||||||
|
|
||||||
str = dm_config_tree_find_str_allow_empty(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
str = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile)
|
||||||
|
: dm_config_tree_find_str_allow_empty(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
||||||
|
|
||||||
if (profile_applied)
|
if (profile_applied)
|
||||||
remove_config_tree_by_source(cmd, profile->source);
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
@@ -1215,7 +1280,8 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
|
|||||||
if (item->type != CFG_TYPE_INT)
|
if (item->type != CFG_TYPE_INT)
|
||||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
|
||||||
|
|
||||||
i = dm_config_tree_find_int(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
i = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile)
|
||||||
|
: dm_config_tree_find_int(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
||||||
|
|
||||||
if (profile_applied)
|
if (profile_applied)
|
||||||
remove_config_tree_by_source(cmd, profile->source);
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
@@ -1236,7 +1302,8 @@ int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *
|
|||||||
if (item->type != CFG_TYPE_INT)
|
if (item->type != CFG_TYPE_INT)
|
||||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
|
||||||
|
|
||||||
i64 = dm_config_tree_find_int64(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
i64 = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile)
|
||||||
|
: dm_config_tree_find_int64(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
||||||
|
|
||||||
if (profile_applied)
|
if (profile_applied)
|
||||||
remove_config_tree_by_source(cmd, profile->source);
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
@@ -1257,7 +1324,8 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
|
|||||||
if (item->type != CFG_TYPE_FLOAT)
|
if (item->type != CFG_TYPE_FLOAT)
|
||||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as float.", path);
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as float.", path);
|
||||||
|
|
||||||
f = dm_config_tree_find_float(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile));
|
f = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile)
|
||||||
|
: dm_config_tree_find_float(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile));
|
||||||
|
|
||||||
if (profile_applied)
|
if (profile_applied)
|
||||||
remove_config_tree_by_source(cmd, profile->source);
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
@@ -1265,6 +1333,23 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int find_config_bool(struct cmd_context *cmd, struct dm_config_tree *cft, int id)
|
||||||
|
{
|
||||||
|
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||||
|
char path[CFG_PATH_MAX_LEN];
|
||||||
|
int b;
|
||||||
|
|
||||||
|
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||||
|
|
||||||
|
if (item->type != CFG_TYPE_BOOL)
|
||||||
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
|
||||||
|
|
||||||
|
b = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL)
|
||||||
|
: dm_config_tree_find_bool(cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL));
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
|
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
{
|
{
|
||||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||||
@@ -1278,7 +1363,8 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
|||||||
if (item->type != CFG_TYPE_BOOL)
|
if (item->type != CFG_TYPE_BOOL)
|
||||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
|
||||||
|
|
||||||
b = dm_config_tree_find_bool(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile));
|
b = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile)
|
||||||
|
: dm_config_tree_find_bool(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile));
|
||||||
|
|
||||||
if (profile_applied)
|
if (profile_applied)
|
||||||
remove_config_tree_by_source(cmd, profile->source);
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
@@ -1286,6 +1372,106 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dm_config_node *_get_array_def_node(struct cmd_context *cmd,
|
||||||
|
cfg_def_item_t *def,
|
||||||
|
struct profile *profile)
|
||||||
|
{
|
||||||
|
struct dm_config_node *cn;
|
||||||
|
|
||||||
|
if (def->flags & CFG_DEFAULT_UNDEFINED)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(cn = dm_config_create_node(cmd->cft, def->name))) {
|
||||||
|
log_error("Failed to create default array node for %s.", def->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cn->v = _get_def_array_values(cmd, cmd->cft, def, 0))) {
|
||||||
|
dm_pool_free(cmd->cft->mem, cn);
|
||||||
|
return_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _config_array_out_handle {
|
||||||
|
struct dm_pool *mem;
|
||||||
|
char *str;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _config_array_line(const struct dm_config_node *cn, const char *line, void *baton)
|
||||||
|
{
|
||||||
|
struct _config_array_out_handle *handle = (struct _config_array_out_handle *) baton;
|
||||||
|
|
||||||
|
if (!(handle->str = dm_pool_strdup(handle->mem, line))) {
|
||||||
|
log_error("_config_array_line: dm_pool_strdup failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _log_array_value_used(struct dm_pool *mem, const struct dm_config_node *cn,
|
||||||
|
const char *path, int default_used)
|
||||||
|
{
|
||||||
|
struct _config_array_out_handle out_handle = { 0 };
|
||||||
|
struct dm_config_node_out_spec out_spec = { 0 };
|
||||||
|
uint32_t old_format_flags;
|
||||||
|
|
||||||
|
out_handle.mem = mem;
|
||||||
|
out_spec.line_fn = _config_array_line;
|
||||||
|
|
||||||
|
old_format_flags = dm_config_value_get_format_flags(cn->v);
|
||||||
|
dm_config_value_set_format_flags(cn->v,
|
||||||
|
DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES |
|
||||||
|
DM_CONFIG_VALUE_FMT_COMMON_ARRAY);
|
||||||
|
|
||||||
|
if (!dm_config_write_one_node_out(cn, &out_spec, &out_handle)) {
|
||||||
|
log_error("_log_array_value_used: failed to write node value");
|
||||||
|
out_handle.mem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_used)
|
||||||
|
log_very_verbose("%s not found in config: defaulting to %s",
|
||||||
|
path, out_handle.mem ? out_handle.str : "<unknown>");
|
||||||
|
else
|
||||||
|
log_very_verbose("Setting %s to %s",
|
||||||
|
path, out_handle.mem ? out_handle.str : "<unknown>");
|
||||||
|
|
||||||
|
if (out_handle.mem)
|
||||||
|
dm_pool_free(out_handle.mem, out_handle.str);
|
||||||
|
dm_config_value_set_format_flags(cn->v, old_format_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
|
||||||
|
{
|
||||||
|
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||||
|
char path[CFG_PATH_MAX_LEN];
|
||||||
|
int profile_applied;
|
||||||
|
const struct dm_config_node *cn = NULL, *cn_def = NULL;
|
||||||
|
profile_applied = _apply_local_profile(cmd, profile);
|
||||||
|
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||||
|
|
||||||
|
if (!(item->type & CFG_TYPE_ARRAY))
|
||||||
|
log_error(INTERNAL_ERROR "%s cfg tree element not declared as array.", path);
|
||||||
|
|
||||||
|
if (_config_disabled(cmd, item, path) ||
|
||||||
|
!(cn = find_config_tree_node(cmd, id, profile)))
|
||||||
|
cn_def = _get_array_def_node(cmd, item, profile);
|
||||||
|
|
||||||
|
if (cn)
|
||||||
|
_log_array_value_used(cmd->cft->mem, cn, path, 0);
|
||||||
|
else if (cn_def) {
|
||||||
|
_log_array_value_used(cmd->cft->mem, cn_def, path, 1);
|
||||||
|
cn = cn_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile_applied)
|
||||||
|
remove_config_tree_by_source(cmd, profile->source);
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
/* Insert cn2 after cn1 */
|
/* Insert cn2 after cn1 */
|
||||||
static void _insert_config_node(struct dm_config_node **cn1,
|
static void _insert_config_node(struct dm_config_node **cn1,
|
||||||
struct dm_config_node *cn2)
|
struct dm_config_node *cn2)
|
||||||
@@ -1414,7 +1600,7 @@ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
|||||||
cs = dm_config_get_custom(cft);
|
cs = dm_config_get_custom(cft);
|
||||||
csn = dm_config_get_custom(newdata);
|
csn = dm_config_get_custom(newdata);
|
||||||
|
|
||||||
if (cs && csn && (cs->timestamp < csn->timestamp))
|
if (cs && csn && timespeccmp(&cs->timestamp, &csn->timestamp, <))
|
||||||
cs->timestamp = csn->timestamp;
|
cs->timestamp = csn->timestamp;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1426,6 +1612,55 @@ struct out_baton {
|
|||||||
struct dm_pool *mem;
|
struct dm_pool *mem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_COMMENT_LINE 512
|
||||||
|
|
||||||
|
static int _copy_one_line(const char *comment, char *line, int *pos, int len)
|
||||||
|
{
|
||||||
|
int p;
|
||||||
|
int i = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (*pos >= len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(line, 0, MAX_COMMENT_LINE+1);
|
||||||
|
|
||||||
|
for (p = *pos; ; p++) {
|
||||||
|
c = comment[p];
|
||||||
|
|
||||||
|
(*pos)++;
|
||||||
|
|
||||||
|
if (c == '\n' || c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
line[i++] = c;
|
||||||
|
|
||||||
|
if (i == MAX_COMMENT_LINE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _get_config_node_version(uint16_t version_enc, char *version)
|
||||||
|
{
|
||||||
|
if (dm_snprintf(version, 9, "%u.%u.%u",
|
||||||
|
(version_enc & 0xE000) >> 13,
|
||||||
|
(version_enc & 0x1E00) >> 9,
|
||||||
|
(version_enc & 0x1FF)) == -1) {
|
||||||
|
log_error("_get_config_node_version: couldn't create version string");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _def_node_is_deprecated(cfg_def_item_t *def, struct config_def_tree_spec *spec)
|
||||||
|
{
|
||||||
|
return def->deprecated_since_version &&
|
||||||
|
(spec->version >= def->deprecated_since_version);
|
||||||
|
}
|
||||||
|
|
||||||
static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
||||||
{
|
{
|
||||||
struct out_baton *out = baton;
|
struct out_baton *out = baton;
|
||||||
@@ -1433,15 +1668,13 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
|||||||
char version[9]; /* 8+1 chars for max version of 7.15.511 */
|
char version[9]; /* 8+1 chars for max version of 7.15.511 */
|
||||||
const char *node_type_name = cn->v ? "option" : "section";
|
const char *node_type_name = cn->v ? "option" : "section";
|
||||||
char path[CFG_PATH_MAX_LEN];
|
char path[CFG_PATH_MAX_LEN];
|
||||||
|
char commentline[MAX_COMMENT_LINE+1];
|
||||||
|
|
||||||
|
if (cn->id <= 0)
|
||||||
if (cn->id < 0)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!cn->id) {
|
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
|
||||||
log_error(INTERNAL_ERROR "Configuration node %s has invalid id.", cn->key);
|
return 1;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
|
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
|
||||||
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
|
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
|
||||||
@@ -1449,12 +1682,32 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
|||||||
|
|
||||||
cfg_def = cfg_def_get_item_p(cn->id);
|
cfg_def = cfg_def_get_item_p(cn->id);
|
||||||
|
|
||||||
if (out->tree_spec->withcomments) {
|
if (out->tree_spec->withsummary || out->tree_spec->withcomments) {
|
||||||
_cfg_def_make_path(path, sizeof(path), cfg_def->id, cfg_def, 1);
|
_cfg_def_make_path(path, sizeof(path), cfg_def->id, cfg_def, 1);
|
||||||
|
fprintf(out->fp, "\n");
|
||||||
fprintf(out->fp, "%s# Configuration %s %s.\n", line, node_type_name, path);
|
fprintf(out->fp, "%s# Configuration %s %s.\n", line, node_type_name, path);
|
||||||
|
|
||||||
if (cfg_def->comment)
|
if (out->tree_spec->withcomments &&
|
||||||
fprintf(out->fp, "%s# %s\n", line, cfg_def->comment);
|
_def_node_is_deprecated(cfg_def, out->tree_spec))
|
||||||
|
fprintf(out->fp, "%s# %s", line, cfg_def->deprecation_comment);
|
||||||
|
|
||||||
|
if (cfg_def->comment) {
|
||||||
|
int pos = 0;
|
||||||
|
while (_copy_one_line(cfg_def->comment, commentline, &pos, strlen(cfg_def->comment))) {
|
||||||
|
if ((commentline[0] == '#') && (strlen(commentline) == 1)) {
|
||||||
|
if (!out->tree_spec->withspaces)
|
||||||
|
continue;
|
||||||
|
commentline[0] = '\0';
|
||||||
|
}
|
||||||
|
fprintf(out->fp, "%s# %s\n", line, commentline);
|
||||||
|
/* withsummary prints only the first comment line. */
|
||||||
|
if (!out->tree_spec->withcomments)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_def_node_is_deprecated(cfg_def, out->tree_spec))
|
||||||
|
fprintf(out->fp, "%s# This configuration %s is deprecated.\n", line, node_type_name);
|
||||||
|
|
||||||
if (cfg_def->flags & CFG_ADVANCED)
|
if (cfg_def->flags & CFG_ADVANCED)
|
||||||
fprintf(out->fp, "%s# This configuration %s is advanced.\n", line, node_type_name);
|
fprintf(out->fp, "%s# This configuration %s is advanced.\n", line, node_type_name);
|
||||||
@@ -1467,34 +1720,101 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
|||||||
|
|
||||||
if (cfg_def->flags & CFG_DEFAULT_UNDEFINED)
|
if (cfg_def->flags & CFG_DEFAULT_UNDEFINED)
|
||||||
fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name);
|
fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name);
|
||||||
|
|
||||||
|
if (cfg_def->flags & CFG_DEFAULT_COMMENTED)
|
||||||
|
fprintf(out->fp, "%s# This configuration %s has an automatic default value.\n", line, node_type_name);
|
||||||
|
|
||||||
|
if ((out->tree_spec->type == CFG_DEF_TREE_FULL) &&
|
||||||
|
(out->tree_spec->check_status[cn->id] & CFG_USED))
|
||||||
|
fprintf(out->fp, "%s# Value defined in existing configuration has been used for this setting.\n", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out->tree_spec->withversions) {
|
if (out->tree_spec->withversions) {
|
||||||
if (dm_snprintf(version, 9, "%u.%u.%u",
|
if (!_get_config_node_version(cfg_def->since_version, version))
|
||||||
(cfg_def->since_version & 0xE000) >> 13,
|
return_0;
|
||||||
(cfg_def->since_version & 0x1E00) >> 9,
|
fprintf(out->fp, "%s# Available since version %s.\n", line, version);
|
||||||
(cfg_def->since_version & 0x1FF)) == -1) {
|
|
||||||
log_error("_out_prefix_fn: couldn't create version string");
|
if (_def_node_is_deprecated(cfg_def, out->tree_spec)) {
|
||||||
return 0;
|
if (!_get_config_node_version(cfg_def->deprecated_since_version, version))
|
||||||
|
return_0;
|
||||||
|
fprintf(out->fp, "%s# Deprecated since version %s.\n", line, version);
|
||||||
}
|
}
|
||||||
fprintf(out->fp, "%s# Since version %s.\n", line, version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _should_print_cfg_with_undef_def_val(struct out_baton *out, cfg_def_item_t *cfg_def,
|
||||||
|
const struct dm_config_node *cn)
|
||||||
|
{
|
||||||
|
if (!(cfg_def->flags & CFG_DEFAULT_UNDEFINED))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* print it only if the value is directly defined in some config = it's used */
|
||||||
|
return out->tree_spec->check_status && (out->tree_spec->check_status[cn->id] & CFG_USED);
|
||||||
|
}
|
||||||
|
|
||||||
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
||||||
{
|
{
|
||||||
struct out_baton *out = baton;
|
struct out_baton *out = baton;
|
||||||
struct cfg_def_item *cfg_def = cfg_def_get_item_p(cn->id);
|
struct cfg_def_item *cfg_def;
|
||||||
|
char config_path[CFG_PATH_MAX_LEN];
|
||||||
|
char summary[MAX_COMMENT_LINE+1];
|
||||||
|
char version[9];
|
||||||
|
int pos = 0;
|
||||||
|
size_t len;
|
||||||
|
char *space_prefix;
|
||||||
|
|
||||||
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
|
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
|
||||||
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
|
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fprintf(out->fp, "%s%s\n", (out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
|
cfg_def = cfg_def_get_item_p(cn->id);
|
||||||
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
|
|
||||||
(cfg_def->flags & CFG_DEFAULT_UNDEFINED) ? "#" : "", line);
|
if (out->tree_spec->type == CFG_DEF_TREE_LIST) {
|
||||||
|
/* List view with node paths and summary. */
|
||||||
|
if (cfg_def->type & CFG_TYPE_SECTION)
|
||||||
|
return 1;
|
||||||
|
if (!_cfg_def_make_path(config_path, CFG_PATH_MAX_LEN, cfg_def->id, cfg_def, 1))
|
||||||
|
return_0;
|
||||||
|
if (out->tree_spec->withversions && !_get_config_node_version(cfg_def->since_version, version))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
summary[0] = '\0';
|
||||||
|
if (out->tree_spec->withsummary && cfg_def->comment)
|
||||||
|
_copy_one_line(cfg_def->comment, summary, &pos, strlen(cfg_def->comment));
|
||||||
|
|
||||||
|
fprintf(out->fp, "%s%s%s%s%s%s%s\n", config_path,
|
||||||
|
*summary || out->tree_spec->withversions ? " - ": "",
|
||||||
|
*summary ? summary : "",
|
||||||
|
*summary ? " " : "",
|
||||||
|
out->tree_spec->withversions ? "[" : "",
|
||||||
|
out->tree_spec->withversions ? version : "",
|
||||||
|
out->tree_spec->withversions ? "]" : "");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usual tree view with nodes and their values. */
|
||||||
|
|
||||||
|
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
|
||||||
|
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
|
||||||
|
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
|
||||||
|
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
|
||||||
|
/* print with # at the front to comment out the line */
|
||||||
|
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
|
||||||
|
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
|
||||||
|
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
|
||||||
|
if (space_prefix)
|
||||||
|
dm_pool_free(out->mem, space_prefix);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print the line as it is */
|
||||||
|
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
|
||||||
|
fprintf(out->fp, "%s\n", line);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1562,20 +1882,31 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
|||||||
{
|
{
|
||||||
struct dm_config_node *cn;
|
struct dm_config_node *cn;
|
||||||
const char *str;
|
const char *str;
|
||||||
|
uint32_t format_flags = 0;
|
||||||
|
|
||||||
if (!(cn = dm_config_create_node(cft, def->name))) {
|
if (!(cn = dm_config_create_node(cft, def->name))) {
|
||||||
log_error("Failed to create default config setting node.");
|
log_error("Failed to create default config setting node.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(def->type & CFG_TYPE_SECTION) && (!(cn->v = dm_config_create_value(cft)))) {
|
if (!(def->type & CFG_TYPE_SECTION) && !(def->type & CFG_TYPE_ARRAY)) {
|
||||||
log_error("Failed to create default config setting node value.");
|
if (!(cn->v = dm_config_create_value(cft))) {
|
||||||
return NULL;
|
log_error("Failed to create default config setting node value.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (spec->withspaces)
|
||||||
|
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
|
||||||
}
|
}
|
||||||
|
|
||||||
cn->id = def->id;
|
cn->id = def->id;
|
||||||
|
|
||||||
if (!(def->type & CFG_TYPE_ARRAY)) {
|
if (spec->unconfigured && def->default_unconfigured_value.v_UNCONFIGURED) {
|
||||||
|
cn->v->type = DM_CFG_STRING;
|
||||||
|
cn->v->v.str = cfg_def_get_default_unconfigured_value_hint(spec->cmd, def);
|
||||||
|
if (def->type != CFG_TYPE_STRING)
|
||||||
|
format_flags |= DM_CONFIG_VALUE_FMT_STRING_NO_QUOTES;
|
||||||
|
dm_config_value_set_format_flags(cn->v, format_flags);
|
||||||
|
} else if (!(def->type & CFG_TYPE_ARRAY)) {
|
||||||
switch (def->type) {
|
switch (def->type) {
|
||||||
case CFG_TYPE_SECTION:
|
case CFG_TYPE_SECTION:
|
||||||
cn->v = NULL;
|
cn->v = NULL;
|
||||||
@@ -1587,6 +1918,8 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
|||||||
case CFG_TYPE_INT:
|
case CFG_TYPE_INT:
|
||||||
cn->v->type = DM_CFG_INT;
|
cn->v->type = DM_CFG_INT;
|
||||||
cn->v->v.i = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_INT, NULL);
|
cn->v->v.i = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_INT, NULL);
|
||||||
|
if (def->flags & CFG_FORMAT_INT_OCTAL)
|
||||||
|
format_flags |= DM_CONFIG_VALUE_FMT_INT_OCTAL;
|
||||||
break;
|
break;
|
||||||
case CFG_TYPE_FLOAT:
|
case CFG_TYPE_FLOAT:
|
||||||
cn->v->type = DM_CFG_FLOAT;
|
cn->v->type = DM_CFG_FLOAT;
|
||||||
@@ -1603,8 +1936,13 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
|||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
dm_config_value_set_format_flags(cn->v, format_flags);
|
||||||
cn->v = _get_def_array_values(cft, def);
|
} else {
|
||||||
|
if (spec->withspaces)
|
||||||
|
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
|
||||||
|
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_ARRAY;
|
||||||
|
cn->v = _get_def_array_values(spec->cmd, cft, def, format_flags);
|
||||||
|
}
|
||||||
|
|
||||||
cn->child = NULL;
|
cn->child = NULL;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@@ -1620,6 +1958,11 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
|||||||
return cn;
|
return cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _should_skip_deprecated_def_node(cfg_def_item_t *def, struct config_def_tree_spec *spec)
|
||||||
|
{
|
||||||
|
return spec->ignoredeprecated && _def_node_is_deprecated(def, spec);
|
||||||
|
}
|
||||||
|
|
||||||
static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_id, int id)
|
static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_id, int id)
|
||||||
{
|
{
|
||||||
cfg_def_item_t *def = cfg_def_get_item_p(id);
|
cfg_def_item_t *def = cfg_def_get_item_p(id);
|
||||||
@@ -1631,6 +1974,8 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
switch (spec->type) {
|
switch (spec->type) {
|
||||||
|
case CFG_DEF_TREE_FULL:
|
||||||
|
/* fall through */
|
||||||
case CFG_DEF_TREE_MISSING:
|
case CFG_DEF_TREE_MISSING:
|
||||||
if (!spec->check_status) {
|
if (!spec->check_status) {
|
||||||
log_error_once(INTERNAL_ERROR "couldn't determine missing "
|
log_error_once(INTERNAL_ERROR "couldn't determine missing "
|
||||||
@@ -1638,19 +1983,27 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ((spec->check_status[id] & CFG_USED) ||
|
if ((spec->check_status[id] & CFG_USED) ||
|
||||||
(def->flags & CFG_NAME_VARIABLE) ||
|
(def->flags & CFG_NAME_VARIABLE))
|
||||||
(def->since_version > spec->version))
|
return 1;
|
||||||
|
|
||||||
|
if ((spec->type == CFG_DEF_TREE_MISSING) &&
|
||||||
|
((def->since_version > spec->version) ||
|
||||||
|
_should_skip_deprecated_def_node(def, spec)))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
case CFG_DEF_TREE_NEW:
|
case CFG_DEF_TREE_NEW:
|
||||||
if (def->since_version != spec->version)
|
if ((def->since_version != spec->version) ||
|
||||||
|
_should_skip_deprecated_def_node(def, spec))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
case CFG_DEF_TREE_PROFILABLE:
|
case CFG_DEF_TREE_PROFILABLE:
|
||||||
|
/* fall through */
|
||||||
case CFG_DEF_TREE_PROFILABLE_CMD:
|
case CFG_DEF_TREE_PROFILABLE_CMD:
|
||||||
|
/* fall through */
|
||||||
case CFG_DEF_TREE_PROFILABLE_MDA:
|
case CFG_DEF_TREE_PROFILABLE_MDA:
|
||||||
if (!(def->flags & CFG_PROFILABLE) ||
|
if (!(def->flags & CFG_PROFILABLE) ||
|
||||||
(def->since_version > spec->version))
|
(def->since_version > spec->version) ||
|
||||||
|
_should_skip_deprecated_def_node(def, spec))
|
||||||
return 1;
|
return 1;
|
||||||
flags = def->flags & ~CFG_PROFILABLE;
|
flags = def->flags & ~CFG_PROFILABLE;
|
||||||
if (spec->type == CFG_DEF_TREE_PROFILABLE_CMD) {
|
if (spec->type == CFG_DEF_TREE_PROFILABLE_CMD) {
|
||||||
@@ -1662,7 +2015,8 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (def->since_version > spec->version)
|
if ((def->since_version > spec->version) ||
|
||||||
|
_should_skip_deprecated_def_node(def, spec))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1701,7 +2055,7 @@ bad:
|
|||||||
|
|
||||||
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
||||||
{
|
{
|
||||||
struct dm_config_tree *cft;
|
struct dm_config_tree *cft = NULL, *tmp_cft = NULL;
|
||||||
struct dm_config_node *root = NULL, *relay = NULL, *tmp;
|
struct dm_config_node *root = NULL, *relay = NULL, *tmp;
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
@@ -1714,6 +2068,9 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
|||||||
if (cfg_def_get_item_p(id)->parent != root_CFG_SECTION)
|
if (cfg_def_get_item_p(id)->parent != root_CFG_SECTION)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (spec->ignorelocal && (id == local_CFG_SECTION))
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((tmp = _add_def_section_subtree(cft, spec, root, relay, id))) {
|
if ((tmp = _add_def_section_subtree(cft, spec, root, relay, id))) {
|
||||||
relay = tmp;
|
relay = tmp;
|
||||||
if (!root)
|
if (!root)
|
||||||
@@ -1722,7 +2079,33 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cft->root = root;
|
cft->root = root;
|
||||||
|
|
||||||
|
if (spec->type == CFG_DEF_TREE_FULL) {
|
||||||
|
if (!(tmp_cft = dm_config_create())) {
|
||||||
|
log_error("Failed to create temporary config tree while creating full tree.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(tmp_cft->root = dm_config_clone_node_with_mem(cft->mem, spec->current_cft->root, 1))) {
|
||||||
|
log_error("Failed to clone current config tree.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!merge_config_tree(spec->cmd, cft, tmp_cft, CONFIG_MERGE_TYPE_RAW)) {
|
||||||
|
log_error("Failed to merge default and current config tree.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_config_destroy(tmp_cft);
|
||||||
|
}
|
||||||
|
|
||||||
return cft;
|
return cft;
|
||||||
|
bad:
|
||||||
|
if (cft)
|
||||||
|
dm_config_destroy(cft);
|
||||||
|
if (tmp_cft)
|
||||||
|
dm_config_destroy(tmp_cft);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
|
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
|
||||||
@@ -1901,6 +2284,11 @@ const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct pr
|
|||||||
return dm_pool_strdup(cmd->mem, buf);
|
return dm_pool_strdup(cmd->mem, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_default_unconfigured_devices_cache_dir_CFG(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
return "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@";
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile)
|
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||||
{
|
{
|
||||||
const char *cache_dir = NULL, *cache_file_prefix = NULL;
|
const char *cache_dir = NULL, *cache_file_prefix = NULL;
|
||||||
@@ -1935,6 +2323,24 @@ const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profil
|
|||||||
return dm_pool_strdup(cmd->mem, buf);
|
return dm_pool_strdup(cmd->mem, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_default_unconfigured_devices_cache_CFG(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const char *cache_file_prefix = NULL;
|
||||||
|
static char buf[PATH_MAX];
|
||||||
|
|
||||||
|
if (find_config_tree_node(cmd, devices_cache_file_prefix_CFG, NULL))
|
||||||
|
cache_file_prefix = find_config_tree_str_allow_empty(cmd, devices_cache_file_prefix_CFG, NULL);
|
||||||
|
|
||||||
|
if (dm_snprintf(buf, sizeof(buf), "%s/%s.cache",
|
||||||
|
get_default_unconfigured_devices_cache_dir_CFG(cmd),
|
||||||
|
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
|
||||||
|
log_error("Persistent cache filename too long.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dm_pool_strdup(cmd->mem, buf);
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||||
{
|
{
|
||||||
static char buf[PATH_MAX];
|
static char buf[PATH_MAX];
|
||||||
@@ -1948,6 +2354,11 @@ const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct pr
|
|||||||
return dm_pool_strdup(cmd->mem, buf);
|
return dm_pool_strdup(cmd->mem, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_default_unconfigured_backup_backup_dir_CFG(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
return "@DEFAULT_SYS_DIR@/@DEFAULT_BACKUP_SUBDIR@";
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||||
{
|
{
|
||||||
static char buf[PATH_MAX];
|
static char buf[PATH_MAX];
|
||||||
@@ -1961,6 +2372,11 @@ const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct p
|
|||||||
return dm_pool_strdup(cmd->mem, buf);
|
return dm_pool_strdup(cmd->mem, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_default_unconfigured_backup_archive_dir_CFG(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
return "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@";
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||||
{
|
{
|
||||||
static char buf[PATH_MAX];
|
static char buf[PATH_MAX];
|
||||||
@@ -1974,6 +2390,11 @@ const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct p
|
|||||||
return dm_pool_strdup(cmd->mem, buf);
|
return dm_pool_strdup(cmd->mem, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_default_unconfigured_config_profile_dir_CFG(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
return "@DEFAULT_SYS_DIR@/@DEFAULT_PROFILE_SUBDIR@";
|
||||||
|
}
|
||||||
|
|
||||||
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile)
|
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||||
{
|
{
|
||||||
return find_config_tree_str(cmd, activation_mirror_device_fault_policy_CFG, profile);
|
return find_config_tree_str(cmd, activation_mirror_device_fault_policy_CFG, profile);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ struct profile_params {
|
|||||||
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CFG_PATH_MAX_LEN 64
|
#define CFG_PATH_MAX_LEN 128
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structures used for definition of a configuration tree.
|
* Structures used for definition of a configuration tree.
|
||||||
@@ -72,6 +72,7 @@ typedef int (*t_fn_CFG_TYPE_INT) (struct cmd_context *cmd, struct profile *profi
|
|||||||
typedef float (*t_fn_CFG_TYPE_FLOAT) (struct cmd_context *cmd, struct profile *profile);
|
typedef float (*t_fn_CFG_TYPE_FLOAT) (struct cmd_context *cmd, struct profile *profile);
|
||||||
typedef const char* (*t_fn_CFG_TYPE_STRING) (struct cmd_context *cmd, struct profile *profile);
|
typedef const char* (*t_fn_CFG_TYPE_STRING) (struct cmd_context *cmd, struct profile *profile);
|
||||||
typedef const char* (*t_fn_CFG_TYPE_ARRAY) (struct cmd_context *cmd, struct profile *profile);
|
typedef const char* (*t_fn_CFG_TYPE_ARRAY) (struct cmd_context *cmd, struct profile *profile);
|
||||||
|
typedef const char* (*t_fn_UNCONFIGURED) (struct cmd_context *cmd);
|
||||||
|
|
||||||
/* configuration definition item value (for item's default value) */
|
/* configuration definition item value (for item's default value) */
|
||||||
typedef union {
|
typedef union {
|
||||||
@@ -88,62 +89,86 @@ typedef union {
|
|||||||
t_fn_CFG_TYPE_ARRAY fn_CFG_TYPE_ARRAY;
|
t_fn_CFG_TYPE_ARRAY fn_CFG_TYPE_ARRAY;
|
||||||
} cfg_def_value_t;
|
} cfg_def_value_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
const char *v_UNCONFIGURED;
|
||||||
|
t_fn_UNCONFIGURED fn_UNCONFIGURED;
|
||||||
|
} cfg_def_unconfigured_value_t;
|
||||||
|
|
||||||
/* configuration definition item flags: */
|
/* configuration definition item flags: */
|
||||||
|
|
||||||
|
|
||||||
/* whether the configuration item name is variable */
|
/* whether the configuration item name is variable */
|
||||||
#define CFG_NAME_VARIABLE 0x01
|
#define CFG_NAME_VARIABLE 0x001
|
||||||
/* whether empty value is allowed */
|
/* whether empty value is allowed */
|
||||||
#define CFG_ALLOW_EMPTY 0x02
|
#define CFG_ALLOW_EMPTY 0x002
|
||||||
/* whether the configuration item is for advanced use only */
|
/* whether the configuration item is for advanced use only */
|
||||||
#define CFG_ADVANCED 0x04
|
#define CFG_ADVANCED 0x004
|
||||||
/* whether the configuration item is not officially supported */
|
/* whether the configuration item is not officially supported */
|
||||||
#define CFG_UNSUPPORTED 0x08
|
#define CFG_UNSUPPORTED 0x008
|
||||||
/* whether the configuration item is customizable by a profile */
|
/* whether the configuration item is customizable by a profile */
|
||||||
#define CFG_PROFILABLE 0x10
|
#define CFG_PROFILABLE 0x010
|
||||||
/* whether the configuration item is customizable by a profile */
|
/* whether the configuration item is customizable by a profile */
|
||||||
/* and whether it can be attached to VG/LV metadata at the same time
|
/* and whether it can be attached to VG/LV metadata at the same time
|
||||||
* The CFG_PROFILABLE_METADATA flag incorporates CFG_PROFILABLE flag!!! */
|
* The CFG_PROFILABLE_METADATA flag incorporates CFG_PROFILABLE flag!!! */
|
||||||
#define CFG_PROFILABLE_METADATA 0x30
|
#define CFG_PROFILABLE_METADATA 0x030
|
||||||
/* whether the default value is undefned */
|
/* whether the default value is undefned */
|
||||||
#define CFG_DEFAULT_UNDEFINED 0x40
|
#define CFG_DEFAULT_UNDEFINED 0x040
|
||||||
/* whether the defualt value is calculated during run time */
|
/* whether the default value is commented out on output */
|
||||||
#define CFG_DEFAULT_RUN_TIME 0x80
|
#define CFG_DEFAULT_COMMENTED 0x080
|
||||||
|
/* whether the default value is calculated during run time */
|
||||||
|
#define CFG_DEFAULT_RUN_TIME 0x100
|
||||||
|
/* whether the configuration setting is disabled (and hence defaults always used) */
|
||||||
|
#define CFG_DISABLED 0x200
|
||||||
|
/* whether to print integers in octal form (prefixed by "0") */
|
||||||
|
#define CFG_FORMAT_INT_OCTAL 0x400
|
||||||
|
/* whether to disable checks for the whole config section subtree */
|
||||||
|
#define CFG_SECTION_NO_CHECK 0x800
|
||||||
|
|
||||||
/* configuration definition item structure */
|
/* configuration definition item structure */
|
||||||
typedef struct cfg_def_item {
|
typedef struct cfg_def_item {
|
||||||
int id; /* ID of this item */
|
int id; /* ID of this item */
|
||||||
int parent; /* ID of parent item */
|
int parent; /* ID of parent item */
|
||||||
const char *name; /* name of the item in configuration tree */
|
const char *name; /* name of the item in configuration tree */
|
||||||
int type; /* configuration item type (bits of cfg_def_type_t) */
|
int type; /* configuration item type (bits of cfg_def_type_t) */
|
||||||
cfg_def_value_t default_value; /* default value (only for settings) */
|
cfg_def_value_t default_value; /* default value (only for settings) */
|
||||||
uint16_t flags; /* configuration item definition flags */
|
uint16_t flags; /* configuration item definition flags */
|
||||||
uint16_t since_version; /* version this item appeared in */
|
uint16_t since_version; /* version this item appeared in */
|
||||||
const char *comment; /* brief comment */
|
cfg_def_unconfigured_value_t default_unconfigured_value; /* default value in terms of @FOO@, pre-configured (only for settings) */
|
||||||
|
uint16_t deprecated_since_version; /* version since this item is deprecated */
|
||||||
|
const char *deprecation_comment; /* comment about reasons for deprecation and settings that supersede this one */
|
||||||
|
const char *comment; /* comment */
|
||||||
} cfg_def_item_t;
|
} cfg_def_item_t;
|
||||||
|
|
||||||
/* configuration definition tree types */
|
/* configuration definition tree types */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CFG_DEF_TREE_CURRENT, /* tree of nodes with values currently set in the config */
|
CFG_DEF_TREE_CURRENT, /* tree of nodes with values currently set in the config */
|
||||||
CFG_DEF_TREE_MISSING, /* tree of nodes missing in current config using default values */
|
CFG_DEF_TREE_MISSING, /* tree of nodes missing in current config using default values */
|
||||||
CFG_DEF_TREE_COMPLETE, /* CURRENT + MISSING, the tree actually used within execution, not implemented yet */
|
CFG_DEF_TREE_FULL, /* CURRENT + MISSING, the tree actually used within execution */
|
||||||
CFG_DEF_TREE_DEFAULT, /* tree of all possible config nodes with default values */
|
CFG_DEF_TREE_DEFAULT, /* tree of all possible config nodes with default values */
|
||||||
CFG_DEF_TREE_NEW, /* tree of all new nodes that appeared in given version */
|
CFG_DEF_TREE_NEW, /* tree of all new nodes that appeared in given version */
|
||||||
CFG_DEF_TREE_PROFILABLE, /* tree of all nodes that are customizable by profiles */
|
CFG_DEF_TREE_PROFILABLE, /* tree of all nodes that are customizable by profiles */
|
||||||
CFG_DEF_TREE_PROFILABLE_CMD, /* tree of all nodes that are customizable by command profiles (subset of PROFILABLE) */
|
CFG_DEF_TREE_PROFILABLE_CMD, /* tree of all nodes that are customizable by command profiles (subset of PROFILABLE) */
|
||||||
CFG_DEF_TREE_PROFILABLE_MDA, /* tree of all nodes that are customizable by metadata profiles (subset of PROFILABLE) */
|
CFG_DEF_TREE_PROFILABLE_MDA, /* tree of all nodes that are customizable by metadata profiles (subset of PROFILABLE) */
|
||||||
CFG_DEF_TREE_DIFF, /* tree of all nodes that differ from defaults */
|
CFG_DEF_TREE_DIFF, /* tree of all nodes that differ from defaults */
|
||||||
|
CFG_DEF_TREE_LIST, /* list all nodes */
|
||||||
} cfg_def_tree_t;
|
} cfg_def_tree_t;
|
||||||
|
|
||||||
/* configuration definition tree specification */
|
/* configuration definition tree specification */
|
||||||
struct config_def_tree_spec {
|
struct config_def_tree_spec {
|
||||||
struct cmd_context *cmd; /* command context (for run-time defaults */
|
struct cmd_context *cmd; /* command context (for run-time defaults */
|
||||||
cfg_def_tree_t type; /* tree type */
|
struct dm_config_tree *current_cft; /* current config tree which is defined explicitly - defaults are not used */
|
||||||
uint16_t version; /* tree at this LVM2 version */
|
cfg_def_tree_t type; /* tree type */
|
||||||
|
uint16_t version; /* tree at this LVM2 version */
|
||||||
unsigned ignoreadvanced:1; /* do not include advanced configs */
|
unsigned ignoreadvanced:1; /* do not include advanced configs */
|
||||||
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||||
unsigned withcomments:1; /* include comments */
|
unsigned ignoredeprecated:1; /* do not include deprecated configs */
|
||||||
|
unsigned ignorelocal:1; /* do not include the local section */
|
||||||
|
unsigned withsummary:1; /* include first line of comments - a summary */
|
||||||
|
unsigned withcomments:1; /* include all comment lines */
|
||||||
unsigned withversions:1; /* include versions */
|
unsigned withversions:1; /* include versions */
|
||||||
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
|
unsigned withspaces:1; /* add more spaces in output for better readability */
|
||||||
|
unsigned unconfigured:1; /* use unconfigured path strings */
|
||||||
|
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -158,11 +183,11 @@ struct config_def_tree_spec {
|
|||||||
* Register ID for each possible item in the configuration tree.
|
* Register ID for each possible item in the configuration tree.
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
#define cfg_section(id, name, parent, flags, since_version, comment) id,
|
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) id,
|
||||||
#define cfg(id, name, parent, flags, type, default_value, since_version, comment) id,
|
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) id,
|
||||||
#define cfg_runtime(id, name, parent, flags, type, since_version, comment) id,
|
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) id,
|
||||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, comment) id,
|
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) id,
|
||||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, comment) id,
|
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) id,
|
||||||
#include "config_settings.h"
|
#include "config_settings.h"
|
||||||
#undef cfg_section
|
#undef cfg_section
|
||||||
#undef cfg
|
#undef cfg
|
||||||
@@ -184,6 +209,8 @@ struct cft_check_handle {
|
|||||||
unsigned skip_if_checked:1; /* skip the check if already done before - return last state */
|
unsigned skip_if_checked:1; /* skip the check if already done before - return last state */
|
||||||
unsigned suppress_messages:1; /* suppress messages during the check if config item is found invalid */
|
unsigned suppress_messages:1; /* suppress messages during the check if config item is found invalid */
|
||||||
unsigned check_diff:1; /* check if the value used differs from default one */
|
unsigned check_diff:1; /* check if the value used differs from default one */
|
||||||
|
unsigned ignoreadvanced:1; /* do not include advnced configs */
|
||||||
|
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||||
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
|
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -202,7 +229,8 @@ typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_
|
|||||||
struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open);
|
struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open);
|
||||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||||
|
int skip_parse);
|
||||||
int config_file_read(struct dm_config_tree *cft);
|
int config_file_read(struct dm_config_tree *cft);
|
||||||
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
|
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
|
||||||
struct cmd_context *cmd);
|
struct cmd_context *cmd);
|
||||||
@@ -211,7 +239,7 @@ int config_write(struct dm_config_tree *cft, struct config_def_tree_spec *tree_s
|
|||||||
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec);
|
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec);
|
||||||
void config_destroy(struct dm_config_tree *cft);
|
void config_destroy(struct dm_config_tree *cft);
|
||||||
|
|
||||||
time_t config_file_timestamp(struct dm_config_tree *cft);
|
struct timespec config_file_timestamp(struct dm_config_tree *cft);
|
||||||
int config_file_changed(struct dm_config_tree *cft);
|
int config_file_changed(struct dm_config_tree *cft);
|
||||||
int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info);
|
int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info);
|
||||||
|
|
||||||
@@ -230,6 +258,12 @@ typedef enum {
|
|||||||
int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
||||||
struct dm_config_tree *newdata, config_merge_t);
|
struct dm_config_tree *newdata, config_merge_t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The next two do not check config overrides and must only be used for the tags section.
|
||||||
|
*/
|
||||||
|
const struct dm_config_node *find_config_node(struct cmd_context *cmd, struct dm_config_tree *cft, int id);
|
||||||
|
int find_config_bool(struct cmd_context *cmd, struct dm_config_tree *cft, int id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These versions check an override tree, if present, first.
|
* These versions check an override tree, if present, first.
|
||||||
*/
|
*/
|
||||||
@@ -240,18 +274,29 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
|
|||||||
int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *profile);
|
int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *profile);
|
||||||
float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *profile);
|
float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *profile);
|
||||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile);
|
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile);
|
||||||
|
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions for configuration settings for which the default
|
* Functions for configuration settings for which the default
|
||||||
* value is evaluated at runtime based on command context.
|
* value is evaluated at runtime based on command context.
|
||||||
*/
|
*/
|
||||||
const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
const char *get_default_unconfigured_devices_cache_dir_CFG(struct cmd_context *cmd);
|
||||||
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile);
|
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
const char *get_default_unconfigured_devices_cache_CFG(struct cmd_context *cmd);
|
||||||
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
const char *get_default_unconfigured_backup_backup_dir_CFG(struct cmd_context *cmd);
|
||||||
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
const char *get_default_unconfigured_backup_archive_dir_CFG(struct cmd_context *cmd);
|
||||||
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
const char *get_default_unconfigured_config_profile_dir_CFG(struct cmd_context *cmd);
|
||||||
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
#define get_default_unconfigured_activation_mirror_image_fault_policy_CFG NULL
|
||||||
int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
#define get_default_unconfigured_allocation_thin_pool_chunk_size_CFG NULL
|
||||||
int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
|
||||||
|
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||||
|
#define get_default_unconfigured_allocation_cache_policy_CFG NULL
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -29,9 +29,12 @@
|
|||||||
|
|
||||||
#define DEFAULT_DEV_DIR "/dev"
|
#define DEFAULT_DEV_DIR "/dev"
|
||||||
#define DEFAULT_PROC_DIR "/proc"
|
#define DEFAULT_PROC_DIR "/proc"
|
||||||
|
#define DEFAULT_SYSTEM_ID_SOURCE "none"
|
||||||
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
|
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
|
||||||
|
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
|
||||||
#define DEFAULT_SYSFS_SCAN 1
|
#define DEFAULT_SYSFS_SCAN 1
|
||||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||||
|
#define DEFAULT_FW_RAID_COMPONENT_DETECTION 0
|
||||||
#define DEFAULT_MD_CHUNK_ALIGNMENT 1
|
#define DEFAULT_MD_CHUNK_ALIGNMENT 1
|
||||||
#define DEFAULT_IGNORE_LVM_MIRRORS 1
|
#define DEFAULT_IGNORE_LVM_MIRRORS 1
|
||||||
#define DEFAULT_MULTIPATH_COMPONENT_DETECTION 1
|
#define DEFAULT_MULTIPATH_COMPONENT_DETECTION 1
|
||||||
@@ -44,18 +47,24 @@
|
|||||||
#define DEFAULT_PV_MIN_SIZE_KB 2048
|
#define DEFAULT_PV_MIN_SIZE_KB 2048
|
||||||
|
|
||||||
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
||||||
|
#define DEFAULT_ERROR_WHEN_FULL 0
|
||||||
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
||||||
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
||||||
#define DEFAULT_WAIT_FOR_LOCKS 1
|
#define DEFAULT_WAIT_FOR_LOCKS 1
|
||||||
|
#define DEFAULT_LVMLOCKD_LOCK_RETRIES 3
|
||||||
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
|
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
|
||||||
#define DEFAULT_USE_MLOCKALL 0
|
#define DEFAULT_USE_MLOCKALL 0
|
||||||
#define DEFAULT_METADATA_READ_ONLY 0
|
#define DEFAULT_METADATA_READ_ONLY 0
|
||||||
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
|
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
|
||||||
|
|
||||||
|
#define DEFAULT_SANLOCK_LV_EXTEND_MB 256
|
||||||
|
|
||||||
#define DEFAULT_MIRRORLOG MIRROR_LOG_DISK
|
#define DEFAULT_MIRRORLOG MIRROR_LOG_DISK
|
||||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||||
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||||
|
#define DEFAULT_RAID_MAX_IMAGES 8
|
||||||
|
|
||||||
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
||||||
|
|
||||||
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
|
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
|
||||||
@@ -72,12 +81,17 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef THIN_CHECK_NEEDS_CHECK
|
#ifdef THIN_CHECK_NEEDS_CHECK
|
||||||
# define DEFAULT_THIN_CHECK_OPTIONS "-q --clear-needs-check-flag"
|
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
|
||||||
|
# define DEFAULT_THIN_CHECK_OPTION2 "--clear-needs-check-flag"
|
||||||
|
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1 "#S" DEFAULT_THIN_CHECK_OPTION2
|
||||||
#else
|
#else
|
||||||
# define DEFAULT_THIN_CHECK_OPTIONS "-q"
|
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
|
||||||
|
# define DEFAULT_THIN_CHECK_OPTION2 ""
|
||||||
|
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEFAULT_THIN_REPAIR_OPTIONS ""
|
#define DEFAULT_THIN_REPAIR_OPTION1 ""
|
||||||
|
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
|
||||||
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||||
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||||
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||||
@@ -89,23 +103,27 @@
|
|||||||
#define DEFAULT_THIN_POOL_ZERO 1
|
#define DEFAULT_THIN_POOL_ZERO 1
|
||||||
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
||||||
|
|
||||||
#define DEFAULT_CACHE_CHECK_OPTIONS "-q"
|
#ifdef CACHE_CHECK_NEEDS_CHECK
|
||||||
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
|
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||||
|
# define DEFAULT_CACHE_CHECK_OPTION2 "--clear-needs-check-flag"
|
||||||
|
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1 "#S" DEFAULT_CACHE_CHECK_OPTION2
|
||||||
|
#else
|
||||||
|
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||||
|
# define DEFAULT_CACHE_CHECK_OPTION2 ""
|
||||||
|
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_CACHE_REPAIR_OPTION1 ""
|
||||||
|
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
|
||||||
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||||
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
||||||
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||||
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||||
#define DEFAULT_CACHE_POOL_CACHEMODE "writethrough"
|
#define DEFAULT_CACHE_POLICY "mq"
|
||||||
#define DEFAULT_CACHE_POOL_POLICY "mq"
|
#define DEFAULT_CACHE_MODE "writethrough"
|
||||||
|
|
||||||
#define DEFAULT_UMASK 0077
|
#define DEFAULT_UMASK 0077
|
||||||
|
|
||||||
#ifdef LVM1_FALLBACK
|
|
||||||
# define DEFAULT_FALLBACK_TO_LVM1 1
|
|
||||||
#else
|
|
||||||
# define DEFAULT_FALLBACK_TO_LVM1 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFAULT_FORMAT "lvm2"
|
#define DEFAULT_FORMAT "lvm2"
|
||||||
|
|
||||||
#define DEFAULT_STRIPESIZE 64 /* KB */
|
#define DEFAULT_STRIPESIZE 64 /* KB */
|
||||||
@@ -136,10 +154,6 @@
|
|||||||
# define DEFAULT_LOG_FACILITY LOG_USER
|
# define DEFAULT_LOG_FACILITY LOG_USER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEFAULT_LOGGED_DEBUG_CLASSES (LOG_CLASS_MEM | LOG_CLASS_DEVS | \
|
|
||||||
LOG_CLASS_ACTIVATION | LOG_CLASS_ALLOC | LOG_CLASS_LVMETAD | \
|
|
||||||
LOG_CLASS_METADATA | LOG_CLASS_CACHE | LOG_CLASS_LOCKING)
|
|
||||||
|
|
||||||
#define DEFAULT_SYSLOG 1
|
#define DEFAULT_SYSLOG 1
|
||||||
#define DEFAULT_VERBOSE 0
|
#define DEFAULT_VERBOSE 0
|
||||||
#define DEFAULT_SILENT 0
|
#define DEFAULT_SILENT 0
|
||||||
@@ -176,6 +190,7 @@
|
|||||||
|
|
||||||
#define DEFAULT_MAX_ERROR_COUNT NO_DEV_ERROR_COUNT_LIMIT
|
#define DEFAULT_MAX_ERROR_COUNT NO_DEV_ERROR_COUNT_LIMIT
|
||||||
|
|
||||||
|
#define DEFAULT_REP_COMPACT_OUTPUT 0
|
||||||
#define DEFAULT_REP_ALIGNED 1
|
#define DEFAULT_REP_ALIGNED 1
|
||||||
#define DEFAULT_REP_BUFFERED 1
|
#define DEFAULT_REP_BUFFERED 1
|
||||||
#define DEFAULT_REP_COLUMNS_AS_ROWS 0
|
#define DEFAULT_REP_COLUMNS_AS_ROWS 0
|
||||||
@@ -184,6 +199,9 @@
|
|||||||
#define DEFAULT_REP_QUOTED 1
|
#define DEFAULT_REP_QUOTED 1
|
||||||
#define DEFAULT_REP_SEPARATOR " "
|
#define DEFAULT_REP_SEPARATOR " "
|
||||||
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
|
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
|
||||||
|
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
|
||||||
|
|
||||||
|
#define DEFAULT_COMPACT_OUTPUT_COLS ""
|
||||||
|
|
||||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
|
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
|
||||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||||
@@ -213,4 +231,6 @@
|
|||||||
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
|
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
|
||||||
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
|
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
|
||||||
|
|
||||||
|
#define DEFAULT_CY_LOCK_TYPE "sanlock"
|
||||||
|
|
||||||
#endif /* _LVM_DEFAULTS_H */
|
#endif /* _LVM_DEFAULTS_H */
|
||||||
|
|||||||
@@ -16,11 +16,14 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "str_list.h"
|
#include "str_list.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
struct dm_list *str_list_create(struct dm_pool *mem)
|
struct dm_list *str_list_create(struct dm_pool *mem)
|
||||||
{
|
{
|
||||||
struct dm_list *sl;
|
struct dm_list *sl;
|
||||||
|
|
||||||
if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) {
|
if (!(sl = mem ? dm_pool_alloc(mem, sizeof(struct dm_list))
|
||||||
|
: dm_malloc(sizeof(struct dm_list)))) {
|
||||||
log_errno(ENOMEM, "str_list allocation failed");
|
log_errno(ENOMEM, "str_list allocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -37,7 +40,8 @@ static int _str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll,
|
|||||||
if (!str)
|
if (!str)
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!(sln = dm_pool_alloc(mem, sizeof(*sln))))
|
if (!(sln = mem ? dm_pool_alloc(mem, sizeof(*sln))
|
||||||
|
: dm_malloc(sizeof(*sln))))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
sln->str = str;
|
sln->str = str;
|
||||||
@@ -71,6 +75,21 @@ int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str)
|
|||||||
return str_list_add_no_dup_check(mem, sll, str);
|
return str_list_add_no_dup_check(mem, sll, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add contents of sll2 to sll */
|
||||||
|
int str_list_add_list(struct dm_pool *mem, struct dm_list *sll, struct dm_list *sll2)
|
||||||
|
{
|
||||||
|
struct dm_str_list *sl;
|
||||||
|
|
||||||
|
if (!sll2)
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
dm_list_iterate_items(sl, sll2)
|
||||||
|
if (!str_list_add(mem, sll, sl->str))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void str_list_del(struct dm_list *sll, const char *str)
|
void str_list_del(struct dm_list *sll, const char *str)
|
||||||
{
|
{
|
||||||
struct dm_list *slh, *slht;
|
struct dm_list *slh, *slht;
|
||||||
@@ -143,3 +162,101 @@ int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list,
|
||||||
|
const char *delim)
|
||||||
|
{
|
||||||
|
size_t delim_len = strlen(delim);
|
||||||
|
unsigned list_size = dm_list_size(list);
|
||||||
|
struct dm_str_list *sl;
|
||||||
|
char *str, *p;
|
||||||
|
size_t len = 0;
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
dm_list_iterate_items(sl, list)
|
||||||
|
len += strlen(sl->str);
|
||||||
|
if (list_size > 1)
|
||||||
|
len += ((list_size - 1) * delim_len);
|
||||||
|
|
||||||
|
str = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||||
|
if (!str) {
|
||||||
|
log_error("str_list_to_str: string allocation failed.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
str[len] = '\0';
|
||||||
|
p = str;
|
||||||
|
|
||||||
|
dm_list_iterate_items(sl, list) {
|
||||||
|
len = strlen(sl->str);
|
||||||
|
memcpy(p, sl->str, len);
|
||||||
|
p += len;
|
||||||
|
|
||||||
|
if (++i != list_size) {
|
||||||
|
memcpy(p, delim, delim_len);
|
||||||
|
p += delim_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str,
|
||||||
|
const char *delim, int ignore_multiple_delim)
|
||||||
|
{
|
||||||
|
size_t delim_len = strlen(delim);
|
||||||
|
struct dm_list *list;
|
||||||
|
const char *p1, *p2, *next;
|
||||||
|
char *str_item;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!(list = str_list_create(mem))) {
|
||||||
|
log_error("str_to_str_list: string list allocation failed.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 = p2 = str;
|
||||||
|
while (*p1) {
|
||||||
|
if (!(p2 = strstr(p1, delim)))
|
||||||
|
next = p2 = str + strlen(str);
|
||||||
|
else
|
||||||
|
next = p2 + delim_len;
|
||||||
|
|
||||||
|
len = p2 - p1;
|
||||||
|
str_item = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||||
|
if (!str_item) {
|
||||||
|
log_error("str_to_str_list: string list item allocation failed.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
memcpy(str_item, p1, len);
|
||||||
|
str_item[len] = '\0';
|
||||||
|
|
||||||
|
if (!str_list_add_no_dup_check(mem, list, str_item))
|
||||||
|
goto_bad;
|
||||||
|
|
||||||
|
if (ignore_multiple_delim) {
|
||||||
|
while (!strncmp(next, delim, delim_len))
|
||||||
|
next += delim_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
bad:
|
||||||
|
if (mem)
|
||||||
|
dm_pool_free(mem, list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void str_list_destroy(struct dm_list *list, int deallocate_strings)
|
||||||
|
{
|
||||||
|
struct dm_str_list *sl, *tmp_sl;
|
||||||
|
|
||||||
|
dm_list_iterate_items_safe(sl, tmp_sl, list) {
|
||||||
|
dm_list_del(&sl->list);
|
||||||
|
if (deallocate_strings)
|
||||||
|
dm_free((char *)sl->str);
|
||||||
|
dm_free(sl);
|
||||||
|
}
|
||||||
|
dm_free(list);
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user