mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-15 13:44:18 +03:00
Compare commits
728 Commits
v2_02_112
...
dev-mornfa
Author | SHA1 | Date | |
---|---|---|---|
|
4aaffe0650 | ||
|
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 |
14
Makefile.in
14
Makefile.in
@@ -95,6 +95,11 @@ DISTCLEAN_TARGETS += cscope.out
|
||||
check check_system check_cluster check_local check_lvmetad unit: all
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate: tools
|
||||
|
||||
generate: conf.generate
|
||||
$(MAKE) -C conf generate
|
||||
|
||||
install_system_dirs:
|
||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||
@@ -122,8 +127,11 @@ endif
|
||||
install_tmpfiles_configuration:
|
||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||
|
||||
LCOV_TRACES = libdm.info lib.info tools.info \
|
||||
daemons/dmeventd.info daemons/clvmd.info
|
||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||
libdaemon/client.info libdaemon/server.info \
|
||||
daemons/clvmd.info daemons/dmeventd.info \
|
||||
daemons/lvmetad.info
|
||||
|
||||
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||
|
||||
ifneq ("$(LCOV)", "")
|
||||
@@ -152,7 +160,7 @@ lcov: $(LCOV_TRACES)
|
||||
$(RM) -r $(LCOV_REPORTS_DIR)
|
||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||
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; \
|
||||
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
||||
-o $(LCOV_REPORTS_DIR) $$lc
|
||||
|
2
README
2
README
@@ -18,7 +18,7 @@ Mailing list for general discussion related to LVM2:
|
||||
|
||||
Mailing lists for LVM2 development, patches and commits:
|
||||
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)
|
||||
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
|
||||
|
@@ -1 +1 @@
|
||||
1.02.91-git (2014-11-11)
|
||||
1.02.96-git (2015-03-24)
|
||||
|
142
WHATS_NEW
142
WHATS_NEW
@@ -1,3 +1,145 @@
|
||||
Version 2.02.119 -
|
||||
==================================
|
||||
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 --withfullcomments option to dumpconfig to print full comment.
|
||||
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.
|
||||
Set correct vgid when updating cache when writing PV metadata.
|
||||
More efficient clvmd singlenode locking emulation.
|
||||
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.
|
||||
|
||||
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
|
||||
=====================================
|
||||
Add cache_{read,write}_{hits,misses} reporting fields.
|
||||
|
32
WHATS_NEW_DM
32
WHATS_NEW_DM
@@ -1,3 +1,35 @@
|
||||
Version 1.02.96 -
|
||||
=================================
|
||||
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
|
||||
====================================
|
||||
Update cache creation and dm_config_node to pass policy.
|
||||
|
@@ -37,6 +37,10 @@ AC_DEFUN([AC_TRY_CCFLAG],
|
||||
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 check if $CC supports given ld flags
|
||||
|
||||
|
@@ -17,24 +17,37 @@ top_builddir = @top_builddir@
|
||||
|
||||
CONFSRC=example.conf
|
||||
CONFDEST=lvm.conf
|
||||
CONFLOCAL=lvmlocal.conf
|
||||
|
||||
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile
|
||||
|
||||
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 --withfullcomments --ignorelocal) > 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 --withfullcomments local) > lvmlocal.conf.in
|
||||
|
||||
install_conf: $(CONFSRC)
|
||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||
echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \
|
||||
$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \
|
||||
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_DIR) $(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
|
||||
|
||||
DISTCLEAN_TARGETS += $(CONFSRC) $(PROFILE_TEMPLATES)
|
||||
DISTCLEAN_TARGETS += $(CONFSRC) $(CONFLOCAL) $(PROFILE_TEMPLATES)
|
||||
|
@@ -18,6 +18,7 @@ global {
|
||||
lvdisplay_shows_full_device_path=0
|
||||
}
|
||||
report {
|
||||
compact_output=0
|
||||
aligned=1
|
||||
buffered=1
|
||||
headings=1
|
||||
|
12
conf/example.conf.base
Normal file
12
conf/example.conf.base
Normal file
@@ -0,0 +1,12 @@
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
|
2494
conf/example.conf.in
2494
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.
|
||||
|
53
conf/lvmlocal.conf.in
Normal file
53
conf/lvmlocal.conf.in
Normal file
@@ -0,0 +1,53 @@
|
||||
# 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 = ""
|
||||
# Example:
|
||||
# Set the system_id to the string 'host1'.
|
||||
# system_id = "host1"
|
||||
# This configuration option does not have a default value defined.
|
||||
# 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.
|
||||
# extra_system_ids=[]
|
||||
}
|
@@ -16,7 +16,7 @@ allocation {
|
||||
thin_pool_zero=1
|
||||
thin_pool_discards="passdown"
|
||||
thin_pool_chunk_size_policy="generic"
|
||||
# thin_pool_chunk_size=64
|
||||
# thin_pool_chunk_size=128
|
||||
}
|
||||
activation {
|
||||
thin_pool_autoextend_threshold=100
|
||||
|
510
configure
vendored
510
configure
vendored
@@ -639,6 +639,7 @@ CLVMD_PIDFILE
|
||||
LVMETAD_PIDFILE
|
||||
DMEVENTD_PIDFILE
|
||||
WRITE_INSTALL
|
||||
VALGRIND_POOL
|
||||
UDEV_HAS_BUILTIN_BLKID
|
||||
UDEV_RULE_EXEC_DETECTION
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS
|
||||
@@ -681,6 +682,7 @@ LDDEPS
|
||||
JOBS
|
||||
INTL_PACKAGE
|
||||
INTL
|
||||
HAVE_VALGRIND
|
||||
HAVE_REALTIME
|
||||
HAVE_LIBDL
|
||||
BLKDEACTIVATE
|
||||
@@ -736,9 +738,10 @@ LVM2CMD_LIB
|
||||
LVM2APP_LIB
|
||||
UDEV_LIBS
|
||||
UDEV_CFLAGS
|
||||
SYSTEMD_LIBS
|
||||
SYSTEMD_CFLAGS
|
||||
BLKID_LIBS
|
||||
BLKID_CFLAGS
|
||||
VALGRIND_POOL
|
||||
VALGRIND_LIBS
|
||||
VALGRIND_CFLAGS
|
||||
CUNIT_LIBS
|
||||
@@ -746,6 +749,7 @@ CUNIT_CFLAGS
|
||||
GENPNG
|
||||
GENHTML
|
||||
LCOV
|
||||
HAVE_WSYNCNAND
|
||||
HAVE_WCLOBBERED
|
||||
HAVE_WJUMP
|
||||
SACKPT_LIBS
|
||||
@@ -796,6 +800,9 @@ INSTALL_PROGRAM
|
||||
EGREP
|
||||
GREP
|
||||
CPP
|
||||
ac_ct_CXX
|
||||
CXXFLAGS
|
||||
CXX
|
||||
OBJEXT
|
||||
EXEEXT
|
||||
ac_ct_CC
|
||||
@@ -874,7 +881,7 @@ with_snapshots
|
||||
with_mirrors
|
||||
with_raid
|
||||
with_default_mirror_segtype
|
||||
with_default_raid10r_segtype
|
||||
with_default_raid10_segtype
|
||||
with_replicators
|
||||
with_default_sparse_segtype
|
||||
with_thin
|
||||
@@ -954,6 +961,9 @@ CFLAGS
|
||||
LDFLAGS
|
||||
LIBS
|
||||
CPPFLAGS
|
||||
CXX
|
||||
CXXFLAGS
|
||||
CCC
|
||||
CPP
|
||||
PKG_CONFIG
|
||||
PKG_CONFIG_PATH
|
||||
@@ -984,6 +994,8 @@ VALGRIND_CFLAGS
|
||||
VALGRIND_LIBS
|
||||
BLKID_CFLAGS
|
||||
BLKID_LIBS
|
||||
SYSTEMD_CFLAGS
|
||||
SYSTEMD_LIBS
|
||||
UDEV_CFLAGS
|
||||
UDEV_LIBS'
|
||||
|
||||
@@ -1747,6 +1759,8 @@ Some influential environment variables:
|
||||
LIBS libraries to pass to the linker, e.g. -l<library>
|
||||
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
|
||||
you have headers in a nonstandard directory <include dir>
|
||||
CXX C++ compiler command
|
||||
CXXFLAGS C++ compiler flags
|
||||
CPP C preprocessor
|
||||
PKG_CONFIG path to pkg-config utility
|
||||
PKG_CONFIG_PATH
|
||||
@@ -1791,6 +1805,10 @@ Some influential environment variables:
|
||||
BLKID_CFLAGS
|
||||
C compiler flags for BLKID, overriding pkg-config
|
||||
BLKID_LIBS linker flags for BLKID, overriding pkg-config
|
||||
SYSTEMD_CFLAGS
|
||||
C compiler flags for SYSTEMD, overriding pkg-config
|
||||
SYSTEMD_LIBS
|
||||
linker flags for SYSTEMD, overriding pkg-config
|
||||
UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config
|
||||
UDEV_LIBS linker flags for UDEV, overriding pkg-config
|
||||
|
||||
@@ -1912,6 +1930,44 @@ fi
|
||||
|
||||
} # ac_fn_c_try_compile
|
||||
|
||||
# ac_fn_cxx_try_compile LINENO
|
||||
# ----------------------------
|
||||
# Try to compile conftest.$ac_ext, and return whether this succeeded.
|
||||
ac_fn_cxx_try_compile ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
rm -f conftest.$ac_objext
|
||||
if { { ac_try="$ac_compile"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
|
||||
$as_echo "$ac_try_echo"; } >&5
|
||||
(eval "$ac_compile") 2>conftest.err
|
||||
ac_status=$?
|
||||
if test -s conftest.err; then
|
||||
grep -v '^ *+' conftest.err >conftest.er1
|
||||
cat conftest.er1 >&5
|
||||
mv -f conftest.er1 conftest.err
|
||||
fi
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; } && {
|
||||
test -z "$ac_cxx_werror_flag" ||
|
||||
test ! -s conftest.err
|
||||
} && test -s conftest.$ac_objext; then :
|
||||
ac_retval=0
|
||||
else
|
||||
$as_echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_retval=1
|
||||
fi
|
||||
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_compile
|
||||
|
||||
# ac_fn_c_try_cpp LINENO
|
||||
# ----------------------
|
||||
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
|
||||
@@ -3903,6 +3959,263 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
ac_ext=cpp
|
||||
ac_cpp='$CXXCPP $CPPFLAGS'
|
||||
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
|
||||
if test -z "$CXX"; then
|
||||
if test -n "$CCC"; then
|
||||
CXX=$CCC
|
||||
else
|
||||
if test -n "$ac_tool_prefix"; then
|
||||
for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
|
||||
do
|
||||
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_CXX+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$CXX"; then
|
||||
ac_cv_prog_CXX="$CXX" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
CXX=$ac_cv_prog_CXX
|
||||
if test -n "$CXX"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
|
||||
$as_echo "$CXX" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
test -n "$CXX" && break
|
||||
done
|
||||
fi
|
||||
if test -z "$CXX"; then
|
||||
ac_ct_CXX=$CXX
|
||||
for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_prog_ac_ct_CXX+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test -n "$ac_ct_CXX"; then
|
||||
ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
|
||||
else
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_prog_ac_ct_CXX="$ac_prog"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
fi
|
||||
fi
|
||||
ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
|
||||
if test -n "$ac_ct_CXX"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
|
||||
$as_echo "$ac_ct_CXX" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
test -n "$ac_ct_CXX" && break
|
||||
done
|
||||
|
||||
if test "x$ac_ct_CXX" = x; then
|
||||
CXX="g++"
|
||||
else
|
||||
case $cross_compiling:$ac_tool_warned in
|
||||
yes:)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
|
||||
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
|
||||
ac_tool_warned=yes ;;
|
||||
esac
|
||||
CXX=$ac_ct_CXX
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
# Provide some information about the compiler.
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
|
||||
set X $ac_compile
|
||||
ac_compiler=$2
|
||||
for ac_option in --version -v -V -qversion; do
|
||||
{ { ac_try="$ac_compiler $ac_option >&5"
|
||||
case "(($ac_try" in
|
||||
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
|
||||
*) ac_try_echo=$ac_try;;
|
||||
esac
|
||||
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
|
||||
$as_echo "$ac_try_echo"; } >&5
|
||||
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
|
||||
ac_status=$?
|
||||
if test -s conftest.err; then
|
||||
sed '10a\
|
||||
... rest of stderr output deleted ...
|
||||
10q' conftest.err >conftest.er1
|
||||
cat conftest.er1 >&5
|
||||
fi
|
||||
rm -f conftest.er1 conftest.err
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
|
||||
$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
|
||||
if ${ac_cv_cxx_compiler_gnu+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
choke me
|
||||
#endif
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
ac_compiler_gnu=yes
|
||||
else
|
||||
ac_compiler_gnu=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
|
||||
$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
|
||||
if test $ac_compiler_gnu = yes; then
|
||||
GXX=yes
|
||||
else
|
||||
GXX=
|
||||
fi
|
||||
ac_test_CXXFLAGS=${CXXFLAGS+set}
|
||||
ac_save_CXXFLAGS=$CXXFLAGS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
|
||||
$as_echo_n "checking whether $CXX accepts -g... " >&6; }
|
||||
if ${ac_cv_prog_cxx_g+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_save_cxx_werror_flag=$ac_cxx_werror_flag
|
||||
ac_cxx_werror_flag=yes
|
||||
ac_cv_prog_cxx_g=no
|
||||
CXXFLAGS="-g"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
ac_cv_prog_cxx_g=yes
|
||||
else
|
||||
CXXFLAGS=""
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
|
||||
else
|
||||
ac_cxx_werror_flag=$ac_save_cxx_werror_flag
|
||||
CXXFLAGS="-g"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_compile "$LINENO"; then :
|
||||
ac_cv_prog_cxx_g=yes
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
ac_cxx_werror_flag=$ac_save_cxx_werror_flag
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
|
||||
$as_echo "$ac_cv_prog_cxx_g" >&6; }
|
||||
if test "$ac_test_CXXFLAGS" = set; then
|
||||
CXXFLAGS=$ac_save_CXXFLAGS
|
||||
elif test $ac_cv_prog_cxx_g = yes; then
|
||||
if test "$GXX" = yes; then
|
||||
CXXFLAGS="-g -O2"
|
||||
else
|
||||
CXXFLAGS="-g"
|
||||
fi
|
||||
else
|
||||
if test "$GXX" = yes; then
|
||||
CXXFLAGS="-O2"
|
||||
else
|
||||
CXXFLAGS=
|
||||
fi
|
||||
fi
|
||||
ac_ext=c
|
||||
ac_cpp='$CPP $CPPFLAGS'
|
||||
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
|
||||
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
|
||||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
ac_ext=c
|
||||
@@ -7260,9 +7573,9 @@ else
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-default-raid10r-segtype was given.
|
||||
if test "${with_default_raid10r_segtype+set}" = set; then :
|
||||
withval=$with_default_raid10r_segtype; DEFAULT_RAID10_SEGTYPE=$withval
|
||||
# Check whether --with-default-raid10-segtype was given.
|
||||
if test "${with_default_raid10_segtype+set}" = set; then :
|
||||
withval=$with_default_raid10_segtype; DEFAULT_RAID10_SEGTYPE=$withval
|
||||
else
|
||||
DEFAULT_RAID10_SEGTYPE="raid10"
|
||||
fi
|
||||
@@ -9902,6 +10215,44 @@ $as_echo "$ac_cv_flag_HAVE_WCLOBBERED" >&6; }
|
||||
|
||||
|
||||
|
||||
|
||||
ac_save_CFLAGS=$CFLAGS
|
||||
CFLAGS=-Wsync-nand
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -Wsync-nand flag" >&5
|
||||
$as_echo_n "checking whether $CC accepts -Wsync-nand flag... " >&6; }
|
||||
if ${ac_cv_flag_HAVE_WSYNCNAND+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
ac_cv_flag_HAVE_WSYNCNAND=yes
|
||||
else
|
||||
ac_cv_flag_HAVE_WSYNCNAND=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_flag_HAVE_WSYNCNAND" >&5
|
||||
$as_echo "$ac_cv_flag_HAVE_WSYNCNAND" >&6; }
|
||||
CFLAGS=$ac_save_CFLAGS
|
||||
HAVE_WSYNCNAND=$ac_cv_flag_HAVE_WSYNCNAND
|
||||
if test "HAVE_WSYNCNAND" = yes; then
|
||||
:
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C optimisation flag" >&5
|
||||
$as_echo_n "checking for C optimisation flag... " >&6; }
|
||||
@@ -10362,8 +10713,7 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $VALGRIND_POOL" >&5
|
||||
$as_echo "$VALGRIND_POOL" >&6; }
|
||||
|
||||
if test "$VALGRIND_POOL" = yes; then
|
||||
pkg_config_init
|
||||
pkg_config_init
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for VALGRIND" >&5
|
||||
@@ -10423,23 +10773,30 @@ fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$VALGRIND_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "bailing out" "$LINENO" 5
|
||||
if test x$VALGRIND_POOL = xyes; then as_fn_error $? "bailing out" "$LINENO" 5; fi
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
as_fn_error $? "bailing out" "$LINENO" 5
|
||||
if test x$VALGRIND_POOL = xyes; then as_fn_error $? "bailing out" "$LINENO" 5; fi
|
||||
else
|
||||
VALGRIND_CFLAGS=$pkg_cv_VALGRIND_CFLAGS
|
||||
VALGRIND_LIBS=$pkg_cv_VALGRIND_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
HAVE_VALGRIND=yes
|
||||
fi
|
||||
|
||||
|
||||
if test x$HAVE_VALGRIND = xyes; then
|
||||
|
||||
$as_echo "#define HAVE_VALGRIND 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
if test x$VALGRIND_POOL = xyes; then
|
||||
|
||||
$as_echo "#define VALGRIND_POOL 1" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -10601,12 +10958,95 @@ $as_echo_n "checking whether to use udev-systemd protocol for jobs in background
|
||||
if test "${enable_udev_systemd_background_jobs+set}" = set; then :
|
||||
enableval=$enable_udev_systemd_background_jobs; UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval
|
||||
else
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=yes
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=maybe
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_SYSTEMD_BACKGROUND_JOBS" >&5
|
||||
$as_echo "$UDEV_SYSTEMD_BACKGROUND_JOBS" >&6; }
|
||||
|
||||
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
|
||||
pkg_config_init
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
|
||||
$as_echo_n "checking for SYSTEMD... " >&6; }
|
||||
|
||||
if test -n "$SYSTEMD_CFLAGS"; then
|
||||
pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 205\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "systemd >= 205") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "systemd >= 205" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$SYSTEMD_LIBS"; then
|
||||
pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 205\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "systemd >= 205") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "systemd >= 205" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
|
||||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd >= 205" 2>&1`
|
||||
else
|
||||
SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd >= 205" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$SYSTEMD_PKG_ERRORS" >&5
|
||||
|
||||
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe; then
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=no
|
||||
else
|
||||
as_fn_error $? "bailing out... systemd >= 205 is required" "$LINENO" 5
|
||||
fi
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe; then
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=no
|
||||
else
|
||||
as_fn_error $? "bailing out... systemd >= 205 is required" "$LINENO" 5
|
||||
fi
|
||||
else
|
||||
SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
|
||||
SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe && UDEV_SYSTEMD_BACKGROUND_JOBS=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable synchronisation with udev processing" >&5
|
||||
$as_echo_n "checking whether to enable synchronisation with udev processing... " >&6; }
|
||||
@@ -11518,6 +11958,40 @@ $as_echo "$as_me: WARNING: Disabling realtime clock" >&2;}
|
||||
fi
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat has st_ctim." >&5
|
||||
$as_echo_n "checking for struct stat has st_ctim.... " >&6; }
|
||||
if ${ac_cv_stat_st_ctim+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <sys/stat.h>
|
||||
long bar(void) { struct stat s; return (long)(s.st_ctim.tv_sec + s.st_ctim.tv_nsec);}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
ac_cv_stat_st_ctim=yes
|
||||
else
|
||||
ac_cv_stat_st_ctim=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_stat_st_ctim" >&5
|
||||
$as_echo "$ac_cv_stat_st_ctim" >&6; }
|
||||
|
||||
if test $ac_cv_stat_st_ctim = yes; then :
|
||||
|
||||
$as_echo "#define HAVE_STAT_ST_CTIM 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
for ac_header in getopt.h
|
||||
do :
|
||||
@@ -11859,6 +12333,11 @@ else
|
||||
fi
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define DEFAULT_ETC_DIR "$CONFDIR"
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
||||
# Check whether --with-staticdir was given.
|
||||
if test "${with_staticdir+set}" = set; then :
|
||||
@@ -12342,8 +12821,8 @@ _ACEOF
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define CLVMD_PATH "$CLVMD_PATH"
|
||||
@@ -12657,11 +13136,13 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@@ -13372,6 +13853,7 @@ do
|
||||
"daemons/lvmetad/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmetad/Makefile" ;;
|
||||
"conf/Makefile") CONFIG_FILES="$CONFIG_FILES conf/Makefile" ;;
|
||||
"conf/example.conf") CONFIG_FILES="$CONFIG_FILES conf/example.conf" ;;
|
||||
"conf/lvmlocal.conf") CONFIG_FILES="$CONFIG_FILES conf/lvmlocal.conf" ;;
|
||||
"conf/command_profile_template.profile") CONFIG_FILES="$CONFIG_FILES conf/command_profile_template.profile" ;;
|
||||
"conf/metadata_profile_template.profile") CONFIG_FILES="$CONFIG_FILES conf/metadata_profile_template.profile" ;;
|
||||
"include/.symlinks") CONFIG_FILES="$CONFIG_FILES include/.symlinks" ;;
|
||||
|
53
configure.in
53
configure.in
@@ -69,6 +69,7 @@ dnl -- Checks for programs.
|
||||
AC_PROG_SED
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
dnl probably no longer needed in 2008, but...
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
@@ -353,7 +354,7 @@ AC_ARG_WITH(default-mirror-segtype,
|
||||
AC_HELP_STRING([--with-default-mirror-segtype=TYPE],
|
||||
[default mirror segtype: raid1/mirror [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],
|
||||
[default mirror segtype: raid10/mirror [raid10]]),
|
||||
DEFAULT_RAID10_SEGTYPE=$withval, DEFAULT_RAID10_SEGTYPE="raid10")
|
||||
@@ -961,6 +962,8 @@ AC_TRY_CCFLAG([-Wjump-misses-init], [HAVE_WJUMP], [], [])
|
||||
AC_SUBST(HAVE_WJUMP)
|
||||
AC_TRY_CCFLAG([-Wclobbered], [HAVE_WCLOBBERED], [], [])
|
||||
AC_SUBST(HAVE_WCLOBBERED)
|
||||
AC_TRY_CCFLAG([-Wsync-nand], [HAVE_WSYNCNAND], [], [])
|
||||
AC_SUBST(HAVE_WSYNCNAND)
|
||||
|
||||
################################################################################
|
||||
dnl -- Override optimisation
|
||||
@@ -1022,12 +1025,16 @@ AC_ARG_ENABLE(valgrind_pool,
|
||||
VALGRIND_POOL=$enableval, VALGRIND_POOL=no)
|
||||
AC_MSG_RESULT($VALGRIND_POOL)
|
||||
|
||||
if test "$VALGRIND_POOL" = yes; then
|
||||
pkg_config_init
|
||||
PKG_CHECK_MODULES(VALGRIND, valgrind, [], [AC_MSG_ERROR(bailing out)])
|
||||
pkg_config_init
|
||||
PKG_CHECK_MODULES(VALGRIND, valgrind, [HAVE_VALGRIND=yes], [if test x$VALGRIND_POOL = xyes; then AC_MSG_ERROR(bailing out); fi])
|
||||
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_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(VALGRIND_CFLAGS)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -1092,13 +1099,26 @@ fi
|
||||
|
||||
################################################################################
|
||||
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_ARG_ENABLE(udev-systemd-background-jobs,
|
||||
AC_HELP_STRING([--disable-udev-systemd-background-jobs],
|
||||
[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)
|
||||
|
||||
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
|
||||
AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
|
||||
@@ -1359,6 +1379,18 @@ if test "$REALTIME" = yes; then
|
||||
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
|
||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
|
||||
@@ -1434,6 +1466,8 @@ AC_ARG_WITH(confdir,
|
||||
AC_HELP_STRING([--with-confdir=DIR],
|
||||
[configuration files in DIR [/etc]]),
|
||||
CONFDIR=$withval, CONFDIR='/etc')
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ETC_DIR, ["$CONFDIR"],
|
||||
[Default system configuration directory.])
|
||||
|
||||
AC_ARG_WITH(staticdir,
|
||||
AC_HELP_STRING([--with-staticdir=DIR],
|
||||
@@ -1532,8 +1566,8 @@ AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
fi
|
||||
|
||||
@@ -1703,6 +1737,7 @@ AC_SUBST(FSADM)
|
||||
AC_SUBST(BLKDEACTIVATE)
|
||||
AC_SUBST(HAVE_LIBDL)
|
||||
AC_SUBST(HAVE_REALTIME)
|
||||
AC_SUBST(HAVE_VALGRIND)
|
||||
AC_SUBST(INTL)
|
||||
AC_SUBST(INTL_PACKAGE)
|
||||
AC_SUBST(JOBS)
|
||||
@@ -1762,6 +1797,7 @@ AC_SUBST(UDEV_SYNC)
|
||||
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMETAD_PIDFILE)
|
||||
@@ -1800,6 +1836,7 @@ daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/lvmetad/Makefile
|
||||
conf/Makefile
|
||||
conf/example.conf
|
||||
conf/lvmlocal.conf
|
||||
conf/command_profile_template.profile
|
||||
conf/metadata_profile_template.profile
|
||||
include/.symlinks
|
||||
|
@@ -208,8 +208,6 @@ static int _lock_resource(const char *resource, int mode, int flags, int *lockid
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
|
||||
retry:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
if (flags & LCKF_CONVERT) {
|
||||
/* In real DLM, lock is identified only by lockid, resource is not used */
|
||||
@@ -269,12 +267,14 @@ retry:
|
||||
dm_list_add(head, &lck->list);
|
||||
}
|
||||
out:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
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)
|
||||
{
|
||||
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"
|
||||
" -t<secs> Command timeout (default 60 seconds)\n"
|
||||
" -T<secs> Startup timeout (default none)\n"
|
||||
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\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"
|
||||
" Available cluster managers: "
|
||||
#ifdef USE_COROSYNC
|
||||
@@ -177,6 +172,11 @@ static void usage(const char *prog, FILE *file)
|
||||
#ifdef USE_SINGLENODE
|
||||
"singlenode "
|
||||
#endif
|
||||
" -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);
|
||||
}
|
||||
|
||||
@@ -899,8 +899,10 @@ static void main_loop(int cmd_timeout)
|
||||
ret = thisfd->callback(thisfd, buf, sizeof(buf),
|
||||
csid, &newfd);
|
||||
/* Ignore EAGAIN */
|
||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR))
|
||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
|
||||
lastfd = thisfd;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Got error or EOF: Remove it from the list safely */
|
||||
if (ret <= 0) {
|
||||
@@ -1128,7 +1130,7 @@ static void dump_message(char *buf, int len)
|
||||
row[j] = buf[i];
|
||||
str[j] = (isprint(buf[i])) ? buf[i] : ' ';
|
||||
|
||||
if ((j == 8) || (i + 1 == len)) {
|
||||
if (i + 1 == len) {
|
||||
for (;j < 8; ++j) {
|
||||
row[j] = 0;
|
||||
str[j] = ' ';
|
||||
|
@@ -136,7 +136,7 @@ static const char *decode_flags(unsigned char flags)
|
||||
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
||||
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
||||
flags & LCK_TEST_MODE ? "TEST|" : "",
|
||||
flags & LCK_CONVERT ? "CONVERT|" : "",
|
||||
flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
||||
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.
|
||||
*/
|
||||
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) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
|
@@ -102,7 +102,8 @@ int dmeventd_lvm2_init(void)
|
||||
goto out;
|
||||
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!getenv("LVM_LOG_FILE_EPOCH"))
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
|
@@ -135,11 +135,21 @@ static int _remove_failed_devices(const char *device)
|
||||
#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),
|
||||
"lvscan --cache", device))
|
||||
return -1;
|
||||
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Re-scan of mirror 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 -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
||||
|
@@ -68,9 +68,6 @@ static void destroy_metadata_hashes(lvmetad_state *s)
|
||||
dm_hash_destroy(s->vgid_to_vgname);
|
||||
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->pvid_to_vgid);
|
||||
}
|
||||
@@ -773,11 +770,46 @@ out: /* FIXME: We should probably abort() on partial failures. */
|
||||
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)
|
||||
{
|
||||
const char *pvid = daemon_request_str(r, "uuid", NULL);
|
||||
int64_t device = daemon_request_int(r, "device", 0);
|
||||
int64_t alt_device = 0;
|
||||
struct dm_config_tree *pvmeta;
|
||||
struct dm_config_node *pvmeta_tmp;
|
||||
char *pvid_old, *vgid;
|
||||
|
||||
DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device);
|
||||
@@ -797,10 +829,13 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
|
||||
|
||||
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 = dm_strdup(vgid)))
|
||||
@@ -815,9 +850,15 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
if (!pvmeta)
|
||||
return reply_unknown("PVID does not exist");
|
||||
|
||||
dm_config_destroy(pvmeta);
|
||||
if (!alt_device)
|
||||
dm_config_destroy(pvmeta);
|
||||
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
if (alt_device) {
|
||||
return daemon_reply_simple("OK",
|
||||
"device = %"PRId64, alt_device,
|
||||
NULL);
|
||||
} else
|
||||
return daemon_reply_simple("OK", NULL );
|
||||
}
|
||||
|
||||
static response pv_clear_all(lvmetad_state *s, request r)
|
||||
@@ -845,11 +886,11 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
const char *vgname = daemon_request_str(r, "vgname", NULL);
|
||||
const char *vgid = daemon_request_str(r, "metadata/id", 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;
|
||||
struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL;
|
||||
char *old;
|
||||
char *pvid_dup;
|
||||
int complete = 0, orphan = 0;
|
||||
int64_t seqno = -1, seqno_old = -1, changed = 0;
|
||||
|
||||
@@ -861,12 +902,8 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device))
|
||||
return reply_fail("need PV device number");
|
||||
|
||||
if (!(cft = dm_config_create()) ||
|
||||
(!(pvid_dup = dm_strdup(pvid)))) {
|
||||
if (cft)
|
||||
dm_config_destroy(cft);
|
||||
if (!(cft = dm_config_create()))
|
||||
return reply_fail("out of memory");
|
||||
}
|
||||
|
||||
lock_pvid_to_pvmeta(s);
|
||||
|
||||
@@ -875,7 +912,6 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
|
||||
if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -885,35 +921,69 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
if (!(cft->root = dm_config_clone_node(cft, pvmeta, 0)))
|
||||
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))
|
||||
changed |= 1;
|
||||
|
||||
if (pvmeta_old_pvid && device != device_old_pvid) {
|
||||
DEBUGLOG(s, "pv %s no longer on device %" PRIu64, pvid, device_old_pvid);
|
||||
dm_free(dm_hash_lookup_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid)));
|
||||
DEBUGLOG(s, "PV %s duplicated on device %" PRIu64, pvid, 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;
|
||||
}
|
||||
|
||||
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);
|
||||
out_of_mem:
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
dm_config_destroy(cft);
|
||||
dm_free(pvid_dup);
|
||||
dm_free(old);
|
||||
return reply_fail("out of memory");
|
||||
}
|
||||
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
|
||||
dm_free(old);
|
||||
|
||||
if (pvmeta_old_pvid)
|
||||
dm_config_destroy(pvmeta_old_pvid);
|
||||
if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid)
|
||||
dm_config_destroy(pvmeta_old_dev);
|
||||
if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid) {
|
||||
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 (!vgid)
|
||||
|
@@ -105,6 +105,7 @@ void _dump_vg(daemon_handle h, const char *uuid)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
daemon_handle h = lvmetad_open();
|
||||
/* FIXME Missing error path */
|
||||
|
||||
if (argc > 1) {
|
||||
int i;
|
||||
@@ -114,6 +115,7 @@ int main(int argc, char **argv) {
|
||||
scan(h, argv[i]);
|
||||
}
|
||||
destroy_toolcontext(cmd);
|
||||
/* FIXME Missing lvmetad_close() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -122,6 +124,6 @@ int main(int argc, char **argv) {
|
||||
_dump_vg(h, vgid);
|
||||
_pv_add(h, uuid3, NULL);
|
||||
|
||||
daemon_close(h);
|
||||
daemon_close(h); /* FIXME lvmetad_close? */
|
||||
return 0;
|
||||
}
|
||||
|
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.
|
||||
|
||||
The multiqueue policy has two sets of 16 queues: one set for entries
|
||||
waiting for the cache and another one for those in the cache.
|
||||
The multiqueue policy has three sets of 16 queues: one set for entries
|
||||
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
|
||||
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
|
||||
costs into account and to adjust to varying load patterns automatically.
|
||||
|
||||
Message and constructor argument pairs are:
|
||||
'sequential_threshold <#nr_sequential_ios>' and
|
||||
'random_threshold <#nr_random_ios>'.
|
||||
'sequential_threshold <#nr_sequential_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
|
||||
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
|
||||
before the stream is treated as random again.
|
||||
|
||||
The sequential and random thresholds default to 512 and 4 respectively.
|
||||
|
||||
Large, sequential ios are probably better left on the origin device
|
||||
since spindles tend to have good bandwidth. The io_tracker counts
|
||||
contiguous I/Os to try to spot when the io is in one of these sequential
|
||||
modes.
|
||||
Large, sequential I/Os are probably better left on the origin device
|
||||
since spindles tend to have good sequential I/O bandwidth. The
|
||||
io_tracker counts contiguous I/Os to try to spot when the I/O is in one
|
||||
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
|
||||
-------
|
||||
|
@@ -50,14 +50,16 @@ other parameters detailed later):
|
||||
which are dirty, and extra hints for use by the policy object.
|
||||
This information could be put on the cache device, but having it
|
||||
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
|
||||
----------------
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
--------------------
|
||||
|
||||
Migrating data between the origin and cache device uses bandwidth.
|
||||
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
|
||||
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
|
||||
-------------------------
|
||||
|
||||
On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
|
||||
written. If no such requests are made then commits will occur every
|
||||
second. This means the cache behaves like a physical disk that has a
|
||||
write cache (the same is true of the thin-provisioning target). If
|
||||
power is lost you may lose some recent writes. The metadata should
|
||||
always be consistent in spite of any crash.
|
||||
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 cache 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.
|
||||
|
||||
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
|
||||
@@ -159,7 +184,7 @@ Constructor
|
||||
block size : cache unit size in sectors
|
||||
|
||||
#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 args : an even number of arguments corresponding to
|
||||
@@ -175,6 +200,13 @@ Optional feature arguments are:
|
||||
back cache block contents later for performance reasons,
|
||||
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
|
||||
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
|
||||
------
|
||||
|
||||
<#used metadata blocks>/<#total metadata blocks> <#read hits> <#read misses>
|
||||
<#write hits> <#write misses> <#demotions> <#promotions> <#blocks in cache>
|
||||
<#dirty> <#features> <features>* <#core args> <core args>* <#policy args>
|
||||
<policy args>*
|
||||
<metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
<cache block size> <#used cache blocks>/<#total cache blocks>
|
||||
<#read hits> <#read misses> <#write hits> <#write misses>
|
||||
<#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||
<#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||
|
||||
#used metadata blocks : Number of metadata blocks used
|
||||
#total metadata blocks : Total number of metadata blocks
|
||||
#read hits : Number of times a READ bio has been mapped
|
||||
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
|
||||
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
|
||||
#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
|
||||
#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
|
||||
#write misses : Number of times a WRITE bio has been
|
||||
#write misses : Number of times a WRITE bio has been
|
||||
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
|
||||
#promotions : Number of times a block has been moved to
|
||||
#promotions : Number of times a block has been moved to
|
||||
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
|
||||
#feature args : Number of feature args to follow
|
||||
feature args : 'writethrough' (optional)
|
||||
#core args : Number of core arguments (must be even)
|
||||
core args : Key/value pairs for tuning the core
|
||||
#feature args : Number of feature args to follow
|
||||
feature args : 'writethrough' (optional)
|
||||
#core args : Number of core arguments (must be even)
|
||||
core args : Key/value pairs for tuning the core
|
||||
e.g. migration_threshold
|
||||
#policy args : Number of policy arguments to follow (must be even)
|
||||
policy args : Key/value pairs
|
||||
e.g. 'sequential_threshold 1024
|
||||
policy name : Name of the policy
|
||||
#policy args : Number of policy arguments to follow (must be even)
|
||||
policy args : Key/value pairs
|
||||
e.g. sequential_threshold
|
||||
|
||||
Messages
|
||||
--------
|
||||
@@ -229,12 +268,28 @@ The message format is:
|
||||
E.g.
|
||||
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
|
||||
========
|
||||
|
||||
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 \
|
||||
/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
|
||||
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> \
|
||||
<offset> [<#opt_params> <opt_params>]
|
||||
|
||||
<cipher>
|
||||
Encryption cipher and an optional IV generation mode.
|
||||
(In format cipher[:keycount]-chainmode-ivopts:ivmode).
|
||||
(In format cipher[:keycount]-chainmode-ivmode[:ivopts]).
|
||||
Examples:
|
||||
des
|
||||
aes-cbc-essiv:sha256
|
||||
@@ -19,7 +22,11 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||
|
||||
<key>
|
||||
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>
|
||||
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.
|
||||
|
||||
Example of optional parameters section:
|
||||
1 allow_discards
|
||||
3 allow_discards same_cpu_crypt submit_from_crypt_cpus
|
||||
|
||||
allow_discards
|
||||
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
|
||||
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
|
||||
===============
|
||||
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
|
||||
encryption with dm-crypt using the 'cryptsetup' utility, see
|
||||
http://code.google.com/p/cryptsetup/
|
||||
https://gitlab.com/cryptsetup/cryptsetup
|
||||
|
||||
[[
|
||||
#!/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.5.0 Add message interface to allow manipulation of the sync_action.
|
||||
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 gives the smallest unit of disk space that can be
|
||||
allocated at a time expressed in units of 512-byte sectors. People
|
||||
primarily interested in thin provisioning may want to use a value such
|
||||
as 1024 (512KB). People doing lots of snapshotting may want a smaller value
|
||||
such as 128 (64KB). If you are not zeroing newly-allocated data,
|
||||
a larger $data_block_size in the region of 256000 (128MB) is suggested.
|
||||
$data_block_size must be the same for the lifetime of the
|
||||
metadata device.
|
||||
allocated at a time expressed in units of 512-byte sectors.
|
||||
$data_block_size must be between 128 (64KB) and 2097152 (1GB) and a
|
||||
multiple of 128 (64KB). $data_block_size cannot be changed after the
|
||||
thin-pool is created. People primarily interested in thin provisioning
|
||||
may want to use a value such as 1024 (512KB). People doing lots of
|
||||
snapshotting may want a smaller value such as 128 (64KB). If you are
|
||||
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
|
||||
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
|
||||
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
|
||||
-----------------
|
||||
|
||||
@@ -234,6 +264,8 @@ i) Constructor
|
||||
read_only: Don't allow any changes to be made to the pool
|
||||
metadata.
|
||||
|
||||
error_if_no_space: Error IOs, instead of queueing, if no space.
|
||||
|
||||
Data block size must be between 64KB (128 sectors) and 1GB
|
||||
(2097152 sectors) inclusive.
|
||||
|
||||
@@ -255,10 +287,9 @@ ii) Status
|
||||
should register for the event and then check the target's status.
|
||||
|
||||
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 root. This feature is not yet implemented so '-' is
|
||||
always returned.
|
||||
held root.
|
||||
|
||||
discard_passdown|no_discard_passdown
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
<nr mapped sectors> <highest mapped sector>
|
||||
|
@@ -11,6 +11,7 @@ Construction Parameters
|
||||
<data_block_size> <hash_block_size>
|
||||
<num_data_blocks> <hash_start_block>
|
||||
<algorithm> <digest> <salt>
|
||||
[<#opt_params> <opt_params>]
|
||||
|
||||
<version>
|
||||
This is the type of the on-disk hash format.
|
||||
@@ -62,6 +63,22 @@ Construction Parameters
|
||||
<salt>
|
||||
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
|
||||
===================
|
||||
|
||||
@@ -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
|
||||
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
|
||||
======
|
||||
@@ -142,7 +159,7 @@ Set up a device:
|
||||
|
||||
A command line tool veritysetup is available to compute or verify
|
||||
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).
|
||||
|
||||
Create hash on the device:
|
||||
|
@@ -13,6 +13,7 @@
|
||||
@top_srcdir@/lib/datastruct/btree.h
|
||||
@top_srcdir@/lib/datastruct/str_list.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/device.h
|
||||
@top_srcdir@/lib/device/device-types.h
|
||||
|
@@ -56,6 +56,7 @@ SOURCES =\
|
||||
datastruct/btree.c \
|
||||
datastruct/str_list.c \
|
||||
device/dev-cache.c \
|
||||
device/dev-ext.c \
|
||||
device/dev-io.c \
|
||||
device/dev-md.c \
|
||||
device/dev-swap.c \
|
||||
@@ -69,6 +70,7 @@ SOURCES =\
|
||||
filters/filter-regex.c \
|
||||
filters/filter-sysfs.c \
|
||||
filters/filter-md.c \
|
||||
filters/filter-fwraid.c \
|
||||
filters/filter-mpath.c \
|
||||
filters/filter-partitioned.c \
|
||||
filters/filter-type.c \
|
||||
@@ -220,7 +222,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS)
|
||||
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
||||
|
@@ -238,6 +238,22 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
{
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
@@ -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,
|
||||
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)
|
||||
{
|
||||
struct dm_info dminfo;
|
||||
@@ -637,8 +655,16 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
}
|
||||
|
||||
/* New thin-pool has no layer, but -tpool suffix needs to be queried */
|
||||
if (!use_layer && lv_is_new_thin_pool(lv))
|
||||
use_layer = 1;
|
||||
if (!use_layer && lv_is_new_thin_pool(lv)) {
|
||||
/* 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,
|
||||
(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())
|
||||
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,
|
||||
@@ -690,19 +716,45 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
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,
|
||||
struct lv_with_info_and_seg_status *lvdm,
|
||||
int with_open_count, int with_read_ahead)
|
||||
/*
|
||||
* Returns 1 if lv_seg_status structure 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)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!_lv_info(cmd, lv, use_layer, lvdm->info, lvdm->seg_status,
|
||||
with_open_count, with_read_ahead))
|
||||
return _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, lv_seg_status, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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
|
||||
@@ -1713,6 +1765,19 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data)
|
||||
struct detached_lv_data *detached = data;
|
||||
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 (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) &&
|
||||
(!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) &&
|
||||
@@ -2173,6 +2238,16 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
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()) {
|
||||
_skip("Activating '%s'.", lv->name);
|
||||
r = 1;
|
||||
|
@@ -36,21 +36,29 @@ typedef enum {
|
||||
SEG_STATUS_RAID,
|
||||
SEG_STATUS_SNAPSHOT,
|
||||
SEG_STATUS_THIN,
|
||||
SEG_STATUS_THIN_POOL
|
||||
SEG_STATUS_THIN_POOL,
|
||||
SEG_STATUS_UNKNOWN
|
||||
} lv_seg_status_type_t;
|
||||
|
||||
struct lv_seg_status {
|
||||
struct dm_pool *mem; /* input */
|
||||
struct lv_segment *seg; /* input */
|
||||
const struct lv_segment *seg; /* input */
|
||||
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 logical_volume *lv; /* input */
|
||||
struct lvinfo *info; /* output */
|
||||
const struct logical_volume *lv; /* input */
|
||||
int info_ok;
|
||||
struct lvinfo info; /* 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 {
|
||||
@@ -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);
|
||||
|
||||
/*
|
||||
* 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,
|
||||
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,
|
||||
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,
|
||||
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 lv_check_not_in_use(const struct logical_volume *lv);
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "config.h"
|
||||
#include "activate.h"
|
||||
#include "lvm-exec.h"
|
||||
#include "str_list.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
@@ -44,6 +45,12 @@ typedef enum {
|
||||
/* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
|
||||
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 dm_pool *mem;
|
||||
|
||||
@@ -54,6 +61,8 @@ struct dev_manager {
|
||||
int flush_required;
|
||||
int activation; /* building activation tree */
|
||||
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;
|
||||
|
||||
char *vg_name;
|
||||
@@ -112,6 +121,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
{
|
||||
struct segment_type *segtype;
|
||||
|
||||
seg_status->type = SEG_STATUS_UNKNOWN;
|
||||
/*
|
||||
* TODO: Add support for other segment types too!
|
||||
* The segment to report status for must be properly
|
||||
@@ -119,10 +129,11 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
* linear/striped, old snapshots and raids have proper
|
||||
* segment selected for status!
|
||||
*/
|
||||
if (strcmp(target_name, "cache"))
|
||||
if (strcmp(target_name, "cache") && strcmp(target_name, "thin-pool"))
|
||||
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) {
|
||||
log_error(INTERNAL_ERROR "_get_segment_status_from_target_params: "
|
||||
@@ -132,30 +143,28 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
}
|
||||
|
||||
if (!strcmp(segtype->name, "cache")) {
|
||||
if (!dm_get_status_cache(seg_status->mem, params,
|
||||
(struct dm_status_cache **) &seg_status->status))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_CACHE;
|
||||
if (!dm_get_status_cache(seg_status->mem, params, &(seg_status->cache)))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_CACHE;
|
||||
} else if (!strcmp(segtype->name, "raid")) {
|
||||
if (!dm_get_status_raid(seg_status->mem, params,
|
||||
(struct dm_status_raid **) &seg_status->status))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_RAID;
|
||||
if (!dm_get_status_raid(seg_status->mem, params, &seg_status->raid))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_RAID;
|
||||
} else if (!strcmp(segtype->name, "thin")) {
|
||||
if (!dm_get_status_thin(seg_status->mem, params,
|
||||
(struct dm_status_thin **) &seg_status->status))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN;
|
||||
if (!dm_get_status_thin(seg_status->mem, params, &seg_status->thin))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN;
|
||||
} else if (!strcmp(segtype->name, "thin-pool")) {
|
||||
if (!dm_get_status_thin_pool(seg_status->mem, params,
|
||||
(struct dm_status_thin_pool **) &seg_status->status))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN_POOL;
|
||||
if (!dm_get_status_thin_pool(seg_status->mem, params, &seg_status->thin_pool))
|
||||
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;
|
||||
if (!dm_get_status_snapshot(seg_status->mem, params, &seg_status->snapshot))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_SNAPSHOT;
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Unsupported segment type %s.", segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -191,9 +200,12 @@ static int _info_run(info_type_t type, const char *name, const char *dlid,
|
||||
case MKNODES:
|
||||
dmtask = DM_DEVICE_MKNODES;
|
||||
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)))
|
||||
return_0;
|
||||
|
||||
@@ -214,8 +226,8 @@ static int _info_run(info_type_t type, const char *name, const char *dlid,
|
||||
do {
|
||||
target = dm_get_next_target(dmt, target, &target_start,
|
||||
&target_length, &target_name, &target_params);
|
||||
if ((seg_status->seg->le * extent_size == target_start) &&
|
||||
(seg_status->seg->len * extent_size == target_length)) {
|
||||
if (((uint64_t) seg_status->seg->le * extent_size == target_start) &&
|
||||
((uint64_t) seg_status->seg->len * extent_size == target_length)) {
|
||||
params_to_process = target_params;
|
||||
break;
|
||||
}
|
||||
@@ -534,18 +546,22 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
}
|
||||
|
||||
/*
|
||||
* Snapshot origin could be sitting on top of a mirror which
|
||||
* could be blocking I/O. Skip snapshot origins entirely for
|
||||
* now.
|
||||
*
|
||||
* FIXME: rather than skipping origin, check if mirror is
|
||||
* underneath and if the mirror is blocking I/O.
|
||||
* FIXME: Snapshot origin could be sitting on top of a mirror
|
||||
* which could be blocking I/O. We should add a check for the
|
||||
* 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).
|
||||
* This is former check used, but it's not correct as it
|
||||
* disables snapshot-origins to be used in a stack in
|
||||
* general, not just over mirrors!
|
||||
*/
|
||||
if (check.check_suspended && target_type && !strcmp(target_type, "snapshot-origin")) {
|
||||
/*if (check.check_suspended && target_type && !strcmp(target_type, "snapshot-origin")) {
|
||||
log_debug_activation("%s: Snapshot-origin device %s not usable.",
|
||||
dev_name(dev), name);
|
||||
goto out;
|
||||
}
|
||||
}*/
|
||||
|
||||
if (target_type && strcmp(target_type, "error"))
|
||||
only_error_target = 0;
|
||||
@@ -1066,6 +1082,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
|
||||
dm_udev_set_sync_support(cmd->current_settings.udev_sync);
|
||||
|
||||
dm_list_init(&dm->pending_delete);
|
||||
|
||||
return dm;
|
||||
|
||||
bad:
|
||||
@@ -1723,6 +1741,12 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1871,6 +1895,8 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
/* let's assume there is no problem to read 64 bytes */
|
||||
if (read(fd, buf, sizeof(buf)) < sizeof(buf)) {
|
||||
log_sys_error("read", argv[args]);
|
||||
if (close(fd))
|
||||
log_sys_error("close", argv[args]);
|
||||
return 0;
|
||||
}
|
||||
for (ret = 0; ret < DM_ARRAY_SIZE(buf); ++ret)
|
||||
@@ -1939,14 +1965,14 @@ static int _pool_register_callback(struct dev_manager *dm,
|
||||
data->skip_zero = 1;
|
||||
data->exec = global_thin_check_executable_CFG;
|
||||
data->opts = global_thin_check_options_CFG;
|
||||
data->defaults = DEFAULT_THIN_CHECK_OPTIONS;
|
||||
data->defaults = DEFAULT_THIN_CHECK_OPTION1 " " DEFAULT_THIN_CHECK_OPTION2;
|
||||
data->global = "thin";
|
||||
} else if (lv_is_cache(lv)) { /* cache pool */
|
||||
data->pool_lv = first_seg(lv)->pool_lv;
|
||||
data->skip_zero = dm->activation;
|
||||
data->exec = global_cache_check_executable_CFG;
|
||||
data->opts = global_cache_check_options_CFG;
|
||||
data->defaults = DEFAULT_CACHE_CHECK_OPTIONS;
|
||||
data->defaults = DEFAULT_CACHE_CHECK_OPTION1;
|
||||
data->global = "cache";
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
|
||||
@@ -2039,13 +2065,7 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
}
|
||||
|
||||
if (lv_is_cache(lv)) {
|
||||
if (lv_is_pending_delete(lv)) {
|
||||
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) {
|
||||
if (!origin_only && !dm->activation && !dm->track_pending_delete) {
|
||||
/* Setup callback for non-activation partial tree */
|
||||
/* Activation gets own callback when needed */
|
||||
/* TODO: extend _cached_dm_info() to return dnode */
|
||||
@@ -2075,13 +2095,16 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
dm->track_pvmove_deps = 1;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
if (lv_is_pending_delete(sl->seg->lv) && lv_is_cache(sl->seg->lv)) {
|
||||
if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
|
||||
return_0;
|
||||
break;
|
||||
if (!dm->track_pending_delete)
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
if (lv_is_pending_delete(sl->seg->lv)) {
|
||||
/* LV is referenced by 'cache pending delete LV */
|
||||
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 */
|
||||
if (lv_is_replicator_dev(lv) &&
|
||||
@@ -2106,6 +2129,8 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
|
||||
for (s = 0; s < seg->area_count; 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))
|
||||
return_0;
|
||||
if (seg_is_raid(seg) &&
|
||||
@@ -2270,7 +2295,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
* is used in the CTR table.
|
||||
*/
|
||||
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))) {
|
||||
/* One each for metadata area and data area */
|
||||
if (!dm_tree_node_add_null_area(node, 0) ||
|
||||
@@ -2549,21 +2574,24 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
{
|
||||
uint32_t s;
|
||||
struct lv_segment *seg_present;
|
||||
const struct segment_type *segtype;
|
||||
const char *target_name;
|
||||
|
||||
/* Ensure required device-mapper targets are loaded */
|
||||
seg_present = find_snapshot(seg->lv) ? : seg;
|
||||
target_name = (seg_present->segtype->ops->target_name ?
|
||||
seg_present->segtype->ops->target_name(seg_present, laopts) :
|
||||
seg_present->segtype->name);
|
||||
segtype = seg_present->segtype;
|
||||
|
||||
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",
|
||||
target_name, seg->lv->name,
|
||||
layer ? "-" : "", layer ? : "");
|
||||
|
||||
if (seg_present->segtype->ops->target_present &&
|
||||
!seg_present->segtype->ops->target_present(seg_present->lv->vg->cmd,
|
||||
seg_present, NULL)) {
|
||||
if (segtype->ops->target_present &&
|
||||
!segtype->ops->target_present(seg_present->lv->vg->cmd,
|
||||
seg_present, NULL)) {
|
||||
log_error("Can't process LV %s: %s target support missing "
|
||||
"from kernel?", seg->lv->name, target_name);
|
||||
return 0;
|
||||
@@ -2598,8 +2626,10 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
/* Add any LVs used by this segment */
|
||||
for (s = 0; s < seg->area_count; ++s) {
|
||||
if ((seg_type(seg, s) == AREA_LV) &&
|
||||
(!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s),
|
||||
laopts, NULL)))
|
||||
/* origin only for cache without pending delete */
|
||||
(!dm->track_pending_delete || !seg_is_cache(seg)) &&
|
||||
!_add_new_lv_to_dtree(dm, dtree, seg_lv(seg, s),
|
||||
laopts, NULL))
|
||||
return_0;
|
||||
if (seg_is_raid(seg) &&
|
||||
!_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s),
|
||||
@@ -2607,7 +2637,13 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
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 1;
|
||||
@@ -2680,6 +2716,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 read_ahead = lv->read_ahead;
|
||||
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 */
|
||||
if (lv_is_pending_delete(lv) && !_cached_dm_info(dm->mem, dtree, lv, NULL))
|
||||
@@ -2767,29 +2804,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
/* Create table */
|
||||
dm->pvmove_mirror_count = 0u;
|
||||
|
||||
if (lv_is_pending_delete(lv)) {
|
||||
if (lv_is_pending_delete(lv))
|
||||
/* Handle LVs with pending delete */
|
||||
if (lv_is_cache(lv)) {
|
||||
/* Use 'error' for cache, metadata and data volumes */
|
||||
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;
|
||||
}
|
||||
/* Fow now used only by cache segtype, TODO snapshots */
|
||||
dm->track_pending_delete = 1;
|
||||
|
||||
/* This is unused cache-pool - make metadata accessible */
|
||||
if (lv_is_cache_pool(lv))
|
||||
@@ -2875,6 +2893,8 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return_0;
|
||||
#endif
|
||||
|
||||
dm->track_pending_delete = save_pending_delete; /* restore */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2967,12 +2987,20 @@ static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
|
||||
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;
|
||||
struct dm_tree_node *child;
|
||||
char *vgname, *lvname, *layer;
|
||||
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))) {
|
||||
if (!(name = dm_tree_node_get_name(child)))
|
||||
@@ -2987,23 +3015,14 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root, char *
|
||||
}
|
||||
|
||||
/* Not meant to be top level? */
|
||||
if (!*layer && (!(layer = strchr(uuid + 4, '-')) || strstr(layer, "-pool") || strstr(layer, "-tpool")))
|
||||
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]))
|
||||
if (!*layer)
|
||||
continue;
|
||||
|
||||
/* If operation was performed on a partial tree, don't remove it */
|
||||
if (non_toplevel_tree_dlid && !strcmp(non_toplevel_tree_dlid, uuid))
|
||||
continue;
|
||||
|
||||
if ((name = strstr(lvname, "_corig")) && !name[6]) {
|
||||
/* 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)))
|
||||
if (!dm_tree_deactivate_children(root, uuid, strlen(uuid)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -3013,7 +3032,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,
|
||||
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"
|
||||
};
|
||||
const size_t DLID_SIZE = ID_LEN + sizeof(UUID_PREFIX) - 1;
|
||||
|
129
lib/cache/lvmcache.c
vendored
129
lib/cache/lvmcache.c
vendored
@@ -56,6 +56,8 @@ struct lvmcache_vginfo {
|
||||
char _padding[7];
|
||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||
char *creation_host;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
size_t vgmetadata_size;
|
||||
char *vgmetadata; /* Copy of VG metadata as format_text string */
|
||||
struct dm_config_tree *cft; /* Config tree created from vgmetadata */
|
||||
@@ -76,6 +78,7 @@ static int _scanning_in_progress = 0;
|
||||
static int _has_scanned = 0;
|
||||
static int _vgs_locked = 0;
|
||||
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)
|
||||
{
|
||||
@@ -284,6 +287,9 @@ void lvmcache_commit_metadata(const char *vgname)
|
||||
|
||||
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. */
|
||||
if (!strcmp(vgname, VG_ORPHANS)) {
|
||||
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
|
||||
@@ -292,7 +298,7 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
||||
|
||||
/* Indicate that PVs could now be missing from the cache */
|
||||
init_full_scan_done(0);
|
||||
} else if (!lvmcache_vgname_is_locked(VG_GLOBAL))
|
||||
} else
|
||||
_drop_metadata(vgname, drop_precommitted);
|
||||
}
|
||||
|
||||
@@ -402,6 +408,16 @@ int lvmcache_vgs_locked(void)
|
||||
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,
|
||||
struct lvmcache_info *info)
|
||||
{
|
||||
@@ -1392,6 +1408,26 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
||||
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;
|
||||
}
|
||||
|
||||
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
|
||||
{
|
||||
if (!_lock_hash && !lvmcache_init()) {
|
||||
@@ -1402,10 +1438,11 @@ int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
|
||||
return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
|
||||
}
|
||||
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host)
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
const char *vgname = vgsummary->vgname;
|
||||
const char *vgid = (char *)&vgsummary->vgid;
|
||||
|
||||
if (!vgname && !info->vginfo) {
|
||||
log_error(INTERNAL_ERROR "NULL vgname handed to cache");
|
||||
/* FIXME Remove this */
|
||||
@@ -1433,10 +1470,11 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
if (!is_orphan_vg(vgname))
|
||||
info->status &= ~CACHE_INVALID;
|
||||
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
|
||||
creation_host, info->fmt) ||
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
|
||||
vgsummary->creation_host, info->fmt) ||
|
||||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
|
||||
!_lvmcache_update_vgstatus(info, vgstatus, creation_host))
|
||||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host) ||
|
||||
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -1447,6 +1485,11 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
struct lvmcache_vgsummary vgsummary = {
|
||||
.vgname = vg->name,
|
||||
.vgstatus = vg->status,
|
||||
.vgid = vg->id
|
||||
};
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
@@ -1454,9 +1497,7 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||
if ((info = lvmcache_info_from_pvid(pvid_s, 0)) &&
|
||||
!lvmcache_update_vgname_and_id(info, vg->name,
|
||||
(char *) &vg->id,
|
||||
vg->status, NULL))
|
||||
!lvmcache_update_vgname_and_id(info, &vgsummary))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -1467,6 +1508,27 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
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;
|
||||
}
|
||||
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid,
|
||||
@@ -1477,6 +1539,14 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct label *label;
|
||||
struct lvmcache_info *existing, *info;
|
||||
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()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
@@ -1539,10 +1609,15 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
||||
//dm_is_dm_major(MAJOR(dev->dev)))
|
||||
//
|
||||
else if (!strcmp(pvid_s, existing->dev->pvid))
|
||||
log_error("Found duplicate PV %s: using %s not "
|
||||
"%s", pvid, dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
else if (!strcmp(pvid_s, existing->dev->pvid)) {
|
||||
log_error("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(existing->dev),
|
||||
dev_name(dev));
|
||||
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
|
||||
_found_duplicate_pvs = 1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (strcmp(pvid_s, existing->dev->pvid))
|
||||
log_debug_cache("Updating pvid cache to %s (%s) from %s (%s)",
|
||||
@@ -1573,7 +1648,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
|
||||
if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
|
||||
if (!existing) {
|
||||
dm_hash_remove(_pvid_hash, pvid_s);
|
||||
strcpy(info->dev->pvid, "");
|
||||
@@ -1982,3 +2057,27 @@ uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info)
|
||||
const struct format_type *lvmcache_fmt(struct lvmcache_info *info) {
|
||||
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;
|
||||
memcpy((char *)&vgsummary->vgid, vginfo->vgid, sizeof(vginfo->vgid));
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
18
lib/cache/lvmcache.h
vendored
18
lib/cache/lvmcache.h
vendored
@@ -39,6 +39,15 @@ struct disk_locn;
|
||||
|
||||
struct lvmcache_vginfo;
|
||||
|
||||
struct lvmcache_vgsummary {
|
||||
const char *vgname;
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
char *creation_host;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
};
|
||||
|
||||
int lvmcache_init(void);
|
||||
void lvmcache_allow_reads_with_lvmetad(void);
|
||||
|
||||
@@ -58,8 +67,7 @@ void lvmcache_del(struct lvmcache_info *info);
|
||||
|
||||
/* Update things */
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *hostname);
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted);
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||
@@ -68,6 +76,7 @@ int lvmcache_verify_lock_order(const char *vgname);
|
||||
|
||||
/* Queries */
|
||||
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. */
|
||||
int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo);
|
||||
@@ -157,4 +166,9 @@ unsigned lvmcache_mda_count(struct lvmcache_info *info);
|
||||
int lvmcache_vgid_is_cached(const char *vgid);
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
76
lib/cache/lvmetad.c
vendored
76
lib/cache/lvmetad.c
vendored
@@ -136,6 +136,9 @@ void lvmetad_set_socket(const char *sock)
|
||||
_lvmetad_socket = sock;
|
||||
}
|
||||
|
||||
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
|
||||
int ignore_obsolete);
|
||||
|
||||
static daemon_reply _lvmetad_send(const char *id, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -183,7 +186,7 @@ retry:
|
||||
max_remaining_sleep_times--; /* Sleep once before rescanning the first time, then 5 times each time after that. */
|
||||
} else {
|
||||
/* If the re-scan fails here, we try again later. */
|
||||
(void) lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL);
|
||||
(void) _lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL, 0);
|
||||
num_rescans++;
|
||||
max_remaining_sleep_times = 5;
|
||||
}
|
||||
@@ -264,15 +267,16 @@ static int _read_mda(struct lvmcache_info *info,
|
||||
|
||||
static struct lvmcache_info *_pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
struct dm_config_node *cn,
|
||||
dev_t fallback)
|
||||
struct format_type *fmt, dev_t fallback)
|
||||
{
|
||||
struct device *dev;
|
||||
struct device *dev, *dev_alternate;
|
||||
struct id pvid, vgid;
|
||||
char mda_id[32];
|
||||
char da_id[32];
|
||||
int i = 0;
|
||||
struct dm_config_node *mda = NULL;
|
||||
struct dm_config_node *da = NULL;
|
||||
struct dm_config_node *mda, *da;
|
||||
struct dm_config_node *alt_devices = dm_config_find_node(cn->child, "devices_alternate");
|
||||
struct dm_config_value *alt_device = NULL;
|
||||
uint64_t offset, size;
|
||||
struct lvmcache_info *info;
|
||||
const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL),
|
||||
@@ -283,7 +287,8 @@ static struct lvmcache_info *_pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
uint64_t devsize = dm_config_find_int64(cn->child, "dev_size", 0),
|
||||
label_sector = dm_config_find_int64(cn->child, "label_sector", 0);
|
||||
|
||||
struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL;
|
||||
if (!fmt && fmt_name)
|
||||
fmt = get_format_by_name(cmd, fmt_name);
|
||||
|
||||
if (!fmt) {
|
||||
log_error("PV %s not recognised. Is the device missing?", pvid_txt);
|
||||
@@ -356,6 +361,20 @@ static struct lvmcache_info *_pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
++i;
|
||||
} while (da);
|
||||
|
||||
if (alt_devices)
|
||||
alt_device = alt_devices->v;
|
||||
|
||||
while (alt_device) {
|
||||
dev_alternate = dev_cache_get_by_devt(alt_device->v.i, cmd->filter);
|
||||
if (dev_alternate)
|
||||
lvmcache_add(fmt->labeller, (const char *)&pvid, dev_alternate,
|
||||
vgname, (const char *)&vgid, 0);
|
||||
else
|
||||
log_warn("Duplicate of PV %s dev %s exists on unknown device %"PRId64 ":%" PRId64,
|
||||
pvid_txt, dev_name(dev), MAJOR(alt_device->v.i), MINOR(alt_device->v.i));
|
||||
alt_device = alt_device->next;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -422,7 +441,7 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
|
||||
if ((pvcn = dm_config_find_node(top, "metadata/physical_volumes")))
|
||||
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
|
||||
_pv_populate_lvmcache(cmd, pvcn, 0);
|
||||
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
|
||||
|
||||
top->key = name;
|
||||
if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
|
||||
@@ -573,7 +592,7 @@ int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found)
|
||||
|
||||
if (!(cn = dm_config_find_node(reply.cft->root, "physical_volume")))
|
||||
goto_out;
|
||||
else if (!_pv_populate_lvmcache(cmd, cn, 0))
|
||||
else if (!_pv_populate_lvmcache(cmd, cn, NULL, 0))
|
||||
goto_out;
|
||||
|
||||
out_success:
|
||||
@@ -603,7 +622,7 @@ int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *f
|
||||
goto out_success;
|
||||
|
||||
cn = dm_config_find_node(reply.cft->root, "physical_volume");
|
||||
if (!cn || !_pv_populate_lvmcache(cmd, cn, dev->dev))
|
||||
if (!cn || !_pv_populate_lvmcache(cmd, cn, NULL, dev->dev))
|
||||
goto_out;
|
||||
|
||||
out_success:
|
||||
@@ -631,7 +650,7 @@ int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
|
||||
|
||||
if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes")))
|
||||
for (cn = cn->child; cn; cn = cn->sib)
|
||||
_pv_populate_lvmcache(cmd, cn, 0);
|
||||
_pv_populate_lvmcache(cmd, cn, NULL, 0);
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
@@ -891,7 +910,9 @@ struct _lvmetad_pvscan_baton {
|
||||
static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct _lvmetad_pvscan_baton *b = baton;
|
||||
struct volume_group *this = mda->ops->vg_read(b->fid, "", mda, 1);
|
||||
struct volume_group *this;
|
||||
|
||||
this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1);
|
||||
|
||||
/* FIXME Also ensure contents match etc. */
|
||||
if (!b->vg || this->seqno > b->vg->seqno)
|
||||
@@ -903,7 +924,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
activation_handler handler)
|
||||
activation_handler handler, int ignore_obsolete)
|
||||
{
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
@@ -932,9 +953,16 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
goto_bad;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
if (ignore_obsolete)
|
||||
log_warn("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
else
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
|
||||
if (ignore_obsolete)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -947,7 +975,7 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
* can scan further devices.
|
||||
*/
|
||||
if (!baton.vg && !(baton.fid->fmt->features & FMT_MDAS))
|
||||
baton.vg = ((struct metadata_area *) dm_list_first(&baton.fid->metadata_areas_in_use))->ops->vg_read(baton.fid, lvmcache_vgname_from_info(info), NULL, 1);
|
||||
baton.vg = ((struct metadata_area *) dm_list_first(&baton.fid->metadata_areas_in_use))->ops->vg_read(baton.fid, lvmcache_vgname_from_info(info), NULL, NULL, NULL, 1);
|
||||
|
||||
if (!baton.vg)
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
@@ -973,7 +1001,8 @@ bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
|
||||
int ignore_obsolete)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
@@ -1015,7 +1044,7 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
stack;
|
||||
break;
|
||||
}
|
||||
if (!lvmetad_pvscan_single(cmd, dev, handler))
|
||||
if (!lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
@@ -1030,3 +1059,16 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
return r;
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
{
|
||||
return _lvmetad_pvscan_all_devs(cmd, handler, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME Implement this function, skipping PVs known to belong to local or clustered,
|
||||
* non-exported VGs.
|
||||
*/
|
||||
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler)
|
||||
{
|
||||
return _lvmetad_pvscan_all_devs(cmd, handler, 1);
|
||||
}
|
||||
|
6
lib/cache/lvmetad.h
vendored
6
lib/cache/lvmetad.h
vendored
@@ -153,9 +153,10 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
|
||||
* Scan a single device and update lvmetad with the result(s).
|
||||
*/
|
||||
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_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
|
||||
|
||||
# else /* LVMETAD_SUPPORT */
|
||||
|
||||
@@ -179,8 +180,9 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
||||
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
||||
# 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_foreign_vgs(cmd, handler) (0)
|
||||
|
||||
# endif /* LVMETAD_SUPPORT */
|
||||
|
||||
|
@@ -19,7 +19,6 @@
|
||||
#include "text_export.h"
|
||||
#include "config.h"
|
||||
#include "str_list.h"
|
||||
#include "targets.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
#include "metadata.h"
|
||||
@@ -69,7 +68,9 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("cache_mode must be a string in");
|
||||
if (!set_cache_pool_feature(&seg->feature_flags, str))
|
||||
return SEG_LOG_ERROR("Unknown cache_mode in");
|
||||
}
|
||||
} else
|
||||
/* When missed in metadata, it's an old stuff - use writethrough */
|
||||
seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
|
||||
if (dm_config_has_node(sn, "policy")) {
|
||||
if (!(str = dm_config_find_str(sn, "policy", NULL)))
|
||||
|
@@ -55,6 +55,128 @@
|
||||
|
||||
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)
|
||||
{
|
||||
const char *e;
|
||||
@@ -288,7 +410,8 @@ static int _check_config(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int process_profilable_config(struct cmd_context *cmd) {
|
||||
int process_profilable_config(struct cmd_context *cmd)
|
||||
{
|
||||
if (!(cmd->default_settings.unit_factor =
|
||||
dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL),
|
||||
&cmd->default_settings.unit_type, 1, NULL))) {
|
||||
@@ -304,9 +427,48 @@ int process_profilable_config(struct cmd_context *cmd) {
|
||||
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;
|
||||
}
|
||||
|
||||
static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
const char *dev_ext_info_src;
|
||||
const char *read_ahead;
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
@@ -340,6 +502,16 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return_0;
|
||||
#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 */
|
||||
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
|
||||
@@ -469,6 +641,9 @@ static int _process_config(struct cmd_context *cmd)
|
||||
|
||||
lvmetad_init(cmd);
|
||||
|
||||
if (!_init_system_id(cmd))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -526,11 +701,12 @@ static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
|
||||
const char *tag;
|
||||
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;
|
||||
|
||||
/* 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_+.- */
|
||||
if (!_set_tag(cmd, cmd->hostname))
|
||||
return_0;
|
||||
@@ -561,7 +737,7 @@ static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
|
||||
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] = "";
|
||||
const char *filler = "";
|
||||
@@ -569,6 +745,10 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
|
||||
if (*tag)
|
||||
filler = "_";
|
||||
else if (local) {
|
||||
filler = "";
|
||||
tag = "local";
|
||||
}
|
||||
|
||||
if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||
cmd->system_dir, filler, tag) < 0) {
|
||||
@@ -596,7 +776,9 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find and read first config file */
|
||||
/*
|
||||
* Find and read lvm.conf.
|
||||
*/
|
||||
static int _init_lvm_conf(struct cmd_context *cmd)
|
||||
{
|
||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||
@@ -608,7 +790,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_load_config_file(cmd, ""))
|
||||
if (!_load_config_file(cmd, "", 0))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -621,7 +803,7 @@ static int _init_tag_configs(struct cmd_context *cmd)
|
||||
|
||||
/* Tag list may grow while inside this loop */
|
||||
dm_list_iterate_items(sl, &cmd->tags) {
|
||||
if (!_load_config_file(cmd, sl->str))
|
||||
if (!_load_config_file(cmd, sl->str, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -835,7 +1017,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_FILTERS 7
|
||||
#define MAX_FILTERS 8
|
||||
|
||||
static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
{
|
||||
@@ -905,7 +1087,14 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
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;
|
||||
|
||||
return composite;
|
||||
@@ -926,7 +1115,7 @@ bad:
|
||||
* sysfs filter -> global regex filter -> type filter ->
|
||||
* usable device filter(FILTER_MODE_PRE_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter ->
|
||||
* md component filter
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
* - cmd->filter - the filter chain used for lvmetad responses:
|
||||
* persistent filter -> usable device filter(FILTER_MODE_POST_LVMETAD) ->
|
||||
@@ -942,7 +1131,7 @@ bad:
|
||||
* global regex filter -> type filter ->
|
||||
* usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter ->
|
||||
* md component filter
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
*/
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
@@ -951,6 +1140,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
struct timespec ts, cts;
|
||||
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
@@ -985,7 +1175,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
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)))
|
||||
if (!(filter = composite_filter_create(2, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
/* we have only one filter component - no need to create composite filter */
|
||||
@@ -1004,7 +1194,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
if (lvmetad_used()) {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
filter_components[1] = cmd->filter;
|
||||
if (!(cmd->full_filter = composite_filter_create(2, filter_components)))
|
||||
if (!(cmd->full_filter = composite_filter_create(2, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
cmd->full_filter = filter;
|
||||
@@ -1023,11 +1213,14 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
*/
|
||||
if (!find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL) &&
|
||||
load_persistent_cache && !cmd->is_long_lived &&
|
||||
!stat(dev_cache, &st) &&
|
||||
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(cmd->filter, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
!stat(dev_cache, &st)) {
|
||||
lvm_stat_ctim(&ts, &st);
|
||||
cts = config_file_timestamp(cmd->cft);
|
||||
if (timespeccmp(&ts, &cts, >) &&
|
||||
!persistent_filter_load(cmd->filter, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
}
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
@@ -1550,6 +1743,10 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (!_init_tags(cmd, cmd->cft))
|
||||
goto_out;
|
||||
|
||||
/* Load lvmlocal.conf */
|
||||
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
|
||||
goto_out;
|
||||
|
||||
if (!_init_tag_configs(cmd))
|
||||
goto_out;
|
||||
|
||||
@@ -1754,6 +1951,10 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_tags(cmd, cft_tmp))
|
||||
return_0;
|
||||
|
||||
/* Load lvmlocal.conf */
|
||||
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
|
||||
return_0;
|
||||
|
||||
/* Doesn't change cmd->cft */
|
||||
if (!_init_tag_configs(cmd))
|
||||
return_0;
|
||||
|
@@ -71,6 +71,7 @@ struct cmd_context {
|
||||
|
||||
struct dm_list formats; /* Available formats */
|
||||
struct dm_list segtypes; /* Available segment types */
|
||||
const char *system_id;
|
||||
const char *hostname;
|
||||
const char *kernel_vsn;
|
||||
|
||||
@@ -95,6 +96,10 @@ struct cmd_context {
|
||||
unsigned threaded:1; /* Set if running within a thread e.g. clvmd */
|
||||
|
||||
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
|
||||
unsigned unknown_system_id:1;
|
||||
unsigned include_foreign_vgs:1;
|
||||
unsigned include_active_foreign_vgs:1;
|
||||
unsigned error_foreign_vgs:1;
|
||||
|
||||
struct dev_types *dev_types;
|
||||
|
||||
@@ -160,4 +165,6 @@ int init_lvmcache_orphans(struct cmd_context *cmd);
|
||||
|
||||
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
|
||||
|
@@ -53,7 +53,7 @@ struct config_file {
|
||||
|
||||
struct config_source {
|
||||
config_source_t type;
|
||||
time_t timestamp;
|
||||
struct timespec timestamp;
|
||||
union {
|
||||
struct config_file *file;
|
||||
struct config_file *profile;
|
||||
@@ -65,11 +65,11 @@ struct config_source {
|
||||
* Map each ID to respective definition of the configuration item.
|
||||
*/
|
||||
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(id, name, parent, flags, type, default_value, since_version, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, 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_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_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_section(id, name, parent, flags, since_version, unconfigured_path, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, unconfigured_path, comment},
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_path, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, unconfigured_path, comment},
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, unconfigured_path, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, unconfigured_path, comment},
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_path, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, unconfigured_path, comment},
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, unconfigured_path, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, unconfigured_path, comment},
|
||||
#include "config_settings.h"
|
||||
#undef cfg_section
|
||||
#undef cfg
|
||||
@@ -173,7 +173,7 @@ int config_file_check(struct dm_config_tree *cft, const char **filename, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
cs->timestamp = info->st_ctime;
|
||||
lvm_stat_ctim(&cs->timestamp, info);
|
||||
cf->exists = 1;
|
||||
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_file *cf;
|
||||
struct stat info;
|
||||
struct timespec ts;
|
||||
|
||||
if (cs->type != CONFIG_FILE) {
|
||||
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? */
|
||||
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;
|
||||
|
||||
reload:
|
||||
@@ -478,9 +481,15 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
|
||||
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,
|
||||
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;
|
||||
int r = 0;
|
||||
@@ -529,9 +538,11 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
fe = fb + size + size2;
|
||||
if (!dm_config_parse(cft, fb, fe))
|
||||
goto_out;
|
||||
if (!checksum_only) {
|
||||
fe = fb + size + size2;
|
||||
if (!dm_config_parse(cft, fb, fe))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
@@ -575,7 +586,7 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
}
|
||||
|
||||
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 (!dev_close(cf->dev))
|
||||
@@ -586,7 +597,7 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
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);
|
||||
return cs->timestamp;
|
||||
@@ -649,8 +660,8 @@ 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(expected_type_name, sizeof(expected_type_name), expected);
|
||||
|
||||
log_warn_suppress(suppress_messages, "Configuration setting \"%s\" has invalid type. "
|
||||
"Found%s, expected%s.", path,
|
||||
log_warn_suppress(suppress_messages, "WARNING: Configuration setting \"%s\" has invalid type. "
|
||||
"Found%s but expected%s.", path,
|
||||
actual_type_name, expected_type_name);
|
||||
}
|
||||
|
||||
@@ -790,6 +801,11 @@ static int _config_def_check_node_single_value(struct cft_check_handle *handle,
|
||||
} else if (!(def->type & CFG_TYPE_STRING)) {
|
||||
_log_type_error(rp, CFG_TYPE_STRING, def->type, handle->suppress_messages);
|
||||
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;
|
||||
default: ;
|
||||
@@ -1140,6 +1156,29 @@ static int _apply_local_profile(struct cmd_context *cmd, struct profile *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)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
@@ -1171,7 +1210,8 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
|
||||
if (item->type != CFG_TYPE_STRING)
|
||||
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)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1194,7 +1234,8 @@ const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, st
|
||||
if (!(item->flags & CFG_ALLOW_EMPTY))
|
||||
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)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1215,7 +1256,8 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
|
||||
if (item->type != CFG_TYPE_INT)
|
||||
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)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1236,7 +1278,8 @@ int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *
|
||||
if (item->type != CFG_TYPE_INT)
|
||||
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)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1257,7 +1300,8 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
|
||||
if (item->type != CFG_TYPE_FLOAT)
|
||||
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)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1265,6 +1309,23 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
|
||||
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)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
@@ -1278,7 +1339,8 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
||||
if (item->type != CFG_TYPE_BOOL)
|
||||
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)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1414,7 +1476,7 @@ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
||||
cs = dm_config_get_custom(cft);
|
||||
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;
|
||||
|
||||
return 1;
|
||||
@@ -1426,6 +1488,36 @@ struct out_baton {
|
||||
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 _out_prefix_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
||||
{
|
||||
struct out_baton *out = baton;
|
||||
@@ -1433,7 +1525,7 @@ 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 */
|
||||
const char *node_type_name = cn->v ? "option" : "section";
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
|
||||
char commentline[MAX_COMMENT_LINE+1];
|
||||
|
||||
if (cn->id < 0)
|
||||
return 1;
|
||||
@@ -1449,12 +1541,20 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
|
||||
cfg_def = cfg_def_get_item_p(cn->id);
|
||||
|
||||
if (out->tree_spec->withcomments) {
|
||||
if (out->tree_spec->withcomments || out->tree_spec->withfullcomments) {
|
||||
_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);
|
||||
|
||||
if (cfg_def->comment)
|
||||
fprintf(out->fp, "%s# %s\n", line, cfg_def->comment);
|
||||
if (cfg_def->comment) {
|
||||
int pos = 0;
|
||||
while (_copy_one_line(cfg_def->comment, commentline, &pos, strlen(cfg_def->comment))) {
|
||||
fprintf(out->fp, "%s# %s\n", line, commentline);
|
||||
/* withcomments prints only the first comment line. */
|
||||
if (!out->tree_spec->withfullcomments)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg_def->flags & CFG_ADVANCED)
|
||||
fprintf(out->fp, "%s# This configuration %s is advanced.\n", line, node_type_name);
|
||||
@@ -1597,6 +1697,9 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
if (!(str = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_STRING, NULL)))
|
||||
str = "";
|
||||
cn->v->v.str = str;
|
||||
|
||||
if (spec->unconfigured && def->unconfigured_path)
|
||||
cn->v->v.str = def->unconfigured_path;
|
||||
break;
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "_add_def_node: unknown type");
|
||||
@@ -1714,6 +1817,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)
|
||||
continue;
|
||||
|
||||
if (spec->ignorelocal && (id == local_CFG_SECTION))
|
||||
continue;
|
||||
|
||||
if ((tmp = _add_def_section_subtree(cft, spec, root, relay, id))) {
|
||||
relay = tmp;
|
||||
if (!root)
|
||||
|
@@ -90,24 +90,27 @@ typedef union {
|
||||
|
||||
/* configuration definition item flags: */
|
||||
|
||||
|
||||
/* whether the configuration item name is variable */
|
||||
#define CFG_NAME_VARIABLE 0x01
|
||||
#define CFG_NAME_VARIABLE 0x001
|
||||
/* whether empty value is allowed */
|
||||
#define CFG_ALLOW_EMPTY 0x02
|
||||
#define CFG_ALLOW_EMPTY 0x002
|
||||
/* 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 */
|
||||
#define CFG_UNSUPPORTED 0x08
|
||||
#define CFG_UNSUPPORTED 0x008
|
||||
/* 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 */
|
||||
/* and whether it can be attached to VG/LV metadata at the same time
|
||||
* 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 */
|
||||
#define CFG_DEFAULT_UNDEFINED 0x40
|
||||
/* whether the defualt value is calculated during run time */
|
||||
#define CFG_DEFAULT_RUN_TIME 0x80
|
||||
#define CFG_DEFAULT_UNDEFINED 0x040
|
||||
/* whether the default value is calculated during run time */
|
||||
#define CFG_DEFAULT_RUN_TIME 0x080
|
||||
/* whether the configuration setting is disabled (and hence defaults always used) */
|
||||
#define CFG_DISABLED 0x100
|
||||
|
||||
/* configuration definition item structure */
|
||||
typedef struct cfg_def_item {
|
||||
@@ -118,6 +121,7 @@ typedef struct cfg_def_item {
|
||||
cfg_def_value_t default_value; /* default value (only for settings) */
|
||||
uint16_t flags; /* configuration item definition flags */
|
||||
uint16_t since_version; /* version this item appeared in */
|
||||
const char *unconfigured_path; /* path in terms of @FOO@, pre-configured */
|
||||
const char *comment; /* brief comment */
|
||||
} cfg_def_item_t;
|
||||
|
||||
@@ -141,8 +145,11 @@ struct config_def_tree_spec {
|
||||
uint16_t version; /* tree at this LVM2 version */
|
||||
unsigned ignoreadvanced:1; /* do not include advanced configs */
|
||||
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||
unsigned withcomments:1; /* include comments */
|
||||
unsigned ignorelocal:1; /* do not include the local section */
|
||||
unsigned withcomments:1; /* include first line of comment */
|
||||
unsigned withfullcomments:1; /* include all comment lines */
|
||||
unsigned withversions:1; /* include versions */
|
||||
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 +165,11 @@ struct config_def_tree_spec {
|
||||
* Register ID for each possible item in the configuration tree.
|
||||
*/
|
||||
enum {
|
||||
#define cfg_section(id, name, parent, flags, since_version, comment) id,
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, comment) id,
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, comment) id,
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, comment) id,
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, comment) id,
|
||||
#define cfg_section(id, name, parent, flags, since_version, unconfigured_path, comment) id,
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_path, comment) id,
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, unconfigured_path, comment) id,
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_path, comment) id,
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, unconfigured_path, comment) id,
|
||||
#include "config_settings.h"
|
||||
#undef cfg_section
|
||||
#undef cfg
|
||||
@@ -202,7 +209,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);
|
||||
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,
|
||||
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);
|
||||
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
|
||||
struct cmd_context *cmd);
|
||||
@@ -211,7 +219,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);
|
||||
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_check(struct dm_config_tree *cft, const char **filename, struct stat *info);
|
||||
|
||||
@@ -230,6 +238,12 @@ typedef enum {
|
||||
int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
||||
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.
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -29,9 +29,12 @@
|
||||
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSTEM_ID_SOURCE "none"
|
||||
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
|
||||
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_FW_RAID_COMPONENT_DETECTION 0
|
||||
#define DEFAULT_MD_CHUNK_ALIGNMENT 1
|
||||
#define DEFAULT_IGNORE_LVM_MIRRORS 1
|
||||
#define DEFAULT_MULTIPATH_COMPONENT_DETECTION 1
|
||||
@@ -44,6 +47,7 @@
|
||||
#define DEFAULT_PV_MIN_SIZE_KB 2048
|
||||
|
||||
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
||||
#define DEFAULT_ERROR_WHEN_FULL 0
|
||||
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
||||
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
||||
#define DEFAULT_WAIT_FOR_LOCKS 1
|
||||
@@ -72,9 +76,11 @@
|
||||
#endif
|
||||
|
||||
#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"
|
||||
#else
|
||||
# define DEFAULT_THIN_CHECK_OPTIONS "-q"
|
||||
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_THIN_CHECK_OPTION2 ""
|
||||
#endif
|
||||
|
||||
#define DEFAULT_THIN_REPAIR_OPTIONS ""
|
||||
@@ -89,7 +95,7 @@
|
||||
#define DEFAULT_THIN_POOL_ZERO 1
|
||||
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
||||
|
||||
#define DEFAULT_CACHE_CHECK_OPTIONS "-q"
|
||||
#define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
|
||||
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
||||
@@ -176,6 +182,7 @@
|
||||
|
||||
#define DEFAULT_MAX_ERROR_COUNT NO_DEV_ERROR_COUNT_LIMIT
|
||||
|
||||
#define DEFAULT_REP_COMPACT_OUTPUT 0
|
||||
#define DEFAULT_REP_ALIGNED 1
|
||||
#define DEFAULT_REP_BUFFERED 1
|
||||
#define DEFAULT_REP_COLUMNS_AS_ROWS 0
|
||||
|
@@ -71,6 +71,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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct dm_list *slh, *slht;
|
||||
|
@@ -21,6 +21,7 @@ struct dm_pool;
|
||||
|
||||
struct dm_list *str_list_create(struct dm_pool *mem);
|
||||
int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str);
|
||||
int str_list_add_list(struct dm_pool *mem, struct dm_list *sll, struct dm_list *sll2);
|
||||
int str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str);
|
||||
int str_list_add_h_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str);
|
||||
void str_list_del(struct dm_list *sll, const char *str);
|
||||
|
@@ -64,6 +64,9 @@ static void _dev_init(struct device *dev, int max_error_count)
|
||||
dev->read_ahead = -1;
|
||||
dev->max_error_count = max_error_count;
|
||||
|
||||
dev->ext.enabled = 0;
|
||||
dev->ext.src = DEV_EXT_NONE;
|
||||
|
||||
dm_list_init(&dev->aliases);
|
||||
dm_list_init(&dev->open_list);
|
||||
}
|
||||
@@ -983,12 +986,31 @@ static struct device *_dev_cache_seek_devt(dev_t dev)
|
||||
*/
|
||||
struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
const char *sysfs_dir;
|
||||
struct stat info;
|
||||
struct device *d = _dev_cache_seek_devt(dev);
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
|
||||
if (!d) {
|
||||
sysfs_dir = dm_sysfs_dir();
|
||||
if (sysfs_dir && *sysfs_dir) {
|
||||
/* First check if dev is sysfs to avoid useless scan */
|
||||
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d",
|
||||
sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) {
|
||||
log_error("dm_snprintf partition failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lstat(path, &info)) {
|
||||
log_debug("No sysfs entry for %d:%d.",
|
||||
(int)MAJOR(dev), (int)MINOR(dev));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_full_scan(0);
|
||||
d = _dev_cache_seek_devt(dev);
|
||||
}
|
||||
|
52
lib/device/dev-ext-udev-constants.h
Normal file
52
lib/device/dev-ext-udev-constants.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 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
|
||||
*/
|
||||
|
||||
/*************************************************************************
|
||||
* Properties saved in udev db and accesible via libudev and used by LVM *
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
* DEV_EXT_UDEV_BLKID_TYPE property with various DEV_EXT_UDEV_BLKID_TYPE_*
|
||||
* values that is saved in udev db via blkid call in udev rules
|
||||
*/
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE "ID_FS_TYPE"
|
||||
/*
|
||||
* mpath_member is forced by multipath - it's set in udev db via
|
||||
* multipath call overwriting any existing ID_FS_TYPE value for
|
||||
* a device which is a multipath component which prevents incorrect
|
||||
* claim of the device by any other block device subsystem
|
||||
*/
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE_MPATH "mpath_member"
|
||||
/* FW RAIDs are all *_raid_member types except linux_raid_member which denotes SW RAID */
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE_RAID_SUFFIX "_raid_member"
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE_SW_RAID "linux_raid_member"
|
||||
#define DEV_EXT_UDEV_BLKID_PART_TABLE_TYPE "ID_PART_TABLE_TYPE"
|
||||
#define DEV_EXT_UDEV_BLKID_PART_ENTRY_DISK "ID_PART_ENTRY_DISK"
|
||||
|
||||
/*
|
||||
* DEV_EXT_UDEV_MPATH_DEVICE_PATH is set by multipath in udev db
|
||||
* with value either 0 or 1. The same functionality as
|
||||
* DEV_EXT_UDEV_BLKID_TYPE_MPATH actually, but introduced later
|
||||
* for some reason.
|
||||
*/
|
||||
#define DEV_EXT_UDEV_MPATH_DEVICE_PATH "DM_MULTIPATH_DEVICE_PATH"
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Sysfs attributes accessible via libudev and used by LVM *
|
||||
***********************************************************/
|
||||
|
||||
/* the value of size sysfs attribute is size in bytes */
|
||||
#define DEV_EXT_UDEV_SYSFS_ATTR_SIZE "size"
|
||||
|
164
lib/device/dev-ext.c
Normal file
164
lib/device/dev-ext.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "device.h"
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#endif
|
||||
|
||||
struct ext_registry_item {
|
||||
const char *name;
|
||||
struct dev_ext *(* dev_ext_get) (struct device *dev);
|
||||
int (*dev_ext_release) (struct device *dev);
|
||||
};
|
||||
|
||||
#define EXT_REGISTER(id,name) [id] = { #name, &_dev_ext_get_ ## name, &_dev_ext_release_ ## name }
|
||||
|
||||
/*
|
||||
* DEV_EXT_NONE
|
||||
*/
|
||||
static struct dev_ext *_dev_ext_get_none(struct device *dev)
|
||||
{
|
||||
dev->ext.handle = NULL;
|
||||
return &dev->ext;
|
||||
}
|
||||
|
||||
static int _dev_ext_release_none(struct device *dev)
|
||||
{
|
||||
dev->ext.handle = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* DEV_EXT_UDEV
|
||||
*/
|
||||
static struct dev_ext *_dev_ext_get_udev(struct device *dev)
|
||||
{
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
struct udev *udev;
|
||||
struct udev_device *udev_device;
|
||||
|
||||
if (dev->ext.handle)
|
||||
return &dev->ext;
|
||||
|
||||
if (!(udev = udev_get_library_context()))
|
||||
return_NULL;
|
||||
|
||||
if (!(udev_device = udev_device_new_from_devnum(udev, 'b', dev->dev)))
|
||||
return_NULL;
|
||||
|
||||
dev->ext.handle = (void *) udev_device;
|
||||
return &dev->ext;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _dev_ext_release_udev(struct device *dev)
|
||||
{
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
if (!dev->ext.handle)
|
||||
return 1;
|
||||
|
||||
/* udev_device_unref can't fail - it has no return value */
|
||||
udev_device_unref((struct udev_device *) dev->ext.handle);
|
||||
dev->ext.handle = NULL;
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct ext_registry_item _ext_registry[DEV_EXT_NUM] = {
|
||||
EXT_REGISTER(DEV_EXT_NONE, none),
|
||||
EXT_REGISTER(DEV_EXT_UDEV, udev)
|
||||
};
|
||||
|
||||
const char *dev_ext_name(struct device *dev)
|
||||
{
|
||||
return _ext_registry[dev->ext.src].name;
|
||||
}
|
||||
|
||||
static const char *_ext_attached_msg = "External handle attached to device";
|
||||
|
||||
struct dev_ext *dev_ext_get(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
void *handle_ptr;
|
||||
|
||||
handle_ptr = dev->ext.handle;
|
||||
|
||||
if (!(ext = _ext_registry[dev->ext.src].dev_ext_get(dev)))
|
||||
log_error("Failed to get external handle for device %s [%s].",
|
||||
dev_name(dev), dev_ext_name(dev));
|
||||
else if (handle_ptr != dev->ext.handle)
|
||||
log_debug_devs("%s %s [%s:%p]", _ext_attached_msg, dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
int dev_ext_release(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
void *handle_ptr;
|
||||
|
||||
if (!dev->ext.enabled ||
|
||||
!dev->ext.handle)
|
||||
return 1;
|
||||
|
||||
handle_ptr = dev->ext.handle;
|
||||
|
||||
if (!(r = _ext_registry[dev->ext.src].dev_ext_release(dev)))
|
||||
log_error("Failed to release external handle for device %s [%s:%p].",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
else
|
||||
log_debug_devs("External handle detached from device %s [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), handle_ptr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_ext_enable(struct device *dev, dev_ext_t src)
|
||||
{
|
||||
if (dev->ext.enabled && (dev->ext.src != src) && !dev_ext_release(dev)) {
|
||||
log_error("Failed to enable external handle for device %s [%s].",
|
||||
dev_name(dev), _ext_registry[src].name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->ext.src = src;
|
||||
dev->ext.enabled = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_ext_disable(struct device *dev)
|
||||
{
|
||||
if (!dev->ext.enabled)
|
||||
return 1;
|
||||
|
||||
if (!dev_ext_release(dev)) {
|
||||
log_error("Failed to disable external handle for device %s [%s].",
|
||||
dev_name(dev), dev_ext_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->ext.enabled = 0;
|
||||
dev->ext.src = DEV_EXT_NONE;
|
||||
|
||||
return 1;
|
||||
}
|
@@ -289,25 +289,22 @@ static int _dev_get_size_file(const struct device *dev, uint64_t *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
|
||||
static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
{
|
||||
int fd;
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
}
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||
if (ioctl(dev_fd(dev), BLKGETSIZE64, size) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||
if (close(fd))
|
||||
if (!dev_close(dev))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
|
||||
if (close(fd))
|
||||
if (!dev_close(dev))
|
||||
log_sys_error("close", name);
|
||||
|
||||
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
|
||||
@@ -377,7 +374,7 @@ static int _dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64
|
||||
* Public functions
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
int dev_get_size(const struct device *dev, uint64_t *size)
|
||||
int dev_get_size(struct device *dev, uint64_t *size)
|
||||
{
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
@@ -15,8 +15,11 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "dev-type.h"
|
||||
#include "metadata.h"
|
||||
#include "xlate.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h> /* for MD detection using udev db records */
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -82,10 +85,31 @@ static uint64_t _v1_sb_offset(uint64_t size, md_minor_version_t minor_version)
|
||||
return sb_offset;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_md(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!(value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE)))
|
||||
return 0;
|
||||
|
||||
return !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID);
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_md(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns -1 on error
|
||||
*/
|
||||
int dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
static int _native_dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
{
|
||||
int ret = 1;
|
||||
md_minor_version_t minor;
|
||||
@@ -130,6 +154,27 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
{
|
||||
|
||||
/*
|
||||
* If non-native device status source is selected, use it
|
||||
* only if offset_found is not requested as this
|
||||
* information is not in udev db.
|
||||
*/
|
||||
if ((dev->ext.src == DEV_EXT_NONE) || offset_found)
|
||||
return _native_dev_is_md(dev, offset_found);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_md(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for MD device recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
|
||||
struct dev_types *dt,
|
||||
struct device *blkdev,
|
||||
|
@@ -25,6 +25,11 @@
|
||||
#include <blkid.h>
|
||||
#endif
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#include "device-types.h"
|
||||
|
||||
struct dev_types *create_dev_types(const char *proc_dir,
|
||||
@@ -112,6 +117,10 @@ struct dev_types *create_dev_types(const char *proc_dir,
|
||||
if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
|
||||
dt->drbd_major = line_maj;
|
||||
|
||||
/* Look for DASD */
|
||||
if (!strncmp("dasd", line + i, 4) && isspace(*(line + i + 4)))
|
||||
dt->dasd_major = line_maj;
|
||||
|
||||
/* Look for EMC powerpath */
|
||||
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
|
||||
dt->emcpower_major = line_maj;
|
||||
@@ -222,6 +231,9 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
|
||||
if (MAJOR(dev->dev) == dt->drbd_major)
|
||||
return "DRBD";
|
||||
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
return "DASD";
|
||||
|
||||
if (MAJOR(dev->dev) == dt->emcpower_major)
|
||||
return "EMCPOWER";
|
||||
|
||||
@@ -272,6 +284,9 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
int parts = major_max_partitions(dt, MAJOR(dev->dev));
|
||||
|
||||
if (MAJOR(dev->dev) == dt->device_mapper_major)
|
||||
return 1;
|
||||
|
||||
/* All MD devices are partitionable via blkext (as of 2.6.28) */
|
||||
if (MAJOR(dev->dev) == dt->md_major)
|
||||
return 1;
|
||||
@@ -314,12 +329,66 @@ static int _has_partition_table(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_partitioned(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_PART_TABLE_TYPE))
|
||||
return 0;
|
||||
|
||||
if (udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_PART_ENTRY_DISK))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_partitioned(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!_is_partitionable(dt, dev))
|
||||
return 0;
|
||||
|
||||
return _has_partition_table(dev);
|
||||
/* Unpartitioned DASD devices are not supported. */
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
return 1;
|
||||
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: failed to open device, considering device "
|
||||
"is partitioned", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = _has_partition_table(dev);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_partitioned(dt, dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_partitioned(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for partition table recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -470,7 +539,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
|
||||
if (!blkid_probe_lookup_value(probe, "TYPE", &type, NULL)) {
|
||||
if (_type_in_flag_list(type, types_to_exclude))
|
||||
return 1;
|
||||
return 2;
|
||||
if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) {
|
||||
log_error(_msg_failed_offset, type, name);
|
||||
return 0;
|
||||
@@ -526,12 +595,17 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
static int _wipe_known_signatures_with_blkid(struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude,
|
||||
uint32_t types_no_prompt,
|
||||
int yes, force_t force)
|
||||
int yes, force_t force, int *wiped)
|
||||
{
|
||||
blkid_probe probe = NULL;
|
||||
int found = 0, wiped = 0, left = 0;
|
||||
int found = 0, left = 0, wiped_tmp;
|
||||
int r_wipe;
|
||||
int r = 0;
|
||||
|
||||
if (!wiped)
|
||||
wiped = &wiped_tmp;
|
||||
*wiped = 0;
|
||||
|
||||
/* TODO: Should we check for valid dev - _dev_is_valid(dev)? */
|
||||
|
||||
if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) {
|
||||
@@ -552,15 +626,17 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
|
||||
while (!blkid_do_probe(probe)) {
|
||||
found++;
|
||||
if (_blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force))
|
||||
wiped++;
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1)
|
||||
(*wiped)++;
|
||||
/* do not count excluded types */
|
||||
if (r_wipe != 2)
|
||||
found++;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
r = 1;
|
||||
|
||||
left = found - wiped;
|
||||
left = found - *wiped;
|
||||
if (!left)
|
||||
r = 1;
|
||||
else
|
||||
@@ -575,7 +651,7 @@ out:
|
||||
#endif /* BLKID_WIPING_SUPPORT */
|
||||
|
||||
static int _wipe_signature(struct device *dev, const char *type, const char *name,
|
||||
int wipe_len, int yes, force_t force,
|
||||
int wipe_len, int yes, force_t force, int *wiped,
|
||||
int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found))
|
||||
{
|
||||
int wipe;
|
||||
@@ -605,17 +681,24 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*wiped)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude __attribute__((unused)),
|
||||
uint32_t types_no_prompt __attribute__((unused)),
|
||||
int yes, force_t force)
|
||||
int yes, force_t force, int *wiped)
|
||||
{
|
||||
if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, dev_is_md) ||
|
||||
!_wipe_signature(dev, "swap signature", name, 10, yes, force, dev_is_swap) ||
|
||||
!_wipe_signature(dev, "LUKS signature", name, 8, yes, force, dev_is_luks))
|
||||
int wiped_tmp;
|
||||
|
||||
if (!wiped)
|
||||
wiped = &wiped_tmp;
|
||||
*wiped = 0;
|
||||
|
||||
if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md) ||
|
||||
!_wipe_signature(dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
|
||||
!_wipe_signature(dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -623,19 +706,20 @@ static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
|
||||
|
||||
int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
|
||||
const char *name, uint32_t types_to_exclude,
|
||||
uint32_t types_no_prompt, int yes, force_t force)
|
||||
uint32_t types_no_prompt, int yes, force_t force,
|
||||
int *wiped)
|
||||
{
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
if (find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL))
|
||||
return _wipe_known_signatures_with_blkid(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force);
|
||||
yes, force, wiped);
|
||||
#endif
|
||||
return _wipe_known_signatures_with_lvm(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force);
|
||||
yes, force, wiped);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -715,7 +799,7 @@ static unsigned long _dev_topology_attribute(struct dev_types *dt,
|
||||
}
|
||||
|
||||
log_very_verbose("Device %s: %s is %lu%s.",
|
||||
dev_name(dev), attribute, result, default_value ? "" : " bytes");
|
||||
dev_name(dev), attribute, value, default_value ? "" : " bytes");
|
||||
|
||||
result = value >> SECTOR_SHIFT;
|
||||
|
||||
|
@@ -44,6 +44,7 @@ struct dev_types {
|
||||
int device_mapper_major;
|
||||
int emcpower_major;
|
||||
int power2_major;
|
||||
int dasd_major;
|
||||
struct dev_type_def dev_type_array[NUMBER_OF_MAJORS];
|
||||
};
|
||||
|
||||
@@ -65,7 +66,7 @@ int dev_is_luks(struct device *dev, uint64_t *signature);
|
||||
#define TYPE_DM_SNAPSHOT_COW 0x004
|
||||
int wipe_known_signatures(struct cmd_context *cmd, struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude, uint32_t types_no_prompt,
|
||||
int yes, force_t force);
|
||||
int yes, force_t force, int *wiped);
|
||||
|
||||
/* Type-specific device properties */
|
||||
unsigned long dev_md_stripe_width(struct dev_types *dt, struct device *dev);
|
||||
|
@@ -28,6 +28,23 @@
|
||||
#define DEV_O_DIRECT 0x00000020 /* Use O_DIRECT */
|
||||
#define DEV_O_DIRECT_TESTED 0x00000040 /* DEV_O_DIRECT is reliable */
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
* Any new external device info source needs to be
|
||||
* registered using EXT_REGISTER macro in dev-ext.c.
|
||||
*/
|
||||
typedef enum {
|
||||
DEV_EXT_NONE,
|
||||
DEV_EXT_UDEV,
|
||||
DEV_EXT_NUM
|
||||
} dev_ext_t;
|
||||
|
||||
struct dev_ext {
|
||||
int enabled;
|
||||
dev_ext_t src;
|
||||
void *handle;
|
||||
};
|
||||
|
||||
/*
|
||||
* All devices in LVM will be represented by one of these.
|
||||
* pointer comparisons are valid.
|
||||
@@ -47,6 +64,7 @@ struct device {
|
||||
uint32_t flags;
|
||||
uint64_t end;
|
||||
struct dm_list open_list;
|
||||
struct dev_ext ext;
|
||||
|
||||
char pvid[ID_LEN + 1];
|
||||
char _padding[7];
|
||||
@@ -63,11 +81,20 @@ struct device_area {
|
||||
uint64_t size; /* Bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
*/
|
||||
const char *dev_ext_name(struct device *dev);
|
||||
int dev_ext_enable(struct device *dev, dev_ext_t src);
|
||||
int dev_ext_disable(struct device *dev);
|
||||
struct dev_ext *dev_ext_get(struct device *dev);
|
||||
int dev_ext_release(struct device *dev);
|
||||
|
||||
/*
|
||||
* All io should use these routines.
|
||||
*/
|
||||
int dev_get_block_size(struct device *dev, unsigned int *phys_block_size, unsigned int *block_size);
|
||||
int dev_get_size(const struct device *dev, uint64_t *size);
|
||||
int dev_get_size(struct device *dev, uint64_t *size);
|
||||
int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead);
|
||||
int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes);
|
||||
|
||||
|
@@ -385,7 +385,7 @@ int pvdisplay_short(const struct cmd_context *cmd __attribute__((unused)),
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return 0;
|
||||
return_0;
|
||||
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
@@ -399,7 +399,8 @@ int pvdisplay_short(const struct cmd_context *cmd __attribute__((unused)),
|
||||
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
|
||||
|
||||
log_print(" ");
|
||||
return 0;
|
||||
|
||||
return 1; /* ECMD_PROCESSED */
|
||||
}
|
||||
|
||||
void lvdisplay_colons(const struct logical_volume *lv)
|
||||
@@ -623,7 +624,7 @@ int lvdisplay_full(struct cmd_context *cmd,
|
||||
|
||||
log_print(" ");
|
||||
|
||||
return 0;
|
||||
return 1; /* ECMD_PROCESSED */
|
||||
}
|
||||
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
|
||||
@@ -695,7 +696,7 @@ void vgdisplay_full(const struct volume_group *vg)
|
||||
|
||||
log_print("--- Volume group ---");
|
||||
log_print("VG Name %s", vg->name);
|
||||
log_print("System ID %s", vg->system_id);
|
||||
log_print("System ID %s", (vg->system_id && *vg->system_id) ? vg->system_id : vg->lvm1_system_id ? : "");
|
||||
log_print("Format %s", vg->fid->fmt->name);
|
||||
if (vg->fid->fmt->features & FMT_MDAS) {
|
||||
log_print("Metadata Areas %d",
|
||||
@@ -855,7 +856,7 @@ void display_name_error(name_error_t name_error)
|
||||
case NAME_INVALID_EMPTY:
|
||||
log_error("Name is zero length.");
|
||||
break;
|
||||
case NAME_INVALID_HYPEN:
|
||||
case NAME_INVALID_HYPHEN:
|
||||
log_error("Name cannot start with hyphen.");
|
||||
break;
|
||||
case NAME_INVALID_DOTS:
|
||||
|
@@ -27,6 +27,17 @@ static int _and_p(struct dev_filter *f, struct device *dev)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _and_p_with_dev_ext_info(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_ext_enable(dev, external_device_info_source());
|
||||
r = _and_p(f, dev);
|
||||
dev_ext_disable(dev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _composite_destroy(struct dev_filter *f)
|
||||
{
|
||||
struct dev_filter **filters;
|
||||
@@ -62,7 +73,7 @@ static void _wipe(struct dev_filter *f)
|
||||
(*filters)->wipe(*filters);
|
||||
}
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters)
|
||||
{
|
||||
struct dev_filter **filters_copy, *cft;
|
||||
|
||||
@@ -83,7 +94,7 @@ struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cft->passes_filter = _and_p;
|
||||
cft->passes_filter = use_dev_ext_info ? _and_p_with_dev_ext_info : _and_p;
|
||||
cft->destroy = _composite_destroy;
|
||||
cft->dump = _dump;
|
||||
cft->wipe = _wipe;
|
||||
|
123
lib/filters/filter-fwraid.c
Normal file
123
lib/filters/filter-fwraid.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter.h"
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)dev->ext.handle, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID) && strstr(value, DEV_EXT_UDEV_BLKID_TYPE_RAID_SUFFIX))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
log_verbose("%s: Firmware RAID detection is not supported by LVM natively. "
|
||||
"Skipping firmware raid detection. ", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_fwraid(dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_fwraid(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for firmware RAID recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ignore_fwraid(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!fwraid_filtering())
|
||||
return 1;
|
||||
|
||||
ret = _dev_is_fwraid(dev);
|
||||
|
||||
if (ret == 1) {
|
||||
log_debug_devs("%s: Skipping firmware RAID component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
log_debug_devs("%s: Skipping: error in firmware RAID component detection",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
if (f->use_count)
|
||||
log_error(INTERNAL_ERROR "Destroying firmware RAID filter while in use %u times.", f->use_count);
|
||||
|
||||
dm_free(f);
|
||||
}
|
||||
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt __attribute__((unused)))
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dm_zalloc(sizeof(*f)))) {
|
||||
log_error("Firmware RAID filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = _ignore_fwraid;
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = NULL;
|
||||
|
||||
log_debug_devs("Firmware RAID filter initialised.");
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt __attribute__((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
@@ -29,7 +29,8 @@ static int _ignore_md(struct dev_filter *f __attribute__((unused)),
|
||||
ret = dev_is_md(dev, NULL);
|
||||
|
||||
if (ret == 1) {
|
||||
log_debug_devs("%s: Skipping md component device", dev_name(dev));
|
||||
log_debug_devs("%s: Skipping md component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,10 @@
|
||||
#include "lib.h"
|
||||
#include "filter.h"
|
||||
#include "activate.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -141,7 +145,33 @@ static int _get_parent_mpath(const char *dir, char *name, int max_size)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_mpath(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
|
||||
return 1;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
|
||||
if (value && !strcmp(value, "1"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_mpath(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
const char *part_name, *name;
|
||||
@@ -200,10 +230,25 @@ static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
return lvm_dm_prefix_check(major, minor, MPATH_PREFIX);
|
||||
}
|
||||
|
||||
static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_mpath(f, dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_mpath(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for mpath recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ignore_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
if (_dev_is_mpath(f, dev) == 1) {
|
||||
log_debug_devs("%s: Skipping mpath component device", dev_name(dev));
|
||||
log_debug_devs("%s: Skipping mpath component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -19,40 +19,14 @@
|
||||
static int _passes_partitioned_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
const char *name = dev_name(dev);
|
||||
int ret = 0;
|
||||
uint64_t size;
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: Skipping: open failed", name);
|
||||
if (dev_is_partitioned(dt, dev)) {
|
||||
log_debug_devs("%s: Skipping: Partition table signature found [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's not too small */
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed", name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: Too small to hold a PV", name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_is_partitioned(dt, dev)) {
|
||||
log_debug_devs("%s: Skipping: Partition table signature found",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _partitioned_filter_destroy(struct dev_filter *f)
|
||||
|
@@ -17,13 +17,12 @@
|
||||
#include "filter.h"
|
||||
#include "config.h"
|
||||
#include "lvm-file.h"
|
||||
#include "activate.h"
|
||||
|
||||
struct pfilter {
|
||||
char *file;
|
||||
struct dm_hash_table *devices;
|
||||
struct dev_filter *real;
|
||||
time_t ctime;
|
||||
struct timespec ctime;
|
||||
struct dev_types *dt;
|
||||
};
|
||||
|
||||
@@ -107,7 +106,7 @@ int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out
|
||||
}
|
||||
|
||||
if (!stat(pf->file, &info))
|
||||
pf->ctime = info.st_ctime;
|
||||
lvm_stat_ctim(&pf->ctime, &info);
|
||||
else {
|
||||
log_very_verbose("%s: stat failed: %s", pf->file,
|
||||
strerror(errno));
|
||||
@@ -178,6 +177,7 @@ static int _persistent_filter_dump(struct dev_filter *f, int merge_existing)
|
||||
struct pfilter *pf;
|
||||
char *tmp_file;
|
||||
struct stat info, info2;
|
||||
struct timespec ts;
|
||||
struct dm_config_tree *cft = NULL;
|
||||
FILE *fp;
|
||||
int lockfd;
|
||||
@@ -228,7 +228,8 @@ static int _persistent_filter_dump(struct dev_filter *f, int merge_existing)
|
||||
/*
|
||||
* If file contents changed since we loaded it, merge new contents
|
||||
*/
|
||||
if (merge_existing && info.st_ctime != pf->ctime)
|
||||
lvm_stat_ctim(&ts, &info);
|
||||
if (merge_existing && timespeccmp(&ts, &pf->ctime, !=))
|
||||
/* Keep cft open to avoid losing lock */
|
||||
persistent_filter_load(f, &cft);
|
||||
|
||||
@@ -353,7 +354,7 @@ struct dev_filter *persistent_filter_create(struct dev_types *dt,
|
||||
|
||||
/* Only merge cache file before dumping it if it changed externally. */
|
||||
if (!stat(pf->file, &info))
|
||||
pf->ctime = info.st_ctime;
|
||||
lvm_stat_ctim(&pf->ctime, &info);
|
||||
|
||||
f->passes_filter = _lookup_p;
|
||||
f->destroy = _persistent_destroy;
|
||||
|
@@ -15,6 +15,101 @@
|
||||
#include "lib.h"
|
||||
#include "filter.h"
|
||||
#include "activate.h" /* device_is_usable */
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
static const char *_too_small_to_hold_pv_msg = "Too small to hold a PV";
|
||||
|
||||
static int _native_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
uint64_t size;
|
||||
int ret = 0;
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: Skipping: open failed [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's not too small */
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg,
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
const char *size_str;
|
||||
char *endp;
|
||||
uint64_t size;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!(size_str = udev_device_get_sysattr_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_SYSFS_ATTR_SIZE))) {
|
||||
log_debug_devs("%s: Skipping: failed to get size from sysfs [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
size = strtoull(size_str, &endp, 10);
|
||||
if (errno || !endp || *endp) {
|
||||
log_debug_devs("%s: Skipping: failed to parse size from sysfs [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg,
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int _udev_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _check_pv_min_size(struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_check_pv_min_size(dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_check_pv_min_size(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for PV min size check "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _passes_usable_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
@@ -22,7 +117,20 @@ static int _passes_usable_filter(struct dev_filter *f, struct device *dev)
|
||||
struct dev_usable_check_params ucp = {0};
|
||||
int r;
|
||||
|
||||
/* filter only device-mapper devices */
|
||||
/* check if the device is not too small to hold a PV */
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
/* fall through */
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
if (!_check_pv_min_size(dev))
|
||||
return 0;
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
}
|
||||
|
||||
/* further checks are done on dm devices only */
|
||||
if (!dm_is_dm_major(MAJOR(dev->dev)))
|
||||
return 1;
|
||||
|
||||
@@ -86,6 +194,7 @@ struct dev_filter *usable_filter_create(struct dev_types *dt __attribute__((unus
|
||||
f->use_count = 0;
|
||||
if (!(f->private = dm_zalloc(sizeof(filter_mode_t)))) {
|
||||
log_error("Usable device filter mode allocation failed");
|
||||
dm_free(f);
|
||||
return NULL;
|
||||
}
|
||||
*((filter_mode_t *) f->private) = mode;
|
||||
|
@@ -20,9 +20,11 @@
|
||||
#include "dev-cache.h"
|
||||
#include "dev-type.h"
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *md_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *mpath_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *partitioned_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *persistent_filter_create(struct dev_types *dt,
|
||||
|
@@ -245,4 +245,6 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
int export_vg_number(struct format_instance *fid, struct dm_list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter);
|
||||
|
||||
int generate_lvm1_system_id(struct cmd_context *cmd, char *s, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
@@ -180,6 +180,8 @@ out:
|
||||
static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda __attribute__((unused)),
|
||||
struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)),
|
||||
unsigned *use_previous_vg __attribute__((unused)),
|
||||
int single_device __attribute__((unused)))
|
||||
{
|
||||
struct volume_group *vg;
|
||||
@@ -496,6 +498,11 @@ static int _format1_vg_setup(struct format_instance *fid, struct volume_group *v
|
||||
if (!vg_check_new_extent_size(vg->fid->fmt, vg->extent_size))
|
||||
return_0;
|
||||
|
||||
/* Generate lvm1_system_id if not yet set */
|
||||
if (!*vg->lvm1_system_id &&
|
||||
!generate_lvm1_system_id(vg->cmd, vg->lvm1_system_id, ""))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -590,7 +597,8 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
fmt->alias = NULL;
|
||||
fmt->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME;
|
||||
fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE |
|
||||
FMT_RESTRICTED_READAHEAD | FMT_OBSOLETE;
|
||||
FMT_RESTRICTED_READAHEAD | FMT_OBSOLETE |
|
||||
FMT_SYSTEMID_ON_PVS;
|
||||
fmt->private = NULL;
|
||||
|
||||
dm_list_init(&fmt->mda_ops);
|
||||
|
@@ -69,14 +69,14 @@ int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
|
||||
|
||||
/* Store system_id from first PV if PV belongs to a VG */
|
||||
if (vg && !*vg->system_id)
|
||||
strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
if (vg && !*vg->lvm1_system_id)
|
||||
strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
|
||||
if (vg &&
|
||||
strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
|
||||
strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
pv_dev_name(pv), vg->system_id);
|
||||
pv_dev_name(pv), vg->lvm1_system_id);
|
||||
|
||||
/*
|
||||
* If exported, we still need to flag in pv->status too because
|
||||
@@ -125,12 +125,12 @@ int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
|
||||
int generate_lvm1_system_id(struct cmd_context *cmd, char *s, const char *prefix)
|
||||
{
|
||||
|
||||
if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
prefix, cmd->hostname, time(NULL)) < 0) {
|
||||
log_error("Generated system_id too long");
|
||||
log_error("Generated LVM1 format system_id too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -156,16 +156,18 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
}
|
||||
|
||||
/* Preserve existing system_id if it exists */
|
||||
if (vg && *vg->system_id)
|
||||
if (vg && vg->lvm1_system_id && *vg->lvm1_system_id)
|
||||
strncpy((char *)pvd->system_id, vg->lvm1_system_id, sizeof(pvd->system_id));
|
||||
else if (vg && vg->system_id && *vg->system_id)
|
||||
strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id));
|
||||
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && vg_is_exported(vg)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!*vg->system_id ||
|
||||
strncmp(vg->system_id, EXPORTED_TAG,
|
||||
if (!*vg->lvm1_system_id ||
|
||||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
return_0;
|
||||
}
|
||||
if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) >
|
||||
@@ -178,22 +180,22 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
}
|
||||
|
||||
/* Is VG being imported? */
|
||||
if (vg && !vg_is_exported(vg) && *vg->system_id &&
|
||||
!strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG))
|
||||
if (vg && !vg_is_exported(vg) && *vg->lvm1_system_id &&
|
||||
!strncmp(vg->lvm1_system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* Generate system_id if PV is in VG */
|
||||
if (!pvd->system_id[0])
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, ""))
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, ""))
|
||||
return_0;
|
||||
|
||||
/* Update internal system_id if we changed it */
|
||||
if (vg &&
|
||||
(!*vg->system_id ||
|
||||
strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
(!*vg->lvm1_system_id ||
|
||||
strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
|
||||
//pvd->pv_major = MAJOR(pv->dev);
|
||||
|
||||
@@ -225,11 +227,9 @@ int import_vg(struct dm_pool *mem,
|
||||
if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name)))
|
||||
return_0;
|
||||
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN + 1)))
|
||||
if (!(vg->lvm1_system_id = dm_pool_zalloc(mem, NAME_LEN + 1)))
|
||||
return_0;
|
||||
|
||||
*vg->system_id = '\0';
|
||||
|
||||
if (vgd->vg_status & VG_EXPORTED)
|
||||
vg->status |= EXPORTED_VG;
|
||||
|
||||
|
@@ -101,6 +101,8 @@ static int _check_usp(const char *vgname, struct user_subpool *usp, int sp_count
|
||||
static struct volume_group *_pool_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda __attribute__((unused)),
|
||||
struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)),
|
||||
unsigned *use_previous_vg __attribute__((unused)),
|
||||
int single_device __attribute__((unused)))
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
@@ -308,7 +308,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
|
||||
if (!(vg = mda->ops->vg_read(tf, vg_name, mda, 0)))
|
||||
if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL, 0)))
|
||||
stack;
|
||||
break;
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "segtype.h"
|
||||
#include "text_export.h"
|
||||
#include "lvm-version.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
@@ -327,7 +328,7 @@ int out_config_node(struct formatter *f, const struct dm_config_node *cn)
|
||||
return dm_config_write_node(cn, _out_line, f);
|
||||
}
|
||||
|
||||
static int _print_header(struct formatter *f,
|
||||
static int _print_header(struct cmd_context *cmd, struct formatter *f,
|
||||
const char *desc)
|
||||
{
|
||||
char *buf;
|
||||
@@ -350,6 +351,8 @@ static int _print_header(struct formatter *f,
|
||||
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||
_utsname.version, _utsname.machine);
|
||||
if (cmd->system_id && *cmd->system_id)
|
||||
outf(f, "creation_host_system_id = \"%s\"", cmd->system_id);
|
||||
outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
|
||||
|
||||
return 1;
|
||||
@@ -390,6 +393,8 @@ static int _out_tags(struct formatter *f, struct dm_list *tagsl)
|
||||
static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
char buffer[4096];
|
||||
const struct format_type *fmt = NULL;
|
||||
uint64_t status = vg->status;
|
||||
|
||||
if (!id_write_format(&vg->id, buffer, sizeof(buffer)))
|
||||
return_0;
|
||||
@@ -398,17 +403,35 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
|
||||
outf(f, "seqno = %u", vg->seqno);
|
||||
|
||||
if (vg->fid && vg->fid->fmt)
|
||||
outfc(f, "# informational", "format = \"%s\"", vg->fid->fmt->name);
|
||||
if (vg->original_fmt)
|
||||
fmt = vg->original_fmt;
|
||||
else if (vg->fid)
|
||||
fmt = vg->fid->fmt;
|
||||
if (fmt)
|
||||
outfc(f, "# informational", "format = \"%s\"", fmt->name);
|
||||
|
||||
if (!_print_flag_config(f, vg->status, VG_FLAGS))
|
||||
/*
|
||||
* Removing WRITE and adding LVM_WRITE_LOCKED makes it read-only
|
||||
* to old versions of lvm that only look for LVM_WRITE.
|
||||
*/
|
||||
if ((status & LVM_WRITE) && vg_flag_write_locked(vg)) {
|
||||
status &= ~LVM_WRITE;
|
||||
status |= LVM_WRITE_LOCKED;
|
||||
}
|
||||
|
||||
if (!_print_flag_config(f, status, VG_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &vg->tags))
|
||||
return_0;
|
||||
|
||||
|
||||
if (vg->system_id && *vg->system_id)
|
||||
outf(f, "system_id = \"%s\"", vg->system_id);
|
||||
else if (vg->lvm1_system_id && *vg->lvm1_system_id)
|
||||
outf(f, "system_id = \"%s\"", vg->lvm1_system_id);
|
||||
|
||||
if (vg->lock_type)
|
||||
outf(f, "lock_type = \"%s\"", vg->lock_type);
|
||||
|
||||
outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
||||
vg->extent_size);
|
||||
@@ -594,6 +617,7 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
int seg_count;
|
||||
struct tm *local_tm;
|
||||
time_t ts;
|
||||
uint64_t status = lv->status;
|
||||
|
||||
outnl(f);
|
||||
outf(f, "%s {", lv->name);
|
||||
@@ -605,7 +629,16 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!_print_flag_config(f, lv->status, LV_FLAGS))
|
||||
/*
|
||||
* Removing WRITE and adding LVM_WRITE_LOCKED makes it read-only
|
||||
* to old versions of lvm that only look for LVM_WRITE.
|
||||
*/
|
||||
if ((status & LVM_WRITE) && vg_flag_write_locked(lv->vg)) {
|
||||
status &= ~LVM_WRITE;
|
||||
status |= LVM_WRITE_LOCKED;
|
||||
}
|
||||
|
||||
if (!_print_flag_config(f, status, LV_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &lv->tags))
|
||||
@@ -744,7 +777,7 @@ static int _text_vg_export(struct formatter *f,
|
||||
if (!_build_pv_names(f, vg))
|
||||
goto_out;
|
||||
|
||||
if (f->header && !_print_header(f, desc))
|
||||
if (f->header && !_print_header(vg->cmd, f, desc))
|
||||
goto_out;
|
||||
|
||||
if (!out_text(f, "%s {", vg->name))
|
||||
@@ -767,7 +800,7 @@ static int _text_vg_export(struct formatter *f,
|
||||
if (!out_text(f, "}"))
|
||||
goto_out;
|
||||
|
||||
if (!f->header && !_print_header(f, desc))
|
||||
if (!f->header && !_print_header(vg->cmd, f, desc))
|
||||
goto_out;
|
||||
|
||||
r = 1;
|
||||
|
@@ -34,6 +34,7 @@ static const struct flag _vg_flags[] = {
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG},
|
||||
{CLUSTERED, "CLUSTERED", STATUS_FLAG},
|
||||
{SHARED, "SHARED", STATUS_FLAG},
|
||||
{PARTIAL_VG, NULL, 0},
|
||||
@@ -53,6 +54,7 @@ static const struct flag _pv_flags[] = {
|
||||
static const struct flag _lv_flags[] = {
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG},
|
||||
{FIXED_MINOR, "FIXED_MINOR", STATUS_FLAG},
|
||||
{VISIBLE_LV, "VISIBLE", STATUS_FLAG},
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
@@ -61,6 +63,7 @@ static const struct flag _lv_flags[] = {
|
||||
{LV_REBUILD, "REBUILD", STATUS_FLAG},
|
||||
{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
|
||||
{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
|
||||
{LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG},
|
||||
{LV_NOSCAN, NULL, 0},
|
||||
{LV_TEMPORARY, NULL, 0},
|
||||
{POOL_METADATA_SPARE, NULL, 0},
|
||||
@@ -89,6 +92,7 @@ static const struct flag _lv_flags[] = {
|
||||
{CACHE_POOL_DATA, NULL, 0},
|
||||
{CACHE_POOL_METADATA, NULL, 0},
|
||||
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
|
||||
{LV_REMOVED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
||||
|
@@ -412,6 +412,11 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8)));
|
||||
struct raw_locn *rlocn, *rlocn_precommitted;
|
||||
struct lvmcache_info *info;
|
||||
struct lvmcache_vgsummary vgsummary_orphan = {
|
||||
.vgname = FMT_TEXT_ORPHAN_VG_NAME,
|
||||
};
|
||||
|
||||
memcpy(&vgsummary_orphan.vgid, FMT_TEXT_ORPHAN_VG_NAME, sizeof(FMT_TEXT_ORPHAN_VG_NAME));
|
||||
|
||||
rlocn = mdah->raw_locns; /* Slot 0 */
|
||||
rlocn_precommitted = rlocn + 1; /* Slot 1 */
|
||||
@@ -449,8 +454,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
|
||||
bad:
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, FMT_TEXT_ORPHAN_VG_NAME,
|
||||
FMT_TEXT_ORPHAN_VG_NAME, 0, NULL);
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -498,6 +502,8 @@ static int _raw_holds_vgname(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct device_area *area,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int precommitted,
|
||||
int single_device)
|
||||
{
|
||||
@@ -526,19 +532,26 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
}
|
||||
|
||||
/* FIXME 64-bit */
|
||||
if (!(vg = text_vg_import_fd(fid, NULL, single_device, area->dev,
|
||||
if (!(vg = text_vg_import_fd(fid, NULL, vg_fmtdata, use_previous_vg, single_device, area->dev,
|
||||
(off_t) (area->start + rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (area->start + MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, rlocn->checksum, &when,
|
||||
&desc)))
|
||||
&desc)) && (!use_previous_vg || !*use_previous_vg))
|
||||
goto_out;
|
||||
log_debug_metadata("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
|
||||
PRIu64, vg->name, precommitted ? "pre-commit " : "",
|
||||
vg->seqno, dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
|
||||
if (precommitted)
|
||||
if (vg)
|
||||
log_debug_metadata("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
|
||||
PRIu64, vg->name, precommitted ? "pre-commit " : "",
|
||||
vg->seqno, dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
else
|
||||
log_debug_metadata("Skipped reading %smetadata from %s at %" PRIu64 " size %"
|
||||
PRIu64 " with matching checksum.", precommitted ? "pre-commit " : "",
|
||||
dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
|
||||
if (vg && precommitted)
|
||||
vg->status |= PRECOMMITTED;
|
||||
|
||||
out:
|
||||
@@ -548,6 +561,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int single_device)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
@@ -556,7 +571,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
if (!dev_open_readonly(mdac->area.dev))
|
||||
return_NULL;
|
||||
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, 0, single_device);
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, single_device);
|
||||
|
||||
if (!dev_close(mdac->area.dev))
|
||||
stack;
|
||||
@@ -566,7 +581,9 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda)
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct volume_group *vg;
|
||||
@@ -574,7 +591,7 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
if (!dev_open_readonly(mdac->area.dev))
|
||||
return_NULL;
|
||||
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, 1, 0);
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, 0);
|
||||
|
||||
if (!dev_close(mdac->area.dev))
|
||||
stack;
|
||||
@@ -885,6 +902,8 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg __attribute__((unused)),
|
||||
int single_device __attribute__((unused)))
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mda->metadata_locn;
|
||||
@@ -894,7 +913,9 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda)
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg __attribute__((unused)))
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mda->metadata_locn;
|
||||
struct volume_group *vg;
|
||||
@@ -1123,26 +1144,24 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct mda_header *mdah,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint64_t *vgstatus, char **creation_host,
|
||||
uint64_t *mda_free_sectors)
|
||||
int vgname_from_mda(const struct format_type *fmt,
|
||||
struct mda_header *mdah, struct device_area *dev_area,
|
||||
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
|
||||
{
|
||||
struct raw_locn *rlocn;
|
||||
uint32_t wrap = 0;
|
||||
const char *vgname = NULL;
|
||||
unsigned int len = 0;
|
||||
char buf[NAME_LEN + 1] __attribute__((aligned(8)));
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
uint64_t buffer_size, current_usage;
|
||||
unsigned used_cached_metadata = 0;
|
||||
|
||||
if (mda_free_sectors)
|
||||
*mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
|
||||
|
||||
if (!mdah) {
|
||||
log_error(INTERNAL_ERROR "vgname_from_mda called with NULL pointer for mda_header");
|
||||
goto_out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Cope with returning a list */
|
||||
@@ -1151,13 +1170,16 @@ const char *vgname_from_mda(const struct format_type *fmt,
|
||||
/*
|
||||
* If no valid offset, do not try to search for vgname
|
||||
*/
|
||||
if (!rlocn->offset)
|
||||
goto out;
|
||||
if (!rlocn->offset) {
|
||||
log_debug("%s: found metadata with offset 0.",
|
||||
dev_name(dev_area->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do quick check for a vgname */
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
NAME_LEN, buf))
|
||||
goto_out;
|
||||
return_0;
|
||||
|
||||
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
|
||||
len < (NAME_LEN - 1))
|
||||
@@ -1167,7 +1189,7 @@ const char *vgname_from_mda(const struct format_type *fmt,
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(buf))
|
||||
goto_out;
|
||||
return_0;
|
||||
|
||||
/* We found a VG - now check the metadata */
|
||||
if (rlocn->offset + rlocn->size > mdah->size)
|
||||
@@ -1176,36 +1198,39 @@ const char *vgname_from_mda(const struct format_type *fmt,
|
||||
if (wrap > rlocn->offset) {
|
||||
log_error("%s: metadata too large for circular buffer",
|
||||
dev_name(dev_area->dev));
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Did we see this metadata before? */
|
||||
vgsummary->mda_checksum = rlocn->checksum;
|
||||
vgsummary->mda_size = rlocn->size;
|
||||
|
||||
if (lvmcache_lookup_mda(vgsummary))
|
||||
used_cached_metadata = 1;
|
||||
|
||||
/* FIXME 64-bit */
|
||||
if (!(vgname = text_vgname_import(fmt, dev_area->dev,
|
||||
(off_t) (dev_area->start +
|
||||
rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (dev_area->start +
|
||||
MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, rlocn->checksum,
|
||||
vgid, vgstatus, creation_host)))
|
||||
goto_out;
|
||||
if (!text_vgname_import(fmt, dev_area->dev,
|
||||
(off_t) (dev_area->start + rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (dev_area->start + MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, vgsummary->vgname ? 1 : 0,
|
||||
vgsummary))
|
||||
return_0;
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(vgname)) {
|
||||
vgname = NULL;
|
||||
goto_out;
|
||||
}
|
||||
if (!validate_name(vgsummary->vgname))
|
||||
return_0;
|
||||
|
||||
if (!id_write_format(vgid, uuid, sizeof(uuid))) {
|
||||
vgname = NULL;
|
||||
goto_out;
|
||||
}
|
||||
if (!id_write_format((struct id *)&vgsummary->vgid, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
|
||||
log_debug_metadata("%s: Found metadata at %" PRIu64 " size %" PRIu64
|
||||
log_debug_metadata("%s: %s metadata at %" PRIu64 " size %" PRIu64
|
||||
" (in area at %" PRIu64 " size %" PRIu64
|
||||
") for %s (%s)",
|
||||
dev_name(dev_area->dev), dev_area->start + rlocn->offset,
|
||||
rlocn->size, dev_area->start, dev_area->size, vgname, uuid);
|
||||
dev_name(dev_area->dev),
|
||||
used_cached_metadata ? "Using cached" : "Found",
|
||||
dev_area->start + rlocn->offset,
|
||||
rlocn->size, dev_area->start, dev_area->size, vgsummary->vgname, uuid);
|
||||
|
||||
if (mda_free_sectors) {
|
||||
current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
|
||||
@@ -1218,19 +1243,16 @@ const char *vgname_from_mda(const struct format_type *fmt,
|
||||
*mda_free_sectors = ((buffer_size - 2 * current_usage) / 2) >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
out:
|
||||
return vgname;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _scan_raw(const struct format_type *fmt, const char *vgname __attribute__((unused)))
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct dm_list *raw_list;
|
||||
const char *scanned_vgname;
|
||||
struct volume_group *vg;
|
||||
struct format_instance fid;
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
struct lvmcache_vgsummary vgsummary = { 0 };
|
||||
struct mda_header *mdah;
|
||||
|
||||
raw_list = &((struct mda_lists *) fmt->private)->raws;
|
||||
@@ -1251,13 +1273,11 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
if ((scanned_vgname = vgname_from_mda(fmt, mdah,
|
||||
&rl->dev_area, &vgid, &vgstatus,
|
||||
NULL, NULL))) {
|
||||
vg = _vg_read_raw_area(&fid, scanned_vgname, &rl->dev_area, 0, 0);
|
||||
/* TODO: caching as in vgname_from_mda() (trigger this code?) */
|
||||
if (vgname_from_mda(fmt, mdah, &rl->dev_area, &vgsummary, NULL)) {
|
||||
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0);
|
||||
if (vg)
|
||||
lvmcache_update_vg(vg, 0);
|
||||
|
||||
}
|
||||
close_dev:
|
||||
if (!dev_close(rl->dev_area.dev))
|
||||
@@ -1298,7 +1318,7 @@ static int _write_single_mda(struct metadata_area *mda, void *baton)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Only for orphans */
|
||||
/* Only for orphans - FIXME That's not true any more */
|
||||
static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv)
|
||||
{
|
||||
struct format_instance *fid = pv->fid;
|
||||
@@ -1312,7 +1332,8 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
|
||||
/* Add a new cache entry with PV info or update existing one. */
|
||||
if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id,
|
||||
pv->dev, pv->vg_name, NULL, 0)))
|
||||
pv->dev, pv->vg_name,
|
||||
is_orphan_vg(pv->vg_name) ? pv->vg_name : pv->vg ? (const char *) &pv->vg->id : NULL, 0)))
|
||||
return_0;
|
||||
|
||||
label = lvmcache_get_label(info);
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "metadata.h"
|
||||
#include "lvmcache.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -49,10 +50,9 @@ struct text_vg_version_ops {
|
||||
unsigned use_cached_pvs);
|
||||
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
|
||||
time_t *when, char **desc);
|
||||
const char *(*read_vgname) (const struct format_type *fmt,
|
||||
const struct dm_config_tree *cft,
|
||||
struct id *vgid, uint64_t *vgstatus,
|
||||
char **creation_host);
|
||||
int (*read_vgname) (const struct format_type *fmt,
|
||||
const struct dm_config_tree *cft,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||
@@ -70,6 +70,8 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
time_t *when, char **desc);
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int single_device,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
@@ -77,12 +79,13 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
checksum_fn_t checksum_fn,
|
||||
uint32_t checksum,
|
||||
time_t *when, char **desc);
|
||||
const char *text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
struct id *vgid, uint64_t *vgstatus,
|
||||
char **creation_host);
|
||||
|
||||
int text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn,
|
||||
int checksum_only,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
|
||||
#endif
|
||||
|
@@ -32,30 +32,41 @@ static void _init_text_import(void)
|
||||
_text_import_initialised = 1;
|
||||
}
|
||||
|
||||
const char *text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
struct id *vgid, uint64_t *vgstatus,
|
||||
char **creation_host)
|
||||
/*
|
||||
* Find out vgname on a given device.
|
||||
*/
|
||||
int text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn,
|
||||
int checksum_only,
|
||||
struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
struct dm_config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
const char *vgname = NULL;
|
||||
int r = 0;
|
||||
|
||||
_init_text_import();
|
||||
|
||||
if (!(cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
|
||||
return_NULL;
|
||||
return_0;
|
||||
|
||||
if ((!dev && !config_file_read(cft)) ||
|
||||
(dev && !config_file_read_fd(cft, dev, offset, size,
|
||||
offset2, size2, checksum_fn, checksum))) {
|
||||
offset2, size2, checksum_fn,
|
||||
vgsummary->mda_checksum,
|
||||
checksum_only))) {
|
||||
log_error("Couldn't read volume group metadata.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (checksum_only) {
|
||||
/* Checksum matches already-cached content - no need to reparse. */
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a set of version functions that can read this file
|
||||
*/
|
||||
@@ -63,20 +74,27 @@ const char *text_vgname_import(const struct format_type *fmt,
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(vgname = (*vsn)->read_vgname(fmt, cft, vgid, vgstatus,
|
||||
creation_host)))
|
||||
if (!(*vsn)->read_vgname(fmt, cft, vgsummary))
|
||||
goto_out;
|
||||
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
config_destroy(cft);
|
||||
return vgname;
|
||||
return r;
|
||||
}
|
||||
|
||||
struct cached_vg_fmtdata {
|
||||
uint32_t cached_mda_checksum;
|
||||
size_t cached_mda_size;
|
||||
};
|
||||
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int single_device,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
@@ -88,6 +106,13 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
struct volume_group *vg = NULL;
|
||||
struct dm_config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
int skip_parse;
|
||||
|
||||
if (vg_fmtdata && !*vg_fmtdata &&
|
||||
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
|
||||
log_error("Failed to allocate VG fmtdata for text format.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_text_import();
|
||||
|
||||
@@ -97,10 +122,22 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
if (!(cft = config_open(CONFIG_FILE_SPECIAL, file, 0)))
|
||||
return_NULL;
|
||||
|
||||
/* Does the metadata match the already-cached VG? */
|
||||
skip_parse = vg_fmtdata &&
|
||||
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
|
||||
((*vg_fmtdata)->cached_mda_size == (size + size2));
|
||||
|
||||
if ((!dev && !config_file_read(cft)) ||
|
||||
(dev && !config_file_read_fd(cft, dev, offset, size,
|
||||
offset2, size2, checksum_fn, checksum)))
|
||||
offset2, size2, checksum_fn, checksum,
|
||||
skip_parse)))
|
||||
goto_out;
|
||||
|
||||
if (skip_parse) {
|
||||
if (use_previous_vg)
|
||||
*use_previous_vg = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a set of version functions that can read this file
|
||||
@@ -116,6 +153,14 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
break;
|
||||
}
|
||||
|
||||
if (vg && vg_fmtdata && *vg_fmtdata) {
|
||||
(*vg_fmtdata)->cached_mda_size = (size + size2);
|
||||
(*vg_fmtdata)->cached_mda_checksum = checksum;
|
||||
}
|
||||
|
||||
if (use_previous_vg)
|
||||
*use_previous_vg = 0;
|
||||
|
||||
out:
|
||||
config_destroy(cft);
|
||||
return vg;
|
||||
@@ -125,7 +170,7 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc)
|
||||
{
|
||||
return text_vg_import_fd(fid, file, 0, NULL, (off_t)0, 0, (off_t)0, 0, NULL, 0,
|
||||
return text_vg_import_fd(fid, file, NULL, NULL, 0, NULL, (off_t)0, 0, (off_t)0, 0, NULL, 0,
|
||||
when, desc);
|
||||
}
|
||||
|
||||
|
@@ -531,7 +531,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
|
||||
const char *str;
|
||||
const struct dm_config_value *cv;
|
||||
const char *hostname;
|
||||
uint64_t timestamp = 0;
|
||||
uint64_t timestamp = 0, lvstatus;
|
||||
|
||||
if (!(lv = alloc_lv(mem)))
|
||||
return_0;
|
||||
@@ -544,12 +544,18 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_flag_config(lvn, &lv->status, LV_FLAGS)) {
|
||||
if (!_read_flag_config(lvn, &lvstatus, LV_FLAGS)) {
|
||||
log_error("Couldn't read status flags for logical volume %s.",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvstatus & LVM_WRITE_LOCKED) {
|
||||
lvstatus |= LVM_WRITE;
|
||||
lvstatus &= ~LVM_WRITE_LOCKED;
|
||||
}
|
||||
lv->status = lvstatus;
|
||||
|
||||
if (dm_config_has_node(lvn, "creation_time")) {
|
||||
if (!_read_uint64(lvn, "creation_time", ×tamp)) {
|
||||
log_error("Invalid creation_time for logical volume %s.",
|
||||
@@ -733,10 +739,11 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
{
|
||||
const struct dm_config_node *vgn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
const char *str, *format_str, *system_id;
|
||||
struct volume_group *vg;
|
||||
struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
|
||||
unsigned scan_done_once = use_cached_pvs;
|
||||
uint64_t vgstatus;
|
||||
|
||||
/* skip any top-level values */
|
||||
for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib)
|
||||
@@ -750,9 +757,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
if (!(vg = alloc_vg("read_vg", fid->fmt->cmd, vgn->key)))
|
||||
return_NULL;
|
||||
|
||||
if (!(vg->system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* The pv hash memorises the pv section names -> pv
|
||||
* structures.
|
||||
@@ -773,8 +777,16 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
if (dm_config_get_str(vgn, "system_id", &str)) {
|
||||
strncpy(vg->system_id, str, NAME_LEN);
|
||||
/* A backup file might be a backup of a different format */
|
||||
if (dm_config_get_str(vgn, "format", &format_str) &&
|
||||
!(vg->original_fmt = get_format_by_name(fid->fmt->cmd, format_str))) {
|
||||
log_error("Unrecognised format %s for volume group %s.", format_str, vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (dm_config_get_str(vgn, "lock_type", &str)) {
|
||||
if (!(vg->lock_type = dm_pool_strdup(vg->vgmem, str)))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_id(&vg->id, vgn, "id")) {
|
||||
@@ -788,12 +800,32 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_flag_config(vgn, &vg->status, VG_FLAGS)) {
|
||||
if (!_read_flag_config(vgn, &vgstatus, VG_FLAGS)) {
|
||||
log_error("Error reading flags of volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* A system id without WRITE_LOCKED is an old lvm1 system id.
|
||||
*/
|
||||
if (dm_config_get_str(vgn, "system_id", &system_id)) {
|
||||
if (!(vgstatus & LVM_WRITE_LOCKED)) {
|
||||
if (!(vg->lvm1_system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
|
||||
goto_bad;
|
||||
strncpy(vg->lvm1_system_id, system_id, NAME_LEN);
|
||||
} else if (!(vg->system_id = dm_pool_strdup(vg->vgmem, system_id))) {
|
||||
log_error("Failed to allocate memory for system_id in _read_vg.");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (vgstatus & LVM_WRITE_LOCKED) {
|
||||
vgstatus |= LVM_WRITE;
|
||||
vgstatus &= ~LVM_WRITE_LOCKED;
|
||||
}
|
||||
vg->status = vgstatus;
|
||||
|
||||
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
|
||||
log_error("Couldn't read extent size for volume group %s.",
|
||||
vg->name);
|
||||
@@ -875,8 +907,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
dm_hash_destroy(pv_hash);
|
||||
dm_hash_destroy(lv_hash);
|
||||
|
||||
/* FIXME Determine format type from file contents */
|
||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||
vg_set_fid(vg, fid);
|
||||
|
||||
/*
|
||||
@@ -911,19 +941,16 @@ static void _read_desc(struct dm_pool *mem,
|
||||
*when = u;
|
||||
}
|
||||
|
||||
static const char *_read_vgname(const struct format_type *fmt,
|
||||
const struct dm_config_tree *cft, struct id *vgid,
|
||||
uint64_t *vgstatus, char **creation_host)
|
||||
static int _read_vgname(const struct format_type *fmt, const struct dm_config_tree *cft,
|
||||
struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
const struct dm_config_node *vgn;
|
||||
struct dm_pool *mem = fmt->cmd->mem;
|
||||
char *vgname;
|
||||
int old_suppress;
|
||||
|
||||
old_suppress = log_suppress(2);
|
||||
*creation_host = dm_pool_strdup(mem,
|
||||
dm_config_find_str_allow_empty(cft->root,
|
||||
"creation_host", ""));
|
||||
vgsummary->creation_host =
|
||||
dm_pool_strdup(mem, dm_config_find_str_allow_empty(cft->root, "creation_host", ""));
|
||||
log_suppress(old_suppress);
|
||||
|
||||
/* skip any top-level values */
|
||||
@@ -934,23 +961,23 @@ static const char *_read_vgname(const struct format_type *fmt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vgname = dm_pool_strdup(mem, vgn->key)))
|
||||
if (!(vgsummary->vgname = dm_pool_strdup(mem, vgn->key)))
|
||||
return_0;
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
if (!_read_id(vgid, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vgname);
|
||||
if (!_read_id(&vgsummary->vgid, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vgsummary->vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_flag_config(vgn, vgstatus, VG_FLAGS)) {
|
||||
if (!_read_flag_config(vgn, &vgsummary->vgstatus, VG_FLAGS)) {
|
||||
log_error("Couldn't find status flags for volume group %s.",
|
||||
vgname);
|
||||
vgsummary->vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vgname;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct text_vg_version_ops _vsn1_ops = {
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "metadata.h"
|
||||
#include "lvmcache.h"
|
||||
#include "uuid.h"
|
||||
|
||||
/* disk_locn and data_area_list are defined in format-text.h */
|
||||
@@ -97,11 +98,8 @@ struct mda_context {
|
||||
#define LVM2_LABEL "LVM2 001"
|
||||
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
|
||||
|
||||
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct mda_header *mdah,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint64_t *vgstatus, char **creation_host,
|
||||
uint64_t *mda_free_sectors);
|
||||
int vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah,
|
||||
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
|
||||
uint64_t *mda_free_sectors);
|
||||
|
||||
#endif
|
||||
|
@@ -319,10 +319,14 @@ static int _update_mda(struct metadata_area *mda, void *baton)
|
||||
const struct format_type *fmt = p->label->labeller->fmt;
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct mda_header *mdah;
|
||||
const char *vgname = NULL;
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
char *creation_host;
|
||||
struct lvmcache_vgsummary vgsummary = { 0 };
|
||||
|
||||
/*
|
||||
* Using the labeller struct to preserve info about
|
||||
* the last parsed vgname, vgid, creation host
|
||||
*
|
||||
* TODO: make lvmcache smarter and move this cache logic there
|
||||
*/
|
||||
|
||||
if (!dev_open_readonly(mdac->area.dev)) {
|
||||
mda_set_ignored(mda, 1);
|
||||
@@ -346,17 +350,14 @@ static int _update_mda(struct metadata_area *mda, void *baton)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((vgname = vgname_from_mda(fmt, mdah,
|
||||
&mdac->area,
|
||||
&vgid, &vgstatus, &creation_host,
|
||||
&mdac->free_sectors)) &&
|
||||
!lvmcache_update_vgname_and_id(p->info, vgname,
|
||||
(char *) &vgid, vgstatus,
|
||||
creation_host)) {
|
||||
if (vgname_from_mda(fmt, mdah, &mdac->area, &vgsummary,
|
||||
&mdac->free_sectors) &&
|
||||
!lvmcache_update_vgname_and_id(p->info, &vgsummary)) {
|
||||
if (!dev_close(mdac->area.dev))
|
||||
stack;
|
||||
return_0;
|
||||
}
|
||||
|
||||
close_dev:
|
||||
if (!dev_close(mdac->area.dev))
|
||||
stack;
|
||||
@@ -465,7 +466,7 @@ struct labeller *text_labeller_create(const struct format_type *fmt)
|
||||
{
|
||||
struct labeller *l;
|
||||
|
||||
if (!(l = dm_malloc(sizeof(*l)))) {
|
||||
if (!(l = dm_zalloc(sizeof(*l)))) {
|
||||
log_error("Couldn't allocate labeller object.");
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -97,6 +97,17 @@ struct labeller *label_get_handler(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _update_lvmcache_orphan(struct lvmcache_info *info)
|
||||
{
|
||||
struct lvmcache_vgsummary vgsummary_orphan = {
|
||||
.vgname = lvmcache_fmt(info)->orphan_vg_name,
|
||||
};
|
||||
|
||||
memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
|
||||
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector,
|
||||
uint64_t scan_sector)
|
||||
@@ -173,9 +184,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
out:
|
||||
if (!found) {
|
||||
if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name,
|
||||
lvmcache_fmt(info)->orphan_vg_name,
|
||||
0, NULL);
|
||||
_update_lvmcache_orphan(info);
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
}
|
||||
|
||||
@@ -271,9 +280,7 @@ int label_read(struct device *dev, struct label **result,
|
||||
stack;
|
||||
|
||||
if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name,
|
||||
lvmcache_fmt(info)->orphan_vg_name,
|
||||
0, NULL);
|
||||
_update_lvmcache_orphan(info);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -348,10 +355,7 @@ int label_verify(struct device *dev)
|
||||
|
||||
if (!dev_open_readonly(dev)) {
|
||||
if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, lvmcache_fmt(info)->orphan_vg_name,
|
||||
lvmcache_fmt(info)->orphan_vg_name,
|
||||
0, NULL);
|
||||
|
||||
_update_lvmcache_orphan(info);
|
||||
return_0;
|
||||
}
|
||||
|
||||
|
@@ -114,7 +114,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
#define LCK_DMEVENTD_MONITOR_MODE 0x04 /* Register with dmeventd */
|
||||
|
||||
/* Not yet used. */
|
||||
#define LCK_CONVERT 0x08 /* Convert existing lock */
|
||||
#define LCK_CONVERT_MODE 0x08 /* Convert existing lock */
|
||||
|
||||
#define LCK_TEST_MODE 0x10 /* Test mode: No activation */
|
||||
#define LCK_ORIGIN_ONLY_MODE 0x20 /* Same as above */
|
||||
|
@@ -18,10 +18,13 @@
|
||||
#include "memlock.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static FILE *_log_file;
|
||||
static char _log_file_path[PATH_MAX];
|
||||
static struct device _log_dev;
|
||||
static struct dm_str_list _log_dev_alias;
|
||||
|
||||
@@ -52,11 +55,58 @@ void init_log_fn(lvm2_log_fn_t log_fn)
|
||||
_lvm2_log_fn = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support envvar LVM_LOG_FILE_EPOCH and allow to attach
|
||||
* extra keyword (consist of upto 32 alpha chars) to
|
||||
* opened log file. After this 'epoch' word pid and starttime
|
||||
* (in kernel units, read from /proc/self/stat)
|
||||
* is automatically attached.
|
||||
* If command/daemon forks multiple times, it could create multiple
|
||||
* log files ensuring, there are no overwrites.
|
||||
*/
|
||||
void init_log_file(const char *log_file, int append)
|
||||
{
|
||||
const char *open_mode = append ? "a" : "w";
|
||||
static const char statfile[] = "/proc/self/stat";
|
||||
const char *env;
|
||||
int pid;
|
||||
long long starttime;
|
||||
FILE *st;
|
||||
int i = 0;
|
||||
|
||||
if (!(_log_file = fopen(log_file, open_mode))) {
|
||||
_log_file_path[0] = '\0';
|
||||
if ((env = getenv("LVM_LOG_FILE_EPOCH"))) {
|
||||
while (isalpha(env[i]) && i < 32) /* Up to 32 alphas */
|
||||
i++;
|
||||
if (env[i]) {
|
||||
if (i)
|
||||
log_warn("WARNING: Ignoring invalid LVM_LOG_FILE_EPOCH envvar \"%s\".", env);
|
||||
goto no_epoch;
|
||||
}
|
||||
|
||||
if (!(st = fopen(statfile, "r")))
|
||||
log_sys_error("fopen", statfile);
|
||||
else if (fscanf(st, "%d %*s %*c %*d %*d %*d %*d " /* tty_nr */
|
||||
"%*d %*u %*u %*u %*u " /* mjflt */
|
||||
"%*u %*u %*u %*d %*d " /* cstim */
|
||||
"%*d %*d %*d %*d " /* itrealvalue */
|
||||
"%llu", &pid, &starttime) != 2) {
|
||||
log_warn("WARNING: Cannot parse content of %s.", statfile);
|
||||
} else {
|
||||
if (fclose(st))
|
||||
log_sys_debug("fclose", statfile);
|
||||
|
||||
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
|
||||
"%s_%s_%d_%lld", log_file, env, pid, starttime) < 0) {
|
||||
log_warn("WARNING: Debug log file path is too long for epoch.");
|
||||
_log_file_path[0] = '\0';
|
||||
} else {
|
||||
log_file = _log_file_path;
|
||||
append = 1; /* force */
|
||||
}
|
||||
}
|
||||
}
|
||||
no_epoch:
|
||||
if (!(_log_file = fopen(log_file, append ? "a" : "w"))) {
|
||||
log_sys_error("fopen", log_file);
|
||||
return;
|
||||
}
|
||||
@@ -64,6 +114,31 @@ void init_log_file(const char *log_file, int append)
|
||||
_log_to_file = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink the log file depeding on command's return value
|
||||
*
|
||||
* When envvar LVM_EXPECTED_EXIT_STATUS is set, compare
|
||||
* resulting status with this string.
|
||||
*
|
||||
* It's possible to specify 2 variants - having it equal to
|
||||
* a single number or having it different from a single number.
|
||||
*
|
||||
* i.e. LVM_EXPECTED_EXIT_STATUS=">1" # delete when ret > 1.
|
||||
*/
|
||||
void unlink_log_file(int ret)
|
||||
{
|
||||
const char *env;
|
||||
|
||||
if (_log_file_path[0] &&
|
||||
(env = getenv("LVM_EXPECTED_EXIT_STATUS")) &&
|
||||
((env[0] == '>' && ret > atoi(env + 1)) ||
|
||||
(atoi(env) == ret))) {
|
||||
if (unlink(_log_file_path))
|
||||
log_sys_error("unlink", _log_file_path);
|
||||
_log_file_path[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void init_log_direct(const char *log_file, int append)
|
||||
{
|
||||
int open_flags = append ? 0 : O_TRUNC;
|
||||
@@ -299,13 +374,13 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
va_start(ap, format);
|
||||
switch (level) {
|
||||
case _LOG_DEBUG:
|
||||
if ((verbose_level() == level) &&
|
||||
(strcmp("<backtrace>", format) == 0))
|
||||
break;
|
||||
if (verbose_level() < _LOG_DEBUG)
|
||||
break;
|
||||
if (!debug_class_is_logged(dm_errno_or_class))
|
||||
break;
|
||||
if ((verbose_level() == level) &&
|
||||
(strcmp("<backtrace>", format) == 0))
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
/* Typically only log_warn goes to stdout */
|
||||
@@ -333,7 +408,7 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
vfprintf(_log_file, trformat, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(_log_file, "\n");
|
||||
fputc('\n', _log_file);
|
||||
fflush(_log_file);
|
||||
}
|
||||
|
||||
|
@@ -109,6 +109,8 @@
|
||||
|
||||
#define return_0 do { stack; return 0; } while (0)
|
||||
#define return_NULL do { stack; return NULL; } while (0)
|
||||
#define return_EINVALID_CMD_LINE \
|
||||
do { stack; return EINVALID_CMD_LINE; } while (0)
|
||||
#define return_ECMD_FAILED do { stack; return ECMD_FAILED; } while (0)
|
||||
#define goto_out do { stack; goto out; } while (0)
|
||||
#define goto_bad do { stack; goto bad; } while (0)
|
||||
|
@@ -40,6 +40,7 @@ void init_indent(int indent);
|
||||
void init_msg_prefix(const char *prefix);
|
||||
|
||||
void init_log_file(const char *log_file, int append);
|
||||
void unlink_log_file(int ret);
|
||||
void init_log_direct(const char *log_file, int append);
|
||||
void init_log_while_suspended(int log_while_suspended);
|
||||
void init_abort_on_internal_errors(int fatal);
|
||||
|
@@ -40,7 +40,7 @@ const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
if (seg->feature_flags & DM_CACHE_FEATURE_PASSTHROUGH)
|
||||
return "passthrough";
|
||||
|
||||
log_error("LV %s has uknown feature flags %" PRIu64,
|
||||
log_error(INTERNAL_ERROR "LV %s has uknown feature flags %" PRIu64 ".",
|
||||
display_lvname(seg->lv), seg->feature_flags);
|
||||
|
||||
return NULL;
|
||||
@@ -70,7 +70,7 @@ int update_cache_pool_params(const struct segment_type *segtype,
|
||||
{
|
||||
uint64_t min_meta_size;
|
||||
uint32_t extent_size = vg->extent_size;
|
||||
uint64_t pool_metadata_size = *pool_metadata_extents * vg->extent_size;
|
||||
uint64_t pool_metadata_size = (uint64_t) *pool_metadata_extents * vg->extent_size;
|
||||
|
||||
if (!(passed_args & PASS_ARG_CHUNK_SIZE))
|
||||
*chunk_size = DEFAULT_CACHE_POOL_CHUNK_SIZE * 2;
|
||||
@@ -395,6 +395,59 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
|
||||
}
|
||||
|
||||
int lv_cache_setpolicy(struct logical_volume *lv, struct dm_config_tree *policy)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
const char *name;
|
||||
struct dm_config_node *cn;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (lv_is_cache(lv))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = policy->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = policy = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node(policy->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
|
||||
if ((name = dm_config_find_str(policy->root, "policy", NULL)) &&
|
||||
!(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name)))
|
||||
goto_out;
|
||||
|
||||
restart: /* remove any 'default" nodes */
|
||||
cn = seg->policy_settings ? seg->policy_settings->child : NULL;
|
||||
while (cn) {
|
||||
if (cn->v->type == DM_CFG_STRING && !strcmp(cn->v->v.str, "default")) {
|
||||
dm_config_remove_node(seg->policy_settings, cn);
|
||||
goto restart;
|
||||
}
|
||||
cn = cn->sib;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (old)
|
||||
dm_config_destroy(old);
|
||||
if (new)
|
||||
dm_config_destroy(new);
|
||||
if (tmp)
|
||||
dm_config_destroy(tmp);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wipe cache pool metadata area before use.
|
||||
*
|
||||
|
@@ -130,7 +130,12 @@ char *lvseg_discards_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
|
||||
char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return dm_pool_strdup(mem, get_cache_pool_cachemode_name(seg));
|
||||
const char *name = get_cache_pool_cachemode_name(seg);
|
||||
|
||||
if (!name)
|
||||
return_NULL;
|
||||
|
||||
return dm_pool_strdup(mem, name);
|
||||
}
|
||||
|
||||
#ifdef DMEVENTD
|
||||
@@ -147,11 +152,10 @@ char *lvseg_monitor_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
|
||||
if (lv_is_cow(seg->lv) && !lv_is_merging_cow(seg->lv))
|
||||
segm = first_seg(seg->lv->snapshot->lv);
|
||||
else if (seg->log_lv)
|
||||
segm = first_seg(seg->log_lv);
|
||||
|
||||
// log_debug("Query LV:%s mon:%s segm:%s tgtm:%p segmon:%d statusm:%d", seg->lv->name, segm->lv->name, segm->segtype->name, segm->segtype->ops->target_monitored, seg_monitored(segm), (int)(segm->status & PVMOVE));
|
||||
if ((dmeventd_monitor_mode() != 1) ||
|
||||
!segm->segtype->ops ||
|
||||
!segm->segtype->ops->target_monitored)
|
||||
/* Nothing to do, monitoring not supported */;
|
||||
else if (lv_is_cow_covering_origin(seg->lv))
|
||||
@@ -634,10 +638,10 @@ int lv_raid_healthy(const struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_with_info_and_seg_status *lvdm)
|
||||
{
|
||||
dm_percent_t snap_percent;
|
||||
struct lvinfo info;
|
||||
const struct logical_volume *lv = lvdm->lv;
|
||||
struct lv_segment *seg;
|
||||
char *repstr;
|
||||
|
||||
@@ -711,30 +715,30 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
|
||||
repstr[3] = (lv->status & FIXED_MINOR) ? 'm' : '-';
|
||||
|
||||
if (!activation() || !lv_info(lv->vg->cmd, lv, 0, &info, 1, 0)) {
|
||||
if (!activation() || !lvdm->info_ok) {
|
||||
repstr[4] = 'X'; /* Unknown */
|
||||
repstr[5] = 'X'; /* Unknown */
|
||||
} else if (info.exists) {
|
||||
if (info.suspended)
|
||||
} else if (lvdm->info.exists) {
|
||||
if (lvdm->info.suspended)
|
||||
repstr[4] = 's'; /* Suspended */
|
||||
else if (info.live_table)
|
||||
else if (lvdm->info.live_table)
|
||||
repstr[4] = 'a'; /* Active */
|
||||
else if (info.inactive_table)
|
||||
else if (lvdm->info.inactive_table)
|
||||
repstr[4] = 'i'; /* Inactive with table */
|
||||
else
|
||||
repstr[4] = 'd'; /* Inactive without table */
|
||||
|
||||
/* Snapshot dropped? */
|
||||
if (info.live_table && lv_is_cow(lv)) {
|
||||
if (lvdm->info.live_table && lv_is_cow(lv)) {
|
||||
if (!lv_snapshot_percent(lv, &snap_percent) ||
|
||||
snap_percent == DM_PERCENT_INVALID) {
|
||||
if (info.suspended)
|
||||
if (lvdm->info.suspended)
|
||||
repstr[4] = 'S'; /* Susp Inv snapshot */
|
||||
else
|
||||
repstr[4] = 'I'; /* Invalid snapshot */
|
||||
}
|
||||
else if (snap_percent == LVM_PERCENT_MERGE_FAILED) {
|
||||
if (info.suspended)
|
||||
if (lvdm->info.suspended)
|
||||
repstr[4] = 'M'; /* Susp snapshot merge failed */
|
||||
else
|
||||
repstr[4] = 'm'; /* snapshot merge failed */
|
||||
@@ -745,10 +749,10 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
* 'R' indicates read-only activation of a device that
|
||||
* does not have metadata flagging it as read-only.
|
||||
*/
|
||||
if (repstr[1] != 'r' && info.read_only)
|
||||
if (repstr[1] != 'r' && lvdm->info.read_only)
|
||||
repstr[1] = 'R';
|
||||
|
||||
repstr[5] = (info.open_count) ? 'o' : '-';
|
||||
repstr[5] = (lvdm->info.open_count) ? 'o' : '-';
|
||||
} else {
|
||||
repstr[4] = '-';
|
||||
repstr[5] = '-';
|
||||
@@ -792,6 +796,16 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
repstr[8] = 'm'; /* RAID has 'm'ismatches */
|
||||
} else if (lv->status & LV_WRITEMOSTLY)
|
||||
repstr[8] = 'w'; /* sub-LV has 'w'ritemostly */
|
||||
} else if (lv_is_thin_pool(lv) &&
|
||||
(lvdm->seg_status.type != SEG_STATUS_NONE)) {
|
||||
if (lvdm->seg_status.type == SEG_STATUS_UNKNOWN)
|
||||
repstr[8] = 'X'; /* Unknown */
|
||||
else if (lvdm->seg_status.thin_pool->fail)
|
||||
repstr[8] = 'F';
|
||||
else if (lvdm->seg_status.thin_pool->out_of_data_space)
|
||||
repstr[8] = 'D';
|
||||
else if (lvdm->seg_status.thin_pool->read_only)
|
||||
repstr[8] = 'M';
|
||||
}
|
||||
|
||||
if (lv->status & LV_ACTIVATION_SKIP)
|
||||
@@ -803,6 +817,28 @@ out:
|
||||
return repstr;
|
||||
}
|
||||
|
||||
/* backward compatible internal API for lvm2api, TODO improve it */
|
||||
char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
char *ret = NULL;
|
||||
struct lv_with_info_and_seg_status status = {
|
||||
.seg_status.type = SEG_STATUS_NONE,
|
||||
.lv = lv
|
||||
};
|
||||
|
||||
if (!(status.seg_status.mem = dm_pool_create("reporter_pool", 1024)))
|
||||
return_0;
|
||||
|
||||
if (!(status.info_ok = lv_info_with_seg_status(lv->vg->cmd, lv, first_seg(lv), 1, &status, 1, 1)))
|
||||
goto_bad;
|
||||
|
||||
ret = lv_attr_dup_with_info_and_seg_status(mem, &status);
|
||||
bad:
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lv_set_creation(struct logical_volume *lv,
|
||||
const char *hostname, uint64_t timestamp)
|
||||
{
|
||||
@@ -980,6 +1016,10 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv)
|
||||
return sl->seg->lv;
|
||||
}
|
||||
|
||||
/* RAID changes visibility of splitted LVs but references them still as leg/meta */
|
||||
if ((lv_is_raid_image(lv) || lv_is_raid_metadata(lv)) && lv_is_visible(lv))
|
||||
return lv;
|
||||
|
||||
/* For other types, by default look for the first user */
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
/* FIXME: complete this exception list */
|
||||
|
@@ -54,8 +54,11 @@ struct logical_volume {
|
||||
const char *hostname;
|
||||
};
|
||||
|
||||
struct lv_with_info_and_seg_status;
|
||||
|
||||
uint64_t lv_size(const struct logical_volume *lv);
|
||||
uint64_t lv_metadata_size(const struct logical_volume *lv);
|
||||
char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_with_info_and_seg_status *lvdm);
|
||||
char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_uuid_dup(const struct logical_volume *lv);
|
||||
char *lv_tags_dup(const struct logical_volume *lv);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -147,6 +147,13 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_error_when_full(lv) &&
|
||||
!seg_can_error_when_full(seg)) {
|
||||
log_error("LV %s: segment %u (%s) does not support flag "
|
||||
"ERROR_WHEN_FULL.", lv->name, seg_count, seg->segtype->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (complete_vg && seg->log_lv &&
|
||||
!seg_is_mirrored(seg) && !(seg->status & RAID_IMAGE)) {
|
||||
log_error("LV %s: segment %u log LV %s is not a "
|
||||
|
@@ -58,6 +58,7 @@
|
||||
|
||||
#define LVM_READ UINT64_C(0x0000000000000100) /* LV, VG */
|
||||
#define LVM_WRITE UINT64_C(0x0000000000000200) /* LV, VG */
|
||||
#define LVM_WRITE_LOCKED UINT64_C(0x0020000000000000) /* LV, VG */
|
||||
|
||||
#define CLUSTERED UINT64_C(0x0000000000000400) /* VG */
|
||||
//#define SHARED UINT64_C(0x0000000000000800) /* VG */
|
||||
@@ -118,8 +119,20 @@
|
||||
#define CACHE UINT64_C(0x0001000000000000) /* LV - Internal use only */
|
||||
|
||||
#define LV_PENDING_DELETE UINT64_C(0x0004000000000000) /* LV - Internal use only */
|
||||
|
||||
/* Next unused flag: UINT64_C(0x0008000000000000) */
|
||||
#define LV_REMOVED UINT64_C(0x0040000000000000) /* LV - Internal use only
|
||||
This flag is used to mark an LV once it has
|
||||
been removed from the VG. It might still
|
||||
be referenced on internal lists of LVs.
|
||||
Any remaining references should check for
|
||||
this flag and ignore the LV is set.
|
||||
FIXME: Remove this flag once we have indexed
|
||||
vg->removed_lvs for quick lookup.
|
||||
*/
|
||||
#define LV_ERROR_WHEN_FULL UINT64_C(0x0008000000000000) /* LV - error when full */
|
||||
#define PV_ALLOCATION_PROHIBITED UINT64_C(0x0010000000000000) /* PV - internal use only - allocation prohibited
|
||||
e.g. to prohibit allocation of a RAID image
|
||||
on a PV already holing an image of the RAID set */
|
||||
/* Next unused flag: UINT64_C(0x0080000000000000) */
|
||||
|
||||
/* Format features flags */
|
||||
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
|
||||
@@ -136,6 +149,9 @@
|
||||
#define FMT_CONFIG_PROFILE 0x000000800U /* Supports configuration profiles? */
|
||||
#define FMT_OBSOLETE 0x000001000U /* Obsolete format? */
|
||||
#define FMT_NON_POWER2_EXTENTS 0x000002000U /* Non-power-of-2 extent sizes? */
|
||||
#define FMT_SYSTEMID_ON_PVS 0x000004000U /* System ID is stored on PVs not VG */
|
||||
|
||||
#define systemid_on_pvs(vg) ((vg)->fid->fmt->features & FMT_SYSTEMID_ON_PVS)
|
||||
|
||||
/* Mirror conversion type flags */
|
||||
#define MIRROR_BY_SEG 0x00000001U /* segment-by-segment mirror */
|
||||
@@ -162,6 +178,9 @@
|
||||
#define FAILED_CLUSTERED 0x00000040U
|
||||
#define FAILED_ALLOCATION 0x00000080U
|
||||
#define FAILED_EXIST 0x00000100U
|
||||
#define FAILED_RECOVERY 0x00000200U
|
||||
#define FAILED_SYSTEMID 0x00000400U
|
||||
#define FAILED_LOCK_TYPE 0x00000800U
|
||||
#define SUCCESS 0x00000000U
|
||||
|
||||
#define VGMETADATACOPIES_ALL UINT32_MAX
|
||||
@@ -191,6 +210,7 @@
|
||||
#define lv_is_mirror_type(lv) (((lv)->status & (MIRROR | MIRROR_LOG | MIRROR_IMAGE)) ? 1 : 0)
|
||||
|
||||
#define lv_is_pending_delete(lv) (((lv)->status & LV_PENDING_DELETE) ? 1 : 0)
|
||||
#define lv_is_error_when_full(lv) (((lv)->status & LV_ERROR_WHEN_FULL) ? 1 : 0)
|
||||
#define lv_is_pvmove(lv) (((lv)->status & PVMOVE) ? 1 : 0)
|
||||
|
||||
#define lv_is_raid(lv) (((lv)->status & RAID) ? 1 : 0)
|
||||
@@ -211,6 +231,8 @@
|
||||
|
||||
#define lv_is_rlog(lv) (((lv)->status & REPLICATOR_LOG) ? 1 : 0)
|
||||
|
||||
#define lv_is_removed(lv) (((lv)->status & LV_REMOVED) ? 1 : 0)
|
||||
|
||||
int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
struct dm_list **layout, struct dm_list **role);
|
||||
|
||||
@@ -634,7 +656,9 @@ struct physical_volume *pv_create(const struct cmd_context *cmd,
|
||||
|
||||
int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
void *handle __attribute__((unused)), unsigned force_count,
|
||||
unsigned prompt);
|
||||
unsigned prompt, struct dm_list *pvslist);
|
||||
int pvremove_many(struct cmd_context *cmd, struct dm_list *pv_names,
|
||||
unsigned force_count, unsigned prompt);
|
||||
|
||||
int pv_resize_single(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
@@ -853,6 +877,7 @@ struct lvcreate_params {
|
||||
uint32_t max_recovery_rate; /* RAID */
|
||||
|
||||
uint64_t feature_flags; /* cache */
|
||||
struct dm_config_tree *cache_policy; /* cache */
|
||||
|
||||
const struct segment_type *segtype; /* all */
|
||||
unsigned target_attr; /* all */
|
||||
@@ -867,6 +892,7 @@ struct lvcreate_params {
|
||||
struct dm_list *pvh; /* all */
|
||||
|
||||
uint64_t permission; /* all */
|
||||
unsigned error_when_full; /* when segment supports it */
|
||||
uint32_t read_ahead; /* all */
|
||||
int approx_alloc; /* all */
|
||||
alloc_policy_t alloc; /* all */
|
||||
@@ -1015,11 +1041,16 @@ int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const char *get_mirror_log_name(int log_count);
|
||||
int set_mirror_log_count(int *log_count, const char *mirrorlog);
|
||||
|
||||
int cluster_mirror_is_available(struct cmd_context *cmd);
|
||||
int is_temporary_mirror_layer(const struct logical_volume *lv);
|
||||
struct logical_volume * find_temporary_mirror(const struct logical_volume *lv);
|
||||
uint32_t lv_mirror_count(const struct logical_volume *lv);
|
||||
|
||||
/* Remove CMIRROR_REGION_COUNT_LIMIT when http://bugzilla.redhat.com/682771 is fixed */
|
||||
#define CMIRROR_REGION_COUNT_LIMIT (256*1024 * 8)
|
||||
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
|
||||
uint32_t region_size, int internal);
|
||||
uint32_t region_size, int internal, int clustered);
|
||||
|
||||
int remove_mirrors_from_segments(struct logical_volume *lv,
|
||||
uint32_t new_mirrors, uint64_t status_mask);
|
||||
int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
@@ -1108,6 +1139,7 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv);
|
||||
struct logical_volume *lv_cache_create(struct logical_volume *pool,
|
||||
struct logical_volume *origin);
|
||||
int lv_cache_remove(struct logical_volume *cache_lv);
|
||||
int lv_cache_setpolicy(struct logical_volume *cache_lv, struct dm_config_tree *pol);
|
||||
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
|
||||
/* -- metadata/cache_manip.c */
|
||||
|
||||
@@ -1148,6 +1180,7 @@ char *generate_lv_name(struct volume_group *vg, const char *format,
|
||||
int pv_change_metadataignore(struct physical_volume *pv, uint32_t mda_ignore);
|
||||
|
||||
|
||||
int vg_flag_write_locked(struct volume_group *vg);
|
||||
int vg_check_write_mode(struct volume_group *vg);
|
||||
#define vg_is_clustered(vg) (vg_status((vg)) & CLUSTERED)
|
||||
#define vg_is_exported(vg) (vg_status((vg)) & EXPORTED_VG)
|
||||
@@ -1166,6 +1199,7 @@ struct vgcreate_params {
|
||||
alloc_policy_t alloc;
|
||||
int clustered; /* FIXME: put this into a 'status' variable instead? */
|
||||
uint32_t vgmetadatacopies;
|
||||
const char *system_id;
|
||||
};
|
||||
|
||||
int validate_major_minor(const struct cmd_context *cmd,
|
||||
|
@@ -1009,7 +1009,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
|
||||
.context.vg_ref.vg_name = vg_name
|
||||
};
|
||||
struct format_instance *fid;
|
||||
int consistent = 0;
|
||||
uint32_t rc;
|
||||
|
||||
if (!validate_name(vg_name)) {
|
||||
@@ -1023,15 +1022,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
|
||||
/* NOTE: let caller decide - this may be check for existence */
|
||||
return _vg_make_handle(cmd, NULL, rc);
|
||||
|
||||
/* FIXME: Is this vg_read_internal necessary? Move it inside
|
||||
vg_lock_newname? */
|
||||
/* is this vg name already in use ? */
|
||||
if ((vg = vg_read_internal(cmd, vg_name, NULL, WARN_PV_READ, &consistent))) {
|
||||
log_error("A volume group called '%s' already exists.", vg_name);
|
||||
unlock_and_release_vg(cmd, vg, vg_name);
|
||||
return _vg_make_handle(cmd, NULL, FAILED_EXIST);
|
||||
}
|
||||
|
||||
/* Strip dev_dir if present */
|
||||
vg_name = strip_dir(vg_name, cmd->dev_dir);
|
||||
|
||||
@@ -1045,10 +1035,10 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
|
||||
}
|
||||
|
||||
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
|
||||
if (!(vg->system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
|
||||
vg->system_id = NULL;
|
||||
if (!(vg->lvm1_system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
|
||||
goto_bad;
|
||||
|
||||
*vg->system_id = '\0';
|
||||
vg->extent_size = DEFAULT_EXTENT_SIZE * 2;
|
||||
vg->max_lv = DEFAULT_MAX_LV;
|
||||
vg->max_pv = DEFAULT_MAX_PV;
|
||||
@@ -1416,7 +1406,7 @@ int vg_split_mdas(struct cmd_context *cmd __attribute__((unused)),
|
||||
* 0 indicates we may not.
|
||||
*/
|
||||
static int _pvcreate_check(struct cmd_context *cmd, const char *name,
|
||||
struct pvcreate_params *pp)
|
||||
struct pvcreate_params *pp, int *wiped)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct device *dev;
|
||||
@@ -1426,6 +1416,8 @@ static int _pvcreate_check(struct cmd_context *cmd, const char *name,
|
||||
|
||||
/* FIXME Check partition type is LVM unless --force is given */
|
||||
|
||||
*wiped = 0;
|
||||
|
||||
/* Is there a pv here already? */
|
||||
pv = find_pv_by_name(cmd, name, 1, 1);
|
||||
|
||||
@@ -1450,6 +1442,33 @@ static int _pvcreate_check(struct cmd_context *cmd, const char *name,
|
||||
|
||||
dev = dev_cache_get(name, cmd->full_filter);
|
||||
|
||||
/*
|
||||
* Refresh+rescan at the end is needed if:
|
||||
* - we don't obtain device list from udev,
|
||||
* hence persistent cache file is used
|
||||
* and we need to trash it and reevaluate
|
||||
* for any changes done outside - adding
|
||||
* any new foreign signature which may affect
|
||||
* filtering - before we do pvcreate, we
|
||||
* need to be sure that we have up-to-date
|
||||
* view for filters
|
||||
*
|
||||
* - we have wiped existing foreign signatures
|
||||
* from dev as this may affect what's filtered
|
||||
* as well
|
||||
*
|
||||
*
|
||||
* Only rescan at the end is needed if:
|
||||
* - we've just checked whether dev is fileterd
|
||||
* by MD filter. We do the refresh in-situ,
|
||||
* so no need to require the refresh at the
|
||||
* end of this fn. This is to allow for
|
||||
* wiping MD signature during pvcreate for
|
||||
* the dev - the dev would normally be
|
||||
* filtered because of MD filter.
|
||||
* This is an exception.
|
||||
*/
|
||||
|
||||
/* Is there an md superblock here? */
|
||||
if (!dev && md_filtering()) {
|
||||
if (!refresh_filters(cmd))
|
||||
@@ -1460,7 +1479,8 @@ static int _pvcreate_check(struct cmd_context *cmd, const char *name,
|
||||
init_md_filtering(1);
|
||||
|
||||
scan_needed = 1;
|
||||
}
|
||||
} else if (!obtain_device_list_from_udev())
|
||||
filter_refresh_needed = scan_needed = 1;
|
||||
|
||||
if (!dev) {
|
||||
log_error("Device %s not found (or ignored by filtering).", name);
|
||||
@@ -1479,12 +1499,13 @@ static int _pvcreate_check(struct cmd_context *cmd, const char *name,
|
||||
|
||||
if (!wipe_known_signatures(cmd, dev, name,
|
||||
TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER,
|
||||
0, pp->yes, pp->force)) {
|
||||
0, pp->yes, pp->force, wiped)) {
|
||||
log_error("Aborting pvcreate on %s.", name);
|
||||
goto out;
|
||||
} else
|
||||
}
|
||||
|
||||
if (wiped)
|
||||
filter_refresh_needed = scan_needed = 1;
|
||||
|
||||
|
||||
if (sigint_caught())
|
||||
goto_out;
|
||||
@@ -1505,11 +1526,12 @@ out:
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (scan_needed)
|
||||
if (scan_needed) {
|
||||
if (!lvmcache_label_scan(cmd, 2)) {
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free_pv_fid(pv);
|
||||
return r;
|
||||
@@ -1620,9 +1642,11 @@ struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_nam
|
||||
{
|
||||
struct physical_volume *pv = NULL;
|
||||
struct device *dev;
|
||||
int wiped = 0;
|
||||
struct dm_list mdas;
|
||||
struct pvcreate_params default_pp;
|
||||
char buffer[64] __attribute__((aligned(8)));
|
||||
dev_ext_t dev_ext_src;
|
||||
|
||||
pvcreate_params_set_defaults(&default_pp);
|
||||
if (!pp)
|
||||
@@ -1644,13 +1668,32 @@ struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_nam
|
||||
}
|
||||
}
|
||||
|
||||
if (!_pvcreate_check(cmd, pv_name, pp))
|
||||
if (!_pvcreate_check(cmd, pv_name, pp, &wiped))
|
||||
goto_bad;
|
||||
|
||||
if (sigint_caught())
|
||||
goto_bad;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->full_filter))) {
|
||||
/*
|
||||
* wipe_known_signatures called in _pvcreate_check fires
|
||||
* WATCH event to update udev database. But at the moment,
|
||||
* we have no way to synchronize with such event - we may
|
||||
* end up still seeing the old info in udev db and pvcreate
|
||||
* can fail to proceed because of the device still being
|
||||
* filtered (because of the stale info in udev db).
|
||||
* Disable udev dev-ext source temporarily here for
|
||||
* this reason and rescan with DEV_EXT_NONE dev-ext
|
||||
* source (so filters use DEV_EXT_NONE source).
|
||||
*/
|
||||
dev_ext_src = external_device_info_source();
|
||||
if (wiped && (dev_ext_src == DEV_EXT_UDEV))
|
||||
init_external_device_info_source(DEV_EXT_NONE);
|
||||
|
||||
dev = dev_cache_get(pv_name, cmd->full_filter);
|
||||
|
||||
init_external_device_info_source(dev_ext_src);
|
||||
|
||||
if (!dev) {
|
||||
log_error("%s: Couldn't find device. Check your filters?",
|
||||
pv_name);
|
||||
goto bad;
|
||||
@@ -2452,6 +2495,12 @@ int vg_validate(struct volume_group *vg)
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (vg->status & LVM_WRITE_LOCKED) {
|
||||
log_error(INTERNAL_ERROR "VG %s has external flag LVM_WRITE_LOCKED set internally.",
|
||||
vg->name);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
/* FIXME Also check there's no data/metadata overlap */
|
||||
if (!(vhash.pvid = dm_hash_create(vg->pv_count))) {
|
||||
log_error("Failed to allocate pvid hash.");
|
||||
@@ -2519,12 +2568,32 @@ int vg_validate(struct volume_group *vg)
|
||||
r = 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->removed_lvs) {
|
||||
if (!(lvl->lv->status & LV_REMOVED)) {
|
||||
log_error(INTERNAL_ERROR "LV %s is not marked as removed while it's part "
|
||||
"of removed LV list for VG %s", lvl->lv->name, vg->name);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Count all non-snapshot invisible LVs
|
||||
*/
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
lv_count++;
|
||||
|
||||
if (lvl->lv->status & LV_REMOVED) {
|
||||
log_error(INTERNAL_ERROR "LV %s is marked as removed while it's "
|
||||
"still part of the VG %s", lvl->lv->name, vg->name);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (lvl->lv->status & LVM_WRITE_LOCKED) {
|
||||
log_error(INTERNAL_ERROR "LV %s has external flag LVM_WRITE_LOCKED set internally.",
|
||||
lvl->lv->name);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
dev_name_len = strlen(lvl->lv->name) + vg_name_len + 3;
|
||||
if (dev_name_len >= NAME_LEN) {
|
||||
log_error(INTERNAL_ERROR "LV name \"%s/%s\" length %"
|
||||
@@ -2807,6 +2876,7 @@ int vg_write(struct volume_group *vg)
|
||||
}
|
||||
|
||||
if (revert || !wrote) {
|
||||
log_error("Failed to write VG %s.", vg->name);
|
||||
dm_list_uniterate(mdah, &vg->fid->metadata_areas_in_use, &mda->list) {
|
||||
mda = dm_list_item(mdah, struct metadata_area);
|
||||
|
||||
@@ -3192,6 +3262,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
unsigned seqno = 0;
|
||||
int reappeared = 0;
|
||||
struct cached_vg_fmtdata *vg_fmtdata = NULL; /* Additional format-specific data about the vg */
|
||||
unsigned use_previous_vg;
|
||||
|
||||
if (is_orphan_vg(vgname)) {
|
||||
if (use_precommitted) {
|
||||
@@ -3278,12 +3350,20 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
/* Ensure contents of all metadata areas match - else do recovery */
|
||||
inconsistent_mda_count=0;
|
||||
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
|
||||
use_previous_vg = 0;
|
||||
|
||||
if ((use_precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
|
||||
(!use_precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, 0)))) {
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg)) {
|
||||
inconsistent = 1;
|
||||
vg_fmtdata = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use previous VG because checksum matches */
|
||||
if (!vg) {
|
||||
vg = correct_vg;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3310,8 +3390,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (vg != correct_vg)
|
||||
if (vg != correct_vg) {
|
||||
release_vg(vg);
|
||||
vg_fmtdata = NULL;
|
||||
}
|
||||
}
|
||||
fid->ref_count--;
|
||||
|
||||
@@ -3427,6 +3509,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
* but we failed to do so (so there's a dangling fid now).
|
||||
*/
|
||||
_destroy_fid(&fid);
|
||||
vg_fmtdata = NULL;
|
||||
|
||||
inconsistent = 0;
|
||||
|
||||
@@ -3457,14 +3540,23 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
/* Ensure contents of all metadata areas match - else recover */
|
||||
inconsistent_mda_count=0;
|
||||
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
|
||||
use_previous_vg = 0;
|
||||
|
||||
if ((use_precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname,
|
||||
mda))) ||
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
|
||||
(!use_precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, 0)))) {
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg)) {
|
||||
inconsistent = 1;
|
||||
vg_fmtdata = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use previous VG because checksum matches */
|
||||
if (!vg) {
|
||||
vg = correct_vg;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!correct_vg) {
|
||||
correct_vg = vg;
|
||||
if (!_update_pv_list(cmd->mem, &all_pvs, correct_vg)) {
|
||||
@@ -3507,8 +3599,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (vg != correct_vg)
|
||||
if (vg != correct_vg) {
|
||||
release_vg(vg);
|
||||
vg_fmtdata = NULL;
|
||||
}
|
||||
}
|
||||
fid->ref_count--;
|
||||
|
||||
@@ -3567,8 +3661,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
|
||||
/* Don't touch if vgids didn't match */
|
||||
if (inconsistent_vgid) {
|
||||
log_error("Inconsistent metadata UUIDs found for "
|
||||
"volume group %s", vgname);
|
||||
log_warn("WARNING: Inconsistent metadata UUIDs found for "
|
||||
"volume group %s.", vgname);
|
||||
*consistent = 0;
|
||||
_free_pv_list(&all_pvs);
|
||||
return correct_vg;
|
||||
@@ -3600,8 +3694,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
release_vg(correct_vg);
|
||||
return_NULL;
|
||||
}
|
||||
log_error("Removing PV %s (%s) that no longer belongs to VG %s",
|
||||
pv_dev_name(pvl->pv), uuid, correct_vg->name);
|
||||
log_warn("WARNING: Removing PV %s (%s) that no longer belongs to VG %s",
|
||||
pv_dev_name(pvl->pv), uuid, correct_vg->name);
|
||||
if (!pv_write_orphan(cmd, pvl->pv)) {
|
||||
_free_pv_list(&all_pvs);
|
||||
release_vg(correct_vg);
|
||||
@@ -3624,10 +3718,9 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
|
||||
log_error("WARNING: Interrupted pvmove detected in "
|
||||
"volume group %s", correct_vg->name);
|
||||
log_error("Please restore the metadata by running "
|
||||
"vgcfgrestore.");
|
||||
log_error("Interrupted pvmove detected in volume group %s.",
|
||||
correct_vg->name);
|
||||
log_print("Please restore the metadata by running vgcfgrestore.");
|
||||
release_vg(correct_vg);
|
||||
return NULL;
|
||||
}
|
||||
@@ -3678,7 +3771,7 @@ struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgnam
|
||||
|
||||
out:
|
||||
if (!*consistent && (warn_flags & WARN_INCONSISTENT))
|
||||
log_warn("WARNING: Volume Group %s is not consistent", vgname);
|
||||
log_warn("WARNING: Volume Group %s is not consistent.", vgname);
|
||||
|
||||
return vg;
|
||||
}
|
||||
@@ -4203,6 +4296,37 @@ int vg_check_write_mode(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if the VG metadata should be written
|
||||
* *without* the LVM_WRITE flag in the status line, and
|
||||
* *with* the LVM_WRITE_LOCKED flag in the flags line.
|
||||
*
|
||||
* If this is done for a VG, it forces previous versions
|
||||
* of lvm (before the LVM_WRITE_LOCKED flag was added), to view
|
||||
* the VG and its LVs as read-only (because the LVM_WRITE flag
|
||||
* is missing). Versions of lvm that understand the
|
||||
* LVM_WRITE_LOCKED flag know to check the other methods of
|
||||
* access control for the VG, specifically system_id and lock_type.
|
||||
*
|
||||
* So, if a VG has a system_id or lock_type, then the
|
||||
* system_id and lock_type control access to the VG in
|
||||
* addition to its basic writable status. Because previous
|
||||
* lvm versions do not know about system_id or lock_type,
|
||||
* VGs depending on either of these should have LVM_WRITE_LOCKED
|
||||
* instead of LVM_WRITE to prevent the previous lvm versions from
|
||||
* assuming they can write the VG and its LVs.
|
||||
*/
|
||||
int vg_flag_write_locked(struct volume_group *vg)
|
||||
{
|
||||
if (vg->system_id && vg->system_id[0])
|
||||
return 1;
|
||||
|
||||
if (vg->lock_type && vg->lock_type[0] && strcmp(vg->lock_type, "none"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a set of checks against a VG according to bits set in status
|
||||
* and returns FAILED_* bits for those that aren't acceptable.
|
||||
@@ -4285,6 +4409,166 @@ static struct volume_group *_recover_vg(struct cmd_context *cmd,
|
||||
return (struct volume_group *)vg;
|
||||
}
|
||||
|
||||
static int _allow_system_id(struct cmd_context *cmd, const char *system_id)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, local_extra_system_ids_CFG, NULL)))
|
||||
return 0;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type == DM_CFG_EMPTY_ARRAY)
|
||||
break;
|
||||
/* Ignore invalid data: Warning message already issued by config.c */
|
||||
if (cv->type != DM_CFG_STRING)
|
||||
continue;
|
||||
str = cv->v.str;
|
||||
if (!*str)
|
||||
continue;
|
||||
|
||||
if (!strcmp(str, system_id))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _access_vg_clustered(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
if (vg_is_clustered(vg) && !locking_is_clustered()) {
|
||||
if (!cmd->ignore_clustered_vgs)
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
else
|
||||
log_verbose("Skipping clustered volume group %s", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
if (!is_real_vg(vg->name))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Until lock_type support is added, reject any VG that has a lock_type.
|
||||
*/
|
||||
if (vg->lock_type && vg->lock_type[0] && strcmp(vg->lock_type, "none")) {
|
||||
log_error("Cannot access VG %s with unsupported lock_type %s.",
|
||||
vg->name, vg->lock_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
/*
|
||||
* LVM1 VGs must not be accessed if a new-style LVM2 system ID is set.
|
||||
*/
|
||||
if (cmd->system_id && systemid_on_pvs(vg)) {
|
||||
log_error("Cannot access VG %s with LVM1 system ID %s when host system ID is set.",
|
||||
vg->name, vg->lvm1_system_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A VG without a system_id can be accessed by anyone.
|
||||
*/
|
||||
if (!vg->system_id || !vg->system_id[0])
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* A few commands allow read-only access to foreign VGs.
|
||||
*/
|
||||
if (cmd->include_foreign_vgs)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* A host can access a VG with a matching system_id.
|
||||
*/
|
||||
if (cmd->system_id && !strcmp(vg->system_id, cmd->system_id))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* A host can access a VG if the VG's system_id is in extra_system_ids list.
|
||||
*/
|
||||
if (cmd->system_id && _allow_system_id(cmd, vg->system_id))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Allow VG access if the local host has active LVs in it.
|
||||
*/
|
||||
if (lvs_in_vg_activated(vg)) {
|
||||
log_warn("WARNING: Found LVs active in VG %s with foreign system ID %s. Possible data corruption.",
|
||||
vg->name, vg->system_id);
|
||||
if (cmd->include_active_foreign_vgs)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A host without a system_id cannot access a VG with a system_id.
|
||||
*/
|
||||
if (!cmd->system_id || cmd->unknown_system_id) {
|
||||
log_error("Cannot access VG %s with system ID %s with unknown local system ID.",
|
||||
vg->name, vg->system_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some commands always produce an error when accessing foreign VG.
|
||||
*/
|
||||
if (cmd->error_foreign_vgs) {
|
||||
log_error("Cannot access VG %s with system ID %s with local system ID %s.",
|
||||
vg->name, vg->system_id, cmd->system_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When include_foreign_vgs is 0 and error_foreign_vgs is 0,
|
||||
* the result is to silently ignore foreign vgs.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: move _vg_bad_status_bits() checks in here.
|
||||
*/
|
||||
static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg, uint32_t *failure)
|
||||
{
|
||||
if (!is_real_vg(vg->name)) {
|
||||
/* Disallow use of LVM1 orphans when a host system ID is set. */
|
||||
if (cmd->system_id && *cmd->system_id && systemid_on_pvs(vg)) {
|
||||
*failure |= FAILED_SYSTEMID;
|
||||
return_0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_access_vg_clustered(cmd, vg)) {
|
||||
*failure |= FAILED_CLUSTERED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_access_vg_lock_type(cmd, vg)) {
|
||||
*failure |= FAILED_LOCK_TYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_access_vg_systemid(cmd, vg)) {
|
||||
*failure |= FAILED_SYSTEMID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Consolidated locking, reading, and status flag checking.
|
||||
*
|
||||
@@ -4344,14 +4628,8 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (vg_is_clustered(vg) && !locking_is_clustered()) {
|
||||
if (!cmd->ignore_clustered_vgs)
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
else
|
||||
log_verbose("Skipping clustered volume group %s", vg->name);
|
||||
failure |= FAILED_CLUSTERED;
|
||||
if (!_vg_access_permitted(cmd, vg, &failure))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */
|
||||
if (!consistent && !failure) {
|
||||
@@ -4359,7 +4637,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
if (!(vg = _recover_vg(cmd, vg_name, vgid))) {
|
||||
log_error("Recovery of volume group \"%s\" failed.",
|
||||
vg_name);
|
||||
failure |= FAILED_INCONSISTENT;
|
||||
failure |= FAILED_RECOVERY;
|
||||
goto bad_no_unlock;
|
||||
}
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ struct dm_config_tree;
|
||||
struct metadata_area;
|
||||
struct alloc_handle;
|
||||
struct lvmcache_info;
|
||||
struct cached_vg_fmtdata;
|
||||
|
||||
/* Per-format per-metadata area operations */
|
||||
struct metadata_area_ops {
|
||||
@@ -79,10 +80,14 @@ struct metadata_area_ops {
|
||||
struct volume_group *(*vg_read) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int single_device);
|
||||
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda);
|
||||
struct metadata_area * mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg);
|
||||
/*
|
||||
* Write out complete VG metadata. You must ensure internal
|
||||
* consistency before calling. eg. PEs can't refer to PVs not
|
||||
@@ -430,9 +435,13 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le);
|
||||
int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
|
||||
int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
|
||||
|
||||
int for_each_sub_lv_except_pools(struct logical_volume *lv,
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data);
|
||||
int for_each_sub_lv(struct logical_volume *lv,
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data);
|
||||
int (*fn)(struct logical_volume *lv, void *data),
|
||||
void *data);
|
||||
|
||||
int move_lv_segments(struct logical_volume *lv_to,
|
||||
struct logical_volume *lv_from,
|
||||
uint64_t set_status, uint64_t reset_status);
|
||||
|
@@ -78,10 +78,9 @@ struct logical_volume *find_temporary_mirror(const struct logical_volume *lv)
|
||||
*
|
||||
* Returns: 1 if available, 0 otherwise
|
||||
*/
|
||||
static int _cluster_mirror_is_available(struct logical_volume *lv)
|
||||
int cluster_mirror_is_available(struct cmd_context *cmd)
|
||||
{
|
||||
unsigned attr = 0;
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
@@ -90,7 +89,7 @@ static int _cluster_mirror_is_available(struct logical_volume *lv)
|
||||
if (!segtype->ops->target_present)
|
||||
return_0;
|
||||
|
||||
if (!segtype->ops->target_present(lv->vg->cmd, NULL, &attr))
|
||||
if (!segtype->ops->target_present(cmd, NULL, &attr))
|
||||
return_0;
|
||||
|
||||
if (!(attr & MIRROR_LOG_CLUSTERED))
|
||||
@@ -160,11 +159,12 @@ struct lv_segment *find_mirror_seg(struct lv_segment *seg)
|
||||
* For internal use only log only in verbose mode
|
||||
*/
|
||||
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
|
||||
uint32_t region_size, int internal)
|
||||
uint32_t region_size, int internal, int clustered)
|
||||
{
|
||||
uint64_t region_max;
|
||||
uint64_t region_min, region_min_pow2;
|
||||
|
||||
region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
|
||||
region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) (1 << (ffs((int)extent_size) - 1));
|
||||
|
||||
if (region_max < UINT32_MAX && region_size > region_max) {
|
||||
region_size = (uint32_t) region_max;
|
||||
@@ -176,6 +176,42 @@ uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
|
||||
PRIu32 " sectors.", region_size);
|
||||
}
|
||||
|
||||
#ifdef CMIRROR_REGION_COUNT_LIMIT
|
||||
if (clustered) {
|
||||
/*
|
||||
* The CPG code used by cluster mirrors can only handle a
|
||||
* payload of < 1MB currently. (This deficiency is tracked by
|
||||
* http://bugzilla.redhat.com/682771.) The region size for cluster
|
||||
* mirrors must be restricted in such a way as to limit the
|
||||
* size of the bitmap to < 512kB, because there are two bitmaps
|
||||
* which get sent around during checkpointing while a cluster
|
||||
* mirror starts up. Ergo, the number of regions must not
|
||||
* exceed 512k * 8. We also need some room for the other
|
||||
* checkpointing structures as well, so we reduce by another
|
||||
* factor of two.
|
||||
*
|
||||
* This code should be removed when the CPG restriction is
|
||||
* lifted.
|
||||
*/
|
||||
region_min = (uint64_t) extents * extent_size / CMIRROR_REGION_COUNT_LIMIT;
|
||||
region_min_pow2 = 1;
|
||||
while (region_min_pow2 < region_min)
|
||||
region_min_pow2 *= 2;
|
||||
|
||||
if (region_size < region_min_pow2) {
|
||||
if (internal)
|
||||
log_print_unless_silent("Increasing mirror region size from %"
|
||||
PRIu32 " to %" PRIu64 " sectors.",
|
||||
region_size, region_min_pow2);
|
||||
else
|
||||
log_verbose("Increasing mirror region size from %"
|
||||
PRIu32 " to %" PRIu64 " sectors.",
|
||||
region_size, region_min_pow2);
|
||||
region_size = region_min_pow2;
|
||||
}
|
||||
}
|
||||
#endif /* CMIRROR_REGION_COUNT_LIMIT */
|
||||
|
||||
return region_size;
|
||||
}
|
||||
|
||||
@@ -421,7 +457,8 @@ static int _activate_lv_like_model(struct logical_volume *model,
|
||||
/*
|
||||
* Delete independent/orphan LV, it must acquire lock.
|
||||
*/
|
||||
static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv)
|
||||
static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv,
|
||||
int reactivate)
|
||||
{
|
||||
struct cmd_context *cmd = mirror_lv->vg->cmd;
|
||||
struct dm_str_list *sl;
|
||||
@@ -441,15 +478,17 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: the 'model' should be 'mirror_lv' not 'lv', I think. */
|
||||
if (!_activate_lv_like_model(lv, lv))
|
||||
return_0;
|
||||
if (reactivate) {
|
||||
/* FIXME: the 'model' should be 'mirror_lv' not 'lv', I think. */
|
||||
if (!_activate_lv_like_model(lv, lv))
|
||||
return_0;
|
||||
|
||||
/* FIXME Is this superfluous now? */
|
||||
sync_local_dev_names(cmd);
|
||||
/* FIXME Is this superfluous now? */
|
||||
sync_local_dev_names(cmd);
|
||||
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!lv_remove(lv))
|
||||
return_0;
|
||||
@@ -800,11 +839,11 @@ static int _split_mirror_images(struct logical_volume *lv,
|
||||
}
|
||||
|
||||
/* Remove original mirror layer if it has been converted to linear */
|
||||
if (sub_lv && !_delete_lv(lv, sub_lv))
|
||||
if (sub_lv && !_delete_lv(lv, sub_lv, 1))
|
||||
return_0;
|
||||
|
||||
/* Remove the log if it has been converted to linear */
|
||||
if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
|
||||
if (detached_log_lv && !_delete_lv(lv, detached_log_lv, 1))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -853,6 +892,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
struct lv_list *lvl;
|
||||
struct dm_list tmp_orphan_lvs;
|
||||
uint32_t orig_removed = num_removed;
|
||||
int reactivate;
|
||||
|
||||
if (removed)
|
||||
*removed = 0;
|
||||
@@ -865,6 +905,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
if (collapse && (old_area_count - num_removed != 1)) {
|
||||
log_error("Incompatible parameters to _remove_mirror_images");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
num_removed = 0;
|
||||
@@ -1094,16 +1135,17 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
}
|
||||
|
||||
/* Save or delete the 'orphan' LVs */
|
||||
reactivate = lv_is_active(lv_lock_holder(lv));
|
||||
if (!collapse) {
|
||||
dm_list_iterate_items(lvl, &tmp_orphan_lvs)
|
||||
if (!_delete_lv(lv, lvl->lv))
|
||||
if (!_delete_lv(lv, lvl->lv, reactivate))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (temp_layer_lv && !_delete_lv(lv, temp_layer_lv))
|
||||
if (temp_layer_lv && !_delete_lv(lv, temp_layer_lv, reactivate))
|
||||
return_0;
|
||||
|
||||
if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
|
||||
if (detached_log_lv && !_delete_lv(lv, detached_log_lv, reactivate))
|
||||
return_0;
|
||||
|
||||
/* Mirror with only 1 area is 'in sync'. */
|
||||
@@ -1703,7 +1745,8 @@ static int _add_mirrors_that_preserve_segments(struct logical_volume *lv,
|
||||
|
||||
adjusted_region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
region_size, 1);
|
||||
region_size, 1,
|
||||
vg_is_clustered(lv->vg));
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0, 0,
|
||||
lv->le_count, allocatable_pvs, alloc, 0,
|
||||
@@ -2127,7 +2170,7 @@ int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!lv_is_pvmove(lv) && !lv_is_locked(lv) &&
|
||||
lv_is_active(lv) &&
|
||||
!lv_is_active_exclusive_locally(lv) && /* lv_is_active_remotely */
|
||||
!_cluster_mirror_is_available(lv)) {
|
||||
!cluster_mirror_is_available(lv->vg->cmd)) {
|
||||
log_error("Shared cluster mirrors are not available.");
|
||||
return 0;
|
||||
}
|
||||
|
@@ -235,6 +235,11 @@ struct lv_segment *find_pool_seg(const struct lv_segment *seg)
|
||||
pool_seg = sl->seg;
|
||||
}
|
||||
|
||||
if (!pool_seg) {
|
||||
log_error("Pool segment not found for %s.", display_lvname(seg->lv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((lv_is_thin_type(seg->lv) && !seg_is_pool(pool_seg))) {
|
||||
log_error("%s on %s is not a %s pool segment",
|
||||
pool_seg->lv->name, seg->lv->name,
|
||||
@@ -397,7 +402,7 @@ int update_pool_params(const struct segment_type *segtype,
|
||||
return_0;
|
||||
|
||||
if ((uint64_t) *chunk_size > (uint64_t) pool_data_extents * vg->extent_size) {
|
||||
log_error("Size of %s data volume cannot be smaller then chunk size %s.",
|
||||
log_error("Size of %s data volume cannot be smaller than chunk size %s.",
|
||||
segtype->name, display_size(vg->cmd, *chunk_size));
|
||||
return 0;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "display.h"
|
||||
#include "label.h"
|
||||
#include "archiver.h"
|
||||
#include "lvm-signal.h"
|
||||
|
||||
static struct pv_segment *_alloc_pv_segment(struct dm_pool *mem,
|
||||
struct physical_volume *pv,
|
||||
@@ -650,7 +651,7 @@ int pv_resize_single(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
|
||||
pv_name, pv_size(pv));
|
||||
pv_name, size);
|
||||
|
||||
if (!pv_resize(pv, vg, size))
|
||||
goto_out;
|
||||
@@ -694,12 +695,11 @@ const char _really_wipe[] =
|
||||
* 0 indicates we may not.
|
||||
*/
|
||||
static int pvremove_check(struct cmd_context *cmd, const char *name,
|
||||
unsigned force_count, unsigned prompt)
|
||||
unsigned force_count, unsigned prompt, struct dm_list *pvslist)
|
||||
{
|
||||
struct device *dev;
|
||||
struct label *label;
|
||||
struct pv_list *pvl;
|
||||
struct dm_list *pvslist;
|
||||
|
||||
struct physical_volume *pv = NULL;
|
||||
int r = 0;
|
||||
@@ -720,10 +720,6 @@ static int pvremove_check(struct cmd_context *cmd, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvmcache_seed_infos_from_lvmetad(cmd);
|
||||
if (!(pvslist = get_pvs(cmd)))
|
||||
return_0;
|
||||
|
||||
dm_list_iterate_items(pvl, pvslist)
|
||||
if (pvl->pv->dev == dev)
|
||||
pv = pvl->pv;
|
||||
@@ -765,26 +761,18 @@ static int pvremove_check(struct cmd_context *cmd, const char *name,
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (pvslist)
|
||||
dm_list_iterate_items(pvl, pvslist)
|
||||
free_pv_fid(pvl->pv);
|
||||
return r;
|
||||
}
|
||||
|
||||
int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
void *handle __attribute__((unused)), unsigned force_count,
|
||||
unsigned prompt)
|
||||
unsigned prompt, struct dm_list *pvslist)
|
||||
{
|
||||
struct device *dev;
|
||||
struct lvmcache_info *info;
|
||||
int r = 0;
|
||||
|
||||
if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pvremove_check(cmd, pv_name, force_count, prompt))
|
||||
if (!pvremove_check(cmd, pv_name, force_count, prompt, pvslist))
|
||||
goto out;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
@@ -819,10 +807,49 @@ int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int pvremove_many(struct cmd_context *cmd, struct dm_list *pv_names,
|
||||
unsigned force_count, unsigned prompt)
|
||||
{
|
||||
int ret = 1;
|
||||
struct dm_list *pvslist = NULL;
|
||||
struct pv_list *pvl;
|
||||
const struct dm_str_list *pv_name;
|
||||
|
||||
if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvmcache_seed_infos_from_lvmetad(cmd);
|
||||
|
||||
if (!(pvslist = get_pvs(cmd))) {
|
||||
ret = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pv_name, pv_names) {
|
||||
if (!pvremove_single(cmd, pv_name->str, NULL, force_count, prompt, pvslist)) {
|
||||
stack;
|
||||
ret = 0;
|
||||
}
|
||||
if (sigint_caught()) {
|
||||
ret = 0;
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
unlock_vg(cmd, VG_ORPHANS);
|
||||
|
||||
return r;
|
||||
if (pvslist)
|
||||
dm_list_iterate_items(pvl, pvslist)
|
||||
free_pv_fid(pvl->pv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pvcreate_single(struct cmd_context *cmd, const char *pv_name,
|
||||
|
@@ -133,8 +133,11 @@ static int _create_maps(struct dm_pool *mem, struct dm_list *pvs, struct dm_list
|
||||
struct pv_list *pvl;
|
||||
|
||||
dm_list_iterate_items(pvl, pvs) {
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV))
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV) ||
|
||||
(pvl->pv->status & PV_ALLOCATION_PROHIBITED)) {
|
||||
pvl->pv->status &= ~PV_ALLOCATION_PROHIBITED;
|
||||
continue;
|
||||
}
|
||||
if (is_missing_pv(pvl->pv))
|
||||
continue;
|
||||
assert(pvl->pv->dev);
|
||||
|
@@ -1040,8 +1040,8 @@ int lv_raid_change_image_count(struct logical_volume *lv,
|
||||
/*
|
||||
* LV must be either in-active or exclusively active
|
||||
*/
|
||||
if (lv_is_active(lv) && vg_is_clustered(lv->vg) &&
|
||||
!lv_is_active_exclusive_locally(lv)) {
|
||||
if (lv_is_active(lv_lock_holder(lv)) && vg_is_clustered(lv->vg) &&
|
||||
!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
|
||||
log_error("%s/%s must be active exclusive locally to"
|
||||
" perform this operation.", lv->vg->name, lv->name);
|
||||
return 0;
|
||||
@@ -1149,12 +1149,6 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!resume_lv(lv->vg->cmd, lv_lock_holder(lv))) {
|
||||
log_error("Failed to resume %s/%s after committing changes",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First activate the newly split LV and LVs on the removal list.
|
||||
* This is necessary so that there are no name collisions due to
|
||||
@@ -1168,6 +1162,18 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
if (!activate_lv_excl_local(cmd, lvl->lv))
|
||||
return_0;
|
||||
|
||||
if (!resume_lv(cmd, lv_lock_holder(lv))) {
|
||||
log_error("Failed to resume %s/%s after committing changes",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since newly split LV is typically already active - we need to call
|
||||
* suspend() and resume() to also rename it.
|
||||
*
|
||||
* TODO: activate should recognize it and avoid these 2 calls
|
||||
*/
|
||||
|
||||
/*
|
||||
* Eliminate the residual LVs
|
||||
@@ -1393,7 +1399,7 @@ static int _convert_mirror_to_raid1(struct logical_volume *lv,
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; ++s) {
|
||||
if (!(new_name = _generate_raid_name(seg_lv(seg, s), "rimage", s)))
|
||||
if (!(new_name = _generate_raid_name(lv, "rimage", s)))
|
||||
return_0;
|
||||
log_debug_metadata("Renaming %s to %s", seg_lv(seg, s)->name, new_name);
|
||||
seg_lv(seg, s)->name = new_name;
|
||||
@@ -1529,6 +1535,29 @@ has_enough_space:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _avoid_pvs_of_lv(struct logical_volume *lv, void *data)
|
||||
{
|
||||
struct dm_list *allocate_pvs = (struct dm_list *) data;
|
||||
struct pv_list *pvl;
|
||||
|
||||
dm_list_iterate_items(pvl, allocate_pvs)
|
||||
if (!(lv->status & PARTIAL_LV) &&
|
||||
lv_is_on_pv(lv, pvl->pv))
|
||||
pvl->pv->status |= PV_ALLOCATION_PROHIBITED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent any PVs holding other image components of @lv from being used for allocation
|
||||
* by setting the internal PV_ALLOCATION_PROHIBITED flag to use it to avoid generating
|
||||
* pv maps for those PVs.
|
||||
*/
|
||||
static int _avoid_pvs_with_other_images_of_lv(struct logical_volume *lv, struct dm_list *allocate_pvs)
|
||||
{
|
||||
return for_each_sub_lv(lv, _avoid_pvs_of_lv, allocate_pvs);
|
||||
}
|
||||
|
||||
/*
|
||||
* lv_raid_replace
|
||||
* @lv
|
||||
@@ -1627,6 +1656,13 @@ int lv_raid_replace(struct logical_volume *lv,
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent any PVs holding image components from being used for allocation */
|
||||
if (!_avoid_pvs_with_other_images_of_lv(lv, allocate_pvs)) {
|
||||
log_error("Failed to prevent PVs holding image components "
|
||||
"from being used for allocation.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the new image components first
|
||||
* - This makes it easy to avoid all currently used devs
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user