mirror of
git://sourceware.org/git/lvm2.git
synced 2026-01-20 08:32:49 +03:00
Compare commits
590 Commits
v2_03_06
...
dev-dct-wr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6e67d688e | ||
|
|
05d23b2dd8 | ||
|
|
5a94126e7a | ||
|
|
c96645781c | ||
|
|
020d1edaa0 | ||
|
|
830c20d33c | ||
|
|
2c31939827 | ||
|
|
7bafae48bb | ||
|
|
e793f34eb7 | ||
|
|
b033384135 | ||
|
|
2183af62e5 | ||
|
|
edb55b767a | ||
|
|
413c88116d | ||
|
|
9740e98cbd | ||
|
|
be94410446 | ||
|
|
8c2779ba34 | ||
|
|
51a532719c | ||
|
|
73ef86ae3f | ||
|
|
6226512ad2 | ||
|
|
f3b723cd8d | ||
|
|
a7f195b7e8 | ||
|
|
677f829e54 | ||
|
|
c7311d4722 | ||
|
|
b3cdf0d881 | ||
|
|
2c9bb67604 | ||
|
|
c74ccd5201 | ||
|
|
c601ec0d6e | ||
|
|
83d0818523 | ||
|
|
6be29e1179 | ||
|
|
fdec4cd3e6 | ||
|
|
bd272e3bce | ||
|
|
756066a2e8 | ||
|
|
3e06061d82 | ||
|
|
a17ec7e0ba | ||
|
|
b75c2dfe1b | ||
|
|
b2a326b511 | ||
|
|
4b0565b82f | ||
|
|
4c1caa7e26 | ||
|
|
58976ccc34 | ||
|
|
d2bdad28d1 | ||
|
|
b50134dc14 | ||
|
|
616e5b854c | ||
|
|
53db14171c | ||
|
|
ee43ec5782 | ||
|
|
99b6173f10 | ||
|
|
5e26a2b74d | ||
|
|
8d9b4c624f | ||
|
|
73a3a0d347 | ||
|
|
117fc64e6e | ||
|
|
1b8c6f09bc | ||
|
|
e1af80c81c | ||
|
|
dd8212365d | ||
|
|
e7fff97b8d | ||
|
|
c65d3a6b8a | ||
|
|
7396f1cfee | ||
|
|
b44db5d1a7 | ||
|
|
b3c7a2b3f0 | ||
|
|
0fe58fc54f | ||
|
|
41f9e372c0 | ||
|
|
9885c9b43a | ||
|
|
2df7ef58a5 | ||
|
|
ae96a43f05 | ||
|
|
91f869e43c | ||
|
|
0143c7aebe | ||
|
|
74ed6e8a99 | ||
|
|
450f272b31 | ||
|
|
ff3945777b | ||
|
|
c32d7fed4f | ||
|
|
d1b7438c9f | ||
|
|
46e5908759 | ||
|
|
2272a32e6f | ||
|
|
82e270c18a | ||
|
|
af8044da3a | ||
|
|
6728788bf5 | ||
|
|
0c89c5a40f | ||
|
|
bd0d4de4e2 | ||
|
|
4cd356b26b | ||
|
|
18c74666ee | ||
|
|
4de6f58085 | ||
|
|
92c0e8c17f | ||
|
|
08e838f488 | ||
|
|
af5f29c7e2 | ||
|
|
3ed11170da | ||
|
|
655342427d | ||
|
|
168e2ffbcd | ||
|
|
fb96e9ab21 | ||
|
|
df6f16c081 | ||
|
|
da14cf68cb | ||
|
|
890c7ef451 | ||
|
|
8952dcbff0 | ||
|
|
bbc164991a | ||
|
|
a89ac3bf6f | ||
|
|
ccb58c109f | ||
|
|
3e003320a7 | ||
|
|
e2577c037d | ||
|
|
e414ebef6e | ||
|
|
2bfa868f91 | ||
|
|
8b22e38087 | ||
|
|
ef59c83f2d | ||
|
|
e2eb1dc501 | ||
|
|
fc9e732811 | ||
|
|
502b895bb4 | ||
|
|
39cdc1469d | ||
|
|
cfc4dd4c7c | ||
|
|
90c50c1b53 | ||
|
|
50a37948b5 | ||
|
|
7c19186271 | ||
|
|
3869c9c4f6 | ||
|
|
e280f56dd3 | ||
|
|
adead83dc2 | ||
|
|
cbed63eeb9 | ||
|
|
3a3307c0d8 | ||
|
|
f38b7afd62 | ||
|
|
642ef54399 | ||
|
|
e08a0421a3 | ||
|
|
5bc66532c7 | ||
|
|
bc9bb534ff | ||
|
|
f507a2564c | ||
|
|
f2878a801c | ||
|
|
531a475afc | ||
|
|
a1074da20d | ||
|
|
e556c7b7c6 | ||
|
|
6c769eb460 | ||
|
|
6b168afcad | ||
|
|
f63aac5309 | ||
|
|
f7c58c636d | ||
|
|
8e3e2c74ed | ||
|
|
530fc17b38 | ||
|
|
1404e5ee61 | ||
|
|
1570e76233 | ||
|
|
4b07ae55f1 | ||
|
|
9fbcba1c40 | ||
|
|
9448476202 | ||
|
|
206620018e | ||
|
|
048e04e417 | ||
|
|
b77595ac8b | ||
|
|
a4137412bf | ||
|
|
8d40859e29 | ||
|
|
a5e867139d | ||
|
|
7f019f2580 | ||
|
|
72b931d664 | ||
|
|
46f43589d0 | ||
|
|
491eb25832 | ||
|
|
37bcd7ce84 | ||
|
|
52d3c4de6e | ||
|
|
49292bccc3 | ||
|
|
2c6bd480b2 | ||
|
|
cf4fed3761 | ||
|
|
d0ccb2521b | ||
|
|
2b36542f41 | ||
|
|
d588de77aa | ||
|
|
ec4e8b5c0e | ||
|
|
7bcc994776 | ||
|
|
7b08133844 | ||
|
|
6d344b4ac0 | ||
|
|
187cc8d344 | ||
|
|
39198eb2ce | ||
|
|
18a60c6340 | ||
|
|
9c0d11ecc9 | ||
|
|
1005fd7b06 | ||
|
|
57e1e037b6 | ||
|
|
64c8827cf3 | ||
|
|
b2978efbff | ||
|
|
c285bf2f37 | ||
|
|
27383a4b3d | ||
|
|
2101e324f9 | ||
|
|
fe77d1a710 | ||
|
|
3008e1be08 | ||
|
|
17dbb24f7c | ||
|
|
7bd015861d | ||
|
|
a940979ff7 | ||
|
|
740d5bf6cd | ||
|
|
a5d45b237d | ||
|
|
a9cb96f146 | ||
|
|
463a61e62e | ||
|
|
93e252c4a3 | ||
|
|
f84a7266bc | ||
|
|
c9b40083fc | ||
|
|
f233d9a909 | ||
|
|
77fdc17d70 | ||
|
|
7db124774a | ||
|
|
223b75ee91 | ||
|
|
d71199920f | ||
|
|
c38c4d9d36 | ||
|
|
9f78acfee9 | ||
|
|
b798554a20 | ||
|
|
3f2e9e3546 | ||
|
|
49d2b27a68 | ||
|
|
3dcd61d3d7 | ||
|
|
678951f635 | ||
|
|
e7bd3ba22d | ||
|
|
bc09803628 | ||
|
|
e7f5acdfa6 | ||
|
|
6d392776b0 | ||
|
|
1f54129c4e | ||
|
|
0210c7076d | ||
|
|
763342016c | ||
|
|
af33a00847 | ||
|
|
a8ea1817ab | ||
|
|
bb62af5b3d | ||
|
|
676ce47754 | ||
|
|
8dea63d30f | ||
|
|
ce5ea07411 | ||
|
|
3388e19489 | ||
|
|
3e6bb77228 | ||
|
|
8d6f1f9768 | ||
|
|
dddf63ebc3 | ||
|
|
10fc3610c4 | ||
|
|
76b1f43e81 | ||
|
|
d8bb85d963 | ||
|
|
f5a669f314 | ||
|
|
8b9028bbe7 | ||
|
|
d1019a6434 | ||
|
|
9a7b81fb72 | ||
|
|
739827ef1c | ||
|
|
ed249a2c53 | ||
|
|
47b5fb138c | ||
|
|
f2c1de783c | ||
|
|
9a06700017 | ||
|
|
fa1290f40e | ||
|
|
38d460ed6e | ||
|
|
ada5728c72 | ||
|
|
bc13c7d246 | ||
|
|
672d5ad98b | ||
|
|
11f08dacc9 | ||
|
|
66803586ef | ||
|
|
1ff1e86deb | ||
|
|
4baedfc578 | ||
|
|
a375657092 | ||
|
|
dbb19f6ace | ||
|
|
56c41b7522 | ||
|
|
a481f42630 | ||
|
|
85e2c7e14d | ||
|
|
1705b439b1 | ||
|
|
de837c15a5 | ||
|
|
534760398c | ||
|
|
fd96f1014b | ||
|
|
cc2218b401 | ||
|
|
0f377a04e5 | ||
|
|
2fbc578cfa | ||
|
|
ef389603dd | ||
|
|
f0614e7cf0 | ||
|
|
b722ce2f10 | ||
|
|
19e9c88faf | ||
|
|
ee0cb17608 | ||
|
|
b918afb693 | ||
|
|
7880896f0d | ||
|
|
fd8d926fc5 | ||
|
|
ce202c3b1c | ||
|
|
ff4827ffb1 | ||
|
|
93c9055591 | ||
|
|
03f9cd95b4 | ||
|
|
fb7a3fe8d6 | ||
|
|
ca54afd701 | ||
|
|
e3e04b99f2 | ||
|
|
9a88a9c4ce | ||
|
|
1d0dc74f91 | ||
|
|
46d15b5e4d | ||
|
|
3e9664baca | ||
|
|
7b41ea61b2 | ||
|
|
135d16fbb8 | ||
|
|
231cdd0efb | ||
|
|
4d9f0606be | ||
|
|
c1d136fea3 | ||
|
|
9f8c331760 | ||
|
|
4f44841045 | ||
|
|
d4d060acd5 | ||
|
|
8f1068c02d | ||
|
|
e12bdd591a | ||
|
|
7a507583d9 | ||
|
|
085760992d | ||
|
|
3c9177fdc0 | ||
|
|
119d594788 | ||
|
|
4667c4b35b | ||
|
|
8f421bdd7a | ||
|
|
00c9a788cc | ||
|
|
23774f997e | ||
|
|
286a793c12 | ||
|
|
d0faad0db3 | ||
|
|
9b9bf8786f | ||
|
|
b7f3667ce2 | ||
|
|
fe78cd4082 | ||
|
|
40266faaab | ||
|
|
ad773511c5 | ||
|
|
3f32f9811e | ||
|
|
094d6f80dd | ||
|
|
88b92d4225 | ||
|
|
b7885dbb73 | ||
|
|
cca2a652d1 | ||
|
|
eb06832b37 | ||
|
|
dccaab3d79 | ||
|
|
bc39d5bec6 | ||
|
|
edbc5a62b2 | ||
|
|
6eb9eba59b | ||
|
|
04bba5ea42 | ||
|
|
2cf0f90780 | ||
|
|
3bd9d81b29 | ||
|
|
ae5634a8be | ||
|
|
2aed2a41f7 | ||
|
|
21b37964eb | ||
|
|
950d2d59c1 | ||
|
|
48872b0369 | ||
|
|
a014c4f341 | ||
|
|
8e2938c963 | ||
|
|
9f38e95a2f | ||
|
|
f32e85ae51 | ||
|
|
b528a9ce90 | ||
|
|
9fbad5bb0f | ||
|
|
6ea3654868 | ||
|
|
ba27b9ee2a | ||
|
|
38eaa1035b | ||
|
|
712c9efbf6 | ||
|
|
48c1a295a2 | ||
|
|
a7b2fc8f57 | ||
|
|
d15c466f95 | ||
|
|
1ee42f1391 | ||
|
|
ce772bfab9 | ||
|
|
240062a183 | ||
|
|
8806f2d5ed | ||
|
|
fa9eb76a5d | ||
|
|
b59127a838 | ||
|
|
d14a8040d4 | ||
|
|
ae029fcced | ||
|
|
7b04ed07ba | ||
|
|
5410dd5441 | ||
|
|
be61bd6ff5 | ||
|
|
74a211cfd3 | ||
|
|
bb41ca86fa | ||
|
|
53803821de | ||
|
|
b5811b7c9c | ||
|
|
70a45c44e8 | ||
|
|
d3b515cea5 | ||
|
|
deb5160181 | ||
|
|
16da6651a1 | ||
|
|
cf74123830 | ||
|
|
ce8277b47e | ||
|
|
33fdeaf3f1 | ||
|
|
2a304d7a75 | ||
|
|
5c095400de | ||
|
|
2f29765e7f | ||
|
|
2d1fe38d84 | ||
|
|
33265467f9 | ||
|
|
5263551a2d | ||
|
|
d945b53ff7 | ||
|
|
4047a32128 | ||
|
|
a509776588 | ||
|
|
d79afd4084 | ||
|
|
cc4051eec0 | ||
|
|
3854931aea | ||
|
|
2aa36209eb | ||
|
|
211eaa284c | ||
|
|
d9e8895a96 | ||
|
|
b6b4ad8e28 | ||
|
|
0dd905c959 | ||
|
|
e10f20bc23 | ||
|
|
3dd11d9ea8 | ||
|
|
98e33ee3fb | ||
|
|
06cbe3cfc6 | ||
|
|
e1c2b41265 | ||
|
|
caff31df19 | ||
|
|
e6b93dc24e | ||
|
|
fc32787c1b | ||
|
|
957904933b | ||
|
|
fbdcc45255 | ||
|
|
dd0fdd846d | ||
|
|
a5b1b52903 | ||
|
|
c9526e859e | ||
|
|
f439716b75 | ||
|
|
b3fa71fbd8 | ||
|
|
212cf8efbd | ||
|
|
caecbcbeac | ||
|
|
4b5bfa779a | ||
|
|
f6667f94cb | ||
|
|
1b711b955d | ||
|
|
f140620043 | ||
|
|
c6746181a3 | ||
|
|
1b79673845 | ||
|
|
b19b7b6111 | ||
|
|
f50e7ce76c | ||
|
|
c392ccaa47 | ||
|
|
9532bb577a | ||
|
|
d02d7bc560 | ||
|
|
84eab461c8 | ||
|
|
81d0333067 | ||
|
|
2284f845b0 | ||
|
|
8153c5f1e6 | ||
|
|
4829f27b76 | ||
|
|
db1d66859f | ||
|
|
cba06012ac | ||
|
|
892a182975 | ||
|
|
25b97e522d | ||
|
|
b9752d719c | ||
|
|
3716aa848e | ||
|
|
8f794f2095 | ||
|
|
744b75f881 | ||
|
|
b756cb3e49 | ||
|
|
96985b1373 | ||
|
|
ffea7daec3 | ||
|
|
2a6078f961 | ||
|
|
9255c7148a | ||
|
|
aa7642a444 | ||
|
|
336361b2f2 | ||
|
|
67f627c8fb | ||
|
|
409362c127 | ||
|
|
e6a3c09017 | ||
|
|
4791d0f035 | ||
|
|
91d16fc049 | ||
|
|
d01f27f411 | ||
|
|
bcfe4993e5 | ||
|
|
555d6d4e62 | ||
|
|
d6ac039b65 | ||
|
|
de43527f94 | ||
|
|
c5e5ae4c95 | ||
|
|
1bde35e596 | ||
|
|
ac38b576f9 | ||
|
|
62ad12d0d0 | ||
|
|
c0de37ab18 | ||
|
|
c1ee6f0eef | ||
|
|
379a7e1288 | ||
|
|
adbb0a8d5b | ||
|
|
64a82a1c79 | ||
|
|
bddbbcb98c | ||
|
|
2444e830a9 | ||
|
|
8810c11bc9 | ||
|
|
7404216241 | ||
|
|
bab3b70e3a | ||
|
|
ecb77e9db3 | ||
|
|
cf844941d4 | ||
|
|
d7bf7091c3 | ||
|
|
7078dd01e8 | ||
|
|
d53bfae273 | ||
|
|
2f6d0a6408 | ||
|
|
151bf52649 | ||
|
|
30f4d0fcd4 | ||
|
|
5ccf3e6f30 | ||
|
|
7737ffb11c | ||
|
|
dad2660a38 | ||
|
|
c496ba6505 | ||
|
|
c3ef41f620 | ||
|
|
87e88078c9 | ||
|
|
a2a993d995 | ||
|
|
2173bdb821 | ||
|
|
2da6f01c15 | ||
|
|
4a52855899 | ||
|
|
611d4107a4 | ||
|
|
3b6defcf1f | ||
|
|
8ab1d489f3 | ||
|
|
89d839e541 | ||
|
|
abc0a8faba | ||
|
|
5555765cfc | ||
|
|
cff16b062b | ||
|
|
e70d5d470c | ||
|
|
4353823306 | ||
|
|
df0bc5081c | ||
|
|
338f4df54b | ||
|
|
3f381784f2 | ||
|
|
ec71df6fec | ||
|
|
91f91b80f1 | ||
|
|
3d7f755674 | ||
|
|
0a7495e680 | ||
|
|
5a88b2ce7f | ||
|
|
3145a85583 | ||
|
|
2e0f273008 | ||
|
|
d051e899a5 | ||
|
|
9cf08836ef | ||
|
|
53126ceada | ||
|
|
94076245df | ||
|
|
74ad2cd76f | ||
|
|
13c629fb78 | ||
|
|
39bd9b111b | ||
|
|
4485b8edca | ||
|
|
657d42e879 | ||
|
|
595aa1d452 | ||
|
|
98a8099da9 | ||
|
|
b400353c71 | ||
|
|
a61272a6f0 | ||
|
|
0c1316cda8 | ||
|
|
56a295f78c | ||
|
|
29db9c6325 | ||
|
|
2037476008 | ||
|
|
1c9b36618e | ||
|
|
bbd8badaef | ||
|
|
b690258518 | ||
|
|
4757ce4c2a | ||
|
|
1e669ab315 | ||
|
|
7474440d3b | ||
|
|
f88f7c0fdc | ||
|
|
496c368528 | ||
|
|
dccc50f6f6 | ||
|
|
7ea71a9eb9 | ||
|
|
31a862a6be | ||
|
|
91df257b53 | ||
|
|
e92d3bd1f7 | ||
|
|
14e01d6316 | ||
|
|
1760b96368 | ||
|
|
9af1d63b4d | ||
|
|
33c1d2e921 | ||
|
|
ad0343d8cb | ||
|
|
9ee3af7efc | ||
|
|
cbabdf2fca | ||
|
|
1da5fd8226 | ||
|
|
61a483a654 | ||
|
|
c38be06531 | ||
|
|
1349a52626 | ||
|
|
219fe72359 | ||
|
|
d4d82dbb70 | ||
|
|
70fb31b5d6 | ||
|
|
1f4968289c | ||
|
|
d67ce9e140 | ||
|
|
0bad3977df | ||
|
|
153e55c20e | ||
|
|
44bf9c9a6a | ||
|
|
82e6b820b8 | ||
|
|
43f149526d | ||
|
|
33c8e4de33 | ||
|
|
13c254fc05 | ||
|
|
9cad26be32 | ||
|
|
38617213f0 | ||
|
|
08f36dd093 | ||
|
|
3b05fd4d07 | ||
|
|
ba313ac84a | ||
|
|
1cc1333599 | ||
|
|
cc865749ae | ||
|
|
43db8f8d5d | ||
|
|
30a23a1941 | ||
|
|
8679d45917 | ||
|
|
e184f77109 | ||
|
|
8263e62b00 | ||
|
|
c67a03727b | ||
|
|
dbaa4cdcdf | ||
|
|
5f064e2221 | ||
|
|
c935f8a327 | ||
|
|
d1c5b3ae74 | ||
|
|
569e328cc0 | ||
|
|
cca5aec0ef | ||
|
|
50b50039d9 | ||
|
|
8689b4ed82 | ||
|
|
3d9fc7d6f3 | ||
|
|
c21440536d | ||
|
|
ab315e7a81 | ||
|
|
80b2de9e6a | ||
|
|
8b3cf53e24 | ||
|
|
508d1808b0 | ||
|
|
f91df163e2 | ||
|
|
f961311436 | ||
|
|
1bbf977577 | ||
|
|
4dcb36aba4 | ||
|
|
f56b21ae2c | ||
|
|
9e15c83673 | ||
|
|
b7aab9ba59 | ||
|
|
89373761c8 | ||
|
|
ed7e365ae5 | ||
|
|
5971da2c72 | ||
|
|
455498f206 | ||
|
|
c786636afb | ||
|
|
e1d3a6c552 | ||
|
|
df2292020b | ||
|
|
5b224d58f7 | ||
|
|
6204955347 | ||
|
|
9d2ef05c5d | ||
|
|
ceb808d26f | ||
|
|
c5f4f2efb6 | ||
|
|
69d4847975 | ||
|
|
293f6d2795 | ||
|
|
a4666f63ad | ||
|
|
b8d4969117 | ||
|
|
22a22a735f | ||
|
|
62136c056a | ||
|
|
12c47e0c98 | ||
|
|
75628a5f4c | ||
|
|
bafe5d15b1 | ||
|
|
b7c64fe8e2 | ||
|
|
b0286fa127 | ||
|
|
1839702cb4 | ||
|
|
df38eb49ab | ||
|
|
25e7bf021a | ||
|
|
7e8296f478 | ||
|
|
2b3c39e402 | ||
|
|
5fdebf9bbf | ||
|
|
6b0d969b2a | ||
|
|
2938b4dcca | ||
|
|
6163b733e1 | ||
|
|
e88fd2edfd | ||
|
|
0e5f39a5ac | ||
|
|
855b16ce14 | ||
|
|
9968be55ed | ||
|
|
6a8bd0c509 | ||
|
|
221edf4030 | ||
|
|
0ba260e397 | ||
|
|
c8b01f33a6 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -30,7 +30,7 @@ make.tmpl
|
||||
/config.log
|
||||
/config.status
|
||||
/configure.scan
|
||||
/cscope.out
|
||||
/cscope.*
|
||||
/html/
|
||||
/reports/
|
||||
/tags
|
||||
@@ -38,6 +38,10 @@ make.tmpl
|
||||
|
||||
coverity/coverity_model.xml
|
||||
|
||||
# gcov files:
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
tools/man-generator
|
||||
tools/man-generator.c
|
||||
|
||||
|
||||
11
README
11
README
@@ -1,7 +1,6 @@
|
||||
This tree contains the LVM2 and device-mapper tools and libraries.
|
||||
|
||||
This is development branch, for stable 2.02 release see 2018-06-01-stable
|
||||
branch.
|
||||
This is development branch, for stable 2.02 release see stable-2.02 branch.
|
||||
|
||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
|
||||
Installation instructions are in INSTALL.
|
||||
@@ -10,7 +9,6 @@ There is no warranty - see COPYING and COPYING.LIB.
|
||||
|
||||
Tarballs are available from:
|
||||
ftp://sourceware.org/pub/lvm2/
|
||||
ftp://sources.redhat.com/pub/lvm2/
|
||||
https://github.com/lvmteam/lvm2/releases
|
||||
|
||||
The source code is stored in git:
|
||||
@@ -45,6 +43,9 @@ Report upstream bugs at:
|
||||
or open issues at:
|
||||
https://github.com/lvmteam/lvm2/issues
|
||||
|
||||
The source code repository used until 7th June 2012 is accessible here:
|
||||
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/?cvsroot=lvm2.
|
||||
The source code repository used until 7th June 2012 is accessible using CVS:
|
||||
|
||||
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 login cvs
|
||||
cvs -d :pserver:cvs@sourceware.org:/cvs/lvm2 checkout LVM2
|
||||
|
||||
The password is cvs.
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.165 (2019-10-23)
|
||||
1.02.175-git (2020-08-09)
|
||||
|
||||
75
WHATS_NEW
75
WHATS_NEW
@@ -1,3 +1,78 @@
|
||||
Version 2.03.11 -
|
||||
==================================
|
||||
Enhance error handling for fsadm and hanled correct fsck result.
|
||||
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
|
||||
Support using BLKZEROOUT for clearing devices.
|
||||
Support interruption when wipping LVs.
|
||||
Support interruption for bcache waiting.
|
||||
Fix bcache when device has too many failing writes.
|
||||
Fix bcache waiting for IO completion with failing disks.
|
||||
Configure use own python path name order to prefer using python3.
|
||||
Add configure --enable-editline support as an alternative to readline.
|
||||
Enhance reporting and error handling when creating thin volumes.
|
||||
Enable vgsplit for VDO volumes.
|
||||
Lvextend of vdo pool volumes ensure at least 1 new VDO slab is added.
|
||||
Use revert_lv() on reload error path after vg_revert().
|
||||
Configure --with-integrity enabled.
|
||||
Restore lost signal blocking while VG lock is held.
|
||||
Improve estimation of needed extents when creating thin-pool.
|
||||
Use extra 1% when resizing thin-pool metadata LV with --use-policy.
|
||||
Enhance --use-policy percentage rounding.
|
||||
Configure --with-vdo and --with-writecache as internal segments.
|
||||
Improving VDO man page examples.
|
||||
Switch code base to use flexible array syntax.
|
||||
Fix 64bit math when calculation cachevol size.
|
||||
Preserve uint32_t for seqno handling.
|
||||
Switch from mmap to plain read when loading regular files.
|
||||
Update lvmvdo man page and better explain DISCARD usage.
|
||||
|
||||
Version 2.03.10 - 09th August 2020
|
||||
==================================
|
||||
Add writecache and integrity support to lvmdbusd.
|
||||
Generate unique cachevol name when default required from lvcreate.
|
||||
Converting RAID1 volume to one with same number of legs now succeeds with a
|
||||
warning.
|
||||
Fix conversion to raid from striped lagging type.
|
||||
Fix conversion to 'mirrored' mirror log with larger regionsize.
|
||||
Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
|
||||
Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
|
||||
Add lvcreate of new cache or writecache lv with single command.
|
||||
Fix running out of free buffers for async writing for larger writes.
|
||||
Add integrity with raid capability.
|
||||
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
|
||||
|
||||
Version 2.03.09 - 26th March 2020
|
||||
=================================
|
||||
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
|
||||
Fix showing of a dm kernel error when uncaching a volume with cachevol.
|
||||
|
||||
Version 2.03.08 - 11th February 2020
|
||||
====================================
|
||||
Prevent problematic snapshots of writecache volumes.
|
||||
Add error handling for failing allocation in _reserve_area().
|
||||
Fix memleak in syncing of internal cache.
|
||||
Fix pvck dump_current_text memleak.
|
||||
Fix lvmlockd result code on error path for _query_lock_lv().
|
||||
Update pvck man page and help output.
|
||||
Reject invalid writecache high/low_watermark setting.
|
||||
Report writecache status.
|
||||
Accept more output lines from vdo_format.
|
||||
Prohibit reshaping of stacked raid LVs.
|
||||
Avoid running cache input arg validation when creating vdo pool.
|
||||
Prevent raid reshaping of stacked volumes.
|
||||
Added VDO lvmdbusd methods for enable/disable compression & dedupe.
|
||||
Added VDO lvmdbusd method for converting LV to VDO pool.
|
||||
|
||||
Version 2.03.07 - 30th November 2019
|
||||
====================================
|
||||
Subcommand in vgck for repairing headers and metadata.
|
||||
Ensure minimum required region size on striped RaidLV creation.
|
||||
Fix resize of thin-pool with data and metadata of different segtype.
|
||||
Improve mirror type leg splitting.
|
||||
Improve error path handling in daemons on shutdown.
|
||||
Fix activation order when removing merged snapshot.
|
||||
Experimental VDO support for lvmdbusd.
|
||||
|
||||
Version 2.03.06 - 23rd October 2019
|
||||
===================================
|
||||
Add _cpool suffix to cache-pool LV name when used by caching LV.
|
||||
|
||||
20
WHATS_NEW_DM
20
WHATS_NEW_DM
@@ -1,3 +1,23 @@
|
||||
Version 1.02.175 -
|
||||
===================================
|
||||
|
||||
Version 1.02.173 - 09th August 2020
|
||||
===================================
|
||||
Add support for VDO in blkdeactivate script.
|
||||
|
||||
Version 1.02.171 - 26th March 2020
|
||||
==================================
|
||||
Try to remove all created devices on dm preload tree error path.
|
||||
Fix dm_list interators with gcc 10 optimization (-ftree-pta).
|
||||
Dmeventd handles timer without looping on short intervals.
|
||||
|
||||
Version 1.02.169 - 11th February 2020
|
||||
=====================================
|
||||
Enhance error messages for device creation.
|
||||
|
||||
Version 1.02.167 - 30th November 2019
|
||||
=====================================
|
||||
|
||||
Version 1.02.165 - 23rd October 2019
|
||||
====================================
|
||||
Add support for DM_DEVICE_GET_TARGET_VERSION.
|
||||
|
||||
16
aclocal.m4
vendored
16
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
||||
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -413,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
|
||||
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
|
||||
])dnl PKG_HAVE_DEFINE_WITH_MODULES
|
||||
|
||||
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -446,10 +446,12 @@ AC_DEFUN([AM_PATH_PYTHON],
|
||||
[
|
||||
dnl Find a Python interpreter. Python versions prior to 2.0 are not
|
||||
dnl supported. (2.0 was released on October 16, 2000).
|
||||
dnl FIXME: Remove the need to hard-code Python versions here.
|
||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
|
||||
[python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
|
||||
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
|
||||
[python python2 python3 dnl
|
||||
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 dnl
|
||||
python3.2 python3.1 python3.0 dnl
|
||||
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 dnl
|
||||
python2.0])
|
||||
|
||||
AC_ARG_VAR([PYTHON], [the Python interpreter])
|
||||
|
||||
@@ -649,7 +651,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
|
||||
sys.exit(sys.hexversion < minverhex)"
|
||||
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
||||
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
||||
@@ -22,7 +22,7 @@ struct dm_hash_node {
|
||||
void *data;
|
||||
unsigned data_len;
|
||||
unsigned keylen;
|
||||
char key[0];
|
||||
char key[];
|
||||
};
|
||||
|
||||
struct dm_hash_table {
|
||||
@@ -59,26 +59,27 @@ static unsigned char _nums[] = {
|
||||
209
|
||||
};
|
||||
|
||||
static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||
static struct dm_hash_node *_create_node(const void *key, unsigned len)
|
||||
{
|
||||
struct dm_hash_node *n = malloc(sizeof(*n) + len);
|
||||
|
||||
if (n) {
|
||||
memcpy(n->key, str, len);
|
||||
memcpy(n->key, key, len);
|
||||
n->keylen = len;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long _hash(const char *str, unsigned len)
|
||||
static unsigned long _hash(const void *key, unsigned len)
|
||||
{
|
||||
const unsigned char *str = key;
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[(unsigned char) *str++];
|
||||
h += _nums[*str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef BASE_DATA_STRUCT_LIST_H
|
||||
#define BASE_DATA_STRUCT_LIST_H
|
||||
|
||||
#include "base/memory/container_of.h"
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
/*
|
||||
@@ -98,7 +100,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
|
||||
* contained in a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define dm_list_struct_base(v, t, head) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
container_of(v, t, head)
|
||||
|
||||
/*
|
||||
* Given the address v of an instance of 'struct dm_list list' contained in
|
||||
@@ -111,7 +113,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
|
||||
* return another element f.
|
||||
*/
|
||||
#define dm_struct_field(v, t, e, f) \
|
||||
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
|
||||
(((t *)((uintptr_t)(v) - offsetof(t, e)))->f)
|
||||
|
||||
/*
|
||||
* Given the address v of a known element e in a known structure of type t,
|
||||
|
||||
@@ -47,7 +47,7 @@ struct value_chain {
|
||||
struct prefix_chain {
|
||||
struct value child;
|
||||
unsigned len;
|
||||
uint8_t prefix[0];
|
||||
uint8_t prefix[];
|
||||
};
|
||||
|
||||
struct node4 {
|
||||
@@ -1032,7 +1032,7 @@ void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||
{
|
||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
|
||||
_iterate(lr.v, it);
|
||||
(void) _iterate(lr.v, it);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
// Copyright (C) 2018 - 2020 Red Hat, Inc. All rights reserved.
|
||||
//
|
||||
// This file is part of LVM2.
|
||||
//
|
||||
@@ -13,10 +13,12 @@
|
||||
#ifndef BASE_MEMORY_CONTAINER_OF_H
|
||||
#define BASE_MEMORY_CONTAINER_OF_H
|
||||
|
||||
#include <stddef.h> // offsetof
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#define container_of(v, t, head) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
((t *)((char *)(v) - offsetof(t, head)))
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -429,7 +429,8 @@ allocation {
|
||||
|
||||
# Configuration option allocation/cache_pool_metadata_require_separate_pvs.
|
||||
# Cache pool metadata and data will always use different PVs.
|
||||
cache_pool_metadata_require_separate_pvs = 0
|
||||
# This configuration option has an automatic default value.
|
||||
# cache_pool_metadata_require_separate_pvs = 0
|
||||
|
||||
# Configuration option allocation/cache_metadata_format.
|
||||
# Sets default metadata format for new cache.
|
||||
@@ -488,8 +489,9 @@ allocation {
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
|
||||
# Thin pool metdata and data will always use different PVs.
|
||||
thin_pool_metadata_require_separate_pvs = 0
|
||||
# Thin pool metadata and data will always use different PVs.
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_pool_metadata_require_separate_pvs = 0
|
||||
|
||||
# Configuration option allocation/thin_pool_zero.
|
||||
# Thin pool data chunks are zeroed before they are first used.
|
||||
@@ -526,6 +528,11 @@ allocation {
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_pool_chunk_size_policy = "generic"
|
||||
|
||||
# Configuration option allocation/zero_metadata.
|
||||
# Zero whole metadata area before use with thin or cache pool.
|
||||
# This configuration option has an automatic default value.
|
||||
# zero_metadata = 1
|
||||
|
||||
# Configuration option allocation/thin_pool_chunk_size.
|
||||
# The minimal chunk size in KiB for thin pool volumes.
|
||||
# Larger chunk sizes may improve performance for plain thin volumes,
|
||||
@@ -986,7 +993,8 @@ global {
|
||||
# logs and conversion to disk/core works.
|
||||
#
|
||||
# Not supported for regular operation!
|
||||
support_mirrored_mirror_log = 0
|
||||
# This configuration option has an automatic default value.
|
||||
# support_mirrored_mirror_log = 0
|
||||
|
||||
# Configuration option global/raid10_segtype_default.
|
||||
# The segment type used by the -i -m combination.
|
||||
@@ -1044,7 +1052,8 @@ global {
|
||||
# activated from these events (the default is all.)
|
||||
# When event_activation is disabled, the system will generally run
|
||||
# a direct activation command to activate LVs in complete VGs.
|
||||
event_activation = 1
|
||||
# This configuration option has an automatic default value.
|
||||
# event_activation = 1
|
||||
|
||||
# Configuration option global/use_aio.
|
||||
# Use async I/O when reading and writing devices.
|
||||
@@ -1288,7 +1297,8 @@ activation {
|
||||
# This enables additional checks (and if necessary, repairs) on entries
|
||||
# in the device directory after udev has completed processing its
|
||||
# events. Useful for diagnosing problems with LVM/udev interactions.
|
||||
verify_udev_operations = 0
|
||||
# This configuration option has an automatic default value.
|
||||
# verify_udev_operations = 0
|
||||
|
||||
# Configuration option activation/retry_deactivation.
|
||||
# Retry failed LV deactivation.
|
||||
@@ -1313,23 +1323,27 @@ activation {
|
||||
# When disabled, the striped target is used. The linear target is an
|
||||
# optimised version of the striped target that only handles a single
|
||||
# stripe.
|
||||
use_linear_target = 1
|
||||
# This configuration option has an automatic default value.
|
||||
# use_linear_target = 1
|
||||
|
||||
# Configuration option activation/reserved_stack.
|
||||
# Stack size in KiB to reserve for use while devices are suspended.
|
||||
# Insufficent reserve risks I/O deadlock during device suspension.
|
||||
reserved_stack = 64
|
||||
# This configuration option has an automatic default value.
|
||||
# reserved_stack = 64
|
||||
|
||||
# Configuration option activation/reserved_memory.
|
||||
# Memory size in KiB to reserve for use while devices are suspended.
|
||||
# Insufficent reserve risks I/O deadlock during device suspension.
|
||||
reserved_memory = 8192
|
||||
# This configuration option has an automatic default value.
|
||||
# reserved_memory = 8192
|
||||
|
||||
# Configuration option activation/process_priority.
|
||||
# Nice value used while devices are suspended.
|
||||
# Use a high priority so that LVs are suspended
|
||||
# for the shortest possible time.
|
||||
process_priority = -18
|
||||
# This configuration option has an automatic default value.
|
||||
# process_priority = -18
|
||||
|
||||
# Configuration option activation/volume_list.
|
||||
# Only LVs selected by this list are activated.
|
||||
@@ -1446,7 +1460,8 @@ activation {
|
||||
# auto
|
||||
# Use default value chosen by kernel.
|
||||
#
|
||||
readahead = "auto"
|
||||
# This configuration option has an automatic default value.
|
||||
# readahead = "auto"
|
||||
|
||||
# Configuration option activation/raid_fault_policy.
|
||||
# Defines how a device failure in a RAID LV is handled.
|
||||
@@ -1582,7 +1597,8 @@ activation {
|
||||
# 8.4G, it is extended to 14.4G:
|
||||
# vdo_pool_autoextend_threshold = 70
|
||||
#
|
||||
vdo_pool_autoextend_threshold = 100
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_pool_autoextend_threshold = 100
|
||||
|
||||
# Configuration option activation/vdo_pool_autoextend_percent.
|
||||
# Auto-extending a VDO pool adds this percent extra space.
|
||||
@@ -1618,7 +1634,8 @@ activation {
|
||||
# Use the old behavior of mlockall to pin all memory.
|
||||
# Prior to version 2.02.62, LVM used mlockall() to pin the whole
|
||||
# process's memory while activating devices.
|
||||
use_mlockall = 0
|
||||
# This configuration option has an automatic default value.
|
||||
# use_mlockall = 0
|
||||
|
||||
# Configuration option activation/monitoring.
|
||||
# Monitor LVs that are activated.
|
||||
@@ -1633,7 +1650,8 @@ activation {
|
||||
# intervals of this number of seconds. If this is set to 0 and there
|
||||
# is only one thing to wait for, there are no progress reports, but
|
||||
# the process is awoken immediately once the operation is complete.
|
||||
polling_interval = 15
|
||||
# This configuration option has an automatic default value.
|
||||
# polling_interval = 15
|
||||
|
||||
# Configuration option activation/auto_set_activation_skip.
|
||||
# Set the activation skip flag on new thin snapshot LVs.
|
||||
@@ -2189,7 +2207,8 @@ dmeventd {
|
||||
# failures. It removes failed devices from a volume group and
|
||||
# reconfigures a mirror as necessary. If no mirror library is
|
||||
# provided, mirrors are not monitored through dmeventd.
|
||||
mirror_library = "libdevmapper-event-lvm2mirror.so"
|
||||
# This configuration option has an automatic default value.
|
||||
# mirror_library = "libdevmapper-event-lvm2mirror.so"
|
||||
|
||||
# Configuration option dmeventd/raid_library.
|
||||
# This configuration option has an automatic default value.
|
||||
@@ -2200,14 +2219,16 @@ dmeventd {
|
||||
# libdevmapper-event-lvm2snapshot.so monitors the filling of snapshots
|
||||
# and emits a warning through syslog when the usage exceeds 80%. The
|
||||
# warning is repeated when 85%, 90% and 95% of the snapshot is filled.
|
||||
snapshot_library = "libdevmapper-event-lvm2snapshot.so"
|
||||
# This configuration option has an automatic default value.
|
||||
# snapshot_library = "libdevmapper-event-lvm2snapshot.so"
|
||||
|
||||
# Configuration option dmeventd/thin_library.
|
||||
# The library dmeventd uses when monitoring a thin device.
|
||||
# libdevmapper-event-lvm2thin.so monitors the filling of a pool
|
||||
# and emits a warning through syslog when the usage exceeds 80%. The
|
||||
# warning is repeated when 85%, 90% and 95% of the pool is filled.
|
||||
thin_library = "libdevmapper-event-lvm2thin.so"
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_library = "libdevmapper-event-lvm2thin.so"
|
||||
|
||||
# Configuration option dmeventd/thin_command.
|
||||
# The plugin runs command with each 5% increment when thin-pool data volume
|
||||
|
||||
227
configure
vendored
227
configure
vendored
@@ -753,6 +753,8 @@ BUILD_CMIRRORD
|
||||
BLKID_PC
|
||||
MODPROBE_CMD
|
||||
MSGFMT
|
||||
EDITLINE_LIBS
|
||||
EDITLINE_CFLAGS
|
||||
PYTHON3_CONFIG
|
||||
pkgpyexecdir
|
||||
pyexecdir
|
||||
@@ -918,7 +920,9 @@ enable_cache_check_needs_check
|
||||
with_vdo
|
||||
with_vdo_format
|
||||
with_writecache
|
||||
with_integrity
|
||||
enable_readline
|
||||
enable_editline
|
||||
enable_realtime
|
||||
enable_ocf
|
||||
with_ocfdir
|
||||
@@ -959,6 +963,7 @@ enable_fsadm
|
||||
enable_blkdeactivate
|
||||
enable_dmeventd
|
||||
enable_selinux
|
||||
enable_blkzeroout
|
||||
enable_nls
|
||||
with_localedir
|
||||
with_confdir
|
||||
@@ -1014,7 +1019,9 @@ SYSTEMD_CFLAGS
|
||||
SYSTEMD_LIBS
|
||||
UDEV_CFLAGS
|
||||
UDEV_LIBS
|
||||
PYTHON'
|
||||
PYTHON
|
||||
EDITLINE_CFLAGS
|
||||
EDITLINE_LIBS'
|
||||
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@@ -1637,6 +1644,7 @@ Optional Features:
|
||||
--disable-cache_check_needs_check
|
||||
required if cache_check version is < 0.5
|
||||
--disable-readline disable readline support
|
||||
--enable-editline enable editline support
|
||||
--disable-realtime disable realtime clock support
|
||||
--enable-ocf enable Open Cluster Framework (OCF) compliant
|
||||
resource agents
|
||||
@@ -1677,6 +1685,7 @@ Optional Features:
|
||||
--disable-blkdeactivate disable blkdeactivate
|
||||
--enable-dmeventd enable the device-mapper event daemon
|
||||
--disable-selinux disable selinux support
|
||||
--disable-blkzeroout do not use BLKZEROOUT for device zeroing
|
||||
--enable-nls enable Native Language Support
|
||||
|
||||
Optional Packages:
|
||||
@@ -1715,15 +1724,16 @@ Optional Packages:
|
||||
cache_restore tool: [autodetect]
|
||||
--with-vdo=TYPE vdo support: internal/none [internal]
|
||||
--with-vdo-format=PATH vdoformat tool: [autodetect]
|
||||
--with-writecache=TYPE writecache support: internal/none [none]
|
||||
--with-writecache=TYPE writecache support: internal/none [internal]
|
||||
--with-integrity=TYPE integrity support: internal/none [internal]
|
||||
--with-ocfdir=DIR install OCF files in
|
||||
[PREFIX/lib/ocf/resource.d/lvm2]
|
||||
--with-default-pid-dir=PID_DIR
|
||||
Default directory to keep PID files in. [autodetect]
|
||||
default directory to keep PID files in [autodetect]
|
||||
--with-default-dm-run-dir=DM_RUN_DIR
|
||||
Default DM run directory. [autodetect]
|
||||
default DM run directory [autodetect]
|
||||
--with-default-run-dir=RUN_DIR
|
||||
Default LVM run directory. [autodetect_run_dir/lvm]
|
||||
default LVM run directory [autodetect_run_dir/lvm]
|
||||
--with-cmirrord-pidfile=PATH
|
||||
cmirrord pidfile [PID_DIR/cmirrord.pid]
|
||||
--with-optimisation=OPT C optimisation flag [OPT=-O2]
|
||||
@@ -1814,6 +1824,10 @@ Some influential environment variables:
|
||||
UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config
|
||||
UDEV_LIBS linker flags for UDEV, overriding pkg-config
|
||||
PYTHON the Python interpreter
|
||||
EDITLINE_CFLAGS
|
||||
C compiler flags for EDITLINE, overriding pkg-config
|
||||
EDITLINE_LIBS
|
||||
linker flags for EDITLINE, overriding pkg-config
|
||||
|
||||
Use these variables to override the choices made by `configure' or to help
|
||||
it to find libraries and programs with nonstandard names/locations.
|
||||
@@ -9584,7 +9598,7 @@ $as_echo_n "checking whether to include vdo... " >&6; }
|
||||
if test "${with_vdo+set}" = set; then :
|
||||
withval=$with_vdo; VDO=$withval
|
||||
else
|
||||
VDO="none"
|
||||
VDO="internal"
|
||||
fi
|
||||
|
||||
|
||||
@@ -9744,7 +9758,7 @@ $as_echo_n "checking whether to include writecache... " >&6; }
|
||||
if test "${with_writecache+set}" = set; then :
|
||||
withval=$with_writecache; WRITECACHE=$withval
|
||||
else
|
||||
WRITECACHE="none"
|
||||
WRITECACHE="internal"
|
||||
fi
|
||||
|
||||
|
||||
@@ -9761,6 +9775,31 @@ $as_echo "#define WRITECACHE_INTERNAL 1" >>confdefs.h
|
||||
*) as_fn_error $? "--with-writecache parameter invalid" "$LINENO" 5 ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include integrity" >&5
|
||||
$as_echo_n "checking whether to include integrity... " >&6; }
|
||||
|
||||
# Check whether --with-integrity was given.
|
||||
if test "${with_integrity+set}" = set; then :
|
||||
withval=$with_integrity; INTEGRITY=$withval
|
||||
else
|
||||
INTEGRITY="internal"
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INTEGRITY" >&5
|
||||
$as_echo "$INTEGRITY" >&6; }
|
||||
|
||||
case "$INTEGRITY" in
|
||||
none) ;;
|
||||
internal)
|
||||
|
||||
$as_echo "#define INTEGRITY_INTERNAL 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
*) as_fn_error $? "--with-integrity parameter invalid" "$LINENO" 5 ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
# Check whether --enable-readline was given.
|
||||
if test "${enable_readline+set}" = set; then :
|
||||
@@ -9770,6 +9809,15 @@ else
|
||||
fi
|
||||
|
||||
|
||||
################################################################################
|
||||
# Check whether --enable-editline was given.
|
||||
if test "${enable_editline+set}" = set; then :
|
||||
enableval=$enable_editline; EDITLINE=$enableval
|
||||
else
|
||||
EDITLINE=no
|
||||
fi
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable realtime support" >&5
|
||||
$as_echo_n "checking whether to enable realtime support... " >&6; }
|
||||
@@ -11797,6 +11845,7 @@ if test "$BUILD_LVMDBUSD" = yes; then
|
||||
|
||||
|
||||
|
||||
|
||||
if test -n "$PYTHON"; then
|
||||
# If the user set $PYTHON, use it and don't search something else.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 3" >&5
|
||||
@@ -11832,7 +11881,7 @@ if ${am_cv_pathless_PYTHON+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
|
||||
for am_cv_pathless_PYTHON in python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
|
||||
for am_cv_pathless_PYTHON in python3 python2 python python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
|
||||
test "$am_cv_pathless_PYTHON" = none && break
|
||||
prog="import sys
|
||||
# split strings by '.' and convert to numeric. Append some zeros
|
||||
@@ -12661,6 +12710,61 @@ fi
|
||||
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BLKZEROOUT in sys/ioctl.h." >&5
|
||||
$as_echo_n "checking for BLKZEROOUT in sys/ioctl.h.... " >&6; }
|
||||
if ${ac_cv_have_blkzeroout+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
int bar(void) { return ioctl(0, BLKZEROOUT, 0); }
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
ac_cv_have_blkzeroout=yes
|
||||
else
|
||||
ac_cv_have_blkzeroout=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_blkzeroout" >&5
|
||||
$as_echo "$ac_cv_have_blkzeroout" >&6; }
|
||||
|
||||
|
||||
# Check whether --enable-blkzeroout was given.
|
||||
if test "${enable_blkzeroout+set}" = set; then :
|
||||
enableval=$enable_blkzeroout; BLKZEROOUT=$enableval
|
||||
else
|
||||
BLKZEROOUT=yes
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use BLKZEROOUT for device zeroing" >&5
|
||||
$as_echo_n "checking whether to use BLKZEROOUT for device zeroing... " >&6; }
|
||||
if test "$BLKZEROOUT" = yes; then
|
||||
if test $ac_cv_have_blkzeroout = yes; then :
|
||||
|
||||
$as_echo "#define HAVE_BLKZEROOUT 1" >>confdefs.h
|
||||
|
||||
else
|
||||
BLKZEROOUT=no
|
||||
fi
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BLKZEROOUT" >&5
|
||||
$as_echo "$BLKZEROOUT" >&6; }
|
||||
|
||||
|
||||
################################################################################
|
||||
RT_LIBS=
|
||||
HAVE_REALTIME=no
|
||||
@@ -12781,6 +12885,86 @@ fi
|
||||
done
|
||||
|
||||
|
||||
################################################################################
|
||||
if test "$EDITLINE" == yes; then
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for EDITLINE" >&5
|
||||
$as_echo_n "checking for EDITLINE... " >&6; }
|
||||
|
||||
if test -n "$EDITLINE_CFLAGS"; then
|
||||
pkg_cv_EDITLINE_CFLAGS="$EDITLINE_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libedit") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_EDITLINE_CFLAGS=`$PKG_CONFIG --cflags "libedit" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$EDITLINE_LIBS"; then
|
||||
pkg_cv_EDITLINE_LIBS="$EDITLINE_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libedit\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "libedit") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_EDITLINE_LIBS=`$PKG_CONFIG --libs "libedit" 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
|
||||
EDITLINE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libedit" 2>&1`
|
||||
else
|
||||
EDITLINE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libedit" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$EDITLINE_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "libedit could not be found which is required for the --enable-readline option." "$LINENO" 5
|
||||
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
as_fn_error $? "libedit could not be found which is required for the --enable-readline option." "$LINENO" 5
|
||||
|
||||
else
|
||||
EDITLINE_CFLAGS=$pkg_cv_EDITLINE_CFLAGS
|
||||
EDITLINE_LIBS=$pkg_cv_EDITLINE_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
|
||||
|
||||
$as_echo "#define EDITLINE_SUPPORT 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
if test "$READLINE" != no; then
|
||||
lvm_saved_libs=$LIBS
|
||||
@@ -13219,6 +13403,28 @@ $as_echo_n "checking whether to enable readline... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $READLINE" >&5
|
||||
$as_echo "$READLINE" >&6; }
|
||||
|
||||
if test "$EDITLINE" = yes; then
|
||||
for ac_header in editline/readline.h editline/history.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
hard_bailout
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable editline" >&5
|
||||
$as_echo_n "checking whether to enable editline... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $EDITLINE" >&5
|
||||
$as_echo "$EDITLINE" >&6; }
|
||||
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
for ac_func in atexit
|
||||
do :
|
||||
@@ -13900,6 +14106,7 @@ _ACEOF
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
@@ -15272,8 +15479,8 @@ $as_echo "$as_me: WARNING: You should install latest cache_check vsn 0.7.0 to us
|
||||
fi
|
||||
|
||||
if test -n "$VDO_CONFIGURE_WARN"; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!" >&5
|
||||
$as_echo "$as_me: WARNING: unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!" >&2;}
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!" >&5
|
||||
$as_echo "$as_me: WARNING: Unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!" >&2;}
|
||||
fi
|
||||
|
||||
|
||||
|
||||
85
configure.ac
85
configure.ac
@@ -607,7 +607,7 @@ AC_MSG_CHECKING(whether to include vdo)
|
||||
AC_ARG_WITH(vdo,
|
||||
AC_HELP_STRING([--with-vdo=TYPE],
|
||||
[vdo support: internal/none [internal]]),
|
||||
VDO=$withval, VDO="none")
|
||||
VDO=$withval, VDO="internal")
|
||||
|
||||
AC_MSG_RESULT($VDO)
|
||||
|
||||
@@ -654,8 +654,8 @@ dnl -- writecache inclusion type
|
||||
AC_MSG_CHECKING(whether to include writecache)
|
||||
AC_ARG_WITH(writecache,
|
||||
AC_HELP_STRING([--with-writecache=TYPE],
|
||||
[writecache support: internal/none [none]]),
|
||||
WRITECACHE=$withval, WRITECACHE="none")
|
||||
[writecache support: internal/none [internal]]),
|
||||
WRITECACHE=$withval, WRITECACHE="internal")
|
||||
|
||||
AC_MSG_RESULT($WRITECACHE)
|
||||
|
||||
@@ -667,12 +667,36 @@ case "$WRITECACHE" in
|
||||
*) AC_MSG_ERROR([--with-writecache parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- integrity inclusion type
|
||||
AC_MSG_CHECKING(whether to include integrity)
|
||||
AC_ARG_WITH(integrity,
|
||||
AC_HELP_STRING([--with-integrity=TYPE],
|
||||
[integrity support: internal/none [internal]]),
|
||||
INTEGRITY=$withval, INTEGRITY="internal")
|
||||
|
||||
AC_MSG_RESULT($INTEGRITY)
|
||||
|
||||
case "$INTEGRITY" in
|
||||
none) ;;
|
||||
internal)
|
||||
AC_DEFINE([INTEGRITY_INTERNAL], 1, [Define to 1 to include built-in support for integrity.])
|
||||
;;
|
||||
*) AC_MSG_ERROR([--with-integrity parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable readline
|
||||
AC_ARG_ENABLE([readline],
|
||||
AC_HELP_STRING([--disable-readline], [disable readline support]),
|
||||
READLINE=$enableval, READLINE=maybe)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable editline
|
||||
AC_ARG_ENABLE([editline],
|
||||
AC_HELP_STRING([--enable-editline], [enable editline support]),
|
||||
EDITLINE=$enableval, EDITLINE=no)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable realtime clock support
|
||||
AC_MSG_CHECKING(whether to enable realtime support)
|
||||
@@ -716,7 +740,7 @@ dnl -- Set up pidfile and run directory
|
||||
AH_TEMPLATE(DEFAULT_PID_DIR)
|
||||
AC_ARG_WITH(default-pid-dir,
|
||||
AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
|
||||
[Default directory to keep PID files in. [autodetect]]),
|
||||
[default directory to keep PID files in [autodetect]]),
|
||||
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR=$RUN_DIR)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
||||
[Default directory to keep PID files in.])
|
||||
@@ -724,7 +748,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
||||
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
|
||||
AC_ARG_WITH(default-dm-run-dir,
|
||||
AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
|
||||
[ Default DM run directory. [autodetect]]),
|
||||
[default DM run directory [autodetect]]),
|
||||
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR=$RUN_DIR)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
||||
[Default DM run directory.])
|
||||
@@ -732,7 +756,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
||||
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
|
||||
AC_ARG_WITH(default-run-dir,
|
||||
AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
|
||||
[Default LVM run directory. [autodetect_run_dir/lvm]]),
|
||||
[default LVM run directory [autodetect_run_dir/lvm]]),
|
||||
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="$RUN_DIR/lvm")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||
[Default LVM run directory.])
|
||||
@@ -1200,6 +1224,9 @@ if test "$BUILD_LVMDBUSD" = yes; then
|
||||
unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
|
||||
unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
|
||||
unset ac_cv_path_PYTHON_CONFIG ac_cv_path_ac_pt_PYTHON_CONFIG
|
||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],[ python3 python2 python dnl
|
||||
python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 dnl
|
||||
python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 ])
|
||||
AM_PATH_PYTHON([3])
|
||||
PYTHON3=$PYTHON
|
||||
test -z "$PYTHON3" && AC_MSG_ERROR([python3 is required for --enable-python3_bindings or --enable-dbus-service but cannot be found])
|
||||
@@ -1327,6 +1354,33 @@ if test "$SELINUX" = yes; then
|
||||
HAVE_SELINUX=no ])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check BLKZEROOUT support
|
||||
|
||||
AC_CACHE_CHECK([for BLKZEROOUT in sys/ioctl.h.],
|
||||
[ac_cv_have_blkzeroout],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
int bar(void) { return ioctl(0, BLKZEROOUT, 0); }]
|
||||
)], [ac_cv_have_blkzeroout=yes], [ac_cv_have_blkzeroout=no])])
|
||||
|
||||
|
||||
AC_ARG_ENABLE(blkzeroout,
|
||||
AC_HELP_STRING([--disable-blkzeroout],
|
||||
[do not use BLKZEROOUT for device zeroing]),
|
||||
BLKZEROOUT=$enableval, BLKZEROOUT=yes)
|
||||
|
||||
AC_MSG_CHECKING(whether to use BLKZEROOUT for device zeroing)
|
||||
if test "$BLKZEROOUT" = yes; then
|
||||
AC_IF_YES(ac_cv_have_blkzeroout,
|
||||
AC_DEFINE(HAVE_BLKZEROOUT, 1,
|
||||
[Define if ioctl BLKZEROOUT can be used for device zeroing.]),
|
||||
BLKZEROOUT=no)
|
||||
fi
|
||||
AC_MSG_RESULT($BLKZEROOUT)
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for realtime clock support
|
||||
RT_LIBS=
|
||||
@@ -1360,6 +1414,16 @@ AC_IF_YES(ac_cv_stat_st_ctim,
|
||||
dnl -- Check for getopt
|
||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for editline
|
||||
if test "$EDITLINE" == yes; then
|
||||
PKG_CHECK_MODULES([EDITLINE], [libedit], [
|
||||
AC_DEFINE([EDITLINE_SUPPORT], 1,
|
||||
[Define to 1 to include the LVM editline shell.])], AC_MSG_ERROR(
|
||||
[libedit could not be found which is required for the --enable-readline option.])
|
||||
)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for readline (Shamelessly copied from parted 1.4.17)
|
||||
if test "$READLINE" != no; then
|
||||
@@ -1492,6 +1556,12 @@ fi
|
||||
AC_MSG_CHECKING(whether to enable readline)
|
||||
AC_MSG_RESULT($READLINE)
|
||||
|
||||
if test "$EDITLINE" = yes; then
|
||||
AC_CHECK_HEADERS(editline/readline.h editline/history.h,,hard_bailout)
|
||||
fi
|
||||
AC_MSG_CHECKING(whether to enable editline)
|
||||
AC_MSG_RESULT($EDITLINE)
|
||||
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_CHECK_FUNCS(atexit,,hard_bailout)
|
||||
fi
|
||||
@@ -1747,6 +1817,7 @@ AC_SUBST(QUORUM_CFLAGS)
|
||||
AC_SUBST(QUORUM_LIBS)
|
||||
AC_SUBST(RT_LIBS)
|
||||
AC_SUBST(READLINE_LIBS)
|
||||
AC_SUBST(EDITLINE_LIBS)
|
||||
AC_SUBST(REPLICATORS)
|
||||
AC_SUBST(SACKPT_CFLAGS)
|
||||
AC_SUBST(SACKPT_LIBS)
|
||||
@@ -1882,7 +1953,7 @@ AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
|
||||
[AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
|
||||
|
||||
AS_IF([test -n "$VDO_CONFIGURE_WARN"],
|
||||
[AC_MSG_WARN([unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!])])
|
||||
[AC_MSG_WARN([Unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!])])
|
||||
|
||||
|
||||
AS_IF([test "$ODIRECT" != yes],
|
||||
|
||||
@@ -46,6 +46,7 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
|
||||
return "STRING";
|
||||
}
|
||||
|
||||
/*
|
||||
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
|
||||
{
|
||||
if (lv)
|
||||
@@ -53,6 +54,7 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
|
||||
|
||||
__coverity_panic__();
|
||||
}
|
||||
*/
|
||||
|
||||
/* simple_memccpy() from glibc */
|
||||
void *memccpy(void *dest, const void *src, int c, size_t n)
|
||||
|
||||
@@ -752,7 +752,7 @@ static void _exit_timeout(void *unused __attribute__((unused)))
|
||||
static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
{
|
||||
struct thread_status *thread;
|
||||
struct timespec timeout;
|
||||
struct timespec timeout, real_time;
|
||||
time_t curr_time;
|
||||
int ret;
|
||||
|
||||
@@ -763,7 +763,16 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
while (!dm_list_empty(&_timeout_registry)) {
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_nsec = 0;
|
||||
#ifndef HAVE_REALTIME
|
||||
curr_time = time(NULL);
|
||||
#else
|
||||
if (clock_gettime(CLOCK_REALTIME, &real_time)) {
|
||||
log_error("Failed to read clock_gettime().");
|
||||
break;
|
||||
}
|
||||
/* 10ms back to the future */
|
||||
curr_time = real_time.tv_sec + ((real_time.tv_nsec > (1000000000 - 10000000)) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
|
||||
if (thread->next_time <= curr_time) {
|
||||
@@ -1485,37 +1494,34 @@ static int _client_read(struct dm_event_fifos *fifos,
|
||||
t.tv_usec = 0;
|
||||
ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
|
||||
|
||||
if (!ret && !bytes) /* nothing to read */
|
||||
return 0;
|
||||
if (!ret && bytes)
|
||||
continue; /* trying to finish read */
|
||||
|
||||
if (!ret) /* trying to finish read */
|
||||
continue;
|
||||
|
||||
if (ret < 0) /* error */
|
||||
return 0;
|
||||
if (ret <= 0) /* nothing to read */
|
||||
goto bad;
|
||||
|
||||
ret = read(fifos->client, buf + bytes, size - bytes);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
|
||||
msg->cmd = ntohl(header[0]);
|
||||
size = msg->size = ntohl(header[1]);
|
||||
bytes = 0;
|
||||
if (!size)
|
||||
break; /* No data -> error */
|
||||
buf = msg->data = malloc(msg->size);
|
||||
if (!buf)
|
||||
break; /* No mem -> error */
|
||||
header = 0;
|
||||
|
||||
if (!(size = msg->size = ntohl(header[1])))
|
||||
break;
|
||||
|
||||
if (!(buf = msg->data = malloc(msg->size)))
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes != size) {
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (bytes == size)
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1745,7 +1751,8 @@ static void _init_thread_signals(void)
|
||||
sigdelset(&my_sigset, SIGHUP);
|
||||
sigdelset(&my_sigset, SIGQUIT);
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
|
||||
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
|
||||
log_sys_error("pthread_sigmask", "SIG_BLOCK");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2021,8 +2028,8 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
||||
static void _restart_dmeventd(void)
|
||||
{
|
||||
struct dm_event_fifos fifos = {
|
||||
.server = -1,
|
||||
.client = -1,
|
||||
.server = -1,
|
||||
/* FIXME Make these either configurable or depend directly on dmeventd_path */
|
||||
.client_path = DM_EVENT_FIFO_CLIENT,
|
||||
.server_path = DM_EVENT_FIFO_SERVER
|
||||
@@ -2236,7 +2243,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
_init_thread_signals();
|
||||
|
||||
pthread_mutex_init(&_global_mutex, NULL);
|
||||
if (pthread_mutex_init(&_global_mutex, NULL))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (!_systemd_activation && !_open_fifos(&fifos))
|
||||
exit(EXIT_FIFO_FAILURE);
|
||||
|
||||
@@ -237,16 +237,16 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
log_error("Unable to read from event server.");
|
||||
return 0;
|
||||
goto bad;
|
||||
}
|
||||
if ((ret == 0) && (i > 4) && !bytes) {
|
||||
log_error("No input from event server.");
|
||||
return 0;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (ret < 1) {
|
||||
log_error("Unable to read from event server.");
|
||||
return 0;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ret = read(fifos->server, buf + bytes, size);
|
||||
@@ -255,25 +255,32 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
continue;
|
||||
|
||||
log_error("Unable to read from event server.");
|
||||
return 0;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
bytes += ret;
|
||||
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
|
||||
msg->cmd = ntohl(header[0]);
|
||||
msg->size = ntohl(header[1]);
|
||||
buf = msg->data = malloc(msg->size);
|
||||
size = msg->size;
|
||||
bytes = 0;
|
||||
header = 0;
|
||||
|
||||
if (!(size = msg->size = ntohl(header[1])))
|
||||
break;
|
||||
|
||||
if (!(buf = msg->data = malloc(msg->size))) {
|
||||
log_error("Unable to allocate message data.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes != size) {
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
}
|
||||
return bytes == size;
|
||||
if (bytes == size)
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
@@ -608,8 +615,8 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_fifos fifos = {
|
||||
.server = -1,
|
||||
.client = -1,
|
||||
.server = -1,
|
||||
/* FIXME Make these either configurable or depend directly on dmeventd_path */
|
||||
.client_path = DM_EVENT_FIFO_CLIENT,
|
||||
.server_path = DM_EVENT_FIFO_SERVER
|
||||
|
||||
@@ -71,7 +71,7 @@ int dmeventd_lvm2_init(void)
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_lvm2_print_log);
|
||||
|
||||
if (!(_lvm_handle = lvm2_init()))
|
||||
if (!(_lvm_handle = lvm2_init_threaded()))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
/* Use parser from new device_mapper library */
|
||||
/*
|
||||
* Use parser from new device_mapper library.
|
||||
* Although during compilation we can see dm_vdo_status_parse()
|
||||
* in runtime we are linked agains systems libdm 'older' library
|
||||
* which does not provide this symbol and plugin fails to load
|
||||
*/
|
||||
#include "device_mapper/vdo/status.c"
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -47,9 +47,11 @@ BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
||||
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
||||
VG_VDO_INTERFACE = BASE_INTERFACE + '.VgVdo'
|
||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
||||
VDO_POOL_INTERFACE = BASE_INTERFACE + '.VdoPool'
|
||||
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
||||
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
||||
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
||||
@@ -61,6 +63,7 @@ PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
|
||||
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
||||
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
||||
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
||||
VDO_POOL_PATH = BASE_OBJ_PATH + "/VdoPool"
|
||||
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
||||
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
||||
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
||||
@@ -71,6 +74,7 @@ pv_id = itertools.count()
|
||||
vg_id = itertools.count()
|
||||
lv_id = itertools.count()
|
||||
thin_id = itertools.count()
|
||||
vdo_id = itertools.count()
|
||||
cache_pool_id = itertools.count()
|
||||
job_id = itertools.count()
|
||||
hidden_lv = itertools.count()
|
||||
@@ -79,6 +83,9 @@ hidden_lv = itertools.count()
|
||||
load = None
|
||||
event = None
|
||||
|
||||
# Boolean to denote if lvm supports VDO integration
|
||||
vdo_support = False
|
||||
|
||||
# Global cached state
|
||||
db = None
|
||||
|
||||
|
||||
@@ -388,6 +388,24 @@ def vg_create_thin_pool(md_full_name, data_full_name, create_options):
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_create_vdo_pool_lv_and_lv(vg_name, pool_name, lv_name, data_size,
|
||||
virtual_size, create_options):
|
||||
cmd = ['lvcreate']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
cmd.extend(['-y', '--type', 'vdo', '-n', lv_name,
|
||||
'-L', '%dB' % data_size, '-V', '%dB' % virtual_size,
|
||||
"%s/%s" % (vg_name, pool_name)])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def vg_create_vdo_pool(pool_full_name, lv_name, virtual_size, create_options):
|
||||
cmd = ['lvconvert']
|
||||
cmd.extend(options_to_cli_args(create_options))
|
||||
cmd.extend(['--type', 'vdo-pool', '-n', lv_name, '--force', '-y',
|
||||
'-V', '%dB' % virtual_size, pool_full_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def lv_remove(lv_path, remove_options):
|
||||
cmd = ['lvremove']
|
||||
cmd.extend(options_to_cli_args(remove_options))
|
||||
@@ -435,6 +453,15 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options):
|
||||
# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV
|
||||
cmd = ['lvconvert']
|
||||
cmd.extend(options_to_cli_args(cache_options))
|
||||
cmd.extend(['-y', '--type', 'writecache', '--cachevol',
|
||||
cache_lv_full_name, lv_full_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
||||
cmd = ['lvconvert']
|
||||
if destroy_cache:
|
||||
@@ -450,6 +477,28 @@ def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def lv_vdo_compression(lv_path, enable, comp_options):
|
||||
cmd = ['lvchange', '--compression']
|
||||
if enable:
|
||||
cmd.append('y')
|
||||
else:
|
||||
cmd.append('n')
|
||||
cmd.extend(options_to_cli_args(comp_options))
|
||||
cmd.append(lv_path)
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def lv_vdo_deduplication(lv_path, enable, dedup_options):
|
||||
cmd = ['lvchange', '--deduplication']
|
||||
if enable:
|
||||
cmd.append('y')
|
||||
else:
|
||||
cmd.append('n')
|
||||
cmd.extend(options_to_cli_args(dedup_options))
|
||||
cmd.append(lv_path)
|
||||
return call(cmd)
|
||||
|
||||
|
||||
def supports_json():
|
||||
cmd = ['help']
|
||||
rc, out, err = call(cmd)
|
||||
@@ -462,6 +511,16 @@ def supports_json():
|
||||
return False
|
||||
|
||||
|
||||
def supports_vdo():
|
||||
cmd = ['segtypes']
|
||||
rc, out, err = call(cmd)
|
||||
if rc == 0:
|
||||
if "vdo" in out:
|
||||
log_debug("We have VDO support")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def lvm_full_report_json():
|
||||
pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
||||
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
||||
@@ -489,6 +548,22 @@ def lvm_full_report_json():
|
||||
|
||||
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
|
||||
|
||||
if cfg.vdo_support:
|
||||
lv_columns.extend(
|
||||
['vdo_operating_mode', 'vdo_compression_state', 'vdo_index_state',
|
||||
'vdo_used_size', 'vdo_saving_percent']
|
||||
)
|
||||
|
||||
lv_seg_columns.extend(
|
||||
['vdo_compression', 'vdo_deduplication',
|
||||
'vdo_use_metadata_hints', 'vdo_minimum_io_size',
|
||||
'vdo_block_map_cache_size', 'vdo_block_map_era_length',
|
||||
'vdo_use_sparse_index', 'vdo_index_memory_size',
|
||||
'vdo_slab_size', 'vdo_ack_threads', 'vdo_bio_threads',
|
||||
'vdo_bio_rotation', 'vdo_cpu_threads', 'vdo_hash_zone_threads',
|
||||
'vdo_logical_threads', 'vdo_physical_threads',
|
||||
'vdo_max_discard', 'vdo_write_policy', 'vdo_header_size'])
|
||||
|
||||
cmd = _dc('fullreport', [
|
||||
'-a', # Need hidden too
|
||||
'--configreport', 'pv', '-o', ','.join(pv_columns),
|
||||
@@ -702,6 +777,7 @@ def activate_deactivate(op, name, activate, control_flags, options):
|
||||
op += 'n'
|
||||
|
||||
cmd.append(op)
|
||||
cmd.append("-y")
|
||||
cmd.append(name)
|
||||
return call(cmd)
|
||||
|
||||
|
||||
@@ -29,11 +29,26 @@ def _main_thread_load(refresh=True, emit_signal=True):
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_lvs(
|
||||
|
||||
lv_changes = load_lvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
|
||||
num_total_changes += lv_changes
|
||||
|
||||
# When the LVs change it can cause another change in the VGs which is
|
||||
# missed if we don't scan through the VGs again. We could achieve this
|
||||
# the other way and re-scan the LVs, but in general there are more LVs than
|
||||
# VGs, thus this should be more efficient. This happens when a LV interface
|
||||
# changes causing the dbus object representing it to be removed and
|
||||
# recreated.
|
||||
if refresh and lv_changes > 0:
|
||||
num_total_changes += load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
|
||||
return num_total_changes
|
||||
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
from .automatedproperties import AutomatedProperties
|
||||
|
||||
from . import utils
|
||||
from .utils import vg_obj_path_generate, log_error
|
||||
from .utils import vg_obj_path_generate, log_error, _handle_execute
|
||||
import dbus
|
||||
from . import cmdhandler
|
||||
from . import cfg
|
||||
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
|
||||
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED
|
||||
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED, VDO_POOL_INTERFACE
|
||||
from .request import RequestEntry
|
||||
from .utils import n, n32
|
||||
from .utils import n, n32, d
|
||||
from .loader import common
|
||||
from .state import State
|
||||
from . import background
|
||||
@@ -74,23 +74,66 @@ def lvs_state_retrieve(selection, cache_refresh=True):
|
||||
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
|
||||
|
||||
for l in lvs:
|
||||
rc.append(LvState(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid']))
|
||||
if cfg.vdo_support:
|
||||
rc.append(LvStateVdo(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid'],
|
||||
l['vdo_operating_mode'],
|
||||
l['vdo_compression_state'],
|
||||
l['vdo_index_state'],
|
||||
n(l['vdo_used_size']),
|
||||
d(l['vdo_saving_percent']),
|
||||
l['vdo_compression'],
|
||||
l['vdo_deduplication'],
|
||||
l['vdo_use_metadata_hints'],
|
||||
n32(l['vdo_minimum_io_size']),
|
||||
n(l['vdo_block_map_cache_size']),
|
||||
n32(l['vdo_block_map_era_length']),
|
||||
l['vdo_use_sparse_index'],
|
||||
n(l['vdo_index_memory_size']),
|
||||
n(l['vdo_slab_size']),
|
||||
n32(l['vdo_ack_threads']),
|
||||
n32(l['vdo_bio_threads']),
|
||||
n32(l['vdo_bio_rotation']),
|
||||
n32(l['vdo_cpu_threads']),
|
||||
n32(l['vdo_hash_zone_threads']),
|
||||
n32(l['vdo_logical_threads']),
|
||||
n32(l['vdo_physical_threads']),
|
||||
n32(l['vdo_max_discard']),
|
||||
l['vdo_write_policy'],
|
||||
n32(l['vdo_header_size'])))
|
||||
else:
|
||||
rc.append(LvState(
|
||||
l['lv_uuid'], l['lv_name'],
|
||||
l['lv_path'], n(l['lv_size']),
|
||||
l['vg_name'],
|
||||
l['vg_uuid'], l['pool_lv_uuid'],
|
||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
||||
n32(l['data_percent']), l['lv_attr'],
|
||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
||||
l['lv_layout'],
|
||||
n32(l['snap_percent']),
|
||||
n32(l['metadata_percent']),
|
||||
n32(l['copy_percent']),
|
||||
n32(l['sync_percent']),
|
||||
n(l['lv_metadata_size']),
|
||||
l['move_pv'],
|
||||
l['move_pv_uuid']))
|
||||
return rc
|
||||
|
||||
|
||||
@@ -194,6 +237,8 @@ class LvState(State):
|
||||
def _object_type_create(self):
|
||||
if self.Attr[0] == 't':
|
||||
return LvThinPool
|
||||
elif self.Attr[0] == 'd':
|
||||
return LvVdoPool
|
||||
elif self.Attr[0] == 'C':
|
||||
if 'pool' in self.layout:
|
||||
return LvCachePool
|
||||
@@ -220,6 +265,34 @@ class LvState(State):
|
||||
return (klass, path_method)
|
||||
|
||||
|
||||
class LvStateVdo(LvState):
|
||||
|
||||
def __init__(self, Uuid, Name, Path, SizeBytes,
|
||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
||||
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
|
||||
MetaDataPercent, CopyPercent, SyncPercent,
|
||||
MetaDataSizeBytes, move_pv, move_pv_uuid,
|
||||
vdo_operating_mode, vdo_compression_state, vdo_index_state,
|
||||
vdo_used_size,vdo_saving_percent,vdo_compression,
|
||||
vdo_deduplication,vdo_use_metadata_hints,
|
||||
vdo_minimum_io_size,vdo_block_map_cache_size,
|
||||
vdo_block_map_era_length,vdo_use_sparse_index,
|
||||
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
|
||||
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
|
||||
vdo_hash_zone_threads,vdo_logical_threads,
|
||||
vdo_physical_threads,vdo_max_discard,
|
||||
vdo_write_policy,vdo_header_size):
|
||||
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
|
||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
||||
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
|
||||
MetaDataPercent, CopyPercent, SyncPercent,
|
||||
MetaDataSizeBytes, move_pv, move_pv_uuid)
|
||||
|
||||
utils.init_class_from_arguments(self, "vdo_", snake_to_pascal=True)
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
|
||||
@@ -275,13 +348,7 @@ class LvCommon(AutomatedProperties):
|
||||
|
||||
@staticmethod
|
||||
def handle_execute(rc, out, err):
|
||||
if rc == 0:
|
||||
cfg.load()
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
_handle_execute(rc, out, err, LV_INTERFACE)
|
||||
|
||||
@staticmethod
|
||||
def validate_dbus_object(lv_uuid, lv_name):
|
||||
@@ -321,6 +388,7 @@ class LvCommon(AutomatedProperties):
|
||||
'l': 'mirror log device', 'c': 'under conversion',
|
||||
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
||||
'e': 'raid or pool metadata or pool metadata spare',
|
||||
'd': 'vdo pool', 'D': 'vdo pool data', 'g': 'integrity',
|
||||
'-': 'Unspecified'}
|
||||
return self.attr_struct(0, type_map)
|
||||
|
||||
@@ -456,8 +524,7 @@ class Lv(LvCommon):
|
||||
# Make sure we have a dbus object representing it
|
||||
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||
# Remove the LV, if successful then remove from the model
|
||||
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.lv_remove(lv_name, remove_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -477,9 +544,8 @@ class Lv(LvCommon):
|
||||
# Make sure we have a dbus object representing it
|
||||
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||
# Rename the logical volume
|
||||
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
|
||||
rename_options)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.lv_rename(lv_name, new_name,
|
||||
rename_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -528,13 +594,11 @@ class Lv(LvCommon):
|
||||
remainder = space % 512
|
||||
optional_size = space + 512 - remainder
|
||||
|
||||
rc, out, err = cmdhandler.vg_lv_snapshot(
|
||||
lv_name, snapshot_options, name, optional_size)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
|
||||
lv_name, snapshot_options,name, optional_size))
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=LV_INTERFACE,
|
||||
in_signature='stia{sv}',
|
||||
@@ -570,9 +634,8 @@ class Lv(LvCommon):
|
||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||
|
||||
size_change = new_size_bytes - dbo.SizeBytes
|
||||
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
|
||||
pv_dests, resize_options)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.lv_resize(
|
||||
dbo.lvm_id, size_change,pv_dests, resize_options))
|
||||
return "/"
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -607,9 +670,8 @@ class Lv(LvCommon):
|
||||
options):
|
||||
# Make sure we have a dbus object representing it
|
||||
LvCommon.validate_dbus_object(uuid, lv_name)
|
||||
rc, out, err = cmdhandler.activate_deactivate(
|
||||
'lvchange', lv_name, activate, control_flags, options)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.activate_deactivate(
|
||||
'lvchange', lv_name, activate, control_flags, options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -643,9 +705,8 @@ class Lv(LvCommon):
|
||||
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
LvCommon.validate_dbus_object(uuid, lv_name)
|
||||
rc, out, err = cmdhandler.lv_tag(
|
||||
lv_name, tags_add, tags_del, tag_options)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.lv_tag(
|
||||
lv_name, tags_add, tags_del, tag_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -682,6 +743,152 @@ class Lv(LvCommon):
|
||||
cb, cbe, return_tuple=False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@staticmethod
|
||||
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||
|
||||
# Make sure we have dbus object representing lv to cache
|
||||
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
|
||||
|
||||
if lv_to_cache:
|
||||
fcn = lv_to_cache.lv_full_name()
|
||||
rc, out, err = cmdhandler.lv_writecache_lv(
|
||||
dbo.lv_full_name(), fcn, cache_options)
|
||||
if rc == 0:
|
||||
# When we cache an LV, the cache pool and the lv that is getting
|
||||
# cached need to be removed from the object manager and
|
||||
# re-created as their interfaces have changed!
|
||||
mt_remove_dbus_objects((dbo, lv_to_cache))
|
||||
cfg.load()
|
||||
|
||||
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE,
|
||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
LV_INTERFACE, 'LV to cache with object path %s not present!' %
|
||||
lv_object_path)
|
||||
return lv_converted
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=LV_INTERFACE,
|
||||
in_signature='oia{sv}',
|
||||
out_signature='(oo)',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def WriteCacheLv(self, lv_object, tmo, cache_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, Lv._writecache_lv,
|
||||
(self.Uuid, self.lvm_id, lv_object,
|
||||
cache_options), cb, cbe)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CompressionState', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexState', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UsedSize', 't')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SavingPercent', 'd')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Compression', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Deduplication', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseMetadataHints', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MinimumIoSize', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapCacheSize', "t")
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapEraLength', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseSparseIndex', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexMemorySize', 't')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SlabSize', 't')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'AckThreads', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioThreads', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioRotation', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CpuThreads', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HashZoneThreads', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'LogicalThreads', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'PhysicalThreads', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MaxDiscard', 'u')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'WritePolicy', 's')
|
||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HeaderSize', 'u')
|
||||
class LvVdoPool(Lv):
|
||||
_DataLv_meta = ("o", VDO_POOL_INTERFACE)
|
||||
|
||||
def __init__(self, object_path, object_state):
|
||||
super(LvVdoPool, self).__init__(object_path, object_state)
|
||||
self.set_interface(VDO_POOL_INTERFACE)
|
||||
self._data_lv, _ = self._get_data_meta()
|
||||
|
||||
@property
|
||||
def DataLv(self):
|
||||
return dbus.ObjectPath(self._data_lv)
|
||||
|
||||
@staticmethod
|
||||
def _enable_disable_compression(pool_uuid, pool_name, enable, comp_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
LvCommon.validate_dbus_object(pool_uuid, pool_name)
|
||||
# Rename the logical volume
|
||||
LvCommon.handle_execute(*cmdhandler.lv_vdo_compression(
|
||||
pool_name, enable, comp_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def EnableCompression(self, tmo, comp_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, LvVdoPool._enable_disable_compression,
|
||||
(self.Uuid, self.lvm_id, True, comp_options),
|
||||
cb, cbe, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def DisableCompression(self, tmo, comp_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, LvVdoPool._enable_disable_compression,
|
||||
(self.Uuid, self.lvm_id, False, comp_options),
|
||||
cb, cbe, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@staticmethod
|
||||
def _enable_disable_deduplication(pool_uuid, pool_name, enable, dedup_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
LvCommon.validate_dbus_object(pool_uuid, pool_name)
|
||||
# Rename the logical volume
|
||||
LvCommon.handle_execute(*cmdhandler.lv_vdo_deduplication(
|
||||
pool_name, enable, dedup_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def EnableDeduplication(self, tmo, dedup_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, LvVdoPool._enable_disable_deduplication,
|
||||
(self.Uuid, self.lvm_id, True, dedup_options),
|
||||
cb, cbe, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VDO_POOL_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
out_signature='o',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
|
||||
r = RequestEntry(
|
||||
tmo, LvVdoPool._enable_disable_deduplication,
|
||||
(self.Uuid, self.lvm_id, False, dedup_options),
|
||||
cb, cbe, False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class LvThinPool(Lv):
|
||||
@@ -705,10 +912,8 @@ class LvThinPool(Lv):
|
||||
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||
|
||||
rc, out, err = cmdhandler.lv_lv_create(
|
||||
lv_name, create_options, name, size_bytes)
|
||||
LvCommon.handle_execute(rc, out, err)
|
||||
LvCommon.handle_execute(*cmdhandler.lv_lv_create(
|
||||
lv_name, create_options, name, size_bytes))
|
||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from lvmdbusd.utils import log_debug, log_error
|
||||
|
||||
|
||||
class DataStore(object):
|
||||
def __init__(self, usejson=True):
|
||||
def __init__(self, usejson=True, vdo_support=False):
|
||||
self.pvs = {}
|
||||
self.vgs = {}
|
||||
self.lvs = {}
|
||||
@@ -43,6 +43,8 @@ class DataStore(object):
|
||||
else:
|
||||
self.json = usejson
|
||||
|
||||
self.vdo_support = vdo_support
|
||||
|
||||
@staticmethod
|
||||
def _insert_record(table, key, record, allowed_multiple):
|
||||
if key in table:
|
||||
@@ -241,8 +243,7 @@ class DataStore(object):
|
||||
|
||||
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||
|
||||
@staticmethod
|
||||
def _parse_lvs_json(_all):
|
||||
def _parse_lvs_json(self, _all):
|
||||
|
||||
c_lvs = OrderedDict()
|
||||
c_lv_full_lookup = {}
|
||||
@@ -262,8 +263,13 @@ class DataStore(object):
|
||||
if 'seg' in r:
|
||||
for s in r['seg']:
|
||||
r = c_lvs[s['lv_uuid']]
|
||||
r.setdefault('seg_pe_ranges', []).append(s['seg_pe_ranges'])
|
||||
r.setdefault('seg_pe_ranges', []).\
|
||||
append(s['seg_pe_ranges'])
|
||||
r.setdefault('segtype', []).append(s['segtype'])
|
||||
if self.vdo_support:
|
||||
for seg_key, seg_val in s.items():
|
||||
if seg_key.startswith("vdo_"):
|
||||
r[seg_key] = seg_val
|
||||
|
||||
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from .utils import log_debug, log_error
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from .cmdhandler import LvmFlightRecorder
|
||||
from .cmdhandler import LvmFlightRecorder, supports_vdo
|
||||
from .request import RequestEntry
|
||||
|
||||
|
||||
@@ -44,10 +44,10 @@ def process_request():
|
||||
try:
|
||||
req = cfg.worker_q.get(True, 5)
|
||||
log_debug(
|
||||
"Running method: %s with args %s" %
|
||||
(str(req.method), str(req.arguments)))
|
||||
"Method start: %s with args %s (callback = %s)" %
|
||||
(str(req.method), str(req.arguments), str(req.cb)))
|
||||
req.run_cmd()
|
||||
log_debug("Method complete ")
|
||||
log_debug("Method complete: %s" % str(req.method))
|
||||
except queue.Empty:
|
||||
pass
|
||||
except Exception:
|
||||
@@ -127,6 +127,14 @@ def main():
|
||||
log_error("You cannot specify --lvmshell and --nojson")
|
||||
sys.exit(1)
|
||||
|
||||
# We will dynamically add interfaces which support vdo if it
|
||||
# exists.
|
||||
cfg.vdo_support = supports_vdo()
|
||||
|
||||
if cfg.vdo_support and not cfg.args.use_json:
|
||||
log_error("You cannot specify --nojson when lvm has VDO support")
|
||||
sys.exit(1)
|
||||
|
||||
# List of threads that we start up
|
||||
thread_list = []
|
||||
|
||||
@@ -147,12 +155,12 @@ def main():
|
||||
cfg.om = Lvm(BASE_OBJ_PATH)
|
||||
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
||||
|
||||
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
||||
cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
|
||||
|
||||
# Using a thread to process requests, we cannot hang the dbus library
|
||||
# thread that is handling the dbus interface
|
||||
thread_list.append(threading.Thread(target=process_request,
|
||||
name='process_request'))
|
||||
thread_list.append(
|
||||
threading.Thread(target=process_request, name='process_request'))
|
||||
|
||||
# Have a single thread handling updating lvm and the dbus model so we
|
||||
# don't have multiple threads doing this as the same time
|
||||
|
||||
@@ -27,7 +27,7 @@ class Manager(AutomatedProperties):
|
||||
|
||||
@property
|
||||
def Version(self):
|
||||
return dbus.String('1.0.0')
|
||||
return dbus.String('1.1.0')
|
||||
|
||||
@staticmethod
|
||||
def handle_execute(rc, out, err):
|
||||
@@ -107,10 +107,10 @@ class Manager(AutomatedProperties):
|
||||
rc = cfg.load(log=False)
|
||||
|
||||
if rc != 0:
|
||||
utils.log_debug('Manager.Refresh - exit %d' % (rc),
|
||||
utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc),
|
||||
'bg_black', 'fg_light_red')
|
||||
else:
|
||||
utils.log_debug('Manager.Refresh - exit %d' % (rc))
|
||||
utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc))
|
||||
return rc + lc
|
||||
|
||||
@dbus.service.method(
|
||||
|
||||
@@ -14,7 +14,7 @@ import dbus
|
||||
from .cfg import PV_INTERFACE
|
||||
from . import cmdhandler
|
||||
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
||||
lv_object_path_method
|
||||
lv_object_path_method, _handle_execute
|
||||
from .loader import common
|
||||
from .request import RequestEntry
|
||||
from .state import State
|
||||
@@ -138,19 +138,12 @@ class Pv(AutomatedProperties):
|
||||
# Remove the PV, if successful then remove from the model
|
||||
# Make sure we have a dbus object representing it
|
||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
||||
Pv.handle_execute(rc, out, err)
|
||||
Pv.handle_execute(*cmdhandler.pv_remove(pv_name, remove_options))
|
||||
return '/'
|
||||
|
||||
@staticmethod
|
||||
def handle_execute(rc, out, err):
|
||||
if rc == 0:
|
||||
cfg.load()
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
raise dbus.exceptions.DBusException(
|
||||
PV_INTERFACE,
|
||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
return _handle_execute(rc, out, err, PV_INTERFACE)
|
||||
|
||||
@staticmethod
|
||||
def validate_dbus_object(pv_uuid, pv_name):
|
||||
@@ -178,10 +171,8 @@ class Pv(AutomatedProperties):
|
||||
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||
|
||||
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
||||
resize_options)
|
||||
Pv.handle_execute(rc, out, err)
|
||||
Pv.handle_execute(*cmdhandler.pv_resize(pv_name, new_size_bytes,
|
||||
resize_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -200,9 +191,8 @@ class Pv(AutomatedProperties):
|
||||
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||
rc, out, err = cmdhandler.pv_allocatable(
|
||||
pv_name, yes_no, allocation_options)
|
||||
Pv.handle_execute(rc, out, err)
|
||||
Pv.handle_execute(*cmdhandler.pv_allocatable(pv_name, yes_no,
|
||||
allocation_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
|
||||
@@ -26,6 +26,15 @@ import signal
|
||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||
|
||||
|
||||
def _handle_execute(rc, out, err, interface):
|
||||
if rc == 0:
|
||||
cfg.load()
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface, 'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
|
||||
|
||||
def rtype(dbus_type):
|
||||
"""
|
||||
Decorator making sure that the decorated function returns a value of
|
||||
@@ -57,8 +66,20 @@ def n32(v):
|
||||
return int(float(v))
|
||||
|
||||
|
||||
@rtype(dbus.Double)
|
||||
def d(v):
|
||||
if not v:
|
||||
return 0.0
|
||||
return float(v)
|
||||
|
||||
|
||||
def _snake_to_pascal(s):
|
||||
return ''.join(x.title() for x in s.split('_'))
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
def init_class_from_arguments(obj_instance):
|
||||
def init_class_from_arguments(
|
||||
obj_instance, begin_suffix=None, snake_to_pascal=False):
|
||||
for k, v in list(sys._getframe(1).f_locals.items()):
|
||||
if k != 'self':
|
||||
nt = k
|
||||
@@ -69,8 +90,17 @@ def init_class_from_arguments(obj_instance):
|
||||
cur = getattr(obj_instance, nt, v)
|
||||
|
||||
# print 'Init class %s = %s' % (nt, str(v))
|
||||
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0):
|
||||
setattr(obj_instance, nt, v)
|
||||
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0)\
|
||||
and (begin_suffix is None or nt.startswith(begin_suffix)):
|
||||
|
||||
if begin_suffix and nt.startswith(begin_suffix):
|
||||
name = nt[len(begin_suffix):]
|
||||
if snake_to_pascal:
|
||||
name = _snake_to_pascal(name)
|
||||
|
||||
setattr(obj_instance, name, v)
|
||||
else:
|
||||
setattr(obj_instance, nt, v)
|
||||
|
||||
|
||||
def get_properties(f):
|
||||
@@ -338,6 +368,8 @@ def lv_object_path_method(name, meta):
|
||||
return _hidden_lv_obj_path_generate
|
||||
elif meta[0][0] == 't':
|
||||
return _thin_pool_obj_path_generate
|
||||
elif meta[0][0] == 'd':
|
||||
return _vdo_pool_object_path_generate
|
||||
elif meta[0][0] == 'C' and 'pool' in meta[1]:
|
||||
return _cache_pool_obj_path_generate
|
||||
|
||||
@@ -355,6 +387,10 @@ def _thin_pool_obj_path_generate():
|
||||
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
|
||||
|
||||
|
||||
def _vdo_pool_object_path_generate():
|
||||
return cfg.VDO_POOL_PATH + "/%d" % next(cfg.vdo_id)
|
||||
|
||||
|
||||
def _cache_pool_obj_path_generate():
|
||||
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
|
||||
|
||||
@@ -446,7 +482,7 @@ _ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
|
||||
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
|
||||
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
|
||||
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
|
||||
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin")
|
||||
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin", "_vdata")
|
||||
|
||||
# Tags can have the characters, based on the code
|
||||
# a-zA-Z0-9._-+/=!:&#
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
from .automatedproperties import AutomatedProperties
|
||||
|
||||
from . import utils
|
||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
|
||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n, \
|
||||
_handle_execute
|
||||
import dbus
|
||||
from . import cfg
|
||||
from .cfg import VG_INTERFACE
|
||||
from .cfg import VG_INTERFACE, VG_VDO_INTERFACE
|
||||
from . import cmdhandler
|
||||
from .request import RequestEntry
|
||||
from .loader import common
|
||||
@@ -46,7 +47,7 @@ def vgs_state_retrieve(selection, cache_refresh=True):
|
||||
|
||||
def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
||||
emit_signal=False, cache_refresh=True):
|
||||
return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
|
||||
return common(vgs_state_retrieve, (Vg, VgVdo, ), vg_specific, object_path, refresh,
|
||||
emit_signal, cache_refresh)
|
||||
|
||||
|
||||
@@ -98,7 +99,11 @@ class VgState(State):
|
||||
if not path:
|
||||
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
||||
self.Uuid, self.internal_name, vg_obj_path_generate)
|
||||
return Vg(path, self)
|
||||
|
||||
if cfg.vdo_support:
|
||||
return VgVdo(path, self)
|
||||
else:
|
||||
return Vg(path, self)
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def creation_signature(self):
|
||||
@@ -154,13 +159,7 @@ class Vg(AutomatedProperties):
|
||||
|
||||
@staticmethod
|
||||
def handle_execute(rc, out, err):
|
||||
if rc == 0:
|
||||
cfg.load()
|
||||
else:
|
||||
# Need to work on error handling, need consistent
|
||||
raise dbus.exceptions.DBusException(
|
||||
VG_INTERFACE,
|
||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||
return _handle_execute(rc, out, err, VG_INTERFACE)
|
||||
|
||||
@staticmethod
|
||||
def validate_dbus_object(vg_uuid, vg_name):
|
||||
@@ -176,9 +175,8 @@ class Vg(AutomatedProperties):
|
||||
def _rename(uuid, vg_name, new_name, rename_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.vg_rename(
|
||||
uuid, new_name, rename_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_rename(
|
||||
uuid, new_name, rename_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -197,8 +195,7 @@ class Vg(AutomatedProperties):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
# Remove the VG, if successful then remove from the model
|
||||
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_remove(vg_name, remove_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -214,8 +211,7 @@ class Vg(AutomatedProperties):
|
||||
@staticmethod
|
||||
def _change(uuid, vg_name, change_options):
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_change(change_options, vg_name))
|
||||
return '/'
|
||||
|
||||
# TODO: This should be broken into a number of different methods
|
||||
@@ -251,9 +247,8 @@ class Vg(AutomatedProperties):
|
||||
VG_INTERFACE,
|
||||
'PV Object path not found = %s!' % pv_op)
|
||||
|
||||
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
|
||||
reduce_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_reduce(
|
||||
vg_name, missing, pv_devices, reduce_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -283,9 +278,8 @@ class Vg(AutomatedProperties):
|
||||
VG_INTERFACE, 'PV Object path not found = %s!' % i)
|
||||
|
||||
if len(extend_devices):
|
||||
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
|
||||
extend_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_extend(
|
||||
vg_name, extend_devices, extend_options))
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
VG_INTERFACE, 'No pv_object_paths provided!')
|
||||
@@ -339,10 +333,8 @@ class Vg(AutomatedProperties):
|
||||
|
||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||
|
||||
rc, out, err = cmdhandler.vg_lv_create(
|
||||
vg_name, create_options, name, size_bytes, pv_dests)
|
||||
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_lv_create(
|
||||
vg_name, create_options, name, size_bytes, pv_dests))
|
||||
return Vg.fetch_new_lv(vg_name, name)
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -380,11 +372,8 @@ class Vg(AutomatedProperties):
|
||||
thin_pool, create_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
|
||||
rc, out, err = cmdhandler.vg_lv_create_linear(
|
||||
vg_name, create_options, name, size_bytes, thin_pool)
|
||||
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_lv_create_linear(
|
||||
vg_name, create_options, name, size_bytes, thin_pool))
|
||||
return Vg.fetch_new_lv(vg_name, name)
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -406,10 +395,9 @@ class Vg(AutomatedProperties):
|
||||
stripe_size_kb, thin_pool, create_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.vg_lv_create_striped(
|
||||
Vg.handle_execute(*cmdhandler.vg_lv_create_striped(
|
||||
vg_name, create_options, name, size_bytes,
|
||||
num_stripes, stripe_size_kb, thin_pool)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
num_stripes, stripe_size_kb, thin_pool))
|
||||
return Vg.fetch_new_lv(vg_name, name)
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -434,9 +422,8 @@ class Vg(AutomatedProperties):
|
||||
num_copies, create_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.vg_lv_create_mirror(
|
||||
vg_name, create_options, name, size_bytes, num_copies)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_lv_create_mirror(
|
||||
vg_name, create_options, name, size_bytes, num_copies))
|
||||
return Vg.fetch_new_lv(vg_name, name)
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -459,10 +446,9 @@ class Vg(AutomatedProperties):
|
||||
num_stripes, stripe_size_kb, create_options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.vg_lv_create_raid(
|
||||
Vg.handle_execute(*cmdhandler.vg_lv_create_raid(
|
||||
vg_name, create_options, name, raid_type, size_bytes,
|
||||
num_stripes, stripe_size_kb)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
num_stripes, stripe_size_kb))
|
||||
return Vg.fetch_new_lv(vg_name, name)
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -560,9 +546,8 @@ class Vg(AutomatedProperties):
|
||||
raise dbus.exceptions.DBusException(
|
||||
VG_INTERFACE, 'PV object path = %s not found' % p)
|
||||
|
||||
rc, out, err = cmdhandler.pv_tag(
|
||||
pv_devices, tags_add, tags_del, tag_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.pv_tag(
|
||||
pv_devices, tags_add, tags_del, tag_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -603,9 +588,8 @@ class Vg(AutomatedProperties):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
|
||||
rc, out, err = cmdhandler.vg_tag(
|
||||
vg_name, tags_add, tags_del, tag_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.vg_tag(
|
||||
vg_name, tags_add, tags_del, tag_options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -644,8 +628,7 @@ class Vg(AutomatedProperties):
|
||||
def _vg_change_set(uuid, vg_name, method, value, options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = method(vg_name, value, options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*method(vg_name, value, options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -705,9 +688,8 @@ class Vg(AutomatedProperties):
|
||||
options):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.activate_deactivate(
|
||||
'vgchange', vg_name, activate, control_flags, options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
Vg.handle_execute(*cmdhandler.activate_deactivate(
|
||||
'vgchange', vg_name, activate, control_flags, options))
|
||||
return '/'
|
||||
|
||||
@dbus.service.method(
|
||||
@@ -795,3 +777,71 @@ class Vg(AutomatedProperties):
|
||||
@property
|
||||
def Clustered(self):
|
||||
return self._attribute(5, 'c')
|
||||
|
||||
|
||||
class VgVdo(Vg):
|
||||
|
||||
# noinspection PyUnusedLocal,PyPep8Naming
|
||||
def __init__(self, object_path, object_state):
|
||||
super(VgVdo, self).__init__(object_path, vgs_state_retrieve)
|
||||
self.set_interface(VG_VDO_INTERFACE)
|
||||
self._object_path = object_path
|
||||
self.state = object_state
|
||||
|
||||
@staticmethod
|
||||
def _lv_vdo_pool_create_with_lv(uuid, vg_name, pool_name, lv_name,
|
||||
data_size, virtual_size, create_options):
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool_lv_and_lv(
|
||||
vg_name, pool_name, lv_name, data_size, virtual_size,
|
||||
create_options))
|
||||
return Vg.fetch_new_lv(vg_name, pool_name)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VG_VDO_INTERFACE,
|
||||
in_signature='ssttia{sv}',
|
||||
out_signature='(oo)',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def CreateVdoPoolandLv(self, pool_name, lv_name, data_size, virtual_size,
|
||||
tmo, create_options, cb, cbe):
|
||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, pool_name)
|
||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, lv_name)
|
||||
|
||||
r = RequestEntry(tmo, VgVdo._lv_vdo_pool_create_with_lv,
|
||||
(self.state.Uuid, self.state.lvm_id,
|
||||
pool_name, lv_name, round_size(data_size),
|
||||
round_size(virtual_size),
|
||||
create_options), cb, cbe)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@staticmethod
|
||||
def _vdo_pool_create(uuid, vg_name, pool_lv, name, virtual_size, create_options):
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
|
||||
# Retrieve the full name of the pool lv
|
||||
pool = cfg.om.get_object_by_path(pool_lv)
|
||||
if not pool:
|
||||
msg = 'LV with object path %s not present!' % \
|
||||
(pool_lv)
|
||||
raise dbus.exceptions.DBusException(VG_VDO_INTERFACE, msg)
|
||||
|
||||
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool(
|
||||
pool.lv_full_name(), name, virtual_size,
|
||||
create_options))
|
||||
return Vg.fetch_new_lv(vg_name, pool.Name)
|
||||
|
||||
@dbus.service.method(
|
||||
dbus_interface=VG_VDO_INTERFACE,
|
||||
in_signature='ostia{sv}',
|
||||
out_signature='(oo)',
|
||||
async_callbacks=('cb', 'cbe'))
|
||||
def CreateVdoPool(self, pool_lv, name, virtual_size,
|
||||
tmo, create_options, cb, cbe):
|
||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, name)
|
||||
|
||||
r = RequestEntry(tmo, VgVdo._vdo_pool_create,
|
||||
(self.state.Uuid, self.state.lvm_id,
|
||||
pool_lv, name,
|
||||
round_size(virtual_size),
|
||||
create_options), cb, cbe)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@@ -280,13 +280,12 @@ static void format_info_line(char *line, char *r_name, char *r_type)
|
||||
|
||||
static void format_info(void)
|
||||
{
|
||||
char line[MAX_LINE];
|
||||
char r_name[MAX_NAME+1];
|
||||
char r_type[MAX_NAME+1];
|
||||
char line[MAX_LINE] = { 0 };
|
||||
char r_name[MAX_NAME+1] = { 0 };
|
||||
char r_type[MAX_NAME+1] = { 0 };
|
||||
int i, j;
|
||||
|
||||
j = 0;
|
||||
memset(line, 0, sizeof(line));
|
||||
|
||||
for (i = 0; i < dump_len; i++) {
|
||||
line[j++] = dump_buf[i];
|
||||
@@ -326,6 +325,8 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
|
||||
{
|
||||
int reply_result;
|
||||
|
||||
*result = NO_LOCKD_RESULT;
|
||||
|
||||
if (reply.error) {
|
||||
log_error("lvmlockd_result reply error %d", reply.error);
|
||||
return 0;
|
||||
@@ -337,7 +338,7 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
|
||||
}
|
||||
|
||||
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
|
||||
if (reply_result == -1000) {
|
||||
if (reply_result == NO_LOCKD_RESULT) {
|
||||
log_error("lvmlockd_result no op_result");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "libdaemon/client/daemon-client.h"
|
||||
|
||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
||||
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
|
||||
|
||||
/* Wrappers to open/close connection */
|
||||
|
||||
@@ -22,9 +23,9 @@ static inline daemon_handle lvmlockd_open(const char *sock)
|
||||
daemon_info lvmlockd_info = {
|
||||
.path = "lvmlockd",
|
||||
.socket = sock ?: LVMLOCKD_SOCKET,
|
||||
.autostart = 0,
|
||||
.protocol = "lvmlockd",
|
||||
.protocol_version = 1,
|
||||
.autostart = 0
|
||||
};
|
||||
|
||||
return daemon_open(lvmlockd_info);
|
||||
@@ -32,7 +33,7 @@ static inline daemon_handle lvmlockd_open(const char *sock)
|
||||
|
||||
static inline void lvmlockd_close(daemon_handle h)
|
||||
{
|
||||
return daemon_close(h);
|
||||
daemon_close(h);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#define EXTERN
|
||||
#include "lvmlockd-internal.h"
|
||||
|
||||
static int str_to_mode(const char *str);
|
||||
|
||||
/*
|
||||
* Basic operation of lvmlockd
|
||||
*
|
||||
@@ -142,6 +144,8 @@ static const char *lvmlockd_protocol = "lvmlockd";
|
||||
static const int lvmlockd_protocol_version = 1;
|
||||
static int daemon_quit;
|
||||
static int adopt_opt;
|
||||
static uint32_t adopt_update_count;
|
||||
static const char *adopt_file;
|
||||
|
||||
/*
|
||||
* We use a separate socket for dumping daemon info.
|
||||
@@ -811,6 +815,144 @@ int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsi
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write new info when a command exits if that command has acquired a new LV
|
||||
* lock. If the command has released an LV lock we don't bother updating the
|
||||
* info. When adopting, we eliminate any LV lock adoptions if there is no dm
|
||||
* device for that LV. If lvmlockd is terminated after acquiring but before
|
||||
* writing this file, those LV locks would not be adopted on restart.
|
||||
*/
|
||||
|
||||
#define ADOPT_VERSION_MAJOR 1
|
||||
#define ADOPT_VERSION_MINOR 0
|
||||
|
||||
static void write_adopt_file(void)
|
||||
{
|
||||
struct lockspace *ls;
|
||||
struct resource *r;
|
||||
struct lock *lk;
|
||||
time_t t;
|
||||
FILE *fp;
|
||||
|
||||
if (!(fp = fopen(adopt_file, "w")))
|
||||
return;
|
||||
|
||||
adopt_update_count++;
|
||||
|
||||
t = time(NULL);
|
||||
fprintf(fp, "lvmlockd adopt_version %u.%u pid %d updates %u %s",
|
||||
ADOPT_VERSION_MAJOR, ADOPT_VERSION_MINOR, getpid(), adopt_update_count, ctime(&t));
|
||||
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
list_for_each_entry(ls, &lockspaces, list) {
|
||||
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
|
||||
continue;
|
||||
fprintf(fp, "VG: %38s %s %s %s\n",
|
||||
ls->vg_uuid, ls->vg_name, lm_str(ls->lm_type), ls->vg_args);
|
||||
list_for_each_entry(r, &ls->resources, list) {
|
||||
if (r->type != LD_RT_LV)
|
||||
continue;
|
||||
if ((r->mode != LD_LK_EX) && (r->mode != LD_LK_SH))
|
||||
continue;
|
||||
list_for_each_entry(lk, &r->locks, list) {
|
||||
fprintf(fp, "LV: %38s %s %s %s %u\n",
|
||||
ls->vg_uuid, r->name, r->lv_args, mode_str(r->mode), r->version);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static int read_adopt_file(struct list_head *vg_lockd)
|
||||
{
|
||||
char adopt_line[512];
|
||||
char vg_uuid[72];
|
||||
char lm_type_str[16];
|
||||
char mode[8];
|
||||
struct lockspace *ls, *ls2;
|
||||
struct resource *r;
|
||||
FILE *fp;
|
||||
|
||||
if (MAX_ARGS != 64 || MAX_NAME != 64)
|
||||
return -1;
|
||||
|
||||
if (!(fp = fopen(adopt_file, "r")))
|
||||
return 0;
|
||||
|
||||
while (fgets(adopt_line, sizeof(adopt_line), fp)) {
|
||||
if (adopt_line[0] == '#')
|
||||
continue;
|
||||
else if (!strncmp(adopt_line, "lvmlockd", 8)) {
|
||||
unsigned int v_major = 0, v_minor = 0;
|
||||
if ((sscanf(adopt_line, "lvmlockd adopt_version %u.%u", &v_major, &v_minor) != 2) ||
|
||||
(v_major != ADOPT_VERSION_MAJOR))
|
||||
goto fail;
|
||||
|
||||
} else if (!strncmp(adopt_line, "VG:", 3)) {
|
||||
if (!(ls = alloc_lockspace()))
|
||||
goto fail;
|
||||
|
||||
memset(vg_uuid, 0, sizeof(vg_uuid));
|
||||
|
||||
if (sscanf(adopt_line, "VG: %63s %64s %16s %64s",
|
||||
vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(ls->vg_uuid, vg_uuid, 64);
|
||||
|
||||
if ((ls->lm_type = str_to_lm(lm_type_str)) < 0)
|
||||
goto fail;
|
||||
|
||||
list_add(&ls->list, vg_lockd);
|
||||
|
||||
} else if (!strncmp(adopt_line, "LV:", 3)) {
|
||||
if (!(r = alloc_resource()))
|
||||
goto fail;
|
||||
|
||||
r->type = LD_RT_LV;
|
||||
|
||||
memset(vg_uuid, 0, sizeof(vg_uuid));
|
||||
|
||||
if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u",
|
||||
vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((r->adopt_mode = str_to_mode(mode)) == LD_LK_IV)
|
||||
goto fail;
|
||||
|
||||
if (ls && !memcmp(ls->vg_uuid, vg_uuid, 64)) {
|
||||
list_add(&r->list, &ls->resources);
|
||||
r = NULL;
|
||||
} else {
|
||||
list_for_each_entry(ls2, vg_lockd, list) {
|
||||
if (memcmp(ls2->vg_uuid, vg_uuid, 64))
|
||||
continue;
|
||||
list_add(&r->list, &ls2->resources);
|
||||
r = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
log_error("No lockspace found for resource %s vg_uuid %s", r->name, vg_uuid);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are few enough that arrays of function pointers can
|
||||
* be avoided.
|
||||
@@ -4689,6 +4831,7 @@ static void *client_thread_main(void *arg_in)
|
||||
struct client *cl;
|
||||
struct action *act;
|
||||
struct action *act_un;
|
||||
uint32_t lock_acquire_count = 0, lock_acquire_written = 0;
|
||||
int rv;
|
||||
|
||||
while (1) {
|
||||
@@ -4720,6 +4863,9 @@ static void *client_thread_main(void *arg_in)
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
if (act->flags & LD_AF_LV_LOCK)
|
||||
lock_acquire_count++;
|
||||
|
||||
/*
|
||||
* The client failed after we acquired an LV lock for
|
||||
* it, but before getting this reply saying it's done.
|
||||
@@ -4741,6 +4887,11 @@ static void *client_thread_main(void *arg_in)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (adopt_opt && (lock_acquire_count > lock_acquire_written)) {
|
||||
lock_acquire_written = lock_acquire_count;
|
||||
write_adopt_file();
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue incoming actions for lockspace threads
|
||||
*/
|
||||
@@ -4814,6 +4965,8 @@ static void *client_thread_main(void *arg_in)
|
||||
pthread_mutex_unlock(&client_mutex);
|
||||
}
|
||||
out:
|
||||
if (adopt_opt && lock_acquire_written)
|
||||
unlink(adopt_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -4846,180 +4999,6 @@ static void close_client_thread(void)
|
||||
log_error("pthread_join client_thread error %d", perrno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a list of all VGs with a lockd type (sanlock|dlm).
|
||||
* We'll match this list against a list of existing lockspaces that are
|
||||
* found in the lock manager.
|
||||
*
|
||||
* For each of these VGs, also create a struct resource on ls->resources to
|
||||
* represent each LV in the VG that uses a lock. For each of these LVs
|
||||
* that are active, we'll attempt to adopt a lock.
|
||||
*/
|
||||
|
||||
static int get_lockd_vgs(struct list_head *vg_lockd)
|
||||
{
|
||||
/* FIXME: get VGs some other way */
|
||||
return -1;
|
||||
#if 0
|
||||
struct list_head update_vgs;
|
||||
daemon_reply reply;
|
||||
struct dm_config_node *cn;
|
||||
struct dm_config_node *metadata;
|
||||
struct dm_config_node *md_cn;
|
||||
struct dm_config_node *lv_cn;
|
||||
struct lockspace *ls, *safe;
|
||||
struct resource *r;
|
||||
const char *vg_name;
|
||||
const char *vg_uuid;
|
||||
const char *lv_uuid;
|
||||
const char *lock_type;
|
||||
const char *lock_args;
|
||||
char find_str_path[PATH_MAX];
|
||||
int rv = 0;
|
||||
|
||||
INIT_LIST_HEAD(&update_vgs);
|
||||
|
||||
reply = send_lvmetad("vg_list", "token = %s", "skip", NULL);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
log_error("vg_list from lvmetad failed %d", reply.error);
|
||||
rv = -EINVAL;
|
||||
goto destroy;
|
||||
}
|
||||
|
||||
if (!(cn = dm_config_find_node(reply.cft->root, "volume_groups"))) {
|
||||
log_error("get_lockd_vgs no vgs");
|
||||
rv = -EINVAL;
|
||||
goto destroy;
|
||||
}
|
||||
|
||||
/* create an update_vgs list of all vg uuids */
|
||||
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
vg_uuid = cn->key;
|
||||
|
||||
if (!(ls = alloc_lockspace())) {
|
||||
rv = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(ls->vg_uuid, vg_uuid, 64);
|
||||
list_add_tail(&ls->list, &update_vgs);
|
||||
log_debug("get_lockd_vgs %s", vg_uuid);
|
||||
}
|
||||
destroy:
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
if (rv < 0)
|
||||
goto out;
|
||||
|
||||
/* get vg_name and lock_type for each vg uuid entry in update_vgs */
|
||||
|
||||
list_for_each_entry(ls, &update_vgs, list) {
|
||||
reply = send_lvmetad("vg_lookup",
|
||||
"token = %s", "skip",
|
||||
"uuid = %s", ls->vg_uuid,
|
||||
NULL);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
log_error("vg_lookup from lvmetad failed %d", reply.error);
|
||||
rv = -EINVAL;
|
||||
goto next;
|
||||
}
|
||||
|
||||
vg_name = daemon_reply_str(reply, "name", NULL);
|
||||
if (!vg_name) {
|
||||
log_error("get_lockd_vgs %s no name", ls->vg_uuid);
|
||||
rv = -EINVAL;
|
||||
goto next;
|
||||
}
|
||||
|
||||
strncpy(ls->vg_name, vg_name, MAX_NAME);
|
||||
|
||||
metadata = dm_config_find_node(reply.cft->root, "metadata");
|
||||
if (!metadata) {
|
||||
log_error("get_lockd_vgs %s name %s no metadata",
|
||||
ls->vg_uuid, ls->vg_name);
|
||||
rv = -EINVAL;
|
||||
goto next;
|
||||
}
|
||||
|
||||
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
|
||||
ls->lm_type = str_to_lm(lock_type);
|
||||
|
||||
if ((ls->lm_type != LD_LM_SANLOCK) && (ls->lm_type != LD_LM_DLM)) {
|
||||
log_debug("get_lockd_vgs %s not lockd type", ls->vg_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
lock_args = dm_config_find_str(metadata, "metadata/lock_args", NULL);
|
||||
if (lock_args)
|
||||
strncpy(ls->vg_args, lock_args, MAX_ARGS);
|
||||
|
||||
log_debug("get_lockd_vgs %s lock_type %s lock_args %s",
|
||||
ls->vg_name, lock_type, lock_args ?: "none");
|
||||
|
||||
/*
|
||||
* Make a record (struct resource) of each lv that uses a lock.
|
||||
* For any lv that uses a lock, we'll check if the lv is active
|
||||
* and if so try to adopt a lock for it.
|
||||
*/
|
||||
|
||||
for (md_cn = metadata->child; md_cn; md_cn = md_cn->sib) {
|
||||
if (strcmp(md_cn->key, "logical_volumes"))
|
||||
continue;
|
||||
|
||||
for (lv_cn = md_cn->child; lv_cn; lv_cn = lv_cn->sib) {
|
||||
snprintf(find_str_path, PATH_MAX, "%s/lock_args", lv_cn->key);
|
||||
lock_args = dm_config_find_str(lv_cn, find_str_path, NULL);
|
||||
if (!lock_args)
|
||||
continue;
|
||||
|
||||
snprintf(find_str_path, PATH_MAX, "%s/id", lv_cn->key);
|
||||
lv_uuid = dm_config_find_str(lv_cn, find_str_path, NULL);
|
||||
|
||||
if (!lv_uuid) {
|
||||
log_error("get_lock_vgs no lv id for name %s", lv_cn->key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(r = alloc_resource())) {
|
||||
rv = -ENOMEM;
|
||||
goto next;
|
||||
}
|
||||
|
||||
r->use_vb = 0;
|
||||
r->type = LD_RT_LV;
|
||||
strncpy(r->name, lv_uuid, MAX_NAME);
|
||||
if (lock_args)
|
||||
strncpy(r->lv_args, lock_args, MAX_ARGS);
|
||||
list_add_tail(&r->list, &ls->resources);
|
||||
log_debug("get_lockd_vgs %s lv %s %s (name %s)",
|
||||
ls->vg_name, r->name, lock_args ? lock_args : "", lv_cn->key);
|
||||
}
|
||||
}
|
||||
next:
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
if (rv < 0)
|
||||
break;
|
||||
}
|
||||
out:
|
||||
/* Return lockd VG's on the vg_lockd list. */
|
||||
|
||||
list_for_each_entry_safe(ls, safe, &update_vgs, list) {
|
||||
list_del(&ls->list);
|
||||
|
||||
if ((ls->lm_type == LD_LM_SANLOCK) || (ls->lm_type == LD_LM_DLM))
|
||||
list_add_tail(&ls->list, vg_lockd);
|
||||
else
|
||||
free(ls);
|
||||
}
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char _dm_uuid[DM_UUID_LEN];
|
||||
|
||||
static char *get_dm_uuid(char *dm_name)
|
||||
@@ -5236,9 +5215,9 @@ static void adopt_locks(void)
|
||||
INIT_LIST_HEAD(&to_unlock);
|
||||
|
||||
/*
|
||||
* Get list of lockspaces from lock managers.
|
||||
* Get list of VGs from lvmetad with a lockd type.
|
||||
* Get list of active lockd type LVs from /dev.
|
||||
* Get list of lockspaces from currently running lock managers.
|
||||
* Get list of shared VGs from file written by prior lvmlockd.
|
||||
* Get list of active LVs (in the shared VGs) from the file.
|
||||
*/
|
||||
|
||||
if (lm_support_dlm() && lm_is_running_dlm()) {
|
||||
@@ -5262,12 +5241,17 @@ static void adopt_locks(void)
|
||||
* Adds a struct lockspace to vg_lockd for each lockd VG.
|
||||
* Adds a struct resource to ls->resources for each LV.
|
||||
*/
|
||||
rv = get_lockd_vgs(&vg_lockd);
|
||||
rv = read_adopt_file(&vg_lockd);
|
||||
if (rv < 0) {
|
||||
log_error("adopt_locks get_lockd_vgs failed");
|
||||
log_error("adopt_locks read_adopt_file failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (list_empty(&vg_lockd)) {
|
||||
log_debug("No lockspaces in adopt file");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each resource on each lockspace, check if the
|
||||
* corresponding LV is active. If so, leave the
|
||||
@@ -5506,7 +5490,7 @@ static void adopt_locks(void)
|
||||
goto fail;
|
||||
act->op = LD_OP_LOCK;
|
||||
act->rt = LD_RT_LV;
|
||||
act->mode = LD_LK_EX;
|
||||
act->mode = r->adopt_mode;
|
||||
act->flags = (LD_AF_ADOPT | LD_AF_PERSISTENT);
|
||||
act->client_id = INTERNAL_CLIENT_ID;
|
||||
act->lm_type = ls->lm_type;
|
||||
@@ -5604,8 +5588,9 @@ static void adopt_locks(void)
|
||||
* Adopt failed because the orphan has a different mode
|
||||
* than initially requested. Repeat the lock-adopt operation
|
||||
* with the other mode. N.B. this logic depends on first
|
||||
* trying sh then ex for GL/VG locks, and ex then sh for
|
||||
* LV locks.
|
||||
* trying sh then ex for GL/VG locks; for LV locks the mode
|
||||
* from the adopt file is tried first, the alternate
|
||||
* (if the mode in adopt file was wrong somehow.)
|
||||
*/
|
||||
|
||||
if ((act->rt != LD_RT_LV) && (act->mode == LD_LK_SH)) {
|
||||
@@ -5613,9 +5598,12 @@ static void adopt_locks(void)
|
||||
act->mode = LD_LK_EX;
|
||||
rv = add_lock_action(act);
|
||||
|
||||
} else if ((act->rt == LD_RT_LV) && (act->mode == LD_LK_EX)) {
|
||||
/* LV locks: attempt to adopt sh after ex failed. */
|
||||
act->mode = LD_LK_SH;
|
||||
} else if (act->rt == LD_RT_LV) {
|
||||
/* LV locks: attempt to adopt the other mode. */
|
||||
if (act->mode == LD_LK_EX)
|
||||
act->mode = LD_LK_SH;
|
||||
else if (act->mode == LD_LK_SH)
|
||||
act->mode = LD_LK_EX;
|
||||
rv = add_lock_action(act);
|
||||
|
||||
} else {
|
||||
@@ -5750,10 +5738,13 @@ static void adopt_locks(void)
|
||||
if (count_start_fail || count_adopt_fail)
|
||||
goto fail;
|
||||
|
||||
unlink(adopt_file);
|
||||
write_adopt_file();
|
||||
log_debug("adopt_locks done");
|
||||
return;
|
||||
|
||||
fail:
|
||||
unlink(adopt_file);
|
||||
log_error("adopt_locks failed, reset host");
|
||||
}
|
||||
|
||||
@@ -6028,6 +6019,8 @@ static void usage(char *prog, FILE *file)
|
||||
fprintf(file, " Set path to the pid file. [%s]\n", LVMLOCKD_PIDFILE);
|
||||
fprintf(file, " --socket-path | -s <path>\n");
|
||||
fprintf(file, " Set path to the socket to listen on. [%s]\n", LVMLOCKD_SOCKET);
|
||||
fprintf(file, " --adopt-file <path>\n");
|
||||
fprintf(file, " Set path to the adopt file. [%s]\n", LVMLOCKD_ADOPT_FILE);
|
||||
fprintf(file, " --syslog-priority | -S err|warning|debug\n");
|
||||
fprintf(file, " Write log messages from this level up to syslog. [%s]\n", _syslog_num_to_name(LOG_SYSLOG_PRIO));
|
||||
fprintf(file, " --gl-type | -g <str>\n");
|
||||
@@ -6045,14 +6038,14 @@ static void usage(char *prog, FILE *file)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
daemon_state ds = {
|
||||
.daemon_main = main_loop,
|
||||
.daemon_init = NULL,
|
||||
.daemon_fini = NULL,
|
||||
.name = "lvmlockd",
|
||||
.pidfile = getenv("LVM_LVMLOCKD_PIDFILE"),
|
||||
.socket_path = getenv("LVM_LVMLOCKD_SOCKET"),
|
||||
.protocol = lvmlockd_protocol,
|
||||
.protocol_version = lvmlockd_protocol_version,
|
||||
.name = "lvmlockd",
|
||||
.daemon_init = NULL,
|
||||
.daemon_fini = NULL,
|
||||
.daemon_main = main_loop,
|
||||
};
|
||||
|
||||
static struct option long_options[] = {
|
||||
@@ -6063,6 +6056,7 @@ int main(int argc, char *argv[])
|
||||
{"daemon-debug", no_argument, 0, 'D' },
|
||||
{"pid-file", required_argument, 0, 'p' },
|
||||
{"socket-path", required_argument, 0, 's' },
|
||||
{"adopt-file", required_argument, 0, 128 },
|
||||
{"gl-type", required_argument, 0, 'g' },
|
||||
{"host-id", required_argument, 0, 'i' },
|
||||
{"host-id-file", required_argument, 0, 'F' },
|
||||
@@ -6085,6 +6079,9 @@ int main(int argc, char *argv[])
|
||||
switch (c) {
|
||||
case '0':
|
||||
break;
|
||||
case 128:
|
||||
adopt_file = strdup(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
@@ -6146,6 +6143,9 @@ int main(int argc, char *argv[])
|
||||
if (!ds.socket_path)
|
||||
ds.socket_path = LVMLOCKD_SOCKET;
|
||||
|
||||
if (!adopt_file)
|
||||
adopt_file = LVMLOCKD_ADOPT_FILE;
|
||||
|
||||
/* runs daemon_main/main_loop */
|
||||
daemon_start(ds);
|
||||
|
||||
|
||||
@@ -398,12 +398,18 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
(void *)1, (void *)1, (void *)1,
|
||||
NULL, NULL);
|
||||
|
||||
if (rv == -1 && errno == -EAGAIN) {
|
||||
if (rv == -1 && (errno == EAGAIN)) {
|
||||
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
||||
ls->name, r->name, ld_mode);
|
||||
rv = -EUCLEAN;
|
||||
goto fail;
|
||||
}
|
||||
if (rv == -1 && (errno == ENOENT)) {
|
||||
log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
|
||||
ls->name, r->name, ld_mode);
|
||||
rv = -ENOENT;
|
||||
goto fail;
|
||||
}
|
||||
if (rv < 0) {
|
||||
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
|
||||
ls->name, r->name, mode, flags, rv, errno);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef _LVM_LVMLOCKD_INTERNAL_H
|
||||
#define _LVM_LVMLOCKD_INTERNAL_H
|
||||
|
||||
#include "base/memory/container_of.h"
|
||||
|
||||
#define MAX_NAME 64
|
||||
#define MAX_ARGS 64
|
||||
|
||||
@@ -145,6 +147,7 @@ struct resource {
|
||||
char name[MAX_NAME+1]; /* vg name or lv name */
|
||||
int8_t type; /* resource type LD_RT_ */
|
||||
int8_t mode;
|
||||
int8_t adopt_mode;
|
||||
unsigned int sh_count; /* number of sh locks on locks list */
|
||||
uint32_t version;
|
||||
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
||||
@@ -155,7 +158,7 @@ struct resource {
|
||||
struct list_head locks;
|
||||
struct list_head actions;
|
||||
char lv_args[MAX_ARGS+1];
|
||||
char lm_data[0]; /* lock manager specific data */
|
||||
char lm_data[]; /* lock manager specific data */
|
||||
};
|
||||
|
||||
#define LD_LF_PERSISTENT 0x00000001
|
||||
@@ -216,10 +219,6 @@ struct val_blk {
|
||||
/* lm_unlock flags */
|
||||
#define LMUF_FREE_VG 0x00000001
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
|
||||
@@ -164,20 +164,20 @@ struct dm_info {
|
||||
struct dm_deps {
|
||||
uint32_t count;
|
||||
uint32_t filler;
|
||||
uint64_t device[0];
|
||||
uint64_t device[];
|
||||
};
|
||||
|
||||
struct dm_names {
|
||||
uint64_t dev;
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct dm_versions {
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
int dm_get_library_version(char *version, size_t size);
|
||||
@@ -234,6 +234,7 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt);
|
||||
int dm_task_secure_data(struct dm_task *dmt);
|
||||
int dm_task_retry_remove(struct dm_task *dmt);
|
||||
int dm_task_deferred_remove(struct dm_task *dmt);
|
||||
void dm_task_skip_reload_params_compare(struct dm_task *dmt);
|
||||
|
||||
/*
|
||||
* Record timestamp immediately after the ioctl returns.
|
||||
@@ -383,7 +384,7 @@ int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_cache **status);
|
||||
|
||||
struct dm_status_writecache {
|
||||
uint32_t error;
|
||||
uint64_t error;
|
||||
uint64_t total_blocks;
|
||||
uint64_t free_blocks;
|
||||
uint64_t writeback_blocks;
|
||||
@@ -392,6 +393,15 @@ struct dm_status_writecache {
|
||||
int dm_get_status_writecache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_writecache **status);
|
||||
|
||||
struct dm_status_integrity {
|
||||
uint64_t number_of_mismatches;
|
||||
uint64_t provided_data_sectors;
|
||||
uint64_t recalc_sector;
|
||||
};
|
||||
|
||||
int dm_get_status_integrity(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_integrity **status);
|
||||
|
||||
/*
|
||||
* Parse params from STATUS call for snapshot target
|
||||
*
|
||||
@@ -941,6 +951,8 @@ struct writecache_settings {
|
||||
uint64_t autocommit_time; /* in milliseconds */
|
||||
uint32_t fua;
|
||||
uint32_t nofua;
|
||||
uint32_t cleaner;
|
||||
uint32_t max_age;
|
||||
|
||||
/*
|
||||
* Allow an unrecognized key and its val to be passed to the kernel for
|
||||
@@ -960,6 +972,8 @@ struct writecache_settings {
|
||||
unsigned autocommit_time_set:1;
|
||||
unsigned fua_set:1;
|
||||
unsigned nofua_set:1;
|
||||
unsigned cleaner_set:1;
|
||||
unsigned max_age_set:1;
|
||||
};
|
||||
|
||||
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||
@@ -970,12 +984,42 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||
uint32_t writecache_block_size,
|
||||
struct writecache_settings *settings);
|
||||
|
||||
struct integrity_settings {
|
||||
char mode[8];
|
||||
uint32_t tag_size;
|
||||
uint32_t block_size; /* optional table param always set by lvm */
|
||||
const char *internal_hash; /* optional table param always set by lvm */
|
||||
|
||||
uint32_t journal_sectors;
|
||||
uint32_t interleave_sectors;
|
||||
uint32_t buffer_sectors;
|
||||
uint32_t journal_watermark;
|
||||
uint32_t commit_time;
|
||||
uint32_t bitmap_flush_interval;
|
||||
uint64_t sectors_per_bit;
|
||||
|
||||
unsigned journal_sectors_set:1;
|
||||
unsigned interleave_sectors_set:1;
|
||||
unsigned buffer_sectors_set:1;
|
||||
unsigned journal_watermark_set:1;
|
||||
unsigned commit_time_set:1;
|
||||
unsigned bitmap_flush_interval_set:1;
|
||||
unsigned sectors_per_bit_set:1;
|
||||
};
|
||||
|
||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *origin_uuid,
|
||||
const char *meta_uuid,
|
||||
struct integrity_settings *settings,
|
||||
int recalculate);
|
||||
|
||||
/*
|
||||
* VDO target
|
||||
*/
|
||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *vdo_pool_name,
|
||||
const char *data_uuid,
|
||||
uint64_t data_size,
|
||||
const struct dm_vdo_target_params *param);
|
||||
@@ -1274,7 +1318,7 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
|
||||
int dm_bit_get_last(dm_bitset_t bs);
|
||||
int dm_bit_get_prev(dm_bitset_t bs, int last_bit);
|
||||
|
||||
#define DM_BITS_PER_INT (sizeof(int) * CHAR_BIT)
|
||||
#define DM_BITS_PER_INT ((unsigned)sizeof(int) * CHAR_BIT)
|
||||
|
||||
#define dm_bit(bs, i) \
|
||||
((bs)[((i) / DM_BITS_PER_INT) + 1] & (0x1 << ((i) & (DM_BITS_PER_INT - 1))))
|
||||
|
||||
@@ -205,7 +205,7 @@ static int _get_proc_number(const char *file, const char *name,
|
||||
}
|
||||
|
||||
while (getline(&line, &len, fl) != -1) {
|
||||
if (sscanf(line, "%d %255s\n", &num, &nm[0]) == 2) {
|
||||
if (sscanf(line, "%u %255s\n", &num, &nm[0]) == 2) {
|
||||
if (!strcmp(name, nm)) {
|
||||
if (number) {
|
||||
*number = num;
|
||||
@@ -805,6 +805,11 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_task_skip_reload_params_compare(struct dm_task *dmt)
|
||||
{
|
||||
dmt->skip_reload_params_compare = 1;
|
||||
}
|
||||
|
||||
int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
|
||||
{
|
||||
switch (add_node) {
|
||||
@@ -1575,11 +1580,29 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
|
||||
len = strlen(t2->params);
|
||||
while (len-- > 0 && t2->params[len] == ' ')
|
||||
t2->params[len] = '\0';
|
||||
if ((t1->start != t2->start) ||
|
||||
(t1->length != t2->length) ||
|
||||
(strcmp(t1->type, t2->type)) ||
|
||||
(strcmp(t1->params, t2->params)))
|
||||
|
||||
if (t1->start != t2->start) {
|
||||
log_debug("reload %u:%u start diff", task->major, task->minor);
|
||||
goto no_match;
|
||||
}
|
||||
if (t1->length != t2->length) {
|
||||
log_debug("reload %u:%u length diff", task->major, task->minor);
|
||||
goto no_match;
|
||||
}
|
||||
if (strcmp(t1->type, t2->type)) {
|
||||
log_debug("reload %u:%u type diff %s %s", task->major, task->minor, t1->type, t2->type);
|
||||
goto no_match;
|
||||
}
|
||||
if (strcmp(t1->params, t2->params)) {
|
||||
if (dmt->skip_reload_params_compare)
|
||||
log_debug("reload %u:%u skip params ignore %s %s",
|
||||
task->major, task->minor, t1->params, t2->params);
|
||||
else {
|
||||
log_debug("reload %u:%u params diff", task->major, task->minor);
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
|
||||
t1 = t1->next;
|
||||
t2 = t2->next;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ struct dm_task {
|
||||
int skip_lockfs;
|
||||
int query_inactive_table;
|
||||
int suppress_identical_reload;
|
||||
int skip_reload_params_compare;
|
||||
dm_add_node_t add_node;
|
||||
uint64_t existing_table_size;
|
||||
int cookie_set;
|
||||
|
||||
@@ -512,7 +512,7 @@ int unmangle_string(const char *str, const char *str_name, size_t len,
|
||||
int strict = mode != DM_STRING_MANGLING_NONE;
|
||||
char str_rest[DM_NAME_LEN];
|
||||
size_t i, j;
|
||||
int code;
|
||||
unsigned int code;
|
||||
int r = 0;
|
||||
|
||||
if (!str || !buf)
|
||||
@@ -1445,7 +1445,7 @@ struct node_op_parms {
|
||||
char *old_name;
|
||||
int warn_if_udev_failed;
|
||||
unsigned rely_on_udev;
|
||||
char names[0];
|
||||
char names[];
|
||||
};
|
||||
|
||||
static void _store_str(char **pos, char **ptr, const char *str)
|
||||
@@ -2012,7 +2012,8 @@ static int _sysfs_get_kernel_name(uint32_t major, uint32_t minor, char *buf, siz
|
||||
log_sys_error("readlink", sysfs_path);
|
||||
else {
|
||||
log_sys_debug("readlink", sysfs_path);
|
||||
return _sysfs_find_kernel_name(major, minor, buf, buf_size);
|
||||
r = _sysfs_find_kernel_name(major, minor, buf, buf_size);
|
||||
goto out;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
@@ -2033,6 +2034,7 @@ static int _sysfs_get_kernel_name(uint32_t major, uint32_t minor, char *buf, siz
|
||||
strcpy(buf, name);
|
||||
r = 1;
|
||||
bad:
|
||||
out:
|
||||
free(temp_buf);
|
||||
free(sysfs_path);
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ enum {
|
||||
SEG_STRIPED,
|
||||
SEG_ZERO,
|
||||
SEG_WRITECACHE,
|
||||
SEG_INTEGRITY,
|
||||
SEG_THIN_POOL,
|
||||
SEG_THIN,
|
||||
SEG_VDO,
|
||||
@@ -78,6 +79,7 @@ static const struct {
|
||||
{ SEG_STRIPED, "striped" },
|
||||
{ SEG_ZERO, "zero"},
|
||||
{ SEG_WRITECACHE, "writecache"},
|
||||
{ SEG_INTEGRITY, "integrity"},
|
||||
{ SEG_THIN_POOL, "thin-pool"},
|
||||
{ SEG_THIN, "thin"},
|
||||
{ SEG_VDO, "vdo" },
|
||||
@@ -221,6 +223,11 @@ struct load_segment {
|
||||
int writecache_pmem; /* writecache, 1 if pmem, 0 if ssd */
|
||||
uint32_t writecache_block_size; /* writecache, in bytes */
|
||||
struct writecache_settings writecache_settings; /* writecache */
|
||||
|
||||
uint64_t integrity_data_sectors; /* integrity (provided_data_sectors) */
|
||||
struct dm_tree_node *integrity_meta_node; /* integrity */
|
||||
struct integrity_settings integrity_settings; /* integrity */
|
||||
int integrity_recalculate; /* integrity */
|
||||
};
|
||||
|
||||
/* Per-device properties */
|
||||
@@ -267,6 +274,16 @@ struct load_properties {
|
||||
*/
|
||||
unsigned delay_resume_if_extended;
|
||||
|
||||
/*
|
||||
* When comparing table lines to decide if a reload is
|
||||
* needed, ignore any differences betwen the lvm device
|
||||
* params and the kernel-reported device params.
|
||||
* dm-integrity reports many internal parameters on the
|
||||
* table line when lvm does not explicitly set them,
|
||||
* causing lvm and the kernel to have differing params.
|
||||
*/
|
||||
unsigned skip_reload_params_compare;
|
||||
|
||||
/*
|
||||
* Call node_send_messages(), set to 2 if there are messages
|
||||
* When != 0, it validates matching transaction id, thus thin-pools
|
||||
@@ -1572,8 +1589,37 @@ static int _thin_pool_node_message(struct dm_tree_node *dnode, struct thin_messa
|
||||
}
|
||||
|
||||
if (!_node_message(dnode->info.major, dnode->info.minor,
|
||||
tm->expected_errno, buf))
|
||||
return_0;
|
||||
tm->expected_errno, buf)) {
|
||||
switch (m->type) {
|
||||
case DM_THIN_MESSAGE_CREATE_SNAP:
|
||||
case DM_THIN_MESSAGE_CREATE_THIN:
|
||||
if (errno == EEXIST) {
|
||||
/*
|
||||
* ATM errno from ioctl() is preserved through code error path chain
|
||||
* If this would ever change, another way need to be used to
|
||||
* obtain result from failed DM message
|
||||
*/
|
||||
log_error("Thin pool %s already contain thin device with device_id %u.",
|
||||
_node_name(dnode), m->u.m_create_snap.device_id);
|
||||
/*
|
||||
* TODO:
|
||||
*
|
||||
* Give some useful advice how to solve this problem,
|
||||
* until lvconvert --repair can handle this automatically
|
||||
*/
|
||||
log_error("Manual intervention may be required to remove device dev_id=%u in thin pool metadata.",
|
||||
m->u.m_create_snap.device_id);
|
||||
log_error("Optionally new thin volume with device_id=%u can be manually added into a volume group.",
|
||||
m->u.m_create_snap.device_id);
|
||||
log_warn("WARNING: When uncertain how to do this, contact support!");
|
||||
return 0;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
return_0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1620,6 +1666,15 @@ static int _thin_pool_node_send_messages(struct dm_tree_node *dnode,
|
||||
if (!have_messages || !send)
|
||||
return 1; /* transaction_id is matching */
|
||||
|
||||
if (stp.fail || stp.read_only || stp.needs_check) {
|
||||
log_error("Cannot send messages to thin pool %s%s%s%s.",
|
||||
_node_name(dnode),
|
||||
stp.fail ? " in failed state" : "",
|
||||
stp.read_only ? " with read only metadata" : "",
|
||||
stp.needs_check ? " which needs check first" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(tmsg, &seg->thin_messages) {
|
||||
if (!(_thin_pool_node_message(dnode, tmsg)))
|
||||
return_0;
|
||||
@@ -2081,7 +2136,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _create_node(struct dm_tree_node *dnode)
|
||||
static int _create_node(struct dm_tree_node *dnode, struct dm_tree_node *parent)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
@@ -2130,38 +2185,15 @@ static int _create_node(struct dm_tree_node *dnode)
|
||||
"Unable to get DM task info for %s.",
|
||||
dnode->name);
|
||||
}
|
||||
|
||||
if (r)
|
||||
dm_list_add_h(&parent->activated, &dnode->activated_list);
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* _remove_node
|
||||
*
|
||||
* This function is only used to remove a DM device that has failed
|
||||
* to load any table.
|
||||
*/
|
||||
static int _remove_node(struct dm_tree_node *dnode)
|
||||
{
|
||||
if (!dnode->info.exists)
|
||||
return 1;
|
||||
|
||||
if (dnode->info.live_table || dnode->info.inactive_table) {
|
||||
log_error(INTERNAL_ERROR
|
||||
"_remove_node called on device with loaded table(s).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_deactivate_node(dnode->name, dnode->info.major, dnode->info.minor,
|
||||
&dnode->dtree->cookie, dnode->udev_flags, 0)) {
|
||||
log_error("Failed to clean-up device with no table: %s.",
|
||||
_node_name(dnode));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node)
|
||||
{
|
||||
if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) {
|
||||
@@ -2653,6 +2685,10 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
||||
count += 1;
|
||||
if (seg->writecache_settings.nofua_set)
|
||||
count += 1;
|
||||
if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner)
|
||||
count += 1;
|
||||
if (seg->writecache_settings.max_age_set)
|
||||
count += 2;
|
||||
if (seg->writecache_settings.new_key)
|
||||
count += 2;
|
||||
|
||||
@@ -2696,6 +2732,14 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
||||
EMIT_PARAMS(pos, " nofua");
|
||||
}
|
||||
|
||||
if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
|
||||
EMIT_PARAMS(pos, " cleaner");
|
||||
}
|
||||
|
||||
if (seg->writecache_settings.max_age_set) {
|
||||
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
|
||||
}
|
||||
|
||||
if (seg->writecache_settings.new_key) {
|
||||
EMIT_PARAMS(pos, " %s %s",
|
||||
seg->writecache_settings.new_key,
|
||||
@@ -2705,6 +2749,84 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _integrity_emit_segment_line(struct dm_task *dmt,
|
||||
struct load_segment *seg,
|
||||
char *params, size_t paramsize)
|
||||
{
|
||||
struct integrity_settings *set = &seg->integrity_settings;
|
||||
int pos = 0;
|
||||
int count;
|
||||
char origin_dev[DM_FORMAT_DEV_BUFSIZE];
|
||||
char meta_dev[DM_FORMAT_DEV_BUFSIZE];
|
||||
|
||||
if (!_build_dev_string(origin_dev, sizeof(origin_dev), seg->origin))
|
||||
return_0;
|
||||
|
||||
if (seg->integrity_meta_node &&
|
||||
!_build_dev_string(meta_dev, sizeof(meta_dev), seg->integrity_meta_node))
|
||||
return_0;
|
||||
|
||||
count = 3; /* block_size, internal_hash, fix_padding options are always passed */
|
||||
|
||||
if (seg->integrity_meta_node)
|
||||
count++;
|
||||
|
||||
if (seg->integrity_recalculate)
|
||||
count++;
|
||||
|
||||
if (set->journal_sectors_set)
|
||||
count++;
|
||||
if (set->interleave_sectors_set)
|
||||
count++;
|
||||
if (set->buffer_sectors_set)
|
||||
count++;
|
||||
if (set->journal_watermark_set)
|
||||
count++;
|
||||
if (set->commit_time_set)
|
||||
count++;
|
||||
if (set->bitmap_flush_interval_set)
|
||||
count++;
|
||||
if (set->sectors_per_bit_set)
|
||||
count++;
|
||||
|
||||
EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s",
|
||||
origin_dev,
|
||||
set->tag_size,
|
||||
set->mode,
|
||||
count,
|
||||
set->block_size,
|
||||
set->internal_hash);
|
||||
|
||||
if (seg->integrity_meta_node)
|
||||
EMIT_PARAMS(pos, " meta_device:%s", meta_dev);
|
||||
|
||||
if (seg->integrity_recalculate)
|
||||
EMIT_PARAMS(pos, " recalculate");
|
||||
|
||||
if (set->journal_sectors_set)
|
||||
EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
|
||||
|
||||
if (set->interleave_sectors_set)
|
||||
EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors);
|
||||
|
||||
if (set->buffer_sectors_set)
|
||||
EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors);
|
||||
|
||||
if (set->journal_watermark_set)
|
||||
EMIT_PARAMS(pos, " journal_watermark:%u", set->journal_watermark);
|
||||
|
||||
if (set->commit_time_set)
|
||||
EMIT_PARAMS(pos, " commit_time:%u", set->commit_time);
|
||||
|
||||
if (set->bitmap_flush_interval_set)
|
||||
EMIT_PARAMS(pos, " bitmap_flush_interval:%u", set->bitmap_flush_interval);
|
||||
|
||||
if (set->sectors_per_bit_set)
|
||||
EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _thin_pool_emit_segment_line(struct dm_task *dmt,
|
||||
struct load_segment *seg,
|
||||
char *params, size_t paramsize)
|
||||
@@ -2889,6 +3011,10 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
if (!_writecache_emit_segment_line(dmt, seg, params, paramsize))
|
||||
return_0;
|
||||
break;
|
||||
case SEG_INTEGRITY:
|
||||
if (!_integrity_emit_segment_line(dmt, seg, params, paramsize))
|
||||
return_0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(seg->type) {
|
||||
@@ -2901,6 +3027,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
case SEG_THIN:
|
||||
case SEG_CACHE:
|
||||
case SEG_WRITECACHE:
|
||||
case SEG_INTEGRITY:
|
||||
break;
|
||||
case SEG_CRYPT:
|
||||
case SEG_LINEAR:
|
||||
@@ -3005,6 +3132,9 @@ static int _load_node(struct dm_tree_node *dnode)
|
||||
if (!dm_task_suppress_identical_reload(dmt))
|
||||
log_warn("WARNING: Failed to suppress reload of identical tables.");
|
||||
|
||||
if (dnode->props.skip_reload_params_compare)
|
||||
dm_task_skip_reload_params_compare(dmt);
|
||||
|
||||
if ((r = dm_task_run(dmt))) {
|
||||
r = dm_task_get_info(dmt, &dnode->info);
|
||||
if (r && !dnode->info.inactive_table)
|
||||
@@ -3023,8 +3153,8 @@ static int _load_node(struct dm_tree_node *dnode)
|
||||
if (!existing_table_size && dnode->props.delay_resume_if_new)
|
||||
dnode->props.size_changed = 0;
|
||||
|
||||
log_debug_activation("Table size changed from %" PRIu64 " to %"
|
||||
PRIu64 " for %s.%s", existing_table_size,
|
||||
log_debug_activation("Table size changed from %" PRIu64 " to %" PRIu64 " for %s.%s",
|
||||
existing_table_size,
|
||||
seg_start, _node_name(dnode),
|
||||
dnode->props.size_changed ? "" : " (Ignoring.)");
|
||||
|
||||
@@ -3076,6 +3206,16 @@ static int _dm_tree_revert_activated(struct dm_tree_node *parent)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _dm_tree_wait_and_revert_activated(struct dm_tree_node *dnode)
|
||||
{
|
||||
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
|
||||
stack;
|
||||
|
||||
dm_tree_set_cookie(dnode, 0);
|
||||
|
||||
return _dm_tree_revert_activated(dnode);
|
||||
}
|
||||
|
||||
int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len)
|
||||
@@ -3105,7 +3245,7 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
return_0;
|
||||
|
||||
/* FIXME Cope if name exists with no uuid? */
|
||||
if (!child->info.exists && !(node_created = _create_node(child)))
|
||||
if (!child->info.exists && !(node_created = _create_node(child, dnode)))
|
||||
return_0;
|
||||
|
||||
/* Propagate delayed resume from exteded child node */
|
||||
@@ -3115,28 +3255,22 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
if (!child->info.inactive_table &&
|
||||
child->props.segment_count &&
|
||||
!_load_node(child)) {
|
||||
stack;
|
||||
/*
|
||||
* If the table load does not succeed, we remove the
|
||||
* device in the kernel that would otherwise have an
|
||||
* empty table. This makes the create + load of the
|
||||
* device atomic. However, if other dependencies have
|
||||
* already been created and loaded; this code is
|
||||
* insufficient to remove those - only the node
|
||||
* encountering the table load failure is removed.
|
||||
* If the table load fails, try to device in the kernel
|
||||
* together with other created and preloaded devices.
|
||||
*/
|
||||
if (node_created) {
|
||||
if (!_remove_node(child))
|
||||
return_0;
|
||||
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
|
||||
stack;
|
||||
dm_tree_set_cookie(dnode, 0);
|
||||
(void) _dm_tree_revert_activated(child);
|
||||
}
|
||||
return_0;
|
||||
if (!_dm_tree_wait_and_revert_activated(dnode))
|
||||
stack;
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No resume for a device without parents or with unchanged or smaller size */
|
||||
if (!dm_tree_node_num_children(child, 1) || (child->props.size_changed <= 0))
|
||||
if (!dm_tree_node_num_children(child, 1))
|
||||
continue;
|
||||
|
||||
if (child->props.size_changed <= 0)
|
||||
continue;
|
||||
|
||||
if (!child->info.inactive_table && !child->info.suspended)
|
||||
@@ -3147,28 +3281,19 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
&child->info, &child->dtree->cookie, child->udev_flags,
|
||||
child->info.suspended)) {
|
||||
log_error("Unable to resume %s.", _node_name(child));
|
||||
/* If the device was not previously active, we might as well remove this node. */
|
||||
if (!child->info.live_table &&
|
||||
!_deactivate_node(child->name, child->info.major, child->info.minor,
|
||||
&child->dtree->cookie, child->udev_flags, 0))
|
||||
log_error("Unable to deactivate %s.", _node_name(child));
|
||||
if (!_dm_tree_wait_and_revert_activated(dnode))
|
||||
stack;
|
||||
r = 0;
|
||||
/* Each child is handled independently */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node_created) {
|
||||
/* Collect newly introduced devices for revert */
|
||||
dm_list_add_h(&dnode->activated, &child->activated_list);
|
||||
|
||||
/* When creating new node also check transaction_id. */
|
||||
if (child->props.send_messages &&
|
||||
!_node_send_messages(child, uuid_prefix, uuid_prefix_len, 0)) {
|
||||
stack;
|
||||
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
|
||||
if (!_dm_tree_wait_and_revert_activated(dnode))
|
||||
stack;
|
||||
dm_tree_set_cookie(dnode, 0);
|
||||
(void) _dm_tree_revert_activated(dnode);
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -3738,6 +3863,48 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *origin_uuid,
|
||||
const char *meta_uuid,
|
||||
struct integrity_settings *settings,
|
||||
int recalculate)
|
||||
{
|
||||
struct load_segment *seg;
|
||||
|
||||
if (!(seg = _add_segment(node, SEG_INTEGRITY, size)))
|
||||
return_0;
|
||||
|
||||
if (!meta_uuid) {
|
||||
log_error("No integrity meta uuid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) {
|
||||
log_error("Missing integrity's meta uuid %s.", meta_uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_link_tree_nodes(node, seg->integrity_meta_node))
|
||||
return_0;
|
||||
|
||||
if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
|
||||
log_error("Missing integrity's origin uuid %s.", origin_uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_link_tree_nodes(node, seg->origin))
|
||||
return_0;
|
||||
|
||||
memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
|
||||
|
||||
seg->integrity_recalculate = recalculate;
|
||||
|
||||
node->props.skip_reload_params_compare = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *rlog_uuid,
|
||||
@@ -4200,6 +4367,7 @@ int dm_tree_node_add_cache_target_base(struct dm_tree_node *node,
|
||||
|
||||
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *vdo_pool_name,
|
||||
const char *data_uuid,
|
||||
uint64_t data_size,
|
||||
const struct dm_vdo_target_params *vtp)
|
||||
@@ -4221,7 +4389,7 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
|
||||
return_0;
|
||||
|
||||
seg->vdo_params = *vtp;
|
||||
seg->vdo_name = node->name;
|
||||
seg->vdo_name = vdo_pool_name;
|
||||
seg->vdo_data_size = data_size;
|
||||
|
||||
node->props.send_messages = 2;
|
||||
|
||||
@@ -749,10 +749,11 @@ static void _display_fields_more(struct dm_report *rh,
|
||||
id_len = strlen(type->prefix) + 3;
|
||||
|
||||
for (f = 0; fields[f].report_fn; f++) {
|
||||
if ((type = _find_type(rh, fields[f].type)) && type->desc)
|
||||
desc = type->desc;
|
||||
else
|
||||
desc = " ";
|
||||
if (!(type = _find_type(rh, fields[f].type))) {
|
||||
log_debug(INTERNAL_ERROR "Field type undefined.");
|
||||
continue;
|
||||
}
|
||||
desc = (type->desc) ? : " ";
|
||||
if (desc != last_desc) {
|
||||
if (*last_desc)
|
||||
log_warn(" ");
|
||||
|
||||
@@ -366,8 +366,8 @@ int dm_get_status_writecache(struct dm_pool *mem, const char *params,
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_writecache))))
|
||||
return_0;
|
||||
|
||||
if (sscanf(params, "%u %llu %llu %llu",
|
||||
&s->error,
|
||||
if (sscanf(params, "%llu %llu %llu %llu",
|
||||
(unsigned long long *)&s->error,
|
||||
(unsigned long long *)&s->total_blocks,
|
||||
(unsigned long long *)&s->free_blocks,
|
||||
(unsigned long long *)&s->writeback_blocks) != 4) {
|
||||
@@ -380,6 +380,33 @@ int dm_get_status_writecache(struct dm_pool *mem, const char *params,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_integrity(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_integrity **status)
|
||||
{
|
||||
struct dm_status_integrity *s;
|
||||
char recalc_str[16] = "\0";
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s))))
|
||||
return_0;
|
||||
|
||||
if (sscanf(params, "%llu %llu %s",
|
||||
(unsigned long long *)&s->number_of_mismatches,
|
||||
(unsigned long long *)&s->provided_data_sectors,
|
||||
recalc_str) != 3) {
|
||||
log_error("Failed to parse integrity params: %s.", params);
|
||||
dm_pool_free(mem, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (recalc_str[0] == '-')
|
||||
s->recalc_sector = 0;
|
||||
else
|
||||
s->recalc_sector = strtoull(recalc_str, NULL, 0);
|
||||
|
||||
*status = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s)
|
||||
{
|
||||
int pos;
|
||||
|
||||
@@ -183,7 +183,7 @@ struct dm_target_spec {
|
||||
struct dm_target_deps {
|
||||
uint32_t count; /* Array size */
|
||||
uint32_t padding; /* unused */
|
||||
uint64_t dev[0]; /* out */
|
||||
uint64_t dev[]; /* out */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -193,7 +193,7 @@ struct dm_name_list {
|
||||
uint64_t dev;
|
||||
uint32_t next; /* offset to the next record from
|
||||
the _start_ of this */
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -203,7 +203,7 @@ struct dm_target_versions {
|
||||
uint32_t next;
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -212,7 +212,7 @@ struct dm_target_versions {
|
||||
struct dm_target_msg {
|
||||
uint64_t sector; /* Device sector */
|
||||
|
||||
char message[0];
|
||||
char message[];
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -98,7 +98,7 @@ void dm_pools_check_leaks(void)
|
||||
p->orig_pool,
|
||||
p->name, p->stats.bytes);
|
||||
#else
|
||||
log_error(" [%p] %s", p, p->name);
|
||||
log_error(" [%p] %s", (void *)p, p->name);
|
||||
#endif
|
||||
}
|
||||
pthread_mutex_unlock(&_dm_pools_mutex);
|
||||
|
||||
@@ -126,6 +126,9 @@
|
||||
/* Library version */
|
||||
#undef DM_LIB_VERSION
|
||||
|
||||
/* Define to 1 to include the LVM editline shell. */
|
||||
#undef EDITLINE_SUPPORT
|
||||
|
||||
/* Path to fsadm binary. */
|
||||
#undef FSADM_PATH
|
||||
|
||||
@@ -151,6 +154,9 @@
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#undef HAVE_ATEXIT
|
||||
|
||||
/* Define if ioctl BLKZEROOUT can be used for device zeroing. */
|
||||
#undef HAVE_BLKZEROOUT
|
||||
|
||||
/* Define to 1 if canonicalize_file_name is available. */
|
||||
#undef HAVE_CANONICALIZE_FILE_NAME
|
||||
|
||||
@@ -176,6 +182,12 @@
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
#undef HAVE_DOPRNT
|
||||
|
||||
/* Define to 1 if you have the <editline/history.h> header file. */
|
||||
#undef HAVE_EDITLINE_HISTORY_H
|
||||
|
||||
/* Define to 1 if you have the <editline/readline.h> header file. */
|
||||
#undef HAVE_EDITLINE_READLINE_H
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
@@ -531,6 +543,9 @@
|
||||
/* Define to 1 if the system has the `__builtin_clzll' built-in function */
|
||||
#undef HAVE___BUILTIN_CLZLL
|
||||
|
||||
/* Define to 1 to include built-in support for integrity. */
|
||||
#undef INTEGRITY_INTERNAL
|
||||
|
||||
/* Internalization package */
|
||||
#undef INTL_PACKAGE
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ SOURCES =\
|
||||
activate/activate.c \
|
||||
cache/lvmcache.c \
|
||||
writecache/writecache.c \
|
||||
integrity/integrity.c \
|
||||
cache_segtype/cache.c \
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
@@ -67,6 +68,7 @@ SOURCES =\
|
||||
log/log.c \
|
||||
metadata/cache_manip.c \
|
||||
metadata/writecache_manip.c \
|
||||
metadata/integrity_manip.c \
|
||||
metadata/lv.c \
|
||||
metadata/lv_manip.c \
|
||||
metadata/merge.c \
|
||||
@@ -74,6 +76,7 @@ SOURCES =\
|
||||
metadata/mirror.c \
|
||||
metadata/pool_manip.c \
|
||||
metadata/pv.c \
|
||||
metadata/pv_list.c \
|
||||
metadata/pv_manip.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/raid_manip.c \
|
||||
|
||||
@@ -185,8 +185,8 @@ void set_activation(int act, int silent)
|
||||
if (warned || !act)
|
||||
return;
|
||||
|
||||
log_error("Compiled without libdevmapper support. "
|
||||
"Can't enable activation.");
|
||||
log_warn("WARNING: Compiled without libdevmapper support. "
|
||||
"Can't enable activation.");
|
||||
|
||||
warned = 1;
|
||||
}
|
||||
@@ -221,23 +221,13 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_la
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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,
|
||||
int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
const struct lv_segment *lv_seg,
|
||||
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)
|
||||
{
|
||||
@@ -284,18 +274,17 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
|
||||
dm_percent_t *percent)
|
||||
int lv_writecache_message(const struct logical_volume *lv, const char *msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_thin_percent(const struct logical_volume *lv, int mapped,
|
||||
dm_percent_t *percent)
|
||||
int lv_thin_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **thin_pool_status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_thin_pool_transaction_id(const struct logical_volume *lv,
|
||||
uint64_t *transaction_id)
|
||||
int lv_thin_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **thin_status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -303,6 +292,15 @@ int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_vdo **vdo_status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lvs_in_vg_activated(const struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
@@ -620,7 +618,7 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int use_layer, struct lvinfo *info,
|
||||
const struct lv_segment *seg,
|
||||
struct lv_seg_status *seg_status,
|
||||
int with_open_count, int with_read_ahead)
|
||||
int with_open_count, int with_read_ahead, int with_name_check)
|
||||
{
|
||||
struct dm_info dminfo;
|
||||
|
||||
@@ -638,7 +636,7 @@ 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)) {
|
||||
/* Check if there isn't existing old thin pool mapping in the table */
|
||||
if (!dev_manager_info(cmd, lv, NULL, 0, 0, &dminfo, NULL, NULL))
|
||||
if (!dev_manager_info(cmd, lv, NULL, 0, 0, 0, &dminfo, NULL, NULL))
|
||||
return_0;
|
||||
if (!dminfo.exists)
|
||||
use_layer = 1;
|
||||
@@ -651,8 +649,9 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
|
||||
if (!dev_manager_info(cmd, lv,
|
||||
(use_layer) ? lv_layer(lv) : NULL,
|
||||
with_open_count, with_read_ahead,
|
||||
&dminfo, (info) ? &info->read_ahead : NULL,
|
||||
with_open_count, with_read_ahead, with_name_check,
|
||||
&dminfo,
|
||||
(info) ? &info->read_ahead : NULL,
|
||||
seg_status))
|
||||
return_0;
|
||||
|
||||
@@ -681,7 +680,16 @@ 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, NULL, with_open_count, with_read_ahead);
|
||||
return _lv_info(cmd, lv, use_layer, info, NULL, NULL, with_open_count, with_read_ahead, 0);
|
||||
}
|
||||
|
||||
int lv_info_with_name_check(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int use_layer, struct lvinfo *info)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
return _lv_info(cmd, lv, use_layer, info, NULL, NULL, 0, 0, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -711,16 +719,16 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
* STATUS is collected from cache LV */
|
||||
if (!(lv_seg = get_only_segment_using_this_lv(lv)))
|
||||
return_0;
|
||||
(void) _lv_info(cmd, lv_seg->lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
|
||||
(void) _lv_info(cmd, lv_seg->lv, 1, NULL, lv_seg, &status->seg_status, 0, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
/* Always collect status for '-tpool' */
|
||||
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0) &&
|
||||
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0, 0) &&
|
||||
(status->seg_status.type == SEG_STATUS_THIN_POOL)) {
|
||||
/* There is -tpool device, but query 'active' state of 'fake' thin-pool */
|
||||
if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0) &&
|
||||
if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0, 0) &&
|
||||
!status->seg_status.thin_pool->needs_check)
|
||||
status->info.exists = 0; /* So pool LV is not active */
|
||||
}
|
||||
@@ -729,10 +737,10 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
|
||||
if (lv_is_external_origin(lv)) {
|
||||
if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL,
|
||||
with_open_count, with_read_ahead))
|
||||
with_open_count, with_read_ahead, 0))
|
||||
return_0;
|
||||
|
||||
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
|
||||
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -745,13 +753,13 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
/* Show INFO for actual origin and grab status for merging origin */
|
||||
if (!_lv_info(cmd, lv, 0, &status->info, lv_seg,
|
||||
lv_is_merging_origin(lv) ? &status->seg_status : NULL,
|
||||
with_open_count, with_read_ahead))
|
||||
with_open_count, with_read_ahead, 0))
|
||||
return_0;
|
||||
|
||||
if (status->info.exists &&
|
||||
(status->seg_status.type != SEG_STATUS_SNAPSHOT)) /* Not merging */
|
||||
/* Grab STATUS from layered -real */
|
||||
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
|
||||
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -760,10 +768,11 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
olv = origin_from_cow(lv);
|
||||
|
||||
if (!_lv_info(cmd, olv, 0, &status->info, first_seg(olv), &status->seg_status,
|
||||
with_open_count, with_read_ahead))
|
||||
with_open_count, with_read_ahead, 0))
|
||||
return_0;
|
||||
|
||||
if (status->seg_status.type == SEG_STATUS_SNAPSHOT) {
|
||||
if (status->seg_status.type == SEG_STATUS_SNAPSHOT ||
|
||||
(lv_is_thin_volume(olv) && (status->seg_status.type == SEG_STATUS_THIN))) {
|
||||
log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
|
||||
display_lvname(lv));
|
||||
/*
|
||||
@@ -781,13 +790,13 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
|
||||
if (lv_is_vdo(lv)) {
|
||||
if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL,
|
||||
with_open_count, with_read_ahead))
|
||||
with_open_count, with_read_ahead, 0))
|
||||
return_0;
|
||||
if (status->info.exists) {
|
||||
/* Status for VDO pool */
|
||||
(void) _lv_info(cmd, seg_lv(lv_seg, 0), 1, NULL,
|
||||
first_seg(seg_lv(lv_seg, 0)),
|
||||
&status->seg_status, 0, 0);
|
||||
&status->seg_status, 0, 0, 0);
|
||||
/* Use VDO pool segtype result for VDO segtype */
|
||||
status->seg_status.seg = lv_seg;
|
||||
}
|
||||
@@ -796,10 +805,10 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
|
||||
if (lv_is_vdo_pool(lv)) {
|
||||
/* Always collect status for '-vpool' */
|
||||
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0) &&
|
||||
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0, 0) &&
|
||||
(status->seg_status.type == SEG_STATUS_VDO_POOL)) {
|
||||
/* There is -tpool device, but query 'active' state of 'fake' vdo-pool */
|
||||
if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0))
|
||||
if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0, 0))
|
||||
status->info.exists = 0; /* So VDO pool LV is not active */
|
||||
}
|
||||
|
||||
@@ -807,7 +816,7 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
return _lv_info(cmd, lv, 0, &status->info, lv_seg, &status->seg_status,
|
||||
with_open_count, with_read_ahead);
|
||||
with_open_count, with_read_ahead, 0);
|
||||
}
|
||||
|
||||
#define OPEN_COUNT_CHECK_RETRIES 25
|
||||
@@ -1237,86 +1246,52 @@ int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns data or metadata percent usage, depends on metadata 0/1.
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
|
||||
dm_percent_t *percent)
|
||||
int lv_thin_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **thin_pool_status)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin %sdata percent for LV %s.",
|
||||
(metadata) ? "meta" : "", display_lvname(lv));
|
||||
log_debug_activation("Checking thin pool status for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!(r = dev_manager_thin_pool_percent(dm, lv, metadata, percent)))
|
||||
stack;
|
||||
if (!dev_manager_thin_pool_status(dm, lv, flush, thin_pool_status)) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
/* User has to call dm_pool_destroy(thin_pool_status->mem)! */
|
||||
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
int lv_thin_percent(const struct logical_volume *lv,
|
||||
int mapped, dm_percent_t *percent)
|
||||
int lv_thin_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **thin_status)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin percent for LV %s.",
|
||||
log_debug_activation("Checking thin status for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!(r = dev_manager_thin_percent(dm, lv, mapped, percent)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if transaction_id set, else 0 on failure.
|
||||
*/
|
||||
int lv_thin_pool_transaction_id(const struct logical_volume *lv,
|
||||
uint64_t *transaction_id)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_thin_pool *status;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin-pool transaction id for LV %s.",
|
||||
display_lvname(lv));
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
if (!dev_manager_thin_status(dm, lv, flush, thin_status)) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(r = dev_manager_thin_pool_status(dm, lv, &status, 0)))
|
||||
stack;
|
||||
else
|
||||
*transaction_id = status->transaction_id;
|
||||
/* User has to call dm_pool_destroy(thin_status->mem)! */
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id)
|
||||
@@ -2186,8 +2161,6 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (laopts->origin_only && lv_is_thin_volume(lv) && lv_is_thin_volume(lv_pre))
|
||||
lockfs = 1;
|
||||
|
||||
critical_section_inc(cmd, "suspending");
|
||||
|
||||
if (!lv_is_locked(lv) && lv_is_locked(lv_pre) &&
|
||||
(pvmove_lv = find_pvmove_lv_in_lv(lv_pre))) {
|
||||
/*
|
||||
@@ -2229,16 +2202,23 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
dm_list_add(&suspend_lvs, &lvl->list);
|
||||
}
|
||||
|
||||
critical_section_inc(cmd, "suspending");
|
||||
|
||||
dm_list_iterate_items(lvl, &suspend_lvs)
|
||||
if (!_lv_suspend_lv(lvl->lv, laopts, lockfs, 1)) {
|
||||
critical_section_dec(cmd, "failed suspend");
|
||||
goto_out; /* FIXME: resume on recovery path? */
|
||||
}
|
||||
} else /* Standard suspend */
|
||||
|
||||
} else { /* Standard suspend */
|
||||
critical_section_inc(cmd, "suspending");
|
||||
|
||||
if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) {
|
||||
critical_section_dec(cmd, "failed suspend");
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
@@ -2258,8 +2238,8 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned o
|
||||
const struct logical_volume *lv, const struct logical_volume *lv_pre)
|
||||
{
|
||||
struct lv_activate_opts laopts = {
|
||||
.origin_only = origin_only,
|
||||
.exclusive = exclusive
|
||||
.exclusive = exclusive,
|
||||
.origin_only = origin_only
|
||||
};
|
||||
|
||||
return _lv_suspend(cmd, lvid_s, &laopts, 0, lv, lv_pre);
|
||||
@@ -2311,6 +2291,9 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
|
||||
laopts->revert ? " (reverting)" : "");
|
||||
|
||||
if (laopts->revert)
|
||||
goto needs_resume;
|
||||
|
||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
@@ -2370,8 +2353,8 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
|
||||
unsigned revert, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = {
|
||||
.origin_only = origin_only,
|
||||
.exclusive = exclusive,
|
||||
.origin_only = origin_only,
|
||||
.revert = revert
|
||||
};
|
||||
|
||||
@@ -2524,6 +2507,13 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((cmd->partial_activation || cmd->degraded_activation) &&
|
||||
lv_is_partial(lv) && lv_is_raid(lv) && lv_raid_has_integrity((struct logical_volume *)lv)) {
|
||||
cmd->partial_activation = 0;
|
||||
cmd->degraded_activation = 0;
|
||||
log_print("No degraded or partial activation for raid with integrity.");
|
||||
}
|
||||
|
||||
if ((!lv->vg->cmd->partial_activation) && lv_is_partial(lv)) {
|
||||
if (!lv_is_raid_type(lv) || !partial_raid_lv_supports_degraded_activation(lv)) {
|
||||
log_error("Refusing activation of partial LV %s. "
|
||||
@@ -2540,6 +2530,14 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
}
|
||||
|
||||
if ((cmd->partial_activation || cmd->degraded_activation) && lv_is_writecache(lv)) {
|
||||
struct logical_volume *lv_fast = first_seg(lv)->writecache;
|
||||
if (lv_is_partial(lv) || (lv_fast && lv_is_partial(lv_fast))) {
|
||||
log_error("Cannot use partial or degraded activation with writecache.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_has_unknown_segments(lv)) {
|
||||
log_error("Refusing activation of LV %s containing "
|
||||
"an unrecognised segment.", display_lvname(lv));
|
||||
@@ -2572,7 +2570,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
laopts->noscan ? " noscan" : "",
|
||||
laopts->temporary ? " temporary" : "");
|
||||
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0))
|
||||
if (!lv_info_with_name_check(cmd, lv, 0, &info))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
@@ -2944,8 +2942,7 @@ int revert_lv(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
|
||||
ret = lv_resume_if_active(cmd, NULL, 0, 0, 1, lv_committed(lv));
|
||||
|
||||
critical_section_dec(cmd, "unlocking on resume");
|
||||
critical_section_dec(cmd, "unlocking on revert");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ typedef enum {
|
||||
SEG_STATUS_THIN_POOL,
|
||||
SEG_STATUS_VDO_POOL,
|
||||
SEG_STATUS_WRITECACHE,
|
||||
SEG_STATUS_INTEGRITY,
|
||||
SEG_STATUS_UNKNOWN
|
||||
} lv_seg_status_type_t;
|
||||
|
||||
@@ -53,6 +54,7 @@ struct lv_seg_status {
|
||||
struct dm_status_thin *thin;
|
||||
struct dm_status_thin_pool *thin_pool;
|
||||
struct dm_status_writecache *writecache;
|
||||
struct dm_status_integrity *integrity;
|
||||
struct lv_status_vdo vdo_pool;
|
||||
};
|
||||
};
|
||||
@@ -144,8 +146,8 @@ int revert_lv(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
*/
|
||||
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);
|
||||
int lv_info_with_name_check(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int use_layer, struct lvinfo *info);
|
||||
|
||||
/*
|
||||
* Returns 1 if lv_info_and_seg_status structure has been populated,
|
||||
@@ -189,13 +191,11 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg);
|
||||
int lv_writecache_message(const struct logical_volume *lv, const char *msg);
|
||||
int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
struct lv_status_cache **status);
|
||||
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
|
||||
dm_percent_t *percent);
|
||||
int lv_thin_percent(const struct logical_volume *lv, int mapped,
|
||||
dm_percent_t *percent);
|
||||
int lv_thin_pool_transaction_id(const struct logical_volume *lv,
|
||||
uint64_t *transaction_id);
|
||||
int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id);
|
||||
int lv_thin_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **status);
|
||||
int lv_thin_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **status);
|
||||
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
|
||||
struct lv_status_vdo **status);
|
||||
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent);
|
||||
@@ -260,6 +260,7 @@ void fs_unlock(void);
|
||||
|
||||
#define TARGET_NAME_CACHE "cache"
|
||||
#define TARGET_NAME_WRITECACHE "writecache"
|
||||
#define TARGET_NAME_INTEGRITY "integrity"
|
||||
#define TARGET_NAME_ERROR "error"
|
||||
#define TARGET_NAME_ERROR_OLD "erro" /* Truncated in older kernels */
|
||||
#define TARGET_NAME_LINEAR "linear"
|
||||
@@ -277,6 +278,7 @@ void fs_unlock(void);
|
||||
#define MODULE_NAME_CLUSTERED_MIRROR "clog"
|
||||
#define MODULE_NAME_CACHE TARGET_NAME_CACHE
|
||||
#define MODULE_NAME_WRITECACHE TARGET_NAME_WRITECACHE
|
||||
#define MODULE_NAME_INTEGRITY TARGET_NAME_INTEGRITY
|
||||
#define MODULE_NAME_ERROR TARGET_NAME_ERROR
|
||||
#define MODULE_NAME_LOG_CLUSTERED "log-clustered"
|
||||
#define MODULE_NAME_LOG_USERSPACE "log-userspace"
|
||||
|
||||
@@ -46,7 +46,7 @@ typedef enum {
|
||||
} action_t;
|
||||
|
||||
/* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
|
||||
const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "cvol", "tdata", "tmeta", "vdata", "vpool", NULL};
|
||||
const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "cvol", "tdata", "tmeta", "vdata", "vpool", "imeta", NULL};
|
||||
|
||||
struct dlid_list {
|
||||
struct dm_list list;
|
||||
@@ -86,7 +86,7 @@ int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts
|
||||
return 0; /* Keep RAID SubLvs writable */
|
||||
|
||||
if (!layer) {
|
||||
if (lv_is_thin_pool(lv))
|
||||
if (lv_is_thin_pool(lv) || lv_is_vdo_pool(lv))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -222,6 +222,10 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
if (!dm_get_status_writecache(seg_status->mem, params, &(seg_status->writecache)))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_WRITECACHE;
|
||||
} else if (segtype_is_integrity(segtype)) {
|
||||
if (!dm_get_status_integrity(seg_status->mem, params, &(seg_status->integrity)))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_INTEGRITY;
|
||||
} else
|
||||
/*
|
||||
* TODO: Add support for other segment types too!
|
||||
@@ -248,6 +252,7 @@ static uint32_t _seg_len(const struct lv_segment *seg)
|
||||
static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
uint32_t *read_ahead,
|
||||
struct lv_seg_status *seg_status,
|
||||
const char *name_check,
|
||||
int with_open_count, int with_read_ahead,
|
||||
uint32_t major, uint32_t minor)
|
||||
{
|
||||
@@ -258,6 +263,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
void *target = NULL;
|
||||
uint64_t target_start, target_length, start, length;
|
||||
char *target_name, *target_params;
|
||||
const char *devname;
|
||||
|
||||
if (seg_status) {
|
||||
dmtask = DM_DEVICE_STATUS;
|
||||
@@ -271,7 +277,12 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
with_open_count, with_flush, 0)))
|
||||
return_0;
|
||||
|
||||
if (with_read_ahead && dminfo->exists) {
|
||||
if (name_check && dminfo->exists &&
|
||||
(devname = dm_task_get_name(dmt)) &&
|
||||
(strcmp(name_check, devname) != 0))
|
||||
dminfo->exists = 0; /* mismatching name -> device does not exist */
|
||||
|
||||
if (with_read_ahead && read_ahead && dminfo->exists) {
|
||||
if (!dm_task_get_read_ahead(dmt, read_ahead))
|
||||
goto_out;
|
||||
} else if (read_ahead)
|
||||
@@ -292,6 +303,9 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
|
||||
if (lv_is_vdo_pool(seg_status->seg->lv))
|
||||
length = get_vdo_pool_virtual_size(seg_status->seg);
|
||||
|
||||
if (lv_is_integrity(seg_status->seg->lv))
|
||||
length = seg_status->seg->integrity_data_sectors;
|
||||
|
||||
do {
|
||||
target = dm_get_next_target(dmt, target, &target_start,
|
||||
&target_length, &target_name, &target_params);
|
||||
@@ -791,18 +805,19 @@ static int _original_uuid_format_check_required(struct cmd_context *cmd)
|
||||
|
||||
static int _info(struct cmd_context *cmd,
|
||||
const char *name, const char *dlid,
|
||||
int with_open_count, int with_read_ahead,
|
||||
int with_open_count, int with_read_ahead, int with_name_check,
|
||||
struct dm_info *dminfo, uint32_t *read_ahead,
|
||||
struct lv_seg_status *seg_status)
|
||||
{
|
||||
char old_style_dlid[sizeof(UUID_PREFIX) + 2 * ID_LEN];
|
||||
const char *suffix, *suffix_position;
|
||||
const char *name_check = (with_name_check) ? name : NULL;
|
||||
unsigned i = 0;
|
||||
|
||||
log_debug_activation("Getting device info for %s [%s].", name, dlid);
|
||||
|
||||
/* Check for dlid */
|
||||
if (!_info_run(dlid, dminfo, read_ahead, seg_status,
|
||||
if (!_info_run(dlid, dminfo, read_ahead, seg_status, name_check,
|
||||
with_open_count, with_read_ahead, 0, 0))
|
||||
return_0;
|
||||
|
||||
@@ -818,7 +833,8 @@ static int _info(struct cmd_context *cmd,
|
||||
(void) strncpy(old_style_dlid, dlid, sizeof(old_style_dlid));
|
||||
old_style_dlid[sizeof(old_style_dlid) - 1] = '\0';
|
||||
if (!_info_run(old_style_dlid, dminfo, read_ahead, seg_status,
|
||||
with_open_count, with_read_ahead, 0, 0))
|
||||
name_check, with_open_count, with_read_ahead,
|
||||
0, 0))
|
||||
return_0;
|
||||
if (dminfo->exists)
|
||||
return 1;
|
||||
@@ -831,7 +847,7 @@ static int _info(struct cmd_context *cmd,
|
||||
|
||||
/* Check for dlid before UUID_PREFIX was added */
|
||||
if (!_info_run(dlid + sizeof(UUID_PREFIX) - 1, dminfo, read_ahead, seg_status,
|
||||
with_open_count, with_read_ahead, 0, 0))
|
||||
name_check, with_open_count, with_read_ahead, 0, 0))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -861,7 +877,7 @@ out:
|
||||
|
||||
static int _info_by_dev(uint32_t major, uint32_t minor, struct dm_info *info)
|
||||
{
|
||||
return _info_run(NULL, info, NULL, 0, 0, 0, major, minor);
|
||||
return _info_run(NULL, info, NULL, NULL, NULL, 0, 0, major, minor);
|
||||
}
|
||||
|
||||
int dev_manager_check_prefix_dm_major_minor(uint32_t major, uint32_t minor, const char *prefix)
|
||||
@@ -883,7 +899,7 @@ int dev_manager_check_prefix_dm_major_minor(uint32_t major, uint32_t minor, cons
|
||||
|
||||
int dev_manager_info(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv, const char *layer,
|
||||
int with_open_count, int with_read_ahead,
|
||||
int with_open_count, int with_read_ahead, int with_name_check,
|
||||
struct dm_info *dminfo, uint32_t *read_ahead,
|
||||
struct lv_seg_status *seg_status)
|
||||
{
|
||||
@@ -896,7 +912,8 @@ int dev_manager_info(struct cmd_context *cmd,
|
||||
if (!(dlid = build_dm_uuid(cmd->mem, lv, layer)))
|
||||
goto_out;
|
||||
|
||||
if (!(r = _info(cmd, name, dlid, with_open_count, with_read_ahead,
|
||||
if (!(r = _info(cmd, name, dlid,
|
||||
with_open_count, with_read_ahead, with_name_check,
|
||||
dminfo, read_ahead, seg_status)))
|
||||
stack;
|
||||
out:
|
||||
@@ -1547,9 +1564,6 @@ int dev_manager_cache_status(struct dev_manager *dm,
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_cache))))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
@@ -1572,8 +1586,11 @@ int dev_manager_cache_status(struct dev_manager *dm,
|
||||
if (!dm_get_status_cache(dm->mem, params, &c))
|
||||
goto_out;
|
||||
|
||||
(*status)->cache = c;
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_cache))))
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem; /* User has to destroy this mem pool later */
|
||||
(*status)->cache = c;
|
||||
if (c->fail || c->error) {
|
||||
(*status)->data_usage =
|
||||
(*status)->metadata_usage =
|
||||
@@ -1595,10 +1612,10 @@ out:
|
||||
}
|
||||
|
||||
int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct dm_status_thin_pool **status,
|
||||
int flush)
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **status)
|
||||
{
|
||||
struct dm_status_thin_pool *dm_status;
|
||||
const char *dlid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
@@ -1619,11 +1636,31 @@ int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
|
||||
dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
|
||||
/* FIXME Check for thin and check there's exactly one target */
|
||||
if (!type || strcmp(type, TARGET_NAME_THIN_POOL)) {
|
||||
log_error("Expected %s segment type but got %s instead.",
|
||||
TARGET_NAME_THIN_POOL, type ? type : "NULL");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_get_status_thin_pool(dm->mem, params, status))
|
||||
if (!dm_get_status_thin_pool(dm->mem, params, &dm_status))
|
||||
goto_out;
|
||||
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_thin_pool))))
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem;
|
||||
(*status)->thin_pool = dm_status;
|
||||
|
||||
if (dm_status->fail || dm_status->error) {
|
||||
(*status)->data_usage =
|
||||
(*status)->metadata_usage = DM_PERCENT_INVALID;
|
||||
} else {
|
||||
(*status)->data_usage = dm_make_percent(dm_status->used_data_blocks,
|
||||
dm_status->total_data_blocks);
|
||||
(*status)->metadata_usage = dm_make_percent(dm_status->used_metadata_blocks,
|
||||
dm_status->total_metadata_blocks);
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
@@ -1631,54 +1668,73 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_manager_thin_pool_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
int metadata, dm_percent_t *percent)
|
||||
int dev_manager_thin_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **status)
|
||||
{
|
||||
char *name;
|
||||
struct dm_status_thin *dm_status;
|
||||
const char *dlid;
|
||||
const char *layer = lv_layer(lv);
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
uint64_t start, length;
|
||||
char *type = NULL;
|
||||
char *params = NULL;
|
||||
uint64_t csize;
|
||||
int r = 0;
|
||||
|
||||
/* Build a name for the top layer */
|
||||
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, layer)))
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_STATUS, &info, NULL, dlid, 0, 0, 0, 0, flush, 0)))
|
||||
return_0;
|
||||
|
||||
log_debug_activation("Getting device status percentage for %s.", name);
|
||||
if (!info.exists)
|
||||
goto_out;
|
||||
|
||||
if (!(_percent(dm, name, dlid, TARGET_NAME_THIN_POOL, 0,
|
||||
(metadata) ? lv : NULL, percent, NULL, 1)))
|
||||
return_0;
|
||||
dm_get_next_target(dmt, NULL, &start, &length, &type, ¶ms);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_manager_thin_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
int mapped, dm_percent_t *percent)
|
||||
{
|
||||
char *name;
|
||||
const char *dlid;
|
||||
const char *layer = lv_layer(lv);
|
||||
|
||||
/* Build a name for the top layer */
|
||||
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
|
||||
return_0;
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, layer)))
|
||||
return_0;
|
||||
|
||||
log_debug_activation("Getting device status percentage for %s", name);
|
||||
|
||||
if (!(_percent(dm, name, dlid, TARGET_NAME_THIN, 0,
|
||||
(mapped) ? NULL : lv, percent, NULL, 1)))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
if (!type || strcmp(type, TARGET_NAME_THIN)) {
|
||||
log_error("Expected %s segment type but got %s instead.",
|
||||
TARGET_NAME_THIN, type ? type : "NULL");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_get_status_thin(dm->mem, params, &dm_status))
|
||||
goto_out;
|
||||
|
||||
if (!(*status = dm_pool_zalloc(dm->mem, sizeof(struct lv_status_thin))))
|
||||
goto_out;
|
||||
|
||||
(*status)->mem = dm->mem;
|
||||
(*status)->thin = dm_status;
|
||||
|
||||
if (dm_status->fail)
|
||||
(*status)->usage = DM_PERCENT_INVALID;
|
||||
else {
|
||||
/* Pool allocates whole chunk so round-up to nearest one */
|
||||
csize = first_seg(first_seg(lv)->pool_lv)->chunk_size;
|
||||
csize = ((lv->size + csize - 1) / csize) * csize;
|
||||
if (dm_status->mapped_sectors > csize) {
|
||||
log_warn("WARNING: LV %s maps %s while the size is only %s.",
|
||||
display_lvname(lv),
|
||||
display_size(dm->cmd, dm_status->mapped_sectors),
|
||||
display_size(dm->cmd, csize));
|
||||
/* Don't show nonsense numbers like i.e. 1000% full */
|
||||
dm_status->mapped_sectors = csize;
|
||||
}
|
||||
(*status)->usage = dm_make_percent(dm_status->mapped_sectors, csize);
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Explore state of running DM table to obtain currently used deviceId
|
||||
*/
|
||||
int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
uint32_t *device_id)
|
||||
@@ -1688,10 +1744,16 @@ int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
struct dm_info info;
|
||||
uint64_t start, length;
|
||||
char *params, *target_type = NULL;
|
||||
const char *layer = lv_layer(lv);
|
||||
int r = 0;
|
||||
|
||||
if (lv_is_merging_origin(lv) && !lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
/* If the merge has already happened, that table
|
||||
* can already be using correct LV without -real layer */
|
||||
layer = NULL;
|
||||
|
||||
/* Build dlid for the thin layer */
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, layer)))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, &info, NULL, dlid, 0, 0, 0, 0, 1, 0)))
|
||||
@@ -2087,7 +2149,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
if (!(dlid = build_dm_uuid(dm->track_pending_delete ? dm->cmd->pending_delete_mem : dm->mem, lv, layer)))
|
||||
return_0;
|
||||
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, &info, NULL, NULL))
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, 0, &info, NULL, NULL))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
@@ -2387,7 +2449,7 @@ static int _add_cvol_subdev_to_dtree(struct dev_manager *dm, struct dm_tree *dtr
|
||||
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, pool_lv->name, layer)))
|
||||
return_0;
|
||||
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, &info, NULL, NULL))
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, 0, &info, NULL, NULL))
|
||||
return_0;
|
||||
|
||||
if (info.exists) {
|
||||
@@ -2601,6 +2663,10 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
if (!_add_lv_to_dtree(dm, dtree, seg->writecache, dm->activation ? origin_only : 1))
|
||||
return_0;
|
||||
}
|
||||
if (seg->integrity_meta_dev && seg_is_integrity(seg)) {
|
||||
if (!_add_lv_to_dtree(dm, dtree, seg->integrity_meta_dev, dm->activation ? origin_only : 1))
|
||||
return_0;
|
||||
}
|
||||
if (seg->pool_lv &&
|
||||
(lv_is_cache_pool(seg->pool_lv) || lv_is_cache_vol(seg->pool_lv) || dm->track_external_lv_deps) &&
|
||||
/* When activating and not origin_only detect linear 'overlay' over pool */
|
||||
@@ -2683,7 +2749,7 @@ static char *_add_error_or_zero_device(struct dev_manager *dm, struct dm_tree *d
|
||||
seg->lv->name, errid)))
|
||||
return_NULL;
|
||||
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, &info, NULL, NULL))
|
||||
if (!_info(dm->cmd, name, dlid, 1, 0, 0, &info, NULL, NULL))
|
||||
return_NULL;
|
||||
|
||||
if (!info.exists) {
|
||||
@@ -3057,6 +3123,11 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
lv_layer(seg->writecache)))
|
||||
return_0;
|
||||
|
||||
if (seg->integrity_meta_dev && !laopts->origin_only &&
|
||||
!_add_new_lv_to_dtree(dm, dtree, seg->integrity_meta_dev, laopts,
|
||||
lv_layer(seg->integrity_meta_dev)))
|
||||
return_0;
|
||||
|
||||
/* Add any LVs used by this segment */
|
||||
for (s = 0; s < seg->area_count; ++s) {
|
||||
if ((seg_type(seg, s) == AREA_LV) &&
|
||||
@@ -3142,8 +3213,8 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
char *dlid_meta;
|
||||
char *dlid_data;
|
||||
char *dlid_pool;
|
||||
uint64_t meta_len = first_seg(lv)->metadata_len;
|
||||
uint64_t data_len = first_seg(lv)->data_len;
|
||||
uint64_t meta_size = first_seg(lv)->metadata_len;
|
||||
uint64_t data_size = first_seg(lv)->data_len;
|
||||
uint16_t udev_flags = _get_udev_flags(dm, lv, layer,
|
||||
laopts->noscan, laopts->temporary,
|
||||
0);
|
||||
@@ -3191,12 +3262,12 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
|
||||
if (dm->track_pending_delete) {
|
||||
log_debug_activation("Using error for pending meta delete %s.", display_lvname(lv));
|
||||
if (!dm_tree_node_add_error_target(dnode_meta, (uint64_t)lv->vg->extent_size * meta_len))
|
||||
if (!dm_tree_node_add_error_target(dnode_meta, meta_size))
|
||||
return_0;
|
||||
} else {
|
||||
/* add load_segment to meta dnode: linear, size of meta area */
|
||||
if (!add_linear_area_to_dtree(dnode_meta,
|
||||
meta_len,
|
||||
meta_size,
|
||||
lv->vg->extent_size,
|
||||
lv->vg->cmd->use_linear_target,
|
||||
lv->vg->name, lv->name))
|
||||
@@ -3220,19 +3291,19 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
|
||||
if (dm->track_pending_delete) {
|
||||
log_debug_activation("Using error for pending data delete %s.", display_lvname(lv));
|
||||
if (!dm_tree_node_add_error_target(dnode_data, (uint64_t)lv->vg->extent_size * data_len))
|
||||
if (!dm_tree_node_add_error_target(dnode_data, data_size))
|
||||
return_0;
|
||||
} else {
|
||||
/* add load_segment to data dnode: linear, size of data area */
|
||||
if (!add_linear_area_to_dtree(dnode_data,
|
||||
data_len,
|
||||
data_size,
|
||||
lv->vg->extent_size,
|
||||
lv->vg->cmd->use_linear_target,
|
||||
lv->vg->name, lv->name))
|
||||
return_0;
|
||||
|
||||
/* add seg_area to prev load_seg: offset 0 maps to cachepool lv after meta */
|
||||
if (!dm_tree_node_add_target_area(dnode_data, NULL, dlid_pool, meta_len))
|
||||
if (!dm_tree_node_add_target_area(dnode_data, NULL, dlid_pool, meta_size))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
@@ -3297,6 +3368,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
if (!layer && lv_is_new_thin_pool(lv))
|
||||
layer = lv_layer(lv);
|
||||
|
||||
/* Adds -real to the dm uuid of wcorig LV. */
|
||||
if (!layer && lv_is_writecache_origin(lv))
|
||||
layer = lv_layer(lv); /* "real" */
|
||||
|
||||
if (!(dlid = build_dm_uuid(dm->mem, lv, layer)))
|
||||
return_0;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ void dev_manager_exit(void);
|
||||
*/
|
||||
int dev_manager_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
const char *layer,
|
||||
int with_open_count, int with_read_ahead,
|
||||
int with_open_count, int with_read_ahead, int with_name_check,
|
||||
struct dm_info *dminfo, uint32_t *read_ahead,
|
||||
struct lv_seg_status *seg_status);
|
||||
|
||||
@@ -69,19 +69,15 @@ int dev_manager_writecache_message(struct dev_manager *dm,
|
||||
int dev_manager_cache_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_cache **status);
|
||||
int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct dm_status_thin_pool **status,
|
||||
int flush);
|
||||
int dev_manager_thin_pool_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
int metadata, dm_percent_t *percent);
|
||||
int dev_manager_thin_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
int mapped, dm_percent_t *percent);
|
||||
int dev_manager_thin_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin **status);
|
||||
int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
uint32_t *device_id);
|
||||
int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv, int flush,
|
||||
struct lv_status_thin_pool **status);
|
||||
int dev_manager_vdo_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_vdo **vdo_status,
|
||||
|
||||
@@ -313,7 +313,7 @@ struct fs_op_parms {
|
||||
char *lv_name;
|
||||
char *dev;
|
||||
char *old_lv_name;
|
||||
char names[0];
|
||||
char names[];
|
||||
};
|
||||
|
||||
static void _store_str(char **pos, char **ptr, const char *str)
|
||||
|
||||
707
lib/cache/lvmcache.c
vendored
707
lib/cache/lvmcache.c
vendored
File diff suppressed because it is too large
Load Diff
22
lib/cache/lvmcache.h
vendored
22
lib/cache/lvmcache.h
vendored
@@ -69,18 +69,19 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
|
||||
int lvmcache_label_scan(struct cmd_context *cmd);
|
||||
int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
int lvmcache_label_rescan_vg_rw(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
int lvmcache_label_reopen_vg_rw(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
|
||||
/* Add/delete a device */
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *labeller, const char *pvid,
|
||||
struct device *dev, uint64_t label_sector,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, int *is_duplicate);
|
||||
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt);
|
||||
int lvmcache_add_orphan_vginfo(struct cmd_context *cmd, const char *vgname, struct format_type *fmt);
|
||||
void lvmcache_del(struct lvmcache_info *info);
|
||||
void lvmcache_del_dev(struct device *dev);
|
||||
|
||||
/* Update things */
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted);
|
||||
int lvmcache_update_vg_from_write(struct volume_group *vg);
|
||||
@@ -161,11 +162,6 @@ struct device *lvmcache_device(struct lvmcache_info *info);
|
||||
unsigned lvmcache_mda_count(struct lvmcache_info *info);
|
||||
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
|
||||
|
||||
struct metadata_area *lvmcache_get_mda(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
struct device *dev,
|
||||
int use_mda_num);
|
||||
|
||||
bool lvmcache_has_duplicate_devs(void);
|
||||
void lvmcache_del_dev_from_duplicates(struct device *dev);
|
||||
bool lvmcache_dev_is_unused_duplicate(struct device *dev);
|
||||
@@ -174,6 +170,7 @@ int lvmcache_get_unused_duplicates(struct cmd_context *cmd, struct dm_list *head
|
||||
int vg_has_duplicate_pvs(struct volume_group *vg);
|
||||
|
||||
int lvmcache_found_duplicate_vgnames(void);
|
||||
bool lvmcache_has_duplicate_local_vgname(const char *vgid, const char *vgname);
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
|
||||
|
||||
@@ -216,4 +213,13 @@ void lvmcache_get_bad_mdas(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid,
|
||||
struct dm_list *bad_mda_list);
|
||||
|
||||
void lvmcache_get_mdas(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid,
|
||||
struct dm_list *mda_list);
|
||||
|
||||
const char *dev_filtered_reason(struct device *dev);
|
||||
const char *devname_error_reason(const char *devname);
|
||||
|
||||
struct metadata_area *lvmcache_get_dev_mda(struct device *dev, int mda_num);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1276,7 +1276,7 @@ int init_lvmcache_orphans(struct cmd_context *cmd)
|
||||
struct format_type *fmt;
|
||||
|
||||
dm_list_iterate_items(fmt, &cmd->formats)
|
||||
if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt))
|
||||
if (!lvmcache_add_orphan_vginfo(cmd, fmt->orphan_vg_name, fmt))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -1362,6 +1362,11 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifdef INTEGRITY_INTERNAL
|
||||
if (!init_integrity_segtypes(cmd, &seglib))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1593,6 +1598,7 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
dm_list_init(&cmd->formats);
|
||||
dm_list_init(&cmd->segtypes);
|
||||
dm_list_init(&cmd->tags);
|
||||
dm_list_init(&cmd->hints);
|
||||
dm_list_init(&cmd->config_files);
|
||||
label_init();
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ struct cmd_context {
|
||||
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
|
||||
unsigned scan_lvs:1;
|
||||
unsigned wipe_outdated_pvs:1;
|
||||
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
|
||||
|
||||
/*
|
||||
* Devices and filtering.
|
||||
|
||||
@@ -503,10 +503,10 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
{
|
||||
char *fb, *fe;
|
||||
int r = 0;
|
||||
int use_mmap = 1;
|
||||
off_t mmap_offset = 0;
|
||||
int sz, use_plain_read = 1;
|
||||
char *buf = NULL;
|
||||
struct config_source *cs = dm_config_get_custom(cft);
|
||||
size_t rsize;
|
||||
|
||||
if (!_is_file_based_config_source(cs->type)) {
|
||||
log_error(INTERNAL_ERROR "config_file_read_fd: expected file, special file "
|
||||
@@ -515,26 +515,28 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Only use mmap with regular files */
|
||||
/* Only use plain read with regular files */
|
||||
if (!(dev->flags & DEV_REGULAR) || size2)
|
||||
use_mmap = 0;
|
||||
use_plain_read = 0;
|
||||
|
||||
if (use_mmap) {
|
||||
mmap_offset = offset % lvm_getpagesize();
|
||||
/* memory map the file */
|
||||
fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
|
||||
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
|
||||
if (fb == (caddr_t) (-1)) {
|
||||
log_sys_error("mmap", dev_name(dev));
|
||||
goto out;
|
||||
if (!(buf = malloc(size + size2))) {
|
||||
log_error("Failed to allocate circular buffer.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (use_plain_read) {
|
||||
/* Note: also used for lvm.conf to read all settings */
|
||||
for (rsize = 0; rsize < size; rsize += sz) {
|
||||
do {
|
||||
sz = read(dev_fd(dev), buf + rsize, size - rsize);
|
||||
} while ((sz < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
|
||||
if (sz < 0) {
|
||||
log_sys_error("read", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
fb = fb + mmap_offset;
|
||||
} else {
|
||||
if (!(buf = malloc(size + size2))) {
|
||||
log_error("Failed to allocate circular buffer.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_read_bytes(dev, offset, size, buf))
|
||||
goto out;
|
||||
|
||||
@@ -542,10 +544,10 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
if (!dev_read_bytes(dev, offset2, size2, buf + size))
|
||||
goto out;
|
||||
}
|
||||
|
||||
fb = buf;
|
||||
}
|
||||
|
||||
fb = buf;
|
||||
|
||||
/*
|
||||
* The checksum passed in is the checksum from the mda_header
|
||||
* preceding this metadata. They should always match.
|
||||
@@ -573,15 +575,7 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (!use_mmap)
|
||||
free(buf);
|
||||
else {
|
||||
/* unmap the file */
|
||||
if (munmap(fb - mmap_offset, size + mmap_offset)) {
|
||||
log_sys_error("munmap", dev_name(dev));
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ cfg(allocation_raid_stripe_all_devices_CFG, "raid_stripe_all_devices", allocatio
|
||||
"stripes to use.\n"
|
||||
"This was the default behaviour until release 2.02.162.\n")
|
||||
|
||||
cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
|
||||
cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
|
||||
"Cache pool metadata and data will always use different PVs.\n")
|
||||
|
||||
cfg(allocation_cache_pool_cachemode_CFG, "cache_pool_cachemode", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 113), NULL, vsn(2, 2, 128),
|
||||
@@ -625,8 +625,8 @@ cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CF
|
||||
"For cache target v1.9 the recommended maximumm is 1000000 chunks.\n"
|
||||
"Using cache pool with more chunks may degrade cache performance.\n")
|
||||
|
||||
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
"Thin pool metdata and data will always use different PVs.\n")
|
||||
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
"Thin pool metadata and data will always use different PVs.\n")
|
||||
|
||||
cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL, 0, NULL,
|
||||
"Thin pool data chunks are zeroed before they are first used.\n"
|
||||
@@ -657,6 +657,9 @@ cfg(allocation_thin_pool_chunk_size_policy_CFG, "thin_pool_chunk_size_policy", a
|
||||
" 512KiB.\n"
|
||||
"#\n")
|
||||
|
||||
cfg(allocation_zero_metadata_CFG, "zero_metadata", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ZERO_METADATA, vsn(2, 3, 10), NULL, 0, NULL,
|
||||
"Zero whole metadata area before use with thin or cache pool.\n")
|
||||
|
||||
cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 99), 0, NULL,
|
||||
"The minimal chunk size in KiB for thin pool volumes.\n"
|
||||
"Larger chunk sizes may improve performance for plain thin volumes,\n"
|
||||
@@ -1028,7 +1031,7 @@ cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECT
|
||||
" fashion in a cluster.\n"
|
||||
"#\n")
|
||||
|
||||
cfg(global_support_mirrored_mirror_log_CFG, "support_mirrored_mirror_log", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 3, 2), NULL, 0, NULL,
|
||||
cfg(global_support_mirrored_mirror_log_CFG, "support_mirrored_mirror_log", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 3, 2), NULL, 0, NULL,
|
||||
"Enable mirrored 'mirror' log type for testing.\n"
|
||||
"#\n"
|
||||
"This type is deprecated to create or convert to but can\n"
|
||||
@@ -1082,7 +1085,7 @@ cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_pa
|
||||
"Previously this was always shown as /dev/vgname/lvname even when that\n"
|
||||
"was never a valid path in the /dev filesystem.\n")
|
||||
|
||||
cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 3, 1), 0, 0, NULL,
|
||||
cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 1), 0, 0, NULL,
|
||||
"Activate LVs based on system-generated device events.\n"
|
||||
"When a device appears on the system, a system-generated event runs\n"
|
||||
"the pvscan command to activate LVs if the new PV completes the VG.\n"
|
||||
@@ -1286,7 +1289,7 @@ cfg(activation_udev_rules_CFG, "udev_rules", activation_CFG_SECTION, 0, CFG_TYPE
|
||||
"active LVs itself. Manual intervention may be required if this\n"
|
||||
"setting is changed while LVs are active.\n")
|
||||
|
||||
cfg(activation_verify_udev_operations_CFG, "verify_udev_operations", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_VERIFY_UDEV_OPERATIONS, vsn(2, 2, 86), NULL, 0, NULL,
|
||||
cfg(activation_verify_udev_operations_CFG, "verify_udev_operations", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_VERIFY_UDEV_OPERATIONS, vsn(2, 2, 86), NULL, 0, NULL,
|
||||
"Use extra checks in LVM to verify udev operations.\n"
|
||||
"This enables additional checks (and if necessary, repairs) on entries\n"
|
||||
"in the device directory after udev has completed processing its\n"
|
||||
@@ -1307,21 +1310,21 @@ cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CF
|
||||
"other than 'error' with mirrored or snapshotted volumes is likely to\n"
|
||||
"result in data corruption.\n")
|
||||
|
||||
cfg(activation_use_linear_target_CFG, "use_linear_target", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LINEAR_TARGET, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
cfg(activation_use_linear_target_CFG, "use_linear_target", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_LINEAR_TARGET, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
"Use the linear target to optimize single stripe LVs.\n"
|
||||
"When disabled, the striped target is used. The linear target is an\n"
|
||||
"optimised version of the striped target that only handles a single\n"
|
||||
"stripe.\n")
|
||||
|
||||
cfg(activation_reserved_stack_CFG, "reserved_stack", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RESERVED_STACK, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
cfg(activation_reserved_stack_CFG, "reserved_stack", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RESERVED_STACK, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Stack size in KiB to reserve for use while devices are suspended.\n"
|
||||
"Insufficent reserve risks I/O deadlock during device suspension.\n")
|
||||
|
||||
cfg(activation_reserved_memory_CFG, "reserved_memory", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RESERVED_MEMORY, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
cfg(activation_reserved_memory_CFG, "reserved_memory", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RESERVED_MEMORY, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Memory size in KiB to reserve for use while devices are suspended.\n"
|
||||
"Insufficent reserve risks I/O deadlock during device suspension.\n")
|
||||
|
||||
cfg(activation_process_priority_CFG, "process_priority", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PROCESS_PRIORITY, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
cfg(activation_process_priority_CFG, "process_priority", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PROCESS_PRIORITY, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Nice value used while devices are suspended.\n"
|
||||
"Use a high priority so that LVs are suspended\n"
|
||||
"for the shortest possible time.\n")
|
||||
@@ -1430,7 +1433,7 @@ cfg(activation_error_when_full_CFG, "error_when_full", activation_CFG_SECTION, C
|
||||
"thin pool data space is extended. New thin pools are assigned the\n"
|
||||
"behavior defined here.\n")
|
||||
|
||||
cfg(activation_readahead_CFG, "readahead", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_READ_AHEAD, vsn(1, 0, 23), NULL, 0, NULL,
|
||||
cfg(activation_readahead_CFG, "readahead", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_READ_AHEAD, vsn(1, 0, 23), NULL, 0, NULL,
|
||||
"Setting to use when there is no readahead setting in metadata.\n"
|
||||
"#\n"
|
||||
"Accepted values:\n"
|
||||
@@ -1558,7 +1561,7 @@ cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent",
|
||||
"thin_pool_autoextend_percent = 20\n"
|
||||
"#\n")
|
||||
|
||||
cfg(activation_vdo_pool_autoextend_threshold_CFG, "vdo_pool_autoextend_threshold", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_VDO_POOL_AUTOEXTEND_THRESHOLD, VDO_1ST_VSN, NULL, 0, NULL,
|
||||
cfg(activation_vdo_pool_autoextend_threshold_CFG, "vdo_pool_autoextend_threshold", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_POOL_AUTOEXTEND_THRESHOLD, VDO_1ST_VSN, NULL, 0, NULL,
|
||||
"Auto-extend a VDO pool when its usage exceeds this percent.\n"
|
||||
"Setting this to 100 disables automatic extension.\n"
|
||||
"The minimum value is 50 (a smaller value is treated as 50.)\n"
|
||||
@@ -1598,7 +1601,7 @@ cfg_array(activation_mlock_filter_CFG, "mlock_filter", activation_CFG_SECTION, C
|
||||
"mlock_filter = [ \"locale/locale-archive\", \"gconv/gconv-modules.cache\" ]\n"
|
||||
"#\n")
|
||||
|
||||
cfg(activation_use_mlockall_CFG, "use_mlockall", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_MLOCKALL, vsn(2, 2, 62), NULL, 0, NULL,
|
||||
cfg(activation_use_mlockall_CFG, "use_mlockall", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_MLOCKALL, vsn(2, 2, 62), NULL, 0, NULL,
|
||||
"Use the old behavior of mlockall to pin all memory.\n"
|
||||
"Prior to version 2.02.62, LVM used mlockall() to pin the whole\n"
|
||||
"process's memory while activating devices.\n")
|
||||
@@ -1608,7 +1611,7 @@ cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, 0, CFG_TYPE
|
||||
"The --ignoremonitoring option overrides this setting.\n"
|
||||
"When enabled, LVM will ask dmeventd to monitor activated LVs.\n")
|
||||
|
||||
cfg(activation_polling_interval_CFG, "polling_interval", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_INTERVAL, vsn(2, 2, 63), NULL, 0, NULL,
|
||||
cfg(activation_polling_interval_CFG, "polling_interval", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_INTERVAL, vsn(2, 2, 63), NULL, 0, NULL,
|
||||
"Check pvmove or lvconvert progress at this interval (seconds).\n"
|
||||
"When pvmove or lvconvert must wait for the kernel to finish\n"
|
||||
"synchronising or merging data, they check and report progress at\n"
|
||||
@@ -2047,7 +2050,7 @@ cfg(report_two_word_unknown_device_CFG, "two_word_unknown_device", report_CFG_SE
|
||||
"Use the two words 'unknown device' in place of '[unknown]'.\n"
|
||||
"This is displayed when the device for a PV is not known.\n")
|
||||
|
||||
cfg(dmeventd_mirror_library_CFG, "mirror_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_MIRROR_LIB, vsn(1, 2, 3), NULL, 0, NULL,
|
||||
cfg(dmeventd_mirror_library_CFG, "mirror_library", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_MIRROR_LIB, vsn(1, 2, 3), NULL, 0, NULL,
|
||||
"The library dmeventd uses when monitoring a mirror device.\n"
|
||||
"libdevmapper-event-lvm2mirror.so attempts to recover from\n"
|
||||
"failures. It removes failed devices from a volume group and\n"
|
||||
@@ -2056,13 +2059,13 @@ cfg(dmeventd_mirror_library_CFG, "mirror_library", dmeventd_CFG_SECTION, 0, CFG_
|
||||
|
||||
cfg(dmeventd_raid_library_CFG, "raid_library", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_RAID_LIB, vsn(2, 2, 87), NULL, 0, NULL, NULL)
|
||||
|
||||
cfg(dmeventd_snapshot_library_CFG, "snapshot_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_SNAPSHOT_LIB, vsn(1, 2, 26), NULL, 0, NULL,
|
||||
cfg(dmeventd_snapshot_library_CFG, "snapshot_library", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_SNAPSHOT_LIB, vsn(1, 2, 26), NULL, 0, NULL,
|
||||
"The library dmeventd uses when monitoring a snapshot device.\n"
|
||||
"libdevmapper-event-lvm2snapshot.so monitors the filling of snapshots\n"
|
||||
"and emits a warning through syslog when the usage exceeds 80%. The\n"
|
||||
"warning is repeated when 85%, 90% and 95% of the snapshot is filled.\n")
|
||||
|
||||
cfg(dmeventd_thin_library_CFG, "thin_library", dmeventd_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_DMEVENTD_THIN_LIB, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
cfg(dmeventd_thin_library_CFG, "thin_library", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_THIN_LIB, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
"The library dmeventd uses when monitoring a thin device.\n"
|
||||
"libdevmapper-event-lvm2thin.so monitors the filling of a pool\n"
|
||||
"and emits a warning through syslog when the usage exceeds 80%. The\n"
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
#define DEFAULT_THIN_POOL_DISCARDS "passdown"
|
||||
#define DEFAULT_THIN_POOL_ZERO 1
|
||||
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
||||
#define DEFAULT_ZERO_METADATA 1 /* thin + cache */
|
||||
|
||||
#ifdef CACHE_CHECK_NEEDS_CHECK
|
||||
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
|
||||
@@ -39,32 +39,32 @@ static uint64_t _min(uint64_t lhs, uint64_t rhs)
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
void bcache_prefetch_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||
void bcache_prefetch_bytes(struct bcache *cache, int di, uint64_t start, size_t len)
|
||||
{
|
||||
block_address bb, be;
|
||||
|
||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||
while (bb < be) {
|
||||
bcache_prefetch(cache, fd, bb);
|
||||
bcache_prefetch(cache, di, bb);
|
||||
bb++;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
||||
bool bcache_read_bytes(struct bcache *cache, int di, uint64_t start, size_t len, void *data)
|
||||
{
|
||||
struct block *b;
|
||||
block_address bb, be;
|
||||
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
||||
uint64_t block_offset = start % block_size;
|
||||
|
||||
bcache_prefetch_bytes(cache, fd, start, len);
|
||||
bcache_prefetch_bytes(cache, di, start, len);
|
||||
|
||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_get(cache, fd, bb, 0, &b))
|
||||
if (!bcache_get(cache, di, bb, 0, &b))
|
||||
return false;
|
||||
|
||||
size_t blen = _min(block_size - block_offset, len);
|
||||
@@ -79,6 +79,21 @@ bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_invalidate_bytes(struct bcache *cache, int di, uint64_t start, size_t len)
|
||||
{
|
||||
block_address bb, be;
|
||||
bool result = true;
|
||||
|
||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_invalidate(cache, di, bb))
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
// Writing bytes and zeroing bytes are very similar, so we factor out
|
||||
@@ -86,8 +101,8 @@ bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
|
||||
|
||||
struct updater;
|
||||
|
||||
typedef bool (*partial_update_fn)(struct updater *u, int fd, block_address bb, uint64_t offset, size_t len);
|
||||
typedef bool (*whole_update_fn)(struct updater *u, int fd, block_address bb, block_address be);
|
||||
typedef bool (*partial_update_fn)(struct updater *u, int di, block_address bb, uint64_t offset, size_t len);
|
||||
typedef bool (*whole_update_fn)(struct updater *u, int di, block_address bb, block_address be);
|
||||
|
||||
struct updater {
|
||||
struct bcache *cache;
|
||||
@@ -96,7 +111,7 @@ struct updater {
|
||||
void *data;
|
||||
};
|
||||
|
||||
static bool _update_bytes(struct updater *u, int fd, uint64_t start, size_t len)
|
||||
static bool _update_bytes(struct updater *u, int di, uint64_t start, size_t len)
|
||||
{
|
||||
struct bcache *cache = u->cache;
|
||||
block_address bb, be;
|
||||
@@ -109,12 +124,12 @@ static bool _update_bytes(struct updater *u, int fd, uint64_t start, size_t len)
|
||||
// If the last block is partial, we will require a read, so let's
|
||||
// prefetch it.
|
||||
if ((start + len) % block_size)
|
||||
bcache_prefetch(cache, fd, (start + len) / block_size);
|
||||
bcache_prefetch(cache, di, (start + len) / block_size);
|
||||
|
||||
// First block may be partial
|
||||
if (block_offset) {
|
||||
size_t blen = _min(block_size - block_offset, len);
|
||||
if (!u->partial_fn(u, fd, bb, block_offset, blen))
|
||||
if (!u->partial_fn(u, di, bb, block_offset, blen))
|
||||
return false;
|
||||
|
||||
len -= blen;
|
||||
@@ -126,7 +141,7 @@ static bool _update_bytes(struct updater *u, int fd, uint64_t start, size_t len)
|
||||
|
||||
// Now we write out a set of whole blocks
|
||||
nr_whole = len / block_size;
|
||||
if (!u->whole_fn(u, fd, bb, bb + nr_whole))
|
||||
if (!u->whole_fn(u, di, bb, bb + nr_whole))
|
||||
return false;
|
||||
|
||||
bb += nr_whole;
|
||||
@@ -136,17 +151,17 @@ static bool _update_bytes(struct updater *u, int fd, uint64_t start, size_t len)
|
||||
return true;
|
||||
|
||||
// Finally we write a partial end block
|
||||
return u->partial_fn(u, fd, bb, 0, len);
|
||||
return u->partial_fn(u, di, bb, 0, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static bool _write_partial(struct updater *u, int fd, block_address bb,
|
||||
static bool _write_partial(struct updater *u, int di, block_address bb,
|
||||
uint64_t offset, size_t len)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b))
|
||||
if (!bcache_get(u->cache, di, bb, GF_DIRTY, &b))
|
||||
return false;
|
||||
|
||||
memcpy(((unsigned char *) b->data) + offset, u->data, len);
|
||||
@@ -156,7 +171,7 @@ static bool _write_partial(struct updater *u, int fd, block_address bb,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _write_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||
static bool _write_whole(struct updater *u, int di, block_address bb, block_address be)
|
||||
{
|
||||
struct block *b;
|
||||
uint64_t block_size = bcache_block_sectors(u->cache) << SECTOR_SHIFT;
|
||||
@@ -164,7 +179,7 @@ static bool _write_whole(struct updater *u, int fd, block_address bb, block_addr
|
||||
for (; bb != be; bb++) {
|
||||
// We don't need to read the block since we are overwriting
|
||||
// it completely.
|
||||
if (!bcache_get(u->cache, fd, bb, GF_ZERO, &b))
|
||||
if (!bcache_get(u->cache, di, bb, GF_ZERO, &b))
|
||||
return false;
|
||||
memcpy(b->data, u->data, block_size);
|
||||
u->data = ((unsigned char *) u->data) + block_size;
|
||||
@@ -174,7 +189,7 @@ static bool _write_whole(struct updater *u, int fd, block_address bb, block_addr
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
||||
bool bcache_write_bytes(struct bcache *cache, int di, uint64_t start, size_t len, void *data)
|
||||
{
|
||||
struct updater u;
|
||||
|
||||
@@ -183,16 +198,16 @@ bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len
|
||||
u.whole_fn = _write_whole;
|
||||
u.data = data;
|
||||
|
||||
return _update_bytes(&u, fd, start, len);
|
||||
return _update_bytes(&u, di, start, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static bool _zero_partial(struct updater *u, int fd, block_address bb, uint64_t offset, size_t len)
|
||||
static bool _zero_partial(struct updater *u, int di, block_address bb, uint64_t offset, size_t len)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b))
|
||||
if (!bcache_get(u->cache, di, bb, GF_DIRTY, &b))
|
||||
return false;
|
||||
|
||||
memset(((unsigned char *) b->data) + offset, 0, len);
|
||||
@@ -201,12 +216,12 @@ static bool _zero_partial(struct updater *u, int fd, block_address bb, uint64_t
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _zero_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||
static bool _zero_whole(struct updater *u, int di, block_address bb, block_address be)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_get(u->cache, fd, bb, GF_ZERO, &b))
|
||||
if (!bcache_get(u->cache, di, bb, GF_ZERO, &b))
|
||||
return false;
|
||||
bcache_put(b);
|
||||
}
|
||||
@@ -214,7 +229,7 @@ static bool _zero_whole(struct updater *u, int fd, block_address bb, block_addre
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||
bool bcache_zero_bytes(struct bcache *cache, int di, uint64_t start, size_t len)
|
||||
{
|
||||
struct updater u;
|
||||
|
||||
@@ -223,17 +238,17 @@ bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||
u.whole_fn = _zero_whole;
|
||||
u.data = NULL;
|
||||
|
||||
return _update_bytes(&u, fd, start, len);
|
||||
return _update_bytes(&u, di, start, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static bool _set_partial(struct updater *u, int fd, block_address bb, uint64_t offset, size_t len)
|
||||
static bool _set_partial(struct updater *u, int di, block_address bb, uint64_t offset, size_t len)
|
||||
{
|
||||
struct block *b;
|
||||
uint8_t val = *((uint8_t *) u->data);
|
||||
|
||||
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b))
|
||||
if (!bcache_get(u->cache, di, bb, GF_DIRTY, &b))
|
||||
return false;
|
||||
|
||||
memset(((unsigned char *) b->data) + offset, val, len);
|
||||
@@ -242,14 +257,14 @@ static bool _set_partial(struct updater *u, int fd, block_address bb, uint64_t o
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _set_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||
static bool _set_whole(struct updater *u, int di, block_address bb, block_address be)
|
||||
{
|
||||
struct block *b;
|
||||
uint8_t val = *((uint8_t *) u->data);
|
||||
uint64_t len = bcache_block_sectors(u->cache) * 512;
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_get(u->cache, fd, bb, GF_ZERO, &b))
|
||||
if (!bcache_get(u->cache, di, bb, GF_ZERO, &b))
|
||||
return false;
|
||||
memset((unsigned char *) b->data, val, len);
|
||||
bcache_put(b);
|
||||
@@ -258,7 +273,7 @@ static bool _set_whole(struct updater *u, int fd, block_address bb, block_addres
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, uint8_t val)
|
||||
bool bcache_set_bytes(struct bcache *cache, int di, uint64_t start, size_t len, uint8_t val)
|
||||
{
|
||||
struct updater u;
|
||||
|
||||
@@ -267,6 +282,6 @@ bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len,
|
||||
u.whole_fn = _set_whole;
|
||||
u.data = &val;
|
||||
|
||||
return _update_bytes(&u, fd, start, len);
|
||||
return _update_bytes(&u, di, start, len);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@
|
||||
|
||||
#define SECTOR_SHIFT 9L
|
||||
|
||||
#define FD_TABLE_INC 1024
|
||||
static int _fd_table_size;
|
||||
static int *_fd_table;
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static void log_sys_warn(const char *call)
|
||||
@@ -61,23 +66,17 @@ struct control_block {
|
||||
struct cb_set {
|
||||
struct dm_list free;
|
||||
struct dm_list allocated;
|
||||
struct control_block *vec;
|
||||
struct control_block vec[];
|
||||
} control_block_set;
|
||||
|
||||
static struct cb_set *_cb_set_create(unsigned nr)
|
||||
{
|
||||
int i;
|
||||
struct cb_set *cbs = malloc(sizeof(*cbs));
|
||||
unsigned i;
|
||||
struct cb_set *cbs = malloc(sizeof(*cbs) + nr * sizeof(*cbs->vec));
|
||||
|
||||
if (!cbs)
|
||||
if (!cbs->vec)
|
||||
return NULL;
|
||||
|
||||
cbs->vec = malloc(nr * sizeof(*cbs->vec));
|
||||
if (!cbs->vec) {
|
||||
free(cbs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dm_list_init(&cbs->free);
|
||||
dm_list_init(&cbs->allocated);
|
||||
|
||||
@@ -97,7 +96,6 @@ static void _cb_set_destroy(struct cb_set *cbs)
|
||||
return;
|
||||
}
|
||||
|
||||
free(cbs->vec);
|
||||
free(cbs);
|
||||
}
|
||||
|
||||
@@ -155,11 +153,11 @@ static void _async_destroy(struct io_engine *ioe)
|
||||
free(e);
|
||||
}
|
||||
|
||||
static int _last_byte_fd;
|
||||
static int _last_byte_di;
|
||||
static uint64_t _last_byte_offset;
|
||||
static int _last_byte_sector_size;
|
||||
|
||||
static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
static bool _async_issue(struct io_engine *ioe, enum dir d, int di,
|
||||
sector_t sb, sector_t se, void *data, void *context)
|
||||
{
|
||||
int r;
|
||||
@@ -183,7 +181,7 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
/*
|
||||
* If bcache block goes past where lvm wants to write, then clamp it.
|
||||
*/
|
||||
if ((d == DIR_WRITE) && _last_byte_offset && (fd == _last_byte_fd)) {
|
||||
if ((d == DIR_WRITE) && _last_byte_offset && (di == _last_byte_di)) {
|
||||
if (offset > _last_byte_offset) {
|
||||
log_error("Limit write at %llu len %llu beyond last byte %llu",
|
||||
(unsigned long long)offset,
|
||||
@@ -268,7 +266,7 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
|
||||
memset(&cb->cb, 0, sizeof(cb->cb));
|
||||
|
||||
cb->cb.aio_fildes = (int) fd;
|
||||
cb->cb.aio_fildes = (int) _fd_table[di];
|
||||
cb->cb.u.c.buf = data;
|
||||
cb->cb.u.c.offset = offset;
|
||||
cb->cb.u.c.nbytes = nbytes;
|
||||
@@ -276,13 +274,15 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
|
||||
#if 0
|
||||
if (d == DIR_READ) {
|
||||
log_debug("io R off %llu bytes %llu",
|
||||
log_debug("io R off %llu bytes %llu di %d fd %d",
|
||||
(unsigned long long)cb->cb.u.c.offset,
|
||||
(unsigned long long)cb->cb.u.c.nbytes);
|
||||
(unsigned long long)cb->cb.u.c.nbytes,
|
||||
di, _fd_table[di]);
|
||||
} else {
|
||||
log_debug("io W off %llu bytes %llu",
|
||||
log_debug("io W off %llu bytes %llu di %d fd %d",
|
||||
(unsigned long long)cb->cb.u.c.offset,
|
||||
(unsigned long long)cb->cb.u.c.nbytes);
|
||||
(unsigned long long)cb->cb.u.c.nbytes,
|
||||
di, _fd_table[di]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -318,9 +318,7 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
|
||||
struct async_engine *e = _to_async(ioe);
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
do {
|
||||
r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
|
||||
} while (r == -EINTR);
|
||||
r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
|
||||
|
||||
if (r < 0) {
|
||||
log_sys_warn("io_getevents");
|
||||
@@ -414,7 +412,7 @@ static void _sync_destroy(struct io_engine *ioe)
|
||||
free(e);
|
||||
}
|
||||
|
||||
static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
static bool _sync_issue(struct io_engine *ioe, enum dir d, int di,
|
||||
sector_t sb, sector_t se, void *data, void *context)
|
||||
{
|
||||
int rv;
|
||||
@@ -430,7 +428,7 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
}
|
||||
|
||||
where = sb * 512;
|
||||
off = lseek(fd, where, SEEK_SET);
|
||||
off = lseek(_fd_table[di], where, SEEK_SET);
|
||||
if (off == (off_t) -1) {
|
||||
log_warn("Device seek error %d for offset %llu", errno, (unsigned long long)where);
|
||||
free(io);
|
||||
@@ -445,7 +443,7 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
/*
|
||||
* If bcache block goes past where lvm wants to write, then clamp it.
|
||||
*/
|
||||
if ((d == DIR_WRITE) && _last_byte_offset && (fd == _last_byte_fd)) {
|
||||
if ((d == DIR_WRITE) && _last_byte_offset && (di == _last_byte_di)) {
|
||||
uint64_t offset = where;
|
||||
uint64_t nbytes = len;
|
||||
sector_t limit_nbytes = 0;
|
||||
@@ -515,6 +513,7 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
(unsigned long long)limit_nbytes,
|
||||
(unsigned long long)extra_nbytes,
|
||||
(unsigned long long)_last_byte_sector_size);
|
||||
free(io);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -525,9 +524,9 @@ static bool _sync_issue(struct io_engine *ioe, enum dir d, int fd,
|
||||
|
||||
while (pos < len) {
|
||||
if (d == DIR_READ)
|
||||
rv = read(fd, (char *)data + pos, len - pos);
|
||||
rv = read(_fd_table[di], (char *)data + pos, len - pos);
|
||||
else
|
||||
rv = write(fd, (char *)data + pos, len - pos);
|
||||
rv = write(_fd_table[di], (char *)data + pos, len - pos);
|
||||
|
||||
if (rv == -1 && errno == EINTR)
|
||||
continue;
|
||||
@@ -687,7 +686,7 @@ struct bcache {
|
||||
//----------------------------------------------------------------
|
||||
|
||||
struct key_parts {
|
||||
uint32_t fd;
|
||||
uint32_t di;
|
||||
uint64_t b;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@@ -696,12 +695,12 @@ union key {
|
||||
uint8_t bytes[12];
|
||||
};
|
||||
|
||||
static struct block *_block_lookup(struct bcache *cache, int fd, uint64_t i)
|
||||
static struct block *_block_lookup(struct bcache *cache, int di, uint64_t i)
|
||||
{
|
||||
union key k;
|
||||
union radix_value v;
|
||||
|
||||
k.parts.fd = fd;
|
||||
k.parts.di = di;
|
||||
k.parts.b = i;
|
||||
|
||||
if (radix_tree_lookup(cache->rtree, k.bytes, k.bytes + sizeof(k.bytes), &v))
|
||||
@@ -715,7 +714,7 @@ static bool _block_insert(struct block *b)
|
||||
union key k;
|
||||
union radix_value v;
|
||||
|
||||
k.parts.fd = b->fd;
|
||||
k.parts.di = b->di;
|
||||
k.parts.b = b->index;
|
||||
v.ptr = b;
|
||||
|
||||
@@ -726,7 +725,7 @@ static void _block_remove(struct block *b)
|
||||
{
|
||||
union key k;
|
||||
|
||||
k.parts.fd = b->fd;
|
||||
k.parts.di = b->di;
|
||||
k.parts.b = b->index;
|
||||
|
||||
radix_tree_remove(b->cache->rtree, k.bytes, k.bytes + sizeof(k.bytes));
|
||||
@@ -868,7 +867,7 @@ static void _issue_low_level(struct block *b, enum dir d)
|
||||
|
||||
dm_list_move(&cache->io_pending, &b->list);
|
||||
|
||||
if (!cache->engine->issue(cache->engine, d, b->fd, sb, se, b->data, b)) {
|
||||
if (!cache->engine->issue(cache->engine, d, b->di, sb, se, b->data, b)) {
|
||||
/* FIXME: if io_submit() set an errno, return that instead of EIO? */
|
||||
_complete_io(b, -EIO);
|
||||
return;
|
||||
@@ -944,21 +943,26 @@ static struct block *_find_unused_clean_block(struct bcache *cache)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct block *_new_block(struct bcache *cache, int fd, block_address i, bool can_wait)
|
||||
static struct block *_new_block(struct bcache *cache, int di, block_address i, bool can_wait)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
b = _alloc_block(cache);
|
||||
while (!b && !dm_list_empty(&cache->clean)) {
|
||||
while (!b) {
|
||||
b = _find_unused_clean_block(cache);
|
||||
if (!b) {
|
||||
if (can_wait) {
|
||||
if (dm_list_empty(&cache->io_pending))
|
||||
_writeback(cache, 16); // FIXME: magic number
|
||||
_wait_io(cache);
|
||||
_wait_all(cache);
|
||||
if (dm_list_size(&cache->errored) >= cache->max_io) {
|
||||
log_debug("bcache no new blocks for di %d index %u with >%d errors.",
|
||||
di, (uint32_t) i, cache->max_io);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
log_debug("bcache no new blocks for fd %d index %u",
|
||||
fd, (uint32_t) i);
|
||||
log_debug("bcache no new blocks for di %d index %u",
|
||||
di, (uint32_t) i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -967,7 +971,7 @@ static struct block *_new_block(struct bcache *cache, int fd, block_address i, b
|
||||
if (b) {
|
||||
dm_list_init(&b->list);
|
||||
b->flags = 0;
|
||||
b->fd = fd;
|
||||
b->di = di;
|
||||
b->index = i;
|
||||
b->ref_count = 0;
|
||||
b->error = 0;
|
||||
@@ -1013,10 +1017,10 @@ static void _miss(struct bcache *cache, unsigned flags)
|
||||
}
|
||||
|
||||
static struct block *_lookup_or_read_block(struct bcache *cache,
|
||||
int fd, block_address i,
|
||||
int di, block_address i,
|
||||
unsigned flags)
|
||||
{
|
||||
struct block *b = _block_lookup(cache, fd, i);
|
||||
struct block *b = _block_lookup(cache, di, i);
|
||||
|
||||
if (b) {
|
||||
// FIXME: this is insufficient. We need to also catch a read
|
||||
@@ -1041,7 +1045,7 @@ static struct block *_lookup_or_read_block(struct bcache *cache,
|
||||
} else {
|
||||
_miss(cache, flags);
|
||||
|
||||
b = _new_block(cache, fd, i, true);
|
||||
b = _new_block(cache, di, i, true);
|
||||
if (b) {
|
||||
if (flags & GF_ZERO)
|
||||
_zero_block(b);
|
||||
@@ -1086,6 +1090,7 @@ struct bcache *bcache_create(sector_t block_sectors, unsigned nr_cache_blocks,
|
||||
struct bcache *cache;
|
||||
unsigned max_io = engine->max_io(engine);
|
||||
long pgsize = sysconf(_SC_PAGESIZE);
|
||||
int i;
|
||||
|
||||
if (pgsize < 0) {
|
||||
log_warn("WARNING: _SC_PAGESIZE returns negative value.");
|
||||
@@ -1146,6 +1151,18 @@ struct bcache *bcache_create(sector_t block_sectors, unsigned nr_cache_blocks,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_fd_table_size = FD_TABLE_INC;
|
||||
|
||||
if (!(_fd_table = malloc(sizeof(int) * _fd_table_size))) {
|
||||
cache->engine->destroy(cache->engine);
|
||||
radix_tree_destroy(cache->rtree);
|
||||
free(cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < _fd_table_size; i++)
|
||||
_fd_table[i] = -1;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@@ -1161,6 +1178,9 @@ void bcache_destroy(struct bcache *cache)
|
||||
radix_tree_destroy(cache->rtree);
|
||||
cache->engine->destroy(cache->engine);
|
||||
free(cache);
|
||||
free(_fd_table);
|
||||
_fd_table = NULL;
|
||||
_fd_table_size = 0;
|
||||
}
|
||||
|
||||
sector_t bcache_block_sectors(struct bcache *cache)
|
||||
@@ -1178,13 +1198,13 @@ unsigned bcache_max_prefetches(struct bcache *cache)
|
||||
return cache->max_io;
|
||||
}
|
||||
|
||||
void bcache_prefetch(struct bcache *cache, int fd, block_address i)
|
||||
void bcache_prefetch(struct bcache *cache, int di, block_address i)
|
||||
{
|
||||
struct block *b = _block_lookup(cache, fd, i);
|
||||
struct block *b = _block_lookup(cache, di, i);
|
||||
|
||||
if (!b) {
|
||||
if (cache->nr_io_pending < cache->max_io) {
|
||||
b = _new_block(cache, fd, i, false);
|
||||
b = _new_block(cache, di, i, false);
|
||||
if (b) {
|
||||
cache->prefetches++;
|
||||
_issue_read(b);
|
||||
@@ -1202,12 +1222,15 @@ static void _recycle_block(struct bcache *cache, struct block *b)
|
||||
_free_block(b);
|
||||
}
|
||||
|
||||
bool bcache_get(struct bcache *cache, int fd, block_address i,
|
||||
bool bcache_get(struct bcache *cache, int di, block_address i,
|
||||
unsigned flags, struct block **result)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
b = _lookup_or_read_block(cache, fd, i, flags);
|
||||
if (di >= _fd_table_size)
|
||||
goto bad;
|
||||
|
||||
b = _lookup_or_read_block(cache, di, i, flags);
|
||||
if (b) {
|
||||
if (b->error) {
|
||||
if (b->io_dir == DIR_READ) {
|
||||
@@ -1226,10 +1249,10 @@ bool bcache_get(struct bcache *cache, int fd, block_address i,
|
||||
*result = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
bad:
|
||||
*result = NULL;
|
||||
|
||||
log_error("bcache failed to get block %u fd %d", (uint32_t) i, fd);
|
||||
log_error("bcache failed to get block %u di %d", (uint32_t) i, di);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1293,7 +1316,7 @@ static bool _invalidate_block(struct bcache *cache, struct block *b)
|
||||
|
||||
if (b->ref_count) {
|
||||
log_warn("bcache_invalidate: block (%d, %llu) still held",
|
||||
b->fd, (unsigned long long) b->index);
|
||||
b->di, (unsigned long long) b->index);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1310,9 +1333,9 @@ static bool _invalidate_block(struct bcache *cache, struct block *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_invalidate(struct bcache *cache, int fd, block_address i)
|
||||
bool bcache_invalidate(struct bcache *cache, int di, block_address i)
|
||||
{
|
||||
return _invalidate_block(cache, _block_lookup(cache, fd, i));
|
||||
return _invalidate_block(cache, _block_lookup(cache, di, i));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@@ -1341,14 +1364,14 @@ static bool _invalidate_v(struct radix_tree_iterator *it,
|
||||
|
||||
if (b->error || _test_flags(b, BF_DIRTY)) {
|
||||
log_warn("bcache_invalidate: block (%d, %llu) still dirty",
|
||||
b->fd, (unsigned long long) b->index);
|
||||
b->di, (unsigned long long) b->index);
|
||||
iit->success = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (b->ref_count) {
|
||||
log_warn("bcache_invalidate: block (%d, %llu) still held",
|
||||
b->fd, (unsigned long long) b->index);
|
||||
b->di, (unsigned long long) b->index);
|
||||
iit->success = false;
|
||||
return true;
|
||||
}
|
||||
@@ -1361,42 +1384,138 @@ static bool _invalidate_v(struct radix_tree_iterator *it,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_invalidate_fd(struct bcache *cache, int fd)
|
||||
bool bcache_invalidate_di(struct bcache *cache, int di)
|
||||
{
|
||||
union key k;
|
||||
struct invalidate_iterator it;
|
||||
|
||||
k.parts.fd = fd;
|
||||
k.parts.di = di;
|
||||
|
||||
it.it.visit = _writeback_v;
|
||||
radix_tree_iterate(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.fd), &it.it);
|
||||
radix_tree_iterate(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.di), &it.it);
|
||||
|
||||
_wait_all(cache);
|
||||
|
||||
it.success = true;
|
||||
it.it.visit = _invalidate_v;
|
||||
radix_tree_iterate(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.fd), &it.it);
|
||||
radix_tree_remove_prefix(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.fd));
|
||||
radix_tree_iterate(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.di), &it.it);
|
||||
|
||||
if (it.success)
|
||||
radix_tree_remove_prefix(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.di));
|
||||
|
||||
return it.success;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
void bcache_set_last_byte(struct bcache *cache, int fd, uint64_t offset, int sector_size)
|
||||
static bool _abort_v(struct radix_tree_iterator *it,
|
||||
uint8_t *kb, uint8_t *ke, union radix_value v)
|
||||
{
|
||||
_last_byte_fd = fd;
|
||||
struct block *b = v.ptr;
|
||||
|
||||
if (b->ref_count) {
|
||||
log_fatal("bcache_abort: block (%d, %llu) still held",
|
||||
b->di, (unsigned long long) b->index);
|
||||
return true;
|
||||
}
|
||||
|
||||
_unlink_block(b);
|
||||
_free_block(b);
|
||||
|
||||
// We can't remove the block from the radix tree yet because
|
||||
// we're in the middle of an iteration.
|
||||
return true;
|
||||
}
|
||||
|
||||
void bcache_abort_di(struct bcache *cache, int di)
|
||||
{
|
||||
union key k;
|
||||
struct radix_tree_iterator it;
|
||||
|
||||
k.parts.di = di;
|
||||
|
||||
it.visit = _abort_v;
|
||||
radix_tree_iterate(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.di), &it);
|
||||
radix_tree_remove_prefix(cache->rtree, k.bytes, k.bytes + sizeof(k.parts.di));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
void bcache_set_last_byte(struct bcache *cache, int di, uint64_t offset, int sector_size)
|
||||
{
|
||||
_last_byte_di = di;
|
||||
_last_byte_offset = offset;
|
||||
_last_byte_sector_size = sector_size;
|
||||
if (!sector_size)
|
||||
_last_byte_sector_size = 512;
|
||||
}
|
||||
|
||||
void bcache_unset_last_byte(struct bcache *cache, int fd)
|
||||
void bcache_unset_last_byte(struct bcache *cache, int di)
|
||||
{
|
||||
if (_last_byte_fd == fd) {
|
||||
_last_byte_fd = 0;
|
||||
if (_last_byte_di == di) {
|
||||
_last_byte_di = 0;
|
||||
_last_byte_offset = 0;
|
||||
_last_byte_sector_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int bcache_set_fd(int fd)
|
||||
{
|
||||
int *new_table = NULL;
|
||||
int new_size = 0;
|
||||
int i;
|
||||
|
||||
retry:
|
||||
for (i = 0; i < _fd_table_size; i++) {
|
||||
if (_fd_table[i] == -1) {
|
||||
_fd_table[i] = fd;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* already tried once, shouldn't happen */
|
||||
if (new_size)
|
||||
return -1;
|
||||
|
||||
new_size = _fd_table_size + FD_TABLE_INC;
|
||||
|
||||
new_table = realloc(_fd_table, sizeof(int) * new_size);
|
||||
if (!new_table) {
|
||||
log_error("Cannot extend bcache fd table");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = _fd_table_size; i < new_size; i++)
|
||||
new_table[i] = -1;
|
||||
|
||||
_fd_table = new_table;
|
||||
_fd_table_size = new_size;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should we check for unflushed or inprogress io on an fd
|
||||
* prior to doing clear_fd or change_fd? (To catch mistakes;
|
||||
* the caller should be smart enough to not do that.)
|
||||
*/
|
||||
|
||||
void bcache_clear_fd(int di)
|
||||
{
|
||||
if (di >= _fd_table_size)
|
||||
return;
|
||||
_fd_table[di] = -1;
|
||||
}
|
||||
|
||||
int bcache_change_fd(int di, int fd)
|
||||
{
|
||||
if (di >= _fd_table_size)
|
||||
return 0;
|
||||
if (di < 0) {
|
||||
log_error(INTERNAL_ERROR "Cannot change not openned DI with FD:%d", fd);
|
||||
return 0;
|
||||
}
|
||||
_fd_table[di] = fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,19 +16,12 @@
|
||||
#define BCACHE_H
|
||||
|
||||
#include "device_mapper/all.h"
|
||||
#include "base/memory/container_of.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
// FIXME: move somewhere more sensible
|
||||
#define container_of(v, t, head) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
enum dir {
|
||||
DIR_READ,
|
||||
DIR_WRITE
|
||||
@@ -41,7 +34,7 @@ typedef void io_complete_fn(void *context, int io_error);
|
||||
|
||||
struct io_engine {
|
||||
void (*destroy)(struct io_engine *e);
|
||||
bool (*issue)(struct io_engine *e, enum dir d, int fd,
|
||||
bool (*issue)(struct io_engine *e, enum dir d, int di,
|
||||
sector_t sb, sector_t se, void *data, void *context);
|
||||
bool (*wait)(struct io_engine *e, io_complete_fn fn);
|
||||
unsigned (*max_io)(struct io_engine *e);
|
||||
@@ -55,7 +48,7 @@ struct io_engine *create_sync_io_engine(void);
|
||||
struct bcache;
|
||||
struct block {
|
||||
/* clients may only access these three fields */
|
||||
int fd;
|
||||
int di;
|
||||
uint64_t index;
|
||||
void *data;
|
||||
|
||||
@@ -113,12 +106,12 @@ unsigned bcache_max_prefetches(struct bcache *cache);
|
||||
* they complete. But we're talking a very small difference, and it's worth it
|
||||
* to keep callbacks out of this interface.
|
||||
*/
|
||||
void bcache_prefetch(struct bcache *cache, int fd, block_address index);
|
||||
void bcache_prefetch(struct bcache *cache, int di, block_address index);
|
||||
|
||||
/*
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool bcache_get(struct bcache *cache, int fd, block_address index,
|
||||
bool bcache_get(struct bcache *cache, int di, block_address index,
|
||||
unsigned flags, struct block **result);
|
||||
void bcache_put(struct block *b);
|
||||
|
||||
@@ -136,30 +129,42 @@ bool bcache_flush(struct bcache *cache);
|
||||
*
|
||||
* If the block is currently held false will be returned.
|
||||
*/
|
||||
bool bcache_invalidate(struct bcache *cache, int fd, block_address index);
|
||||
bool bcache_invalidate(struct bcache *cache, int di, block_address index);
|
||||
|
||||
/*
|
||||
* Invalidates all blocks on the given descriptor. Call this before closing
|
||||
* the descriptor to make sure everything is written back.
|
||||
*/
|
||||
bool bcache_invalidate_fd(struct bcache *cache, int fd);
|
||||
bool bcache_invalidate_di(struct bcache *cache, int di);
|
||||
|
||||
/*
|
||||
* Call this function if flush, or invalidate fail and you do not
|
||||
* wish to retry the writes. This will throw away any dirty data
|
||||
* not written. If any blocks for di are held, then it will call
|
||||
* abort().
|
||||
*/
|
||||
void bcache_abort_di(struct bcache *cache, int di);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// The next four functions are utilities written in terms of the above api.
|
||||
|
||||
// Prefetches the blocks neccessary to satisfy a byte range.
|
||||
void bcache_prefetch_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
|
||||
void bcache_prefetch_bytes(struct bcache *cache, int di, uint64_t start, size_t len);
|
||||
|
||||
// Reads, writes and zeroes bytes. Returns false if errors occur.
|
||||
bool bcache_read_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data);
|
||||
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data);
|
||||
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
|
||||
bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, uint8_t val);
|
||||
bool bcache_read_bytes(struct bcache *cache, int di, uint64_t start, size_t len, void *data);
|
||||
bool bcache_write_bytes(struct bcache *cache, int di, uint64_t start, size_t len, void *data);
|
||||
bool bcache_zero_bytes(struct bcache *cache, int di, uint64_t start, size_t len);
|
||||
bool bcache_set_bytes(struct bcache *cache, int di, uint64_t start, size_t len, uint8_t val);
|
||||
bool bcache_invalidate_bytes(struct bcache *cache, int di, uint64_t start, size_t len);
|
||||
|
||||
void bcache_set_last_byte(struct bcache *cache, int fd, uint64_t offset, int sector_size);
|
||||
void bcache_unset_last_byte(struct bcache *cache, int fd);
|
||||
void bcache_set_last_byte(struct bcache *cache, int di, uint64_t offset, int sector_size);
|
||||
void bcache_unset_last_byte(struct bcache *cache, int di);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
int bcache_set_fd(int fd); /* returns di */
|
||||
void bcache_clear_fd(int di);
|
||||
int bcache_change_fd(int di, int fd);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,7 @@ struct dev_iter {
|
||||
|
||||
struct dir_list {
|
||||
struct dm_list list;
|
||||
char dir[0];
|
||||
char dir[];
|
||||
};
|
||||
|
||||
static struct {
|
||||
@@ -65,6 +65,8 @@ static int _insert(const char *path, const struct stat *info,
|
||||
static void _dev_init(struct device *dev)
|
||||
{
|
||||
dev->fd = -1;
|
||||
dev->bcache_fd = -1;
|
||||
dev->bcache_di = -1;
|
||||
dev->read_ahead = -1;
|
||||
|
||||
dev->ext.enabled = 0;
|
||||
@@ -357,12 +359,14 @@ static int _get_sysfs_value(const char *path, char *buf, size_t buf_size, int er
|
||||
int r = 0;
|
||||
|
||||
if (!(fp = fopen(path, "r"))) {
|
||||
log_sys_error("fopen", path);
|
||||
if (error_if_no_value)
|
||||
log_sys_error("fopen", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fgets(buf, buf_size, fp)) {
|
||||
log_sys_error("fgets", path);
|
||||
if (error_if_no_value)
|
||||
log_sys_error("fgets", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1154,13 +1158,13 @@ static int _insert(const char *path, const struct stat *info,
|
||||
}
|
||||
|
||||
if (rec && !_insert_dir(path))
|
||||
return_0;
|
||||
return 0;
|
||||
} else { /* add a device */
|
||||
if (!S_ISBLK(info->st_mode))
|
||||
return 1;
|
||||
|
||||
if (!_insert_dev(path, info->st_rdev))
|
||||
return_0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1419,17 +1423,9 @@ const char *dev_name_confirmed(struct device *dev, int quiet)
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
/* Provide a custom reason when a device is ignored */
|
||||
const char *dev_cache_filtered_reason(const char *name)
|
||||
struct device *dev_hash_get(const char *name)
|
||||
{
|
||||
const char *reason = "not found";
|
||||
struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
|
||||
if (d)
|
||||
/* FIXME Record which filter caused the exclusion */
|
||||
reason = "excluded by a filter";
|
||||
|
||||
return reason;
|
||||
return (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
}
|
||||
|
||||
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f)
|
||||
@@ -1460,6 +1456,7 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
|
||||
_insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev());
|
||||
d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
if (!d) {
|
||||
log_debug_devs("Device name not found in dev_cache repeat dev_cache_scan for %s", name);
|
||||
dev_cache_scan();
|
||||
d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
}
|
||||
@@ -1522,7 +1519,7 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
|
||||
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",
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
|
||||
sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) {
|
||||
log_error("dm_snprintf partition failed.");
|
||||
return NULL;
|
||||
@@ -1535,6 +1532,8 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
|
||||
}
|
||||
}
|
||||
|
||||
log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d",
|
||||
(int)MAJOR(dev), (int)MINOR(dev));
|
||||
dev_cache_scan();
|
||||
d = _dev_cache_seek_devt(dev);
|
||||
}
|
||||
@@ -1650,4 +1649,3 @@ bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ struct cmd_context;
|
||||
struct dev_filter {
|
||||
int (*passes_filter) (struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name);
|
||||
void (*destroy) (struct dev_filter *f);
|
||||
void (*wipe) (struct dev_filter *f);
|
||||
void (*wipe) (struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name);
|
||||
void *private;
|
||||
unsigned use_count;
|
||||
const char *name;
|
||||
@@ -54,10 +54,11 @@ int dev_cache_has_scanned(void);
|
||||
|
||||
int dev_cache_add_dir(const char *path);
|
||||
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f);
|
||||
const char *dev_cache_filtered_reason(const char *name);
|
||||
|
||||
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t device, struct dev_filter *f, int *filtered);
|
||||
|
||||
struct device *dev_hash_get(const char *name);
|
||||
|
||||
void dev_set_preferred_name(struct dm_str_list *sl, struct device *dev);
|
||||
|
||||
/*
|
||||
|
||||
@@ -86,6 +86,9 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
int fd = dev->bcache_fd;
|
||||
int do_close = 0;
|
||||
|
||||
if (dm_list_empty(&dev->aliases))
|
||||
return 0;
|
||||
|
||||
if (dev->size_seqno == _dev_size_seqno) {
|
||||
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
|
||||
name, dev->size);
|
||||
@@ -94,7 +97,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
}
|
||||
|
||||
if (fd <= 0) {
|
||||
if (!dev_open_readonly(dev))
|
||||
if (!dev_open_readonly_quiet(dev))
|
||||
return_0;
|
||||
fd = dev_fd(dev);
|
||||
do_close = 1;
|
||||
@@ -103,7 +106,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||
if (do_close && !dev_close_immediate(dev))
|
||||
log_sys_error("close", name);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,7 +117,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
|
||||
|
||||
if (do_close && !dev_close_immediate(dev))
|
||||
log_sys_error("close", name);
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -128,8 +131,10 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_error("Failed to open to get readahead %s", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl(dev->fd, BLKRAGET, &read_ahead_long) < 0) {
|
||||
log_sys_error("ioctl BLKRAGET", dev_name(dev));
|
||||
@@ -194,7 +199,7 @@ int dev_get_direct_block_sizes(struct device *dev, unsigned int *physical_block_
|
||||
}
|
||||
|
||||
if (fd <= 0) {
|
||||
if (!dev_open_readonly(dev))
|
||||
if (!dev_open_readonly_quiet(dev))
|
||||
return 0;
|
||||
fd = dev_fd(dev);
|
||||
do_close = 1;
|
||||
@@ -444,7 +449,7 @@ int dev_open_readonly_quiet(struct device *dev)
|
||||
static void _close(struct device *dev)
|
||||
{
|
||||
if (close(dev->fd))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
log_sys_debug("close", dev_name(dev));
|
||||
dev->fd = -1;
|
||||
|
||||
log_debug_devs("Closed %s", dev_name(dev));
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/device/dev-type.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
#include "lib/misc/crc.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h> /* for MD detection using udev db records */
|
||||
#include "lib/device/dev-ext-udev-constants.h"
|
||||
@@ -48,44 +49,89 @@ static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the position of the superblock.
|
||||
* It is always aligned to a 4K boundary and
|
||||
* depending on minor_version, it can be:
|
||||
* 0: At least 8K, but less than 12K, from end of device
|
||||
* 1: At start of device
|
||||
* 2: 4K from start of device.
|
||||
*/
|
||||
typedef enum {
|
||||
MD_MINOR_VERSION_MIN,
|
||||
MD_MINOR_V0 = MD_MINOR_VERSION_MIN,
|
||||
MD_MINOR_V1,
|
||||
MD_MINOR_V2,
|
||||
MD_MINOR_VERSION_MAX = MD_MINOR_V2
|
||||
} md_minor_version_t;
|
||||
#define IMSM_SIGNATURE "Intel Raid ISM Cfg Sig. "
|
||||
#define IMSM_SIG_LEN (sizeof(IMSM_SIGNATURE) - 1)
|
||||
|
||||
static uint64_t _v1_sb_offset(uint64_t size, md_minor_version_t minor_version)
|
||||
static int _dev_has_imsm_magic(struct device *dev, uint64_t devsize_sectors)
|
||||
{
|
||||
uint64_t sb_offset;
|
||||
char imsm_signature[IMSM_SIG_LEN];
|
||||
uint64_t off = (devsize_sectors * 512) - 1024;
|
||||
|
||||
switch(minor_version) {
|
||||
case MD_MINOR_V0:
|
||||
sb_offset = (size - 8 * 2) & ~(4 * 2 - 1ULL);
|
||||
break;
|
||||
case MD_MINOR_V1:
|
||||
sb_offset = 0;
|
||||
break;
|
||||
case MD_MINOR_V2:
|
||||
sb_offset = 4 * 2;
|
||||
break;
|
||||
default:
|
||||
log_warn(INTERNAL_ERROR "WARNING: Unknown minor version %d.",
|
||||
minor_version);
|
||||
if (!dev_read_bytes(dev, off, IMSM_SIG_LEN, imsm_signature))
|
||||
return_0;
|
||||
|
||||
if (!memcmp(imsm_signature, IMSM_SIGNATURE, IMSM_SIG_LEN))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DDF_MAGIC 0xDE11DE11
|
||||
struct ddf_header {
|
||||
uint32_t magic;
|
||||
uint32_t crc;
|
||||
char guid[24];
|
||||
char revision[8];
|
||||
char padding[472];
|
||||
};
|
||||
|
||||
static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint64_t *sb_offset)
|
||||
{
|
||||
struct ddf_header hdr;
|
||||
uint32_t crc, our_crc;
|
||||
uint64_t off;
|
||||
uint64_t devsize_bytes = devsize_sectors * 512;
|
||||
|
||||
if (devsize_bytes < 0x30000)
|
||||
return 0;
|
||||
}
|
||||
sb_offset <<= SECTOR_SHIFT;
|
||||
|
||||
return sb_offset;
|
||||
/* 512 bytes before the end of device (from libblkid) */
|
||||
off = ((devsize_bytes / 0x200) - 1) * 0x200;
|
||||
|
||||
if (!dev_read_bytes(dev, off, 512, &hdr))
|
||||
return_0;
|
||||
|
||||
if ((hdr.magic == cpu_to_be32(DDF_MAGIC)) ||
|
||||
(hdr.magic == cpu_to_le32(DDF_MAGIC))) {
|
||||
crc = hdr.crc;
|
||||
hdr.crc = 0xffffffff;
|
||||
our_crc = calc_crc(0, (const uint8_t *)&hdr, 512);
|
||||
|
||||
if ((cpu_to_be32(our_crc) == crc) ||
|
||||
(cpu_to_le32(our_crc) == crc)) {
|
||||
*sb_offset = off;
|
||||
return 1;
|
||||
} else {
|
||||
log_debug_devs("Found md ddf magic at %llu wrong crc %x disk %x %s",
|
||||
(unsigned long long)off, our_crc, crc, dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 128KB before the end of device (from libblkid) */
|
||||
off = ((devsize_bytes / 0x200) - 257) * 0x200;
|
||||
|
||||
if (!dev_read_bytes(dev, off, 512, &hdr))
|
||||
return_0;
|
||||
|
||||
if ((hdr.magic == cpu_to_be32(DDF_MAGIC)) ||
|
||||
(hdr.magic == cpu_to_le32(DDF_MAGIC))) {
|
||||
crc = hdr.crc;
|
||||
hdr.crc = 0xffffffff;
|
||||
our_crc = calc_crc(0, (const uint8_t *)&hdr, 512);
|
||||
|
||||
if ((cpu_to_be32(our_crc) == crc) ||
|
||||
(cpu_to_le32(our_crc) == crc)) {
|
||||
*sb_offset = off;
|
||||
return 1;
|
||||
} else {
|
||||
log_debug_devs("Found md ddf magic at %llu wrong crc %x disk %x %s",
|
||||
(unsigned long long)off, our_crc, crc, dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -130,8 +176,7 @@ static int _udev_dev_is_md_component(struct device *dev)
|
||||
*/
|
||||
static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
md_minor_version_t minor;
|
||||
uint64_t size, sb_offset;
|
||||
uint64_t size, sb_offset = 0;
|
||||
int ret;
|
||||
|
||||
if (!scan_bcache)
|
||||
@@ -146,9 +191,9 @@ static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_foun
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Old md versions locate the magic number at the end of the device.
|
||||
* Those checks can't be satisfied with the initial bcache data, and
|
||||
* would require an extra read i/o at the end of every device. Issuing
|
||||
* Some md versions locate the magic number at the end of the device.
|
||||
* Those checks can't be satisfied with the initial scan data, and
|
||||
* require an extra read i/o at the end of every device. Issuing
|
||||
* an extra read to every device in every command, just to check for
|
||||
* the old md format is a bad tradeoff.
|
||||
*
|
||||
@@ -159,42 +204,81 @@ static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_foun
|
||||
* and set it for commands that could possibly write to an md dev
|
||||
* (pvcreate/vgcreate/vgextend).
|
||||
*/
|
||||
if (!full) {
|
||||
sb_offset = 0;
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
log_debug_devs("Found md magic number at offset 0 of %s.", dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sb_offset = 8 << SECTOR_SHIFT;
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
log_debug_devs("Found md magic number at offset %d of %s.", (int)sb_offset, dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* md superblock version 1.1 at offset 0 from start
|
||||
*/
|
||||
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check if it is an md component device. */
|
||||
/* Version 0.90.0 */
|
||||
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
if (_dev_has_md_magic(dev, 0)) {
|
||||
log_debug_devs("Found md magic number at offset 0 of %s.", dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
minor = MD_MINOR_VERSION_MIN;
|
||||
/* Version 1, try v1.0 -> v1.2 */
|
||||
do {
|
||||
sb_offset = _v1_sb_offset(size, minor);
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
} while (++minor <= MD_MINOR_VERSION_MAX);
|
||||
/*
|
||||
* md superblock version 1.2 at offset 4KB from start
|
||||
*/
|
||||
|
||||
if (_dev_has_md_magic(dev, 4096)) {
|
||||
log_debug_devs("Found md magic number at offset 4096 of %s.", dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!full) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle superblocks at the end of the device.
|
||||
*/
|
||||
|
||||
/*
|
||||
* md superblock version 0 at 64KB from end of device
|
||||
* (after end is aligned to 64KB)
|
||||
*/
|
||||
|
||||
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
|
||||
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
log_debug_devs("Found md magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* md superblock version 1.0 at 8KB from end of device
|
||||
*/
|
||||
|
||||
sb_offset = ((size - 8 * 2) & ~(4 * 2 - 1ULL)) << SECTOR_SHIFT;
|
||||
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
log_debug_devs("Found md magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* md imsm superblock 1K from end of device
|
||||
*/
|
||||
|
||||
if (_dev_has_imsm_magic(dev, size)) {
|
||||
log_debug_devs("Found md imsm magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
|
||||
sb_offset = 1024;
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* md ddf superblock 512 bytes from end, or 128KB from end
|
||||
*/
|
||||
|
||||
if (_dev_has_ddf_magic(dev, size, &sb_offset)) {
|
||||
log_debug_devs("Found md ddf magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
|
||||
@@ -42,7 +42,6 @@ int dev_is_pmem(struct device *dev)
|
||||
{
|
||||
FILE *fp;
|
||||
char path[PATH_MAX];
|
||||
char buffer[64];
|
||||
int is_pmem = 0;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/queue/dax",
|
||||
@@ -56,27 +55,16 @@ int dev_is_pmem(struct device *dev)
|
||||
if (!(fp = fopen(path, "r")))
|
||||
return 0;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
log_warn("Failed to read %s.", path);
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
return 0;
|
||||
} else if (sscanf(buffer, "%d", &is_pmem) != 1) {
|
||||
log_warn("Failed to parse %s '%s'.", path, buffer);
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
return 0;
|
||||
}
|
||||
if (fscanf(fp, "%d", &is_pmem) != 1)
|
||||
log_warn("Failed to parse DAX %s.", path);
|
||||
|
||||
if (is_pmem)
|
||||
log_debug("%s is pmem", dev_name(dev));
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
|
||||
if (is_pmem) {
|
||||
log_debug("%s is pmem", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return is_pmem ? 1 : 0;
|
||||
}
|
||||
|
||||
int dev_is_lv(struct device *dev)
|
||||
@@ -84,6 +72,7 @@ int dev_is_lv(struct device *dev)
|
||||
FILE *fp;
|
||||
char path[PATH_MAX];
|
||||
char buffer[64];
|
||||
int ret = 0;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/uuid",
|
||||
dm_sysfs_dir(),
|
||||
@@ -96,17 +85,15 @@ int dev_is_lv(struct device *dev)
|
||||
if (!(fp = fopen(path, "r")))
|
||||
return 0;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
log_warn("Failed to read %s.", path);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
if (!fgets(buffer, sizeof(buffer), fp))
|
||||
log_debug("Failed to read %s.", path);
|
||||
else if (!strncmp(buffer, "LVM-", 4))
|
||||
ret = 1;
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_debug("fclose", path);
|
||||
|
||||
if (!strncmp(buffer, "LVM-", 4))
|
||||
return 1;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dev_types *create_dev_types(const char *proc_dir,
|
||||
@@ -659,6 +646,31 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
int get_fs_block_size(struct device *dev, uint32_t *fs_block_size)
|
||||
{
|
||||
char *block_size_str = NULL;
|
||||
|
||||
if ((block_size_str = blkid_get_tag_value(NULL, "BLOCK_SIZE", dev_name(dev)))) {
|
||||
*fs_block_size = (uint32_t)atoi(block_size_str);
|
||||
free(block_size_str);
|
||||
log_debug("Found blkid BLOCK_SIZE %u for fs on %s", *fs_block_size, dev_name(dev));
|
||||
return 1;
|
||||
} else {
|
||||
log_debug("No blkid BLOCK_SIZE for fs on %s", dev_name(dev));
|
||||
*fs_block_size = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int get_fs_block_size(struct device *dev, uint32_t *fs_block_size)
|
||||
{
|
||||
log_debug("Disabled blkid BLOCK_SIZE for fs.");
|
||||
*fs_block_size = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
|
||||
static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
|
||||
|
||||
@@ -97,4 +97,6 @@ int dev_is_pmem(struct device *dev);
|
||||
|
||||
int dev_is_lv(struct device *dev);
|
||||
|
||||
int get_fs_block_size(struct device *dev, uint32_t *fs_block_size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -71,7 +71,9 @@ struct device {
|
||||
int logical_block_size; /* From BLKSSZGET: lowest possible block size that the storage device can address */
|
||||
int read_ahead;
|
||||
int bcache_fd;
|
||||
int bcache_di;
|
||||
uint32_t flags;
|
||||
uint32_t filtered_flags;
|
||||
unsigned size_seqno;
|
||||
uint64_t size;
|
||||
uint64_t end;
|
||||
|
||||
@@ -406,10 +406,12 @@ int lvdisplay_full(struct cmd_context *cmd,
|
||||
struct lv_segment *seg = NULL;
|
||||
int lvm1compat;
|
||||
dm_percent_t snap_percent;
|
||||
int thin_data_active = 0, thin_metadata_active = 0;
|
||||
dm_percent_t thin_data_percent, thin_metadata_percent;
|
||||
int thin_pool_active = 0;
|
||||
dm_percent_t thin_data_percent = 0, thin_metadata_percent = 0;
|
||||
int thin_active = 0;
|
||||
dm_percent_t thin_percent;
|
||||
dm_percent_t thin_percent = 0;
|
||||
struct lv_status_thin *thin_status = NULL;
|
||||
struct lv_status_thin_pool *thin_pool_status = NULL;
|
||||
struct lv_status_cache *cache_status = NULL;
|
||||
struct lv_status_vdo *vdo_status = NULL;
|
||||
|
||||
@@ -503,15 +505,18 @@ int lvdisplay_full(struct cmd_context *cmd,
|
||||
if (seg->merge_lv)
|
||||
log_print("LV merging to %s",
|
||||
seg->merge_lv->name);
|
||||
if (inkernel)
|
||||
thin_active = lv_thin_percent(lv, 0, &thin_percent);
|
||||
if (inkernel && (thin_active = lv_thin_status(lv, 0, &thin_status))) {
|
||||
thin_percent = thin_status->usage;
|
||||
dm_pool_destroy(thin_status->mem);
|
||||
}
|
||||
if (lv_is_merging_origin(lv))
|
||||
log_print("LV merged with %s",
|
||||
find_snapshot(lv)->lv->name);
|
||||
} else if (lv_is_thin_pool(lv)) {
|
||||
if (lv_info(cmd, lv, 1, &info, 1, 1) && info.exists) {
|
||||
thin_data_active = lv_thin_pool_percent(lv, 0, &thin_data_percent);
|
||||
thin_metadata_active = lv_thin_pool_percent(lv, 1, &thin_metadata_percent);
|
||||
if ((thin_pool_active = lv_thin_pool_status(lv, 0, &thin_pool_status))) {
|
||||
thin_data_percent = thin_pool_status->data_usage;
|
||||
thin_metadata_percent = thin_pool_status->metadata_usage;
|
||||
dm_pool_destroy(thin_pool_status->mem);
|
||||
}
|
||||
/* FIXME: display thin_pool targets transid for activated LV as well */
|
||||
seg = first_seg(lv);
|
||||
@@ -591,13 +596,12 @@ int lvdisplay_full(struct cmd_context *cmd,
|
||||
dm_pool_destroy(cache_status->mem);
|
||||
}
|
||||
|
||||
if (thin_data_active)
|
||||
if (thin_pool_active) {
|
||||
log_print("Allocated pool data %s%%",
|
||||
display_percent(cmd, thin_data_percent));
|
||||
|
||||
if (thin_metadata_active)
|
||||
log_print("Allocated metadata %s%%",
|
||||
display_percent(cmd, thin_metadata_percent));
|
||||
}
|
||||
|
||||
if (thin_active)
|
||||
log_print("Mapped size %s%%",
|
||||
|
||||
@@ -60,13 +60,16 @@ static void _composite_destroy(struct dev_filter *f)
|
||||
free(f);
|
||||
}
|
||||
|
||||
static void _wipe(struct dev_filter *f)
|
||||
static void _wipe(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_filter **filters;
|
||||
|
||||
for (filters = (struct dev_filter **) f->private; *filters; ++filters)
|
||||
for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
|
||||
if (use_filter_name && strcmp((*filters)->name, use_filter_name))
|
||||
continue;
|
||||
if ((*filters)->wipe)
|
||||
(*filters)->wipe(*filters);
|
||||
(*filters)->wipe(cmd, *filters, dev, use_filter_name);
|
||||
}
|
||||
}
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/filters/filter.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
@@ -69,6 +70,11 @@ static int _ignore_fwraid(struct cmd_context *cmd, struct dev_filter *f __attrib
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cmd->filter_nodata_only)
|
||||
return 1;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_FWRAID;
|
||||
|
||||
if (!fwraid_filtering())
|
||||
return 1;
|
||||
|
||||
@@ -80,12 +86,14 @@ static int _ignore_fwraid(struct cmd_context *cmd, struct dev_filter *f __attrib
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
dev->filtered_flags |= DEV_FILTERED_FWRAID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
log_debug_devs("%s: Skipping: error in firmware RAID component detection",
|
||||
dev_name(dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_FWRAID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ static int _passes_internal(struct cmd_context *cmd, struct dev_filter *f __attr
|
||||
{
|
||||
struct device_list *devl;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_INTERNAL;
|
||||
|
||||
if (!internal_filtering())
|
||||
return 1;
|
||||
|
||||
@@ -50,6 +52,7 @@ static int _passes_internal(struct cmd_context *cmd, struct dev_filter *f __attr
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev->filtered_flags |= DEV_FILTERED_INTERNAL;
|
||||
log_debug_devs("%s: Skipping for internal filtering.", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,11 @@ static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __att
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cmd->filter_nodata_only)
|
||||
return 1;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_MD_COMPONENT;
|
||||
|
||||
/*
|
||||
* When md_component_dectection=0, don't even try to skip md
|
||||
* components.
|
||||
@@ -112,12 +117,14 @@ static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __att
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
dev->filtered_flags |= DEV_FILTERED_MD_COMPONENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
log_debug_devs("%s: Skipping: error in md component detection",
|
||||
dev_name(dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_MD_COMPONENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,12 +274,15 @@ static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
|
||||
static int _ignore_mpath(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT;
|
||||
|
||||
if (_dev_is_mpath(f, dev) == 1) {
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
dev->filtered_flags |= DEV_FILTERED_MPATH_COMPONENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/filters/filter.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping: Partition table signature found"
|
||||
|
||||
@@ -24,6 +25,11 @@ static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
int ret;
|
||||
|
||||
if (cmd->filter_nodata_only)
|
||||
return 1;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_PARTITIONED;
|
||||
|
||||
ret = dev_is_partitioned(dt, dev);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
@@ -39,6 +45,7 @@ static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
dev->filtered_flags |= DEV_FILTERED_PARTITIONED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,11 +64,17 @@ static int _init_hash(struct pfilter *pf)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _persistent_filter_wipe(struct dev_filter *f)
|
||||
static void _persistent_filter_wipe(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
struct dm_str_list *sl;
|
||||
|
||||
dm_hash_wipe(pf->devices);
|
||||
if (!dev) {
|
||||
dm_hash_wipe(pf->devices);
|
||||
} else {
|
||||
dm_list_iterate_items(sl, &dev->aliases)
|
||||
dm_hash_remove(pf->devices, sl->str);
|
||||
}
|
||||
}
|
||||
|
||||
static int _lookup_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
|
||||
@@ -151,6 +151,8 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
struct dm_str_list *sl;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_REGEX;
|
||||
|
||||
dm_list_iterate_items(sl, &dev->aliases) {
|
||||
m = dm_regex_match(rf->engine, sl->str);
|
||||
|
||||
@@ -168,8 +170,10 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (rejected)
|
||||
if (rejected) {
|
||||
dev->filtered_flags |= DEV_FILTERED_REGEX;
|
||||
log_debug_devs("%s: Skipping (regex)", dev_name(dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* pass everything that doesn't match
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/filters/filter.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -27,6 +28,11 @@ static int _ignore_signature(struct cmd_context *cmd, struct dev_filter *f __att
|
||||
char buf[BUFSIZE];
|
||||
int ret = 0;
|
||||
|
||||
if (cmd->filter_nodata_only)
|
||||
return 1;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_SIGNATURE;
|
||||
|
||||
if (!scan_bcache) {
|
||||
/* let pass, call again after scan */
|
||||
log_debug_devs("filter signature deferred %s", dev_name(dev));
|
||||
@@ -40,18 +46,21 @@ static int _ignore_signature(struct cmd_context *cmd, struct dev_filter *f __att
|
||||
log_debug_devs("%s: Skipping: error in signature detection",
|
||||
dev_name(dev));
|
||||
ret = 0;
|
||||
dev->filtered_flags |= DEV_FILTERED_SIGNATURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_is_lvm1(dev, buf, BUFSIZE)) {
|
||||
log_debug_devs("%s: Skipping lvm1 device", dev_name(dev));
|
||||
ret = 0;
|
||||
dev->filtered_flags |= DEV_FILTERED_SIGNATURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_is_pool(dev, buf, BUFSIZE)) {
|
||||
log_debug_devs("%s: Skipping gfs-pool device", dev_name(dev));
|
||||
ret = 0;
|
||||
dev->filtered_flags |= DEV_FILTERED_SIGNATURE;
|
||||
goto out;
|
||||
}
|
||||
ret = 1;
|
||||
|
||||
@@ -264,6 +264,8 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
|
||||
{
|
||||
struct dev_set *ds = (struct dev_set *) f->private;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
|
||||
|
||||
if (!ds->initialised)
|
||||
_init_devs(ds);
|
||||
|
||||
@@ -273,6 +275,7 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
|
||||
|
||||
if (!_set_lookup(ds, dev->dev)) {
|
||||
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_SYSFS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,13 @@ static int _passes_lvm_type_device_filter(struct cmd_context *cmd, struct dev_fi
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_DEVTYPE;
|
||||
|
||||
/* Is this a recognised device type? */
|
||||
if (!dt->dev_type_array[MAJOR(dev->dev)].max_partitions) {
|
||||
log_debug_devs("%s: Skipping: Unrecognised LVM device type %"
|
||||
PRIu64, name, (uint64_t) MAJOR(dev->dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_DEVTYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,9 @@ static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f,
|
||||
struct dev_usable_check_params ucp = {0};
|
||||
int r = 1;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_MINSIZE;
|
||||
dev->filtered_flags &= ~DEV_FILTERED_UNUSABLE;
|
||||
|
||||
/* further checks are done on dm devices only */
|
||||
if (dm_is_dm_major(MAJOR(dev->dev))) {
|
||||
switch (mode) {
|
||||
@@ -142,8 +145,10 @@ static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(r = device_is_usable(dev, ucp)))
|
||||
if (!(r = device_is_usable(dev, ucp))) {
|
||||
dev->filtered_flags |= DEV_FILTERED_UNUSABLE;
|
||||
log_debug_devs("%s: Skipping unusable device.", dev_name(dev));
|
||||
}
|
||||
}
|
||||
|
||||
if (r) {
|
||||
@@ -153,6 +158,8 @@ static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f,
|
||||
/* fall through */
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
r = _check_pv_min_size(dev);
|
||||
if (!r)
|
||||
dev->filtered_flags |= DEV_FILTERED_MINSIZE;
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
/* nothing to do here */
|
||||
|
||||
@@ -52,4 +52,16 @@ typedef enum {
|
||||
} filter_mode_t;
|
||||
struct dev_filter *usable_filter_create(struct cmd_context *cmd, struct dev_types *dt, filter_mode_t mode);
|
||||
|
||||
#define DEV_FILTERED_FWRAID 0x00000001
|
||||
#define DEV_FILTERED_INTERNAL 0x00000002
|
||||
#define DEV_FILTERED_MD_COMPONENT 0x00000004
|
||||
#define DEV_FILTERED_MPATH_COMPONENT 0x00000008
|
||||
#define DEV_FILTERED_PARTITIONED 0x00000010
|
||||
#define DEV_FILTERED_REGEX 0x00000020
|
||||
#define DEV_FILTERED_SIGNATURE 0x00000040
|
||||
#define DEV_FILTERED_SYSFS 0x00000080
|
||||
#define DEV_FILTERED_DEVTYPE 0x00000100
|
||||
#define DEV_FILTERED_MINSIZE 0x00000200
|
||||
#define DEV_FILTERED_UNUSABLE 0x00000400
|
||||
|
||||
#endif /* _LVM_FILTER_H */
|
||||
|
||||
@@ -315,7 +315,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, NULL, NULL)))
|
||||
if (!(vg = mda->ops->vg_read(cmd, tf, vg_name, mda, NULL, NULL)))
|
||||
stack;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ static const struct flag _lv_flags[] = {
|
||||
{LV_VDO_POOL, NULL, 0},
|
||||
{LV_VDO_POOL_DATA, NULL, 0},
|
||||
{WRITECACHE, NULL, 0},
|
||||
{INTEGRITY, NULL, 0},
|
||||
{INTEGRITY_METADATA, NULL, 0},
|
||||
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
|
||||
{LV_REMOVED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
|
||||
@@ -277,8 +277,7 @@ static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
dev_set_last_byte(dev, start_byte + MDA_HEADER_SIZE);
|
||||
|
||||
if (!dev_write_bytes(dev, start_byte, MDA_HEADER_SIZE, mdah)) {
|
||||
dev_unset_last_byte(dev);
|
||||
log_error("Failed to write mda header to %s fd %d", dev_name(dev), dev->bcache_fd);
|
||||
log_error("Failed to write mda header to %s.", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
dev_unset_last_byte(dev);
|
||||
@@ -291,7 +290,8 @@ static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
* in the label scanning path.
|
||||
*/
|
||||
|
||||
static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
|
||||
static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
|
||||
struct device_area *dev_area,
|
||||
struct mda_header *mdah, int primary_mda,
|
||||
const char *vgname,
|
||||
int *precommitted)
|
||||
@@ -342,7 +342,7 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
|
||||
* Don't try to check existing metadata
|
||||
* if given vgname is an empty string.
|
||||
*/
|
||||
if (!*vgname)
|
||||
if (!vgname || !*vgname)
|
||||
return rlocn;
|
||||
|
||||
/*
|
||||
@@ -370,7 +370,7 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
|
||||
vgnamebuf, vgname);
|
||||
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
|
||||
!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
|
||||
!lvmcache_update_vgname_and_id(cmd, info, &vgsummary_orphan))
|
||||
stack;
|
||||
|
||||
return NULL;
|
||||
@@ -448,7 +448,8 @@ static uint64_t _next_rlocn_offset(struct volume_group *vg, struct raw_locn *rlo
|
||||
return new_start;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct device_area *area,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
@@ -469,7 +470,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _read_metadata_location_vg(area, mdah, primary_mda, vgname, &precommitted))) {
|
||||
if (!(rlocn = _read_metadata_location_vg(cmd, area, mdah, primary_mda, vgname, &precommitted))) {
|
||||
log_debug_metadata("VG %s not found on %s", vgname, dev_name(area->dev));
|
||||
goto out;
|
||||
}
|
||||
@@ -504,7 +505,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
return vg;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_raw(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
@@ -513,12 +515,13 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct volume_group *vg;
|
||||
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
|
||||
vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
|
||||
|
||||
return vg;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_precommit_raw(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
@@ -527,34 +530,11 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct volume_group *vg;
|
||||
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
|
||||
vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
|
||||
|
||||
return vg;
|
||||
}
|
||||
|
||||
#define MAX_DESC_LEN 2048
|
||||
|
||||
static char *_build_desc_write(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
size_t len = strlen(cmd->cmd_line) + 32;
|
||||
char *desc;
|
||||
|
||||
if (len > MAX_DESC_LEN)
|
||||
len = MAX_DESC_LEN;
|
||||
|
||||
if (!(desc = zalloc(len)))
|
||||
return_NULL;
|
||||
|
||||
vg->write_count++;
|
||||
|
||||
if (vg->write_count == 1)
|
||||
dm_snprintf(desc, len, "Write from %s.", cmd->cmd_line);
|
||||
else
|
||||
dm_snprintf(desc, len, "Write[%u] from %s.", vg->write_count, cmd->cmd_line);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/*
|
||||
* VG metadata updates:
|
||||
*
|
||||
@@ -599,6 +579,7 @@ static char *_build_desc_write(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
char desc[2048];
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
|
||||
struct raw_locn *rlocn_old;
|
||||
@@ -673,12 +654,15 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
write_buf_size = fidtc->write_buf_size;
|
||||
new_size = fidtc->new_metadata_size;
|
||||
} else {
|
||||
char *desc = _build_desc_write(fid->fmt->cmd, vg);
|
||||
if (!vg->write_count++)
|
||||
(void) dm_snprintf(desc, sizeof(desc), "Write from %s.", vg->cmd->cmd_line);
|
||||
else
|
||||
(void) dm_snprintf(desc, sizeof(desc), "Write[%u] from %s.", vg->write_count, vg->cmd->cmd_line);
|
||||
|
||||
new_size = text_vg_export_raw(vg, desc, &write_buf, &write_buf_size);
|
||||
fidtc->write_buf = write_buf;
|
||||
fidtc->write_buf_size = write_buf_size;
|
||||
fidtc->new_metadata_size = new_size;
|
||||
free(desc);
|
||||
}
|
||||
|
||||
if (!new_size || !write_buf) {
|
||||
@@ -988,8 +972,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
(unsigned long long)write2_size);
|
||||
|
||||
if (!dev_write_bytes(mdac->area.dev, write1_start, (size_t)write1_size, write_buf)) {
|
||||
log_error("Failed to write metadata to %s fd %d", devname, mdac->area.dev->bcache_fd);
|
||||
dev_unset_last_byte(mdac->area.dev);
|
||||
log_error("Failed to write metadata to %s.", devname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1001,8 +984,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!dev_write_bytes(mdac->area.dev, write2_start, write2_size,
|
||||
write_buf + new_size - new_wrap)) {
|
||||
log_error("Failed to write metadata wrap to %s fd %d", devname, mdac->area.dev->bcache_fd);
|
||||
dev_unset_last_byte(mdac->area.dev);
|
||||
log_error("Failed to write metadata wrap to %s", devname);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1343,7 +1325,7 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
return vg;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_file(struct cmd_context *cmd, struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
@@ -1354,7 +1336,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
return _vg_read_file_name(fid, vgname, tc->path_live);
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_precommit_file(struct cmd_context *cmd, struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
@@ -1529,6 +1511,7 @@ static int _vg_remove_file(struct format_instance *fid __attribute__((unused)),
|
||||
}
|
||||
|
||||
int read_metadata_location_summary(const struct format_type *fmt,
|
||||
struct metadata_area *mda,
|
||||
struct mda_header *mdah, int primary_mda, struct device_area *dev_area,
|
||||
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
|
||||
{
|
||||
@@ -1586,6 +1569,17 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to read the vg summary during label scan.
|
||||
* Save the text start location and checksum during scan. After the VG
|
||||
* lock is acquired in vg_read, we can reread the mda_header, and
|
||||
* compare rlocn->offset,checksum to what was saved during scan. If
|
||||
* unchanged, it means that the metadata was not changed between scan
|
||||
* and the read.
|
||||
*/
|
||||
mda->scan_text_offset = rlocn->offset;
|
||||
mda->scan_text_checksum = rlocn->checksum;
|
||||
|
||||
/*
|
||||
* When the current metadata wraps around the end of the metadata area
|
||||
* (so some is located at the end and some is located at the
|
||||
@@ -1723,7 +1717,7 @@ static int _set_ext_flags(struct physical_volume *pv, struct lvmcache_info *info
|
||||
}
|
||||
|
||||
/* Only for orphans - FIXME That's not true any more */
|
||||
static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv)
|
||||
static int _text_pv_write(struct cmd_context *cmd, const struct format_type *fmt, struct physical_volume *pv)
|
||||
{
|
||||
struct format_instance *fid = pv->fid;
|
||||
const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id);
|
||||
@@ -1735,7 +1729,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
unsigned mda_index;
|
||||
|
||||
/* Add a new cache entry with PV info or update existing one. */
|
||||
if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id,
|
||||
if (!(info = lvmcache_add(cmd, fmt->labeller, (const char *) &pv->id,
|
||||
pv->dev, pv->label_sector, pv->vg_name,
|
||||
is_orphan_vg(pv->vg_name) ? pv->vg_name : pv->vg ? (const char *) &pv->vg->id : NULL, 0, NULL)))
|
||||
return_0;
|
||||
@@ -2222,8 +2216,10 @@ static int _create_vg_text_instance(struct format_instance *fid,
|
||||
}
|
||||
|
||||
if (type & FMT_INSTANCE_MDAS) {
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id)))
|
||||
goto_out;
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id))) {
|
||||
log_debug("No cached vginfo for VG %s and ID %s.", vg_name, vg_id);
|
||||
goto out;
|
||||
}
|
||||
if (!lvmcache_fid_add_mdas_vg(vginfo, fid))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
@@ -47,11 +47,15 @@ enum pv_vg_lv_e {
|
||||
|
||||
struct text_vg_version_ops {
|
||||
int (*check_version) (const struct dm_config_tree * cf);
|
||||
struct volume_group *(*read_vg) (struct format_instance * fid,
|
||||
const struct dm_config_tree *cf,
|
||||
unsigned allow_lvmetad_extensions);
|
||||
|
||||
struct volume_group *(*read_vg) (struct cmd_context *cmd,
|
||||
const struct format_type *fmt,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft);
|
||||
|
||||
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
|
||||
time_t *when, char **desc);
|
||||
|
||||
int (*read_vgsummary) (const struct format_type *fmt,
|
||||
const struct dm_config_tree *cft,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "import-export.h"
|
||||
|
||||
/* FIXME Use tidier inclusion method */
|
||||
@@ -181,7 +182,7 @@ struct volume_group *text_read_metadata(struct format_instance *fid,
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
|
||||
if (!(vg = (*vsn)->read_vg(fid->fmt->cmd, fid->fmt, fid, cft)))
|
||||
goto_out;
|
||||
|
||||
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
|
||||
@@ -210,9 +211,9 @@ struct volume_group *text_read_metadata_file(struct format_instance *fid,
|
||||
when, desc);
|
||||
}
|
||||
|
||||
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
static struct volume_group *_import_vg_from_config_tree(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
unsigned allow_lvmetad_extensions)
|
||||
const struct dm_config_tree *cft)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct text_vg_version_ops **vsn;
|
||||
@@ -227,7 +228,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
|
||||
* The only path to this point uses cached vgmetadata,
|
||||
* so it can use cached PV state too.
|
||||
*/
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, allow_lvmetad_extensions)))
|
||||
if (!(vg = (*vsn)->read_vg(cmd, fid->fmt, fid, cft)))
|
||||
stack;
|
||||
else {
|
||||
set_pv_devices(fid, vg, NULL);
|
||||
@@ -243,8 +244,21 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid)
|
||||
struct volume_group *import_vg_from_config_tree(struct cmd_context *cmd,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft)
|
||||
{
|
||||
return _import_vg_from_config_tree(cft, fid, 0);
|
||||
return _import_vg_from_config_tree(cmd, fid, cft);
|
||||
}
|
||||
|
||||
struct volume_group *vg_from_config_tree(struct cmd_context *cmd, const struct dm_config_tree *cft)
|
||||
{
|
||||
static struct text_vg_version_ops *ops;
|
||||
|
||||
_init_text_import();
|
||||
|
||||
ops = _text_vsn_list[0];
|
||||
|
||||
return ops->read_vg(cmd, cmd->fmt, NULL, cft);
|
||||
}
|
||||
|
||||
|
||||
@@ -993,7 +993,7 @@ static int _read_lvsegs(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
static int _read_sections(struct cmd_context *cmd,
|
||||
struct format_type *fmt,
|
||||
const struct format_type *fmt,
|
||||
struct format_instance *fid,
|
||||
struct dm_pool *mem,
|
||||
const char *section, section_fn fn,
|
||||
@@ -1016,19 +1016,18 @@ static int _read_sections(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
for (n = n->child; n; n = n->sib) {
|
||||
if (!fn(cmd, fmt, fid, mem, vg, vgsummary, n, vgn, pv_hash, lv_hash))
|
||||
if (!fn(cmd, (struct format_type *)fmt, fid, mem, vg, vgsummary, n, vgn, pv_hash, lv_hash))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
const struct dm_config_tree *cft,
|
||||
unsigned allow_lvmetad_extensions)
|
||||
static struct volume_group *_read_vg(struct cmd_context *cmd,
|
||||
const struct format_type *fmt,
|
||||
struct format_instance *fid,
|
||||
const struct dm_config_tree *cft)
|
||||
{
|
||||
struct cmd_context *cmd = fid->fmt->cmd;
|
||||
struct format_type *fmt = (struct format_type *)fid->fmt;
|
||||
struct dm_pool *mem;
|
||||
const struct dm_config_node *vgn;
|
||||
const struct dm_config_value *cv;
|
||||
@@ -1234,7 +1233,8 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
dm_hash_destroy(pv_hash);
|
||||
dm_hash_destroy(lv_hash);
|
||||
|
||||
vg_set_fid(vg, fid);
|
||||
if (fid)
|
||||
vg_set_fid(vg, fid);
|
||||
|
||||
/*
|
||||
* Finished.
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/format_text/format-text.h"
|
||||
#include "lib/cache/lvmcache.h"
|
||||
#include "lib/uuid/uuid.h"
|
||||
|
||||
/* disk_locn and data_area_list are defined in format-text.h */
|
||||
|
||||
/*
|
||||
* PV header extension versions:
|
||||
* - version 1: bootloader area support
|
||||
@@ -34,7 +33,7 @@ struct pv_header_extension {
|
||||
uint32_t version;
|
||||
uint32_t flags;
|
||||
/* NULL-terminated list of bootloader areas */
|
||||
struct disk_locn bootloader_areas_xl[0];
|
||||
struct disk_locn bootloader_areas_xl[];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Fields with the suffix _xl should be xlate'd wherever they appear */
|
||||
@@ -47,7 +46,7 @@ struct pv_header {
|
||||
|
||||
/* NULL-terminated list of data areas followed by */
|
||||
/* NULL-terminated list of metadata area headers */
|
||||
struct disk_locn disk_areas_xl[0]; /* Two lists */
|
||||
struct disk_locn disk_areas_xl[]; /* Two lists */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
@@ -77,7 +76,7 @@ struct mda_header {
|
||||
uint64_t start; /* Absolute start byte of mda_header */
|
||||
uint64_t size; /* Size of metadata area */
|
||||
|
||||
struct raw_locn raw_locns[0]; /* NULL-terminated list */
|
||||
struct raw_locn raw_locns[]; /* NULL-terminated list */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mda_header *raw_read_mda_header(const struct format_type *fmt,
|
||||
@@ -104,7 +103,8 @@ struct mda_context {
|
||||
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
|
||||
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
|
||||
|
||||
int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
|
||||
int read_metadata_location_summary(const struct format_type *fmt,
|
||||
struct metadata_area *mda, struct mda_header *mdah, int primary_mda,
|
||||
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
|
||||
uint64_t *mda_free_sectors);
|
||||
|
||||
|
||||
@@ -332,14 +332,12 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
log_warn("WARNING: bad metadata header on %s at %llu.",
|
||||
dev_name(mdac->area.dev),
|
||||
(unsigned long long)mdac->area.start);
|
||||
if (mda)
|
||||
mda->header_start = mdac->area.start;
|
||||
mda->header_start = mdac->area.start;
|
||||
*bad_fields |= BAD_MDA_HEADER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mda)
|
||||
mda->header_start = mdah->start;
|
||||
mda->header_start = mdah->start;
|
||||
|
||||
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
|
||||
|
||||
@@ -351,7 +349,7 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
|
||||
if (!read_metadata_location_summary(fmt, mda, mdah, mda_is_primary(mda), &mdac->area,
|
||||
vgsummary, &mdac->free_sectors)) {
|
||||
if (vgsummary->zero_offset)
|
||||
return 1;
|
||||
@@ -372,7 +370,7 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
* the metadata is at for those PVs.
|
||||
*/
|
||||
|
||||
static int _text_read(struct labeller *labeller, struct device *dev, void *label_buf,
|
||||
static int _text_read(struct cmd_context *cmd, struct labeller *labeller, struct device *dev, void *label_buf,
|
||||
uint64_t label_sector, int *is_duplicate)
|
||||
{
|
||||
struct lvmcache_vgsummary vgsummary;
|
||||
@@ -412,7 +410,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label
|
||||
*
|
||||
* Other reasons for lvmcache_add to return NULL are internal errors.
|
||||
*/
|
||||
if (!(info = lvmcache_add(labeller, (char *)pvhdr->pv_uuid, dev, label_sector,
|
||||
if (!(info = lvmcache_add(cmd, labeller, (char *)pvhdr->pv_uuid, dev, label_sector,
|
||||
FMT_TEXT_ORPHAN_VG_NAME,
|
||||
FMT_TEXT_ORPHAN_VG_NAME, 0, is_duplicate)))
|
||||
return_0;
|
||||
@@ -505,7 +503,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label
|
||||
rv1 = _read_mda_header_and_metadata(fmt, mda1, &vgsummary, &bad_fields);
|
||||
|
||||
if (rv1 && !vgsummary.zero_offset && !vgsummary.mda_ignored) {
|
||||
if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
|
||||
if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) {
|
||||
/* I believe this is only an internal error. */
|
||||
|
||||
dm_list_del(&mda1->list);
|
||||
@@ -556,7 +554,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label
|
||||
rv2 = _read_mda_header_and_metadata(fmt, mda2, &vgsummary, &bad_fields);
|
||||
|
||||
if (rv2 && !vgsummary.zero_offset && !vgsummary.mda_ignored) {
|
||||
if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
|
||||
if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) {
|
||||
dm_list_del(&mda2->list);
|
||||
|
||||
/* Are there other cases besides mismatch and internal error? */
|
||||
|
||||
343
lib/integrity/integrity.c
Normal file
343
lib/integrity/integrity.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/metadata/segtype.h"
|
||||
#include "lib/display/display.h"
|
||||
#include "lib/format_text/text_export.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/datastruct/str_list.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/metadata/lv_alloc.h"
|
||||
#include "lib/config/defaults.h"
|
||||
|
||||
#define SEG_LOG_ERROR(t, p...) \
|
||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||
|
||||
static void _integrity_display(const struct lv_segment *seg)
|
||||
{
|
||||
/* TODO: lvdisplay segments */
|
||||
}
|
||||
|
||||
static int _integrity_text_import(struct lv_segment *seg,
|
||||
const struct dm_config_node *sn,
|
||||
struct dm_hash_table *pv_hash __attribute__((unused)))
|
||||
{
|
||||
struct integrity_settings *set;
|
||||
struct logical_volume *origin_lv = NULL;
|
||||
struct logical_volume *meta_lv = NULL;
|
||||
const char *origin_name = NULL;
|
||||
const char *meta_dev = NULL;
|
||||
const char *mode = NULL;
|
||||
const char *hash = NULL;
|
||||
|
||||
memset(&seg->integrity_settings, 0, sizeof(struct integrity_settings));
|
||||
set = &seg->integrity_settings;
|
||||
|
||||
/* origin always set */
|
||||
|
||||
if (!dm_config_has_node(sn, "origin"))
|
||||
return SEG_LOG_ERROR("origin not specified in");
|
||||
|
||||
if (!dm_config_get_str(sn, "origin", &origin_name))
|
||||
return SEG_LOG_ERROR("origin must be a string in");
|
||||
|
||||
if (!(origin_lv = find_lv(seg->lv->vg, origin_name)))
|
||||
return SEG_LOG_ERROR("Unknown LV specified for integrity origin %s in", origin_name);
|
||||
|
||||
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
|
||||
return_0;
|
||||
|
||||
/* data_sectors always set */
|
||||
|
||||
if (!dm_config_get_uint64(sn, "data_sectors", &seg->integrity_data_sectors))
|
||||
return SEG_LOG_ERROR("integrity data_sectors must be set in");
|
||||
|
||||
/* mode always set */
|
||||
|
||||
if (!dm_config_get_str(sn, "mode", &mode))
|
||||
return SEG_LOG_ERROR("integrity mode must be set in");
|
||||
|
||||
if (strlen(mode) > 7)
|
||||
return SEG_LOG_ERROR("integrity mode invalid in");
|
||||
|
||||
strncpy(set->mode, mode, 7);
|
||||
|
||||
/* tag_size always set */
|
||||
|
||||
if (!dm_config_get_uint32(sn, "tag_size", &set->tag_size))
|
||||
return SEG_LOG_ERROR("integrity tag_size must be set in");
|
||||
|
||||
/* block_size always set */
|
||||
|
||||
if (!dm_config_get_uint32(sn, "block_size", &set->block_size))
|
||||
return SEG_LOG_ERROR("integrity block_size invalid in");
|
||||
|
||||
/* internal_hash always set */
|
||||
|
||||
if (!dm_config_get_str(sn, "internal_hash", &hash))
|
||||
return SEG_LOG_ERROR("integrity internal_hash must be set in");
|
||||
|
||||
if (!(set->internal_hash = dm_pool_strdup(seg->lv->vg->vgmem, hash)))
|
||||
return SEG_LOG_ERROR("integrity internal_hash failed to be set in");
|
||||
|
||||
/* meta_dev optional */
|
||||
|
||||
if (dm_config_has_node(sn, "meta_dev")) {
|
||||
if (!dm_config_get_str(sn, "meta_dev", &meta_dev))
|
||||
return SEG_LOG_ERROR("meta_dev must be a string in");
|
||||
|
||||
if (!(meta_lv = find_lv(seg->lv->vg, meta_dev)))
|
||||
return SEG_LOG_ERROR("Unknown logical volume %s specified for integrity in", meta_dev);
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "recalculate")) {
|
||||
if (!dm_config_get_uint32(sn, "recalculate", &seg->integrity_recalculate))
|
||||
return SEG_LOG_ERROR("integrity recalculate error in");
|
||||
}
|
||||
|
||||
/* the rest are optional */
|
||||
|
||||
if (dm_config_has_node(sn, "journal_sectors")) {
|
||||
if (!dm_config_get_uint32(sn, "journal_sectors", &set->journal_sectors))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->journal_sectors_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "interleave_sectors")) {
|
||||
if (!dm_config_get_uint32(sn, "interleave_sectors", &set->interleave_sectors))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->interleave_sectors_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "buffer_sectors")) {
|
||||
if (!dm_config_get_uint32(sn, "buffer_sectors", &set->buffer_sectors))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->buffer_sectors_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "journal_watermark")) {
|
||||
if (!dm_config_get_uint32(sn, "journal_watermark", &set->journal_watermark))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->journal_watermark_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "commit_time")) {
|
||||
if (!dm_config_get_uint32(sn, "commit_time", &set->commit_time))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->commit_time_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "bitmap_flush_interval")) {
|
||||
if (!dm_config_get_uint32(sn, "bitmap_flush_interval", &set->bitmap_flush_interval))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->bitmap_flush_interval_set = 1;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "sectors_per_bit")) {
|
||||
if (!dm_config_get_uint64(sn, "sectors_per_bit", &set->sectors_per_bit))
|
||||
return SEG_LOG_ERROR("Unknown integrity_setting in");
|
||||
set->sectors_per_bit_set = 1;
|
||||
}
|
||||
|
||||
seg->origin = origin_lv;
|
||||
seg->integrity_meta_dev = meta_lv;
|
||||
seg->lv->status |= INTEGRITY;
|
||||
|
||||
if (meta_lv)
|
||||
meta_lv->status |= INTEGRITY_METADATA;
|
||||
|
||||
if (meta_lv && !add_seg_to_segs_using_this_lv(meta_lv, seg))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _integrity_text_import_area_count(const struct dm_config_node *sn,
|
||||
uint32_t *area_count)
|
||||
{
|
||||
*area_count = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _integrity_text_export(const struct lv_segment *seg,
|
||||
struct formatter *f)
|
||||
{
|
||||
const struct integrity_settings *set = &seg->integrity_settings;
|
||||
|
||||
outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name);
|
||||
outf(f, "data_sectors = %llu", (unsigned long long)seg->integrity_data_sectors);
|
||||
|
||||
outf(f, "mode = \"%s\"", set->mode);
|
||||
outf(f, "tag_size = %u", set->tag_size);
|
||||
outf(f, "block_size = %u", set->block_size);
|
||||
outf(f, "internal_hash = \"%s\"", set->internal_hash);
|
||||
|
||||
if (seg->integrity_meta_dev)
|
||||
outf(f, "meta_dev = \"%s\"", seg->integrity_meta_dev->name);
|
||||
|
||||
if (seg->integrity_recalculate)
|
||||
outf(f, "recalculate = %u", seg->integrity_recalculate);
|
||||
|
||||
if (set->journal_sectors_set)
|
||||
outf(f, "journal_sectors = %u", set->journal_sectors);
|
||||
|
||||
if (set->interleave_sectors_set)
|
||||
outf(f, "interleave_sectors = %u", set->interleave_sectors);
|
||||
|
||||
if (set->buffer_sectors_set)
|
||||
outf(f, "buffer_sectors = %u", set->buffer_sectors);
|
||||
|
||||
if (set->journal_watermark_set)
|
||||
outf(f, "journal_watermark = %u", set->journal_watermark);
|
||||
|
||||
if (set->commit_time_set)
|
||||
outf(f, "commit_time = %u", set->commit_time);
|
||||
|
||||
if (set->bitmap_flush_interval)
|
||||
outf(f, "bitmap_flush_interval = %u", set->bitmap_flush_interval);
|
||||
|
||||
if (set->sectors_per_bit)
|
||||
outf(f, "sectors_per_bit = %llu", (unsigned long long)set->sectors_per_bit);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct segment_type *segtype)
|
||||
{
|
||||
free((void *) segtype);
|
||||
}
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
|
||||
static int _target_present(struct cmd_context *cmd,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
{
|
||||
static int _integrity_checked = 0;
|
||||
static int _integrity_present = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!_integrity_checked) {
|
||||
_integrity_checked = 1;
|
||||
_integrity_present = target_present(cmd, TARGET_NAME_INTEGRITY, 1);
|
||||
|
||||
if (!target_version(TARGET_NAME_INTEGRITY, &maj, &min, &patchlevel))
|
||||
return 0;
|
||||
|
||||
if (maj < 1 || min < 6) {
|
||||
log_error("Integrity target version older than minimum 1.6.0");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return _integrity_present;
|
||||
}
|
||||
|
||||
static int _modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
struct dm_list *modules)
|
||||
{
|
||||
if (!str_list_add(mem, modules, MODULE_NAME_INTEGRITY)) {
|
||||
log_error("String list allocation failed for integrity module.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _integrity_add_target_line(struct dev_manager *dm,
|
||||
struct dm_pool *mem,
|
||||
struct cmd_context *cmd __attribute__((unused)),
|
||||
void **target_state __attribute__((unused)),
|
||||
struct lv_segment *seg,
|
||||
const struct lv_activate_opts *laopts,
|
||||
struct dm_tree_node *node, uint64_t len,
|
||||
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
||||
{
|
||||
char *origin_uuid;
|
||||
char *meta_uuid = NULL;
|
||||
|
||||
if (!seg_is_integrity(seg)) {
|
||||
log_error(INTERNAL_ERROR "Passed segment is not integrity.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0), NULL)))
|
||||
return_0;
|
||||
|
||||
if (seg->integrity_meta_dev) {
|
||||
if (!(meta_uuid = build_dm_uuid(mem, seg->integrity_meta_dev, NULL)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!seg->integrity_data_sectors) {
|
||||
log_error("_integrity_add_target_line zero size");
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!dm_tree_node_add_integrity_target(node, seg->integrity_data_sectors,
|
||||
origin_uuid, meta_uuid,
|
||||
&seg->integrity_settings,
|
||||
seg->integrity_recalculate))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
static struct segtype_handler _integrity_ops = {
|
||||
.display = _integrity_display,
|
||||
.text_import = _integrity_text_import,
|
||||
.text_import_area_count = _integrity_text_import_area_count,
|
||||
.text_export = _integrity_text_export,
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
.add_target_line = _integrity_add_target_line,
|
||||
.target_present = _target_present,
|
||||
.modules_needed = _modules_needed,
|
||||
#endif
|
||||
.destroy = _destroy,
|
||||
};
|
||||
|
||||
int init_integrity_segtypes(struct cmd_context *cmd,
|
||||
struct segtype_library *seglib)
|
||||
{
|
||||
struct segment_type *segtype = zalloc(sizeof(*segtype));
|
||||
|
||||
if (!segtype) {
|
||||
log_error("Failed to allocate memory for integrity segtype");
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = SEG_TYPE_NAME_INTEGRITY;
|
||||
segtype->flags = SEG_INTEGRITY;
|
||||
segtype->ops = &_integrity_ops;
|
||||
|
||||
if (!lvm_register_segtype(seglib, segtype))
|
||||
return_0;
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -135,11 +135,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/label/label.h"
|
||||
#include "lib/misc/crc.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
#include "lib/cache/lvmcache.h"
|
||||
#include "lib/device/bcache.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
@@ -191,8 +190,10 @@ static int _hints_exists(void)
|
||||
|
||||
if (!stat(_hints_file, &buf))
|
||||
return 1;
|
||||
|
||||
if (errno != ENOENT)
|
||||
log_debug("hints_exist errno %d", errno);
|
||||
log_debug("hints_exist errno %d %s", errno, _hints_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -202,8 +203,10 @@ static int _nohints_exists(void)
|
||||
|
||||
if (!stat(_nohints_file, &buf))
|
||||
return 1;
|
||||
|
||||
if (errno != ENOENT)
|
||||
log_debug("nohints_exist errno %d", errno);
|
||||
log_debug("nohints_exist errno %d %s", errno, _nohints_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -213,8 +216,10 @@ static int _newhints_exists(void)
|
||||
|
||||
if (!stat(_newhints_file, &buf))
|
||||
return 1;
|
||||
|
||||
if (errno != ENOENT)
|
||||
log_debug("newhints_exist errno %d", errno);
|
||||
log_debug("newhints_exist errno %d %s", errno, _newhints_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -244,29 +249,33 @@ static int _touch_hints(void)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (!(fp = fopen(_hints_file, "w")))
|
||||
return_0;
|
||||
if (!(fp = fopen(_hints_file, "w"))) {
|
||||
log_debug("touch_hints errno %d %s", errno, _hints_file);
|
||||
return 0;
|
||||
}
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
log_debug("touch_hints close errno %d %s", errno, _hints_file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _unlink_nohints(void)
|
||||
{
|
||||
if (unlink(_nohints_file))
|
||||
log_debug("unlink_nohints errno %d", errno);
|
||||
log_debug("unlink_nohints errno %d %s", errno, _nohints_file);
|
||||
}
|
||||
|
||||
|
||||
static void _unlink_hints(void)
|
||||
{
|
||||
if (unlink(_hints_file))
|
||||
log_debug("unlink_hints errno %d", errno);
|
||||
log_debug("unlink_hints errno %d %s", errno, _hints_file);
|
||||
}
|
||||
|
||||
static void _unlink_newhints(void)
|
||||
{
|
||||
if (unlink(_newhints_file))
|
||||
log_debug("unlink_newhints errno %d", errno);
|
||||
log_debug("unlink_newhints errno %d %s", errno, _newhints_file);
|
||||
}
|
||||
|
||||
static int _clear_hints(struct cmd_context *cmd)
|
||||
@@ -275,7 +284,7 @@ static int _clear_hints(struct cmd_context *cmd)
|
||||
time_t t;
|
||||
|
||||
if (!(fp = fopen(_hints_file, "w"))) {
|
||||
log_warn("Failed to clear hint file.");
|
||||
log_debug("clear_hints open errno %d", errno);
|
||||
/* shouldn't happen, but try to unlink in case */
|
||||
_unlink_hints();
|
||||
return 0;
|
||||
@@ -286,10 +295,10 @@ static int _clear_hints(struct cmd_context *cmd)
|
||||
fprintf(fp, "# Created empty by %s pid %d %s", cmd->name, getpid(), ctime(&t));
|
||||
|
||||
if (fflush(fp))
|
||||
log_debug("clear_hints flush errno %d", errno);
|
||||
log_debug("clear_hints flush errno %d %s", errno, _hints_file);
|
||||
|
||||
if (fclose(fp))
|
||||
log_debug("clear_hints close errno %d", errno);
|
||||
log_debug("clear_hints close errno %d %s", errno, _hints_file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -313,7 +322,7 @@ static int _lock_hints(struct cmd_context *cmd, int mode, int nonblock)
|
||||
|
||||
fd = open(_hints_file, O_RDWR);
|
||||
if (fd < 0) {
|
||||
log_debug("lock_hints open errno %d", errno);
|
||||
log_debug("lock_hints open errno %d %s", errno, _hints_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -325,7 +334,8 @@ static int _lock_hints(struct cmd_context *cmd, int mode, int nonblock)
|
||||
}
|
||||
|
||||
if (close(fd))
|
||||
stack;
|
||||
log_debug("lock_hints close errno %d %s", errno, _hints_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -352,9 +362,20 @@ static void _unlock_hints(struct cmd_context *cmd)
|
||||
|
||||
void hints_exit(struct cmd_context *cmd)
|
||||
{
|
||||
free_hints(&cmd->hints);
|
||||
if (_hints_fd == -1)
|
||||
return;
|
||||
return _unlock_hints(cmd);
|
||||
_unlock_hints(cmd);
|
||||
}
|
||||
|
||||
void free_hints(struct dm_list *hints)
|
||||
{
|
||||
struct hint *hint, *hint2;
|
||||
|
||||
dm_list_iterate_items_safe(hint, hint2, hints) {
|
||||
dm_list_del(&hint->list);
|
||||
free(hint);
|
||||
}
|
||||
}
|
||||
|
||||
static struct hint *_find_hint_name(struct dm_list *hints, const char *name)
|
||||
@@ -410,6 +431,9 @@ static int _dev_in_hint_hash(struct cmd_context *cmd, struct device *dev)
|
||||
{
|
||||
uint64_t devsize = 0;
|
||||
|
||||
if (dm_list_empty(&dev->aliases))
|
||||
return 0;
|
||||
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "regex"))
|
||||
return 0;
|
||||
|
||||
@@ -421,7 +445,7 @@ static int _dev_in_hint_hash(struct cmd_context *cmd, struct device *dev)
|
||||
return 0;
|
||||
|
||||
if (!dev_get_size(dev, &devsize) || !devsize)
|
||||
return 0;
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -638,7 +662,8 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
char devpath[PATH_MAX];
|
||||
FILE *fp;
|
||||
struct dev_iter *iter;
|
||||
struct hint *hint;
|
||||
struct hint hint;
|
||||
struct hint *alloc_hint;
|
||||
struct device *dev;
|
||||
char *split[HINT_LINE_WORDS];
|
||||
char *name, *pvid, *devn, *vgname, *p, *filter_str = NULL;
|
||||
@@ -649,7 +674,7 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
int found = 0;
|
||||
int keylen;
|
||||
int hv_major, hv_minor;
|
||||
int major, minor;
|
||||
int major = -1, minor = -1;
|
||||
int ret = 1;
|
||||
int i;
|
||||
|
||||
@@ -662,11 +687,7 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
split[i] = NULL;
|
||||
|
||||
while (fgets(_hint_line, sizeof(_hint_line), fp)) {
|
||||
if (!(hint = zalloc(sizeof(struct hint)))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
if (_hint_line[0] == '#')
|
||||
continue;
|
||||
|
||||
@@ -704,13 +725,11 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
_filter_to_str(cmd, devices_global_filter_CFG, &filter_str);
|
||||
if (!filter_str || strcmp(filter_str, _hint_line + keylen)) {
|
||||
log_debug("ignore hints with different global_filter");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -719,23 +738,20 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
_filter_to_str(cmd, devices_filter_CFG, &filter_str);
|
||||
if (!filter_str || strcmp(filter_str, _hint_line + keylen)) {
|
||||
log_debug("ignore hints with different filter");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
keylen = strlen("scan_lvs:");
|
||||
if (!strncmp(_hint_line, "scan_lvs:", keylen)) {
|
||||
int scan_lvs = 0;
|
||||
sscanf(_hint_line + keylen, "%u", &scan_lvs);
|
||||
|
||||
if (scan_lvs != cmd->scan_lvs) {
|
||||
log_debug("ignore hints with different scan_lvs");
|
||||
unsigned scan_lvs = 0;
|
||||
if ((sscanf(_hint_line + keylen, "%u", &scan_lvs) != 1) ||
|
||||
scan_lvs != cmd->scan_lvs) {
|
||||
log_debug("ignore hints with different or unreadable scan_lvs");
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
@@ -744,7 +760,11 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
|
||||
keylen = strlen("devs_hash:");
|
||||
if (!strncmp(_hint_line, "devs_hash:", keylen)) {
|
||||
sscanf(_hint_line + keylen, "%u %u", &read_hash, &read_count);
|
||||
if (sscanf(_hint_line + keylen, "%u %u", &read_hash, &read_count) != 2) {
|
||||
log_debug("ignore hints with invalid devs_hash");
|
||||
*needs_refresh = 1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -764,24 +784,33 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
vgname = split[3];
|
||||
|
||||
if (name && !strncmp(name, "scan:", 5))
|
||||
strncpy(hint->name, name+5, PATH_MAX);
|
||||
if (!dm_strncpy(hint.name, name + 5, sizeof(hint.name)))
|
||||
continue;
|
||||
|
||||
if (pvid && !strncmp(pvid, "pvid:", 5))
|
||||
strncpy(hint->pvid, pvid+5, ID_LEN);
|
||||
if (!dm_strncpy(hint.pvid, pvid + 5, sizeof(hint.pvid)))
|
||||
continue;
|
||||
|
||||
if (devn && sscanf(devn, "devn:%d:%d", &major, &minor) == 2)
|
||||
hint->devt = makedev(major, minor);
|
||||
hint.devt = makedev(major, minor);
|
||||
|
||||
if (vgname && (strlen(vgname) > 3) && (vgname[4] != '-'))
|
||||
strncpy(hint->vgname, vgname+3, NAME_LEN);
|
||||
if (!dm_strncpy(hint.vgname, vgname + 3, sizeof(hint.vgname)))
|
||||
continue;
|
||||
|
||||
log_debug("add hint %s %s %d:%d %s", hint->name, hint->pvid, major, minor, vgname);
|
||||
dm_list_add(hints, &hint->list);
|
||||
if (!(alloc_hint = malloc(sizeof(struct hint)))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
memcpy(alloc_hint, &hint, sizeof(hint));
|
||||
|
||||
log_debug("add hint %s %s %d:%d %s", hint.name, hint.pvid, major, minor, vgname);
|
||||
dm_list_add(hints, &alloc_hint->list);
|
||||
found++;
|
||||
}
|
||||
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
log_debug("read_hint_file close errno %d", errno);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
@@ -800,8 +829,7 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (!_dev_in_hint_hash(cmd, dev))
|
||||
continue;
|
||||
memset(devpath, 0, sizeof(devpath));
|
||||
strncpy(devpath, dev_name(dev), PATH_MAX);
|
||||
(void) dm_strncpy(devpath, dev_name(dev), sizeof(devpath));
|
||||
calc_hash = calc_crc(calc_hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
calc_count++;
|
||||
}
|
||||
@@ -911,13 +939,11 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
|
||||
_filter_to_str(cmd, devices_global_filter_CFG, &filter_str);
|
||||
fprintf(fp, "global_filter:%s\n", filter_str ?: "-");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
|
||||
_filter_to_str(cmd, devices_filter_CFG, &filter_str);
|
||||
fprintf(fp, "filter:%s\n", filter_str ?: "-");
|
||||
if (filter_str)
|
||||
free(filter_str);
|
||||
free(filter_str);
|
||||
|
||||
fprintf(fp, "scan_lvs:%d\n", cmd->scan_lvs);
|
||||
|
||||
@@ -951,8 +977,7 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
* detect when the devices on the system change, which
|
||||
* invalidates the existing hints.
|
||||
*/
|
||||
memset(devpath, 0, sizeof(devpath));
|
||||
strncpy(devpath, dev_name(dev), PATH_MAX);
|
||||
(void) dm_strncpy(devpath, dev_name(dev), sizeof(devpath));
|
||||
hash = calc_crc(hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
count++;
|
||||
|
||||
@@ -1006,7 +1031,7 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
|
||||
out_close:
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
log_debug("write_hint_file close errno %d", errno);
|
||||
|
||||
out_unlock:
|
||||
/* get_hints() took ex lock before returning with newhints set */
|
||||
@@ -1104,8 +1129,10 @@ void pvscan_recreate_hints_begin(struct cmd_context *cmd)
|
||||
|
||||
log_debug("pvscan_recreate_hints_begin");
|
||||
|
||||
if (!_touch_hints())
|
||||
if (!_touch_hints()) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
/* limit potential delay blocking on hints lock next */
|
||||
if (!_touch_nohints())
|
||||
@@ -1179,7 +1206,8 @@ static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
|
||||
|
||||
if (!(st = strchr(arg, '/'))) {
|
||||
/* simple vgname */
|
||||
name = strdup(arg);
|
||||
if (!(name = strdup(arg)))
|
||||
return;
|
||||
goto check;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1215,8 @@ static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
|
||||
for (p = arg; p < st; p++)
|
||||
namebuf[i++] = *p;
|
||||
|
||||
name = strdup(namebuf);
|
||||
if (!(name = strdup(namebuf)))
|
||||
return;
|
||||
|
||||
check:
|
||||
/*
|
||||
@@ -1202,6 +1231,8 @@ check:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1261,8 +1292,9 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
*/
|
||||
if (_newhints_exists()) {
|
||||
log_debug("get_hints: newhints file");
|
||||
if (!_hints_exists())
|
||||
_touch_hints();
|
||||
if (!_hints_exists() && !_touch_hints())
|
||||
return 0;
|
||||
|
||||
if (!_lock_hints(cmd, LOCK_EX, NONBLOCK))
|
||||
return 0;
|
||||
/* create new hints after scan */
|
||||
@@ -1300,6 +1332,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
*/
|
||||
if (!_read_hint_file(cmd, &hints_list, &needs_refresh)) {
|
||||
log_debug("get_hints: read fail");
|
||||
free_hints(&hints_list);
|
||||
_unlock_hints(cmd);
|
||||
return 0;
|
||||
}
|
||||
@@ -1312,6 +1345,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
*/
|
||||
if (needs_refresh) {
|
||||
log_debug("get_hints: needs refresh");
|
||||
free_hints(&hints_list);
|
||||
|
||||
if (!_lock_hints(cmd, LOCK_EX, NONBLOCK))
|
||||
return 0;
|
||||
@@ -1355,6 +1389,9 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
dm_list_size(devs_out), dm_list_size(devs_in));
|
||||
|
||||
dm_list_splice(hints_out, &hints_list);
|
||||
|
||||
free(vgname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ struct hint {
|
||||
unsigned chosen:1; /* this hint's dev was chosen for scanning */
|
||||
};
|
||||
|
||||
void free_hints(struct dm_list *hints);
|
||||
|
||||
int write_hint_file(struct cmd_context *cmd, int newhints);
|
||||
|
||||
void clear_hint_file(struct cmd_context *cmd);
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/label/label.h"
|
||||
#include "lib/misc/crc.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/label/hints.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/format_text/layout.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -42,7 +43,7 @@ struct labeller_i {
|
||||
struct dm_list list;
|
||||
|
||||
struct labeller *l;
|
||||
char name[0];
|
||||
char name[];
|
||||
};
|
||||
|
||||
static struct dm_list _labellers;
|
||||
@@ -218,7 +219,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
|
||||
if (!dev_write_bytes(dev, offset, LABEL_SIZE, buf)) {
|
||||
log_debug_devs("Failed to write label to %s", dev_name(dev));
|
||||
r = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_unset_last_byte(dev);
|
||||
@@ -361,34 +362,33 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
uint64_t sector = 0;
|
||||
int is_duplicate = 0;
|
||||
int ret = 0;
|
||||
int pass;
|
||||
|
||||
dev->flags &= ~DEV_SCAN_FOUND_LABEL;
|
||||
|
||||
/*
|
||||
* The device may have signatures that exclude it from being processed.
|
||||
* If filters were applied before bcache data was available, some
|
||||
* filters may have deferred their check until the point where bcache
|
||||
* data had been read (here). They set this flag to indicate that the
|
||||
* filters should be retested now that data from the device is ready.
|
||||
* The device may have signatures that exclude it from being processed,
|
||||
* even if it might look like a PV. Now that the device has been read
|
||||
* and data is available in bcache for it, recheck filters, including
|
||||
* those that use data. The device needs to be excluded before it
|
||||
* begins to be processed as a PV.
|
||||
*/
|
||||
if (f && (dev->flags & DEV_FILTER_AFTER_SCAN)) {
|
||||
dev->flags &= ~DEV_FILTER_AFTER_SCAN;
|
||||
if (f) {
|
||||
if (!f->passes_filter(cmd, f, dev, NULL)) {
|
||||
/*
|
||||
* If this device was previously scanned (not common)
|
||||
* and if it passed filters at that point, lvmcache
|
||||
* info may have been saved for it. Now the same
|
||||
* device is being scanned again, and it may fail
|
||||
* filters this time. If the caller did not clear
|
||||
* lvmcache info for this dev before rescanning, do
|
||||
* that now. It's unlikely this is actually needed.
|
||||
*/
|
||||
if (dev->pvid[0]) {
|
||||
log_print("Clear pvid and info for filtered dev %s", dev_name(dev));
|
||||
lvmcache_del_dev(dev);
|
||||
memset(dev->pvid, 0, sizeof(dev->pvid));
|
||||
}
|
||||
|
||||
log_debug_devs("Scan filtering %s", dev_name(dev));
|
||||
|
||||
pass = f->passes_filter(cmd, f, dev, NULL);
|
||||
|
||||
if ((pass == -EAGAIN) || (dev->flags & DEV_FILTER_AFTER_SCAN)) {
|
||||
/* Shouldn't happen */
|
||||
dev->flags &= ~DEV_FILTER_OUT_SCAN;
|
||||
log_debug_devs("Scan filter should not be deferred %s", dev_name(dev));
|
||||
pass = 1;
|
||||
}
|
||||
|
||||
if (!pass) {
|
||||
log_very_verbose("%s: Not processing filtered", dev_name(dev));
|
||||
dev->flags |= DEV_FILTER_OUT_SCAN;
|
||||
*is_lvm_device = 0;
|
||||
goto_out;
|
||||
}
|
||||
@@ -413,10 +413,15 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
|
||||
log_very_verbose("%s: No lvm label detected", dev_name(dev));
|
||||
|
||||
lvmcache_del_dev(dev); /* FIXME: if this is needed, fix it. */
|
||||
/* See comment above */
|
||||
if (dev->pvid[0]) {
|
||||
log_print("Clear pvid and info for no lvm header %s", dev_name(dev));
|
||||
lvmcache_del_dev(dev);
|
||||
memset(dev->pvid, 0, sizeof(dev->pvid));
|
||||
}
|
||||
|
||||
*is_lvm_device = 0;
|
||||
goto_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->flags |= DEV_SCAN_FOUND_LABEL;
|
||||
@@ -430,7 +435,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
* info/vginfo structs. That lvmcache info is used later when the
|
||||
* command wants to read the VG to do something to it.
|
||||
*/
|
||||
ret = labeller->ops->read(labeller, dev, label_buf, sector, &is_duplicate);
|
||||
ret = labeller->ops->read(cmd, labeller, dev, label_buf, sector, &is_duplicate);
|
||||
|
||||
if (!ret) {
|
||||
if (is_duplicate) {
|
||||
@@ -466,10 +471,11 @@ static int _scan_dev_open(struct device *dev)
|
||||
struct dm_list *name_list;
|
||||
struct dm_str_list *name_sl;
|
||||
const char *name;
|
||||
const char *modestr;
|
||||
struct stat sbuf;
|
||||
int retried = 0;
|
||||
int flags = 0;
|
||||
int fd;
|
||||
int fd, di;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
@@ -480,10 +486,10 @@ static int _scan_dev_open(struct device *dev)
|
||||
dev->flags &= ~DEV_IN_BCACHE;
|
||||
}
|
||||
|
||||
if (dev->bcache_fd > 0) {
|
||||
if (dev->bcache_di != -1) {
|
||||
/* Shouldn't happen */
|
||||
log_error("Device open %s already open with fd %d",
|
||||
dev_name(dev), dev->bcache_fd);
|
||||
log_error("Device open %s already open with di %d fd %d",
|
||||
dev_name(dev), dev->bcache_di, dev->bcache_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -513,10 +519,13 @@ static int _scan_dev_open(struct device *dev)
|
||||
if (dev->flags & DEV_BCACHE_EXCL) {
|
||||
flags |= O_EXCL;
|
||||
flags |= O_RDWR;
|
||||
modestr = "rwex";
|
||||
} else if (dev->flags & DEV_BCACHE_WRITE) {
|
||||
flags |= O_RDWR;
|
||||
modestr = "rw";
|
||||
} else {
|
||||
flags |= O_RDONLY;
|
||||
modestr = "ro";
|
||||
}
|
||||
|
||||
retry_open:
|
||||
@@ -567,6 +576,20 @@ retry_open:
|
||||
|
||||
dev->flags |= DEV_IN_BCACHE;
|
||||
dev->bcache_fd = fd;
|
||||
|
||||
di = bcache_set_fd(fd);
|
||||
|
||||
if (di == -1) {
|
||||
log_error("Failed to set bcache fd.");
|
||||
close(fd);
|
||||
dev->bcache_fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("open %s %s di %d fd %d", dev_name(dev), modestr, di, fd);
|
||||
|
||||
dev->bcache_di = di;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -577,15 +600,21 @@ static int _scan_dev_close(struct device *dev)
|
||||
|
||||
dev->flags &= ~DEV_IN_BCACHE;
|
||||
dev->flags &= ~DEV_BCACHE_EXCL;
|
||||
dev->flags &= ~DEV_BCACHE_WRITE;
|
||||
|
||||
if (dev->bcache_fd < 0) {
|
||||
if (dev->bcache_di == -1) {
|
||||
log_error("scan_dev_close %s already closed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
bcache_clear_fd(dev->bcache_di);
|
||||
|
||||
if (close(dev->bcache_fd))
|
||||
log_warn("close %s errno %d", dev_name(dev), errno);
|
||||
|
||||
dev->bcache_fd = -1;
|
||||
dev->bcache_di = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -620,6 +649,14 @@ static void _drop_bad_aliases(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
// Like bcache_invalidate, only it throws any dirty data away if the
|
||||
// write fails.
|
||||
static void _invalidate_di(struct bcache *cache, int di)
|
||||
{
|
||||
if (!bcache_invalidate_di(cache, di))
|
||||
bcache_abort_di(cache, di);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read or reread label/metadata from selected devs.
|
||||
*
|
||||
@@ -632,7 +669,7 @@ static void _drop_bad_aliases(struct device *dev)
|
||||
*/
|
||||
|
||||
static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
struct dm_list *devs, int *failed)
|
||||
struct dm_list *devs, int want_other_devs, int *failed)
|
||||
{
|
||||
struct dm_list wait_devs;
|
||||
struct dm_list done_devs;
|
||||
@@ -645,9 +682,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
int scan_failed_count = 0;
|
||||
int rem_prefetches;
|
||||
int submit_count;
|
||||
int scan_failed;
|
||||
int is_lvm_device;
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
dm_list_init(&wait_devs);
|
||||
@@ -681,7 +716,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
}
|
||||
}
|
||||
|
||||
bcache_prefetch(scan_bcache, devl->dev->bcache_fd, 0);
|
||||
bcache_prefetch(scan_bcache, devl->dev->bcache_di, 0);
|
||||
|
||||
rem_prefetches--;
|
||||
submit_count++;
|
||||
@@ -694,28 +729,24 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
|
||||
dm_list_iterate_items_safe(devl, devl2, &wait_devs) {
|
||||
bb = NULL;
|
||||
error = 0;
|
||||
scan_failed = 0;
|
||||
is_lvm_device = 0;
|
||||
|
||||
if (!bcache_get(scan_bcache, devl->dev->bcache_fd, 0, 0, &bb)) {
|
||||
log_debug_devs("Scan failed to read %s error %d.", dev_name(devl->dev), error);
|
||||
scan_failed = 1;
|
||||
if (!bcache_get(scan_bcache, devl->dev->bcache_di, 0, 0, &bb)) {
|
||||
log_debug_devs("Scan failed to read %s.", dev_name(devl->dev));
|
||||
scan_read_errors++;
|
||||
scan_failed_count++;
|
||||
lvmcache_del_dev(devl->dev);
|
||||
} else {
|
||||
log_debug_devs("Processing data from device %s %d:%d fd %d block %p",
|
||||
log_debug_devs("Processing data from device %s %d:%d di %d block %p",
|
||||
dev_name(devl->dev),
|
||||
(int)MAJOR(devl->dev->dev),
|
||||
(int)MINOR(devl->dev->dev),
|
||||
devl->dev->bcache_fd, bb);
|
||||
devl->dev->bcache_di, (void *)bb);
|
||||
|
||||
ret = _process_block(cmd, f, devl->dev, bb, 0, 0, &is_lvm_device);
|
||||
|
||||
if (!ret && is_lvm_device) {
|
||||
log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
|
||||
scan_failed = 1;
|
||||
scan_process_errors++;
|
||||
scan_failed_count++;
|
||||
}
|
||||
@@ -728,10 +759,12 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
* Keep the bcache block of lvm devices we have processed so
|
||||
* that the vg_read phase can reuse it. If bcache failed to
|
||||
* read the block, or the device does not belong to lvm, then
|
||||
* drop it from bcache.
|
||||
* drop it from bcache. When "want_other_devs" is set, it
|
||||
* means the caller wants to scan and keep open non-lvm devs,
|
||||
* e.g. to pvcreate them.
|
||||
*/
|
||||
if (scan_failed || !is_lvm_device) {
|
||||
bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
|
||||
if (!is_lvm_device && !want_other_devs) {
|
||||
_invalidate_di(scan_bcache, devl->dev->bcache_di);
|
||||
_scan_dev_close(devl->dev);
|
||||
}
|
||||
|
||||
@@ -850,16 +883,6 @@ static int _setup_bcache(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _free_hints(struct dm_list *hints)
|
||||
{
|
||||
struct hint *hint, *hint2;
|
||||
|
||||
dm_list_iterate_items_safe(hint, hint2, hints) {
|
||||
dm_list_del(&hint->list);
|
||||
free(hint);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't know how many of num_devs will be PVs that we need to
|
||||
* keep open, but if it's greater than the soft limit, then we'll
|
||||
@@ -913,6 +936,74 @@ static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_d
|
||||
#endif
|
||||
}
|
||||
|
||||
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out)
|
||||
{
|
||||
char buf[LABEL_SIZE] __attribute__((aligned(8)));
|
||||
struct dm_list devs;
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
struct pv_header *pvh;
|
||||
int ret = 0;
|
||||
|
||||
dm_list_init(&devs);
|
||||
|
||||
dev_cache_scan();
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter, 0))) {
|
||||
log_error("Scanning failed to get devices.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_devs("Filtering devices to scan");
|
||||
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
continue;
|
||||
devl->dev = dev;
|
||||
dm_list_add(&devs, &devl->list);
|
||||
};
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
if (!scan_bcache) {
|
||||
if (!_setup_bcache())
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_debug_devs("Reading labels for pvid");
|
||||
|
||||
dm_list_iterate_items(devl, &devs) {
|
||||
dev = devl->dev;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (!label_scan_open(dev))
|
||||
continue;
|
||||
|
||||
if (!dev_read_bytes(dev, 512, LABEL_SIZE, buf)) {
|
||||
_scan_dev_close(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pvh = (struct pv_header *)(buf + 32);
|
||||
|
||||
if (!memcmp(pvh->pv_uuid, pvid, ID_LEN)) {
|
||||
*dev_out = devl->dev;
|
||||
_scan_dev_close(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
ret = 1;
|
||||
out:
|
||||
dm_list_iterate_items_safe(devl, devl2, &devs) {
|
||||
dm_list_del(&devl->list);
|
||||
free(devl);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan devices on the system to discover which are LVM devices.
|
||||
* Info about the LVM devices (PVs) is saved in lvmcache in a
|
||||
@@ -924,6 +1015,7 @@ static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_d
|
||||
int label_scan(struct cmd_context *cmd)
|
||||
{
|
||||
struct dm_list all_devs;
|
||||
struct dm_list filtered_devs;
|
||||
struct dm_list scan_devs;
|
||||
struct dm_list hints_list;
|
||||
struct dev_iter *iter;
|
||||
@@ -936,9 +1028,15 @@ int label_scan(struct cmd_context *cmd)
|
||||
log_debug_devs("Finding devices to scan");
|
||||
|
||||
dm_list_init(&all_devs);
|
||||
dm_list_init(&filtered_devs);
|
||||
dm_list_init(&scan_devs);
|
||||
dm_list_init(&hints_list);
|
||||
|
||||
if (!scan_bcache) {
|
||||
if (!_setup_bcache())
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_cache_scan() creates a list of devices on the system
|
||||
* (saved in in dev-cache) which we can iterate through to
|
||||
@@ -962,29 +1060,15 @@ int label_scan(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the iterator that is needed to step through each device in
|
||||
* dev cache.
|
||||
* Create a list of all devices in dev-cache (all found on the system.)
|
||||
* Do not apply filters and do not read any (the filter arg is NULL).
|
||||
* Invalidate bcache data for all devs (there will usually be no bcache
|
||||
* data to invalidate.)
|
||||
*/
|
||||
if (!(iter = dev_iter_create(cmd->filter, 0))) {
|
||||
if (!(iter = dev_iter_create(NULL, 0))) {
|
||||
log_error("Scanning failed to get devices.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_devs("Filtering devices to scan");
|
||||
|
||||
/*
|
||||
* Iterate through all devices in dev cache and apply filters
|
||||
* to exclude devs that we do not need to scan. Those devs
|
||||
* that pass the filters are returned by the iterator and
|
||||
* saved in a list of devs that we will proceed to scan to
|
||||
* check if they are LVM devs. IOW this loop is the
|
||||
* application of filters (those that do not require reading
|
||||
* the devs) to the list of all devices. It does that because
|
||||
* the 'cmd->filter' is used above when setting up the iterator.
|
||||
* Unfortunately, it's not obvious that this is what's happening
|
||||
* here. filters that require reading the device are not applied
|
||||
* here, but in process_block(), see DEV_FILTER_AFTER_SCAN.
|
||||
*/
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
continue;
|
||||
@@ -993,19 +1077,43 @@ int label_scan(struct cmd_context *cmd)
|
||||
|
||||
/*
|
||||
* label_scan should not generally be called a second time,
|
||||
* so this will usually not be true.
|
||||
* so this will usually do nothing.
|
||||
*/
|
||||
if (_in_bcache(dev)) {
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
label_scan_invalidate(dev);
|
||||
};
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
if (!scan_bcache) {
|
||||
if (!_setup_bcache())
|
||||
return 0;
|
||||
/*
|
||||
* Exclude devices that fail nodata filters. (Those filters that can be
|
||||
* checked without reading data from the device.)
|
||||
*
|
||||
* The result of checking nodata filters is saved by the "persistent
|
||||
* filter", and this result needs to be cleared (wiped) so that the
|
||||
* complete set of filters (including those that require data) can be
|
||||
* checked in _process_block, where headers have been read.
|
||||
*/
|
||||
log_debug_devs("Filtering devices to scan (nodata)");
|
||||
|
||||
cmd->filter_nodata_only = 1;
|
||||
dm_list_iterate_items_safe(devl, devl2, &all_devs) {
|
||||
dev = devl->dev;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, NULL)) {
|
||||
dm_list_del(&devl->list);
|
||||
dm_list_add(&filtered_devs, &devl->list);
|
||||
|
||||
if (dev->pvid[0]) {
|
||||
log_print("Clear pvid and info for filtered dev %s", dev_name(dev));
|
||||
lvmcache_del_dev(dev);
|
||||
memset(dev->pvid, 0, sizeof(dev->pvid));
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd->filter_nodata_only = 0;
|
||||
|
||||
dm_list_iterate_items(devl, &all_devs)
|
||||
cmd->filter->wipe(cmd, cmd->filter, devl->dev, NULL);
|
||||
dm_list_iterate_items(devl, &filtered_devs)
|
||||
cmd->filter->wipe(cmd, cmd->filter, devl->dev, NULL);
|
||||
|
||||
/*
|
||||
* In some common cases we can avoid scanning all devices
|
||||
@@ -1028,8 +1136,6 @@ int label_scan(struct cmd_context *cmd)
|
||||
} else
|
||||
using_hints = 1;
|
||||
|
||||
log_debug("Will scan %d devices skip %d", dm_list_size(&scan_devs), dm_list_size(&all_devs));
|
||||
|
||||
/*
|
||||
* If the total number of devices exceeds the soft open file
|
||||
* limit, then increase the soft limit to the hard/max limit
|
||||
@@ -1042,7 +1148,7 @@ int label_scan(struct cmd_context *cmd)
|
||||
/*
|
||||
* Do the main scan.
|
||||
*/
|
||||
_scan_list(cmd, cmd->filter, &scan_devs, NULL);
|
||||
_scan_list(cmd, cmd->filter, &scan_devs, 0, NULL);
|
||||
|
||||
/*
|
||||
* Metadata could be larger than total size of bcache, and bcache
|
||||
@@ -1089,8 +1195,8 @@ int label_scan(struct cmd_context *cmd)
|
||||
if (using_hints) {
|
||||
if (!validate_hints(cmd, &hints_list)) {
|
||||
log_debug("Will scan %d remaining devices", dm_list_size(&all_devs));
|
||||
_scan_list(cmd, cmd->filter, &all_devs, NULL);
|
||||
_free_hints(&hints_list);
|
||||
_scan_list(cmd, cmd->filter, &all_devs, 0, NULL);
|
||||
free_hints(&hints_list);
|
||||
using_hints = 0;
|
||||
create_hints = 0;
|
||||
} else {
|
||||
@@ -1150,6 +1256,69 @@ int label_scan(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the header of the disk and if it's a PV
|
||||
* save the pvid in dev->pvid.
|
||||
*/
|
||||
int label_read_pvid(struct device *dev)
|
||||
{
|
||||
char buf[4096] __attribute__((aligned(8)));
|
||||
struct label_header *lh;
|
||||
struct pv_header *pvh;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (!label_scan_open(dev))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* We could do:
|
||||
* dev_read_bytes(dev, 512, LABEL_SIZE, buf);
|
||||
* which works, but there's a bcache issue that
|
||||
* prevents proper invalidation after that.
|
||||
*/
|
||||
if (!dev_read_bytes(dev, 0, 4096, buf)) {
|
||||
label_scan_invalidate(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lh = (struct label_header *)(buf + 512);
|
||||
if (memcmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
/* Not an lvm deice */
|
||||
label_scan_invalidate(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* wipefs -a just clears the type field, leaving the
|
||||
* rest of the label_header intact.
|
||||
*/
|
||||
if (memcmp(lh->type, LVM2_LABEL, sizeof(lh->type))) {
|
||||
/* Not an lvm deice */
|
||||
label_scan_invalidate(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvh = (struct pv_header *)(buf + 512 + 32);
|
||||
memcpy(dev->pvid, pvh->pv_uuid, ID_LEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* label_scan_devs without invalidating data for the devs first,
|
||||
* when the caller wants to make use of any bcache data that
|
||||
* they may have already read.
|
||||
*/
|
||||
int label_scan_devs_cached(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs)
|
||||
{
|
||||
if (!scan_bcache)
|
||||
return 0;
|
||||
|
||||
_scan_list(cmd, f, devs, 0, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan and cache lvm data from the listed devices. If a device is already
|
||||
* scanned and cached, this replaces the previously cached lvm data for the
|
||||
@@ -1168,23 +1337,15 @@ int label_scan_devs(struct cmd_context *cmd, struct dev_filter *f, struct dm_lis
|
||||
}
|
||||
|
||||
dm_list_iterate_items(devl, devs) {
|
||||
if (_in_bcache(devl->dev)) {
|
||||
bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
|
||||
_scan_dev_close(devl->dev);
|
||||
}
|
||||
if (_in_bcache(devl->dev))
|
||||
_invalidate_di(scan_bcache, devl->dev->bcache_di);
|
||||
}
|
||||
|
||||
_scan_list(cmd, f, devs, NULL);
|
||||
_scan_list(cmd, f, devs, 0, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used when the caller plans to write to the devs, so opening
|
||||
* them RW during rescan avoids needing to close and reopen with WRITE in
|
||||
* dev_write_bytes.
|
||||
*/
|
||||
|
||||
int label_scan_devs_rw(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs)
|
||||
{
|
||||
struct device_list *devl;
|
||||
@@ -1195,40 +1356,32 @@ int label_scan_devs_rw(struct cmd_context *cmd, struct dev_filter *f, struct dm_
|
||||
}
|
||||
|
||||
dm_list_iterate_items(devl, devs) {
|
||||
if (_in_bcache(devl->dev)) {
|
||||
bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
|
||||
_scan_dev_close(devl->dev);
|
||||
}
|
||||
/*
|
||||
* With this flag set, _scan_dev_open() done by
|
||||
* _scan_list() will do open RW
|
||||
*/
|
||||
if (_in_bcache(devl->dev))
|
||||
_invalidate_di(scan_bcache, devl->dev->bcache_di);
|
||||
devl->dev->flags |= DEV_BCACHE_WRITE;
|
||||
}
|
||||
|
||||
_scan_list(cmd, f, devs, NULL);
|
||||
_scan_list(cmd, f, devs, 0, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int label_scan_devs_excl(struct dm_list *devs)
|
||||
int label_scan_devs_excl(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs)
|
||||
{
|
||||
struct device_list *devl;
|
||||
int failed = 0;
|
||||
|
||||
dm_list_iterate_items(devl, devs) {
|
||||
if (_in_bcache(devl->dev)) {
|
||||
bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
|
||||
_scan_dev_close(devl->dev);
|
||||
}
|
||||
label_scan_invalidate(devl->dev);
|
||||
/*
|
||||
* With this flag set, _scan_dev_open() done by
|
||||
* _scan_list() will do open EXCL
|
||||
*/
|
||||
devl->dev->flags |= DEV_BCACHE_EXCL;
|
||||
devl->dev->flags |= DEV_BCACHE_WRITE;
|
||||
}
|
||||
|
||||
_scan_list(NULL, NULL, devs, &failed);
|
||||
_scan_list(cmd, f, devs, 1, &failed);
|
||||
|
||||
if (failed)
|
||||
return 0;
|
||||
@@ -1238,7 +1391,7 @@ int label_scan_devs_excl(struct dm_list *devs)
|
||||
void label_scan_invalidate(struct device *dev)
|
||||
{
|
||||
if (_in_bcache(dev)) {
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
}
|
||||
@@ -1306,7 +1459,7 @@ void label_scan_destroy(struct cmd_context *cmd)
|
||||
* device, this is not a commonly used function.
|
||||
*/
|
||||
|
||||
int label_read(struct device *dev)
|
||||
int label_scan_dev(struct device *dev)
|
||||
{
|
||||
struct dm_list one_dev;
|
||||
struct device_list *devl;
|
||||
@@ -1319,12 +1472,9 @@ int label_read(struct device *dev)
|
||||
dm_list_init(&one_dev);
|
||||
dm_list_add(&one_dev, &devl->list);
|
||||
|
||||
if (_in_bcache(dev)) {
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
label_scan_invalidate(dev);
|
||||
|
||||
_scan_list(NULL, NULL, &one_dev, &failed);
|
||||
_scan_list(NULL, NULL, &one_dev, 0, &failed);
|
||||
|
||||
free(devl);
|
||||
|
||||
@@ -1347,7 +1497,7 @@ int label_scan_setup_bcache(void)
|
||||
* This is needed to write to a new non-lvm device.
|
||||
* Scanning that dev would not keep it open or in
|
||||
* bcache, but to use bcache_write we need the dev
|
||||
* to be open so we can use dev->bcache_fd to write.
|
||||
* to be open so we can use dev->bcache_di to write.
|
||||
*/
|
||||
|
||||
int label_scan_open(struct device *dev)
|
||||
@@ -1360,9 +1510,8 @@ int label_scan_open(struct device *dev)
|
||||
int label_scan_open_excl(struct device *dev)
|
||||
{
|
||||
if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_EXCL)) {
|
||||
/* FIXME: avoid tossing out bcache blocks just to replace fd. */
|
||||
log_debug("Close and reopen excl %s", dev_name(dev));
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
log_debug("close and reopen excl %s", dev_name(dev));
|
||||
_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
dev->flags |= DEV_BCACHE_EXCL;
|
||||
@@ -1373,15 +1522,77 @@ int label_scan_open_excl(struct device *dev)
|
||||
int label_scan_open_rw(struct device *dev)
|
||||
{
|
||||
if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) {
|
||||
/* FIXME: avoid tossing out bcache blocks just to replace fd. */
|
||||
log_debug("Close and reopen rw %s", dev_name(dev));
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
log_debug("close and reopen rw %s", dev_name(dev));
|
||||
_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
return label_scan_open(dev);
|
||||
}
|
||||
|
||||
int label_scan_reopen_rw(struct device *dev)
|
||||
{
|
||||
int flags = 0;
|
||||
int prev_fd = dev->bcache_fd;
|
||||
int fd;
|
||||
|
||||
if (!(dev->flags & DEV_IN_BCACHE)) {
|
||||
if ((dev->bcache_fd != -1) || (dev->bcache_di != -1)) {
|
||||
/* shouldn't happen */
|
||||
log_debug("Reopen writeable %s uncached fd %d di %d",
|
||||
dev_name(dev), dev->bcache_fd, dev->bcache_di);
|
||||
return 0;
|
||||
}
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
return _scan_dev_open(dev);
|
||||
}
|
||||
|
||||
if ((dev->flags & DEV_BCACHE_WRITE))
|
||||
return 1;
|
||||
|
||||
if (dev->bcache_fd == -1) {
|
||||
log_error("Failed to open writable %s index %d fd none",
|
||||
dev_name(dev), dev->bcache_di);
|
||||
return 0;
|
||||
}
|
||||
if (dev->bcache_di == -1) {
|
||||
log_error("Failed to open writeable %s index none fd %d",
|
||||
dev_name(dev), dev->bcache_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
flags |= O_DIRECT;
|
||||
flags |= O_NOATIME;
|
||||
flags |= O_RDWR;
|
||||
|
||||
fd = open(dev_name(dev), flags, 0777);
|
||||
if (fd < 0) {
|
||||
log_error("Failed to open rw %s errno %d di %d fd %d.",
|
||||
dev_name(dev), errno, dev->bcache_di, dev->bcache_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bcache_change_fd(dev->bcache_di, fd)) {
|
||||
log_error("Failed to change to rw fd %s di %d fd %d.",
|
||||
dev_name(dev), dev->bcache_di, fd);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (close(dev->bcache_fd))
|
||||
log_debug("reopen writeable %s close prev errno %d di %d fd %d.",
|
||||
dev_name(dev), errno, dev->bcache_di, dev->bcache_fd);
|
||||
|
||||
dev->flags |= DEV_IN_BCACHE;
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
dev->bcache_fd = fd;
|
||||
|
||||
log_debug("reopen writable %s di %d prev %d fd %d",
|
||||
dev_name(dev), dev->bcache_di, prev_fd, fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool dev_read_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
{
|
||||
if (!scan_bcache) {
|
||||
@@ -1390,7 +1601,7 @@ bool dev_read_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dev->bcache_fd <= 0) {
|
||||
if (dev->bcache_di < 0) {
|
||||
/* This is not often needed. */
|
||||
if (!label_scan_open(dev)) {
|
||||
log_error("Error opening device %s for reading at %llu length %u.",
|
||||
@@ -1399,7 +1610,7 @@ bool dev_read_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
if (!bcache_read_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
|
||||
if (!bcache_read_bytes(scan_bcache, dev->bcache_di, start, len, data)) {
|
||||
log_error("Error reading device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
label_scan_invalidate(dev);
|
||||
@@ -1422,15 +1633,15 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
|
||||
if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) {
|
||||
/* FIXME: avoid tossing out bcache blocks just to replace fd. */
|
||||
log_debug("Close and reopen to write %s", dev_name(dev));
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
log_debug("close and reopen to write %s", dev_name(dev));
|
||||
_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
_scan_dev_close(dev);
|
||||
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
label_scan_open(dev);
|
||||
}
|
||||
|
||||
if (dev->bcache_fd <= 0) {
|
||||
if (dev->bcache_di < 0) {
|
||||
/* This is not often needed. */
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
if (!label_scan_open(dev)) {
|
||||
@@ -1440,9 +1651,10 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
if (!bcache_write_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
|
||||
if (!bcache_write_bytes(scan_bcache, dev->bcache_di, start, len, data)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
@@ -1450,65 +1662,27 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
if (!bcache_flush(scan_bcache)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
|
||||
{
|
||||
return bcache_invalidate_bytes(scan_bcache, dev->bcache_di, start, len);
|
||||
}
|
||||
|
||||
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len)
|
||||
{
|
||||
if (test_mode())
|
||||
return true;
|
||||
|
||||
if (!scan_bcache) {
|
||||
log_error("dev_write_zeros bcache not set up %s", dev_name(dev));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) {
|
||||
/* FIXME: avoid tossing out bcache blocks just to replace fd. */
|
||||
log_debug("Close and reopen to write %s", dev_name(dev));
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
_scan_dev_close(dev);
|
||||
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
label_scan_open(dev);
|
||||
}
|
||||
|
||||
if (dev->bcache_fd <= 0) {
|
||||
/* This is not often needed. */
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
if (!label_scan_open(dev)) {
|
||||
log_error("Error opening device %s for writing at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_last_byte(dev, start + len);
|
||||
|
||||
if (!bcache_zero_bytes(scan_bcache, dev->bcache_fd, start, len)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bcache_flush(scan_bcache)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
dev_unset_last_byte(dev);
|
||||
return true;
|
||||
return dev_set_bytes(dev, start, len, 0);
|
||||
}
|
||||
|
||||
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val)
|
||||
{
|
||||
bool rv;
|
||||
|
||||
if (test_mode())
|
||||
return true;
|
||||
|
||||
@@ -1518,14 +1692,13 @@ bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val)
|
||||
}
|
||||
|
||||
if (_in_bcache(dev) && !(dev->flags & DEV_BCACHE_WRITE)) {
|
||||
/* FIXME: avoid tossing out bcache blocks just to replace fd. */
|
||||
log_debug("Close and reopen to write %s", dev_name(dev));
|
||||
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
|
||||
log_debug("close and reopen to write %s", dev_name(dev));
|
||||
_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
_scan_dev_close(dev);
|
||||
/* goes to label_scan_open() since bcache_fd < 0 */
|
||||
/* goes to label_scan_open() since bcache_di < 0 */
|
||||
}
|
||||
|
||||
if (dev->bcache_fd <= 0) {
|
||||
if (dev->bcache_di == -1) {
|
||||
/* This is not often needed. */
|
||||
dev->flags |= DEV_BCACHE_WRITE;
|
||||
if (!label_scan_open(dev)) {
|
||||
@@ -1537,24 +1710,30 @@ bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val)
|
||||
|
||||
dev_set_last_byte(dev, start + len);
|
||||
|
||||
if (!bcache_set_bytes(scan_bcache, dev->bcache_fd, start, len, val)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
if (!val)
|
||||
rv = bcache_zero_bytes(scan_bcache, dev->bcache_di, start, len);
|
||||
else
|
||||
rv = bcache_set_bytes(scan_bcache, dev->bcache_di, start, len, val);
|
||||
|
||||
if (!rv) {
|
||||
log_error("Error writing device value %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!bcache_flush(scan_bcache)) {
|
||||
log_error("Error writing device %s at %llu length %u.",
|
||||
dev_name(dev), (unsigned long long)start, (uint32_t)len);
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev_unset_last_byte(dev);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
dev_unset_last_byte(dev);
|
||||
label_scan_invalidate(dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
void dev_set_last_byte(struct device *dev, uint64_t offset)
|
||||
@@ -1586,11 +1765,10 @@ void dev_set_last_byte(struct device *dev, uint64_t offset)
|
||||
bs = 512;
|
||||
}
|
||||
|
||||
bcache_set_last_byte(scan_bcache, dev->bcache_fd, offset, bs);
|
||||
bcache_set_last_byte(scan_bcache, dev->bcache_di, offset, bs);
|
||||
}
|
||||
|
||||
void dev_unset_last_byte(struct device *dev)
|
||||
{
|
||||
bcache_unset_last_byte(scan_bcache, dev->bcache_fd);
|
||||
bcache_unset_last_byte(scan_bcache, dev->bcache_di);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ struct label_ops {
|
||||
/*
|
||||
* Read a label from a volume.
|
||||
*/
|
||||
int (*read) (struct labeller * l, struct device * dev,
|
||||
int (*read) (struct cmd_context *cmd, struct labeller * l, struct device * dev,
|
||||
void *label_buf, uint64_t label_sector, int *is_duplicate);
|
||||
|
||||
/*
|
||||
@@ -104,19 +104,23 @@ extern struct bcache *scan_bcache;
|
||||
|
||||
int label_scan(struct cmd_context *cmd);
|
||||
int label_scan_devs(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs);
|
||||
int label_scan_devs_cached(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs);
|
||||
int label_scan_devs_rw(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs);
|
||||
int label_scan_devs_excl(struct dm_list *devs);
|
||||
int label_scan_devs_excl(struct cmd_context *cmd, struct dev_filter *f, struct dm_list *devs);
|
||||
int label_scan_dev(struct device *dev);
|
||||
void label_scan_invalidate(struct device *dev);
|
||||
void label_scan_invalidate_lv(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
void label_scan_drop(struct cmd_context *cmd);
|
||||
void label_scan_destroy(struct cmd_context *cmd);
|
||||
int label_read(struct device *dev);
|
||||
int label_read_sector(struct device *dev, uint64_t scan_sector);
|
||||
void label_scan_confirm(struct device *dev);
|
||||
int label_scan_setup_bcache(void);
|
||||
int label_scan_open(struct device *dev);
|
||||
int label_scan_open_excl(struct device *dev);
|
||||
int label_scan_open_rw(struct device *dev);
|
||||
int label_scan_reopen_rw(struct device *dev);
|
||||
int label_read_pvid(struct device *dev);
|
||||
|
||||
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out);
|
||||
|
||||
/*
|
||||
* Wrappers around bcache equivalents.
|
||||
@@ -126,6 +130,7 @@ bool dev_read_bytes(struct device *dev, uint64_t start, size_t len, void *data);
|
||||
bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data);
|
||||
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
|
||||
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
|
||||
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len);
|
||||
void dev_set_last_byte(struct device *dev, uint64_t offset);
|
||||
void dev_unset_last_byte(struct device *dev);
|
||||
|
||||
|
||||
@@ -183,7 +183,11 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t fla
|
||||
|
||||
block_signals(flags);
|
||||
|
||||
ret = _locking.lock_resource(cmd, resource, flags, NULL);
|
||||
if ((ret = _locking.lock_resource(cmd, resource, flags, NULL)))
|
||||
/* ensure signals are blocked while VG_GLOBAL lock is held */
|
||||
_update_vg_lock_count(resource, flags);
|
||||
else
|
||||
stack;
|
||||
|
||||
_unblock_signals();
|
||||
|
||||
@@ -287,8 +291,6 @@ out_hold:
|
||||
else if (lck_type == LCK_UNLOCK)
|
||||
lvmcache_unlock_vgname(resource);
|
||||
|
||||
/* FIXME: we shouldn't need to keep track of this either. */
|
||||
_update_vg_lock_count(resource, flags);
|
||||
return 1;
|
||||
|
||||
out_fail:
|
||||
@@ -338,7 +340,7 @@ int sync_local_dev_names(struct cmd_context* cmd)
|
||||
* an explicitly acquired ex global lock to sh in process_each.
|
||||
*/
|
||||
|
||||
static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
|
||||
static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert, int nonblock)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
int ret;
|
||||
@@ -346,6 +348,9 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
|
||||
if (convert)
|
||||
flags |= LCK_CONVERT;
|
||||
|
||||
if (nonblock)
|
||||
flags |= LCK_NONBLOCK;
|
||||
|
||||
if (!strcmp(mode, "ex")) {
|
||||
flags |= LCK_WRITE;
|
||||
|
||||
@@ -379,7 +384,7 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
|
||||
|
||||
int lockf_global(struct cmd_context *cmd, const char *mode)
|
||||
{
|
||||
return _lockf_global(cmd, mode, 0);
|
||||
return _lockf_global(cmd, mode, 0, 0);
|
||||
}
|
||||
|
||||
int lockf_global_convert(struct cmd_context *cmd, const char *mode)
|
||||
@@ -388,7 +393,12 @@ int lockf_global_convert(struct cmd_context *cmd, const char *mode)
|
||||
if (cmd->lockf_global_ex && !strcmp(mode, "ex"))
|
||||
return 1;
|
||||
|
||||
return _lockf_global(cmd, mode, 1);
|
||||
return _lockf_global(cmd, mode, 1, 0);
|
||||
}
|
||||
|
||||
int lockf_global_nonblock(struct cmd_context *cmd, const char *mode)
|
||||
{
|
||||
return _lockf_global(cmd, mode, 0, 1);
|
||||
}
|
||||
|
||||
int lock_global(struct cmd_context *cmd, const char *mode)
|
||||
|
||||
@@ -75,6 +75,7 @@ int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusiv
|
||||
|
||||
int lockf_global(struct cmd_context *cmd, const char *mode);
|
||||
int lockf_global_convert(struct cmd_context *cmd, const char *mode);
|
||||
int lockf_global_nonblock(struct cmd_context *cmd, const char *mode);
|
||||
int lock_global(struct cmd_context *cmd, const char *mode);
|
||||
int lock_global_convert(struct cmd_context *cmd, const char *mode);
|
||||
|
||||
|
||||
@@ -635,7 +635,6 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in
|
||||
const char *vg_lock_args = NULL;
|
||||
const char *opts = NULL;
|
||||
struct pv_list *pvl;
|
||||
struct device *sector_dev;
|
||||
uint32_t sector_size = 0;
|
||||
unsigned int physical_block_size, logical_block_size;
|
||||
int num_mb = 0;
|
||||
@@ -656,16 +655,11 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!dev_get_direct_block_sizes(pvl->pv->dev, &physical_block_size, &logical_block_size))
|
||||
continue;
|
||||
|
||||
if (!sector_size) {
|
||||
sector_size = logical_block_size;
|
||||
sector_dev = pvl->pv->dev;
|
||||
} else if (sector_size != logical_block_size) {
|
||||
log_error("Inconsistent logical block sizes for %s and %s.",
|
||||
dev_name(pvl->pv->dev), dev_name(sector_dev));
|
||||
return 0;
|
||||
}
|
||||
if ((physical_block_size == 4096) || (logical_block_size == 4096))
|
||||
sector_size = 4096;
|
||||
}
|
||||
if (!sector_size)
|
||||
sector_size = 512;
|
||||
|
||||
log_debug("Using sector size %u for sanlock LV", sector_size);
|
||||
|
||||
@@ -2092,7 +2086,8 @@ static int _query_lock_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
log_error("Lock query failed for LV %s/%s", vg->name, lv_name);
|
||||
return 0;
|
||||
} else {
|
||||
ret = (result < 0) ? 0 : 1;
|
||||
/* ENOENT => The lv was not active/locked. */
|
||||
ret = (result < 0 && (result != -ENOENT)) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
@@ -2110,11 +2105,7 @@ static int _query_lock_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
/* The lv was not active/locked. */
|
||||
if (result == -ENOENT)
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2320,6 +2311,49 @@ static int _lockd_lv_thin(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
pool_lv->lock_args, def_mode, flags);
|
||||
}
|
||||
|
||||
static int _lockd_lv_vdo(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const char *def_mode, uint32_t flags)
|
||||
{
|
||||
struct logical_volume *pool_lv = NULL;
|
||||
|
||||
if (lv_is_vdo(lv)) {
|
||||
if (first_seg(lv))
|
||||
pool_lv = seg_lv(first_seg(lv), 0);
|
||||
|
||||
} else if (lv_is_vdo_pool(lv)) {
|
||||
pool_lv = lv;
|
||||
|
||||
} else if (lv_is_vdo_pool_data(lv)) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* This should not happen AFAIK. */
|
||||
log_error("Lock on incorrect vdo lv type %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pool_lv) {
|
||||
/* This happens in lvremove where it's harmless. */
|
||||
log_debug("No vdo pool for %s/%s", lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locking a locked lv (pool in this case) is a no-op.
|
||||
* Unlock when the pool is no longer active.
|
||||
*/
|
||||
|
||||
if (def_mode && !strcmp(def_mode, "un") &&
|
||||
lv_is_vdo_pool(pool_lv) && lv_is_active(lv_lock_holder(pool_lv)))
|
||||
return 1;
|
||||
|
||||
flags |= LDLV_MODE_NO_SH;
|
||||
|
||||
return lockd_lv_name(cmd, pool_lv->vg, pool_lv->name, &pool_lv->lvid.id[1],
|
||||
pool_lv->lock_args, def_mode, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the VG has no lock_type, then this function can return immediately.
|
||||
* The LV itself may have no lock (NULL lv->lock_args), but the lock request
|
||||
@@ -2361,12 +2395,23 @@ int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (lv_is_thin_type(lv))
|
||||
return _lockd_lv_thin(cmd, lv, def_mode, flags);
|
||||
|
||||
if (lv_is_vdo_type(lv))
|
||||
return _lockd_lv_vdo(cmd, lv, def_mode, flags);
|
||||
|
||||
/*
|
||||
* An LV with NULL lock_args does not have a lock of its own.
|
||||
*/
|
||||
if (!lv->lock_args)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* A cachevol LV is one exception, where the LV keeps lock_args (so
|
||||
* they do not need to be reallocated on split) but the lvmlockd lock
|
||||
* is not used.
|
||||
*/
|
||||
if (lv_is_cache_vol(lv))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* LV type cannot be active concurrently on multiple hosts,
|
||||
* so shared mode activation is not allowed.
|
||||
@@ -2375,6 +2420,7 @@ int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
lv_is_thin_type(lv) ||
|
||||
lv_is_mirror_type(lv) ||
|
||||
lv_is_raid_type(lv) ||
|
||||
lv_is_vdo_type(lv) ||
|
||||
lv_is_cache_type(lv)) {
|
||||
flags |= LDLV_MODE_NO_SH;
|
||||
}
|
||||
@@ -2674,7 +2720,7 @@ int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logic
|
||||
log_error("Failed to find origin LV %s/%s", vg->name, lp->origin_name);
|
||||
return 0;
|
||||
}
|
||||
if (!lockd_lv(cmd, origin_lv, "ex", LDLV_PERSISTENT)) {
|
||||
if (!lockd_lv(cmd, origin_lv, "ex", 0)) {
|
||||
log_error("Failed to lock origin LV %s/%s", vg->name, lp->origin_name);
|
||||
return 0;
|
||||
}
|
||||
@@ -2724,6 +2770,27 @@ int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logic
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (seg_is_vdo(lp)) {
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* A vdo lv is being created in a vdo pool. The vdo lv does
|
||||
* not have its own lock, the lock of the vdo pool is used, and
|
||||
* the vdo pool needs to be locked to create a vdo lv in it.
|
||||
*/
|
||||
|
||||
if (!(lvl = find_lv_in_vg(vg, lp->pool_name))) {
|
||||
log_error("Failed to find vdo pool %s/%s", vg->name, lp->pool_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lockd_lv(cmd, lvl->lv, "ex", LDLV_PERSISTENT)) {
|
||||
log_error("Failed to lock vdo pool %s/%s", vg->name, lp->pool_name);
|
||||
return 0;
|
||||
}
|
||||
lv->lock_args = NULL;
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/* Creating a normal lv. */
|
||||
/* lv_name_lock = lv_name; */
|
||||
@@ -2963,6 +3030,12 @@ int lockd_lv_uses_lock(struct logical_volume *lv)
|
||||
if (lv_is_pool_metadata_spare(lv))
|
||||
return 0;
|
||||
|
||||
if (lv_is_vdo(lv))
|
||||
return 0;
|
||||
|
||||
if (lv_is_vdo_pool_data(lv))
|
||||
return 0;
|
||||
|
||||
if (lv_is_cache_vol(lv))
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "lib/config/defaults.h"
|
||||
#include "lib/metadata/lv_alloc.h"
|
||||
#include "lib/misc/lvm-signal.h"
|
||||
#include "lib/activate/dev_manager.h"
|
||||
|
||||
/* https://github.com/jthornber/thin-provisioning-tools/blob/master/caching/cache_metadata_size.cc */
|
||||
#define DM_TRANSACTION_OVERHEAD 4096 /* KiB */
|
||||
@@ -223,7 +222,7 @@ int update_cache_pool_params(struct cmd_context *cmd,
|
||||
*chunk_size = get_default_allocation_cache_pool_chunk_size_CFG(cmd,
|
||||
profile);
|
||||
/* Use power-of-2 for min chunk size when unspecified */
|
||||
min_chunk_size = 1 << (32 - clz(min_chunk_size - 1));
|
||||
min_chunk_size = UINT64_C(1) << (32 - clz(min_chunk_size - 1));
|
||||
}
|
||||
if (*chunk_size < min_chunk_size) {
|
||||
/*
|
||||
@@ -481,7 +480,7 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
|
||||
const struct logical_volume *lock_lv = lv_lock_holder(cache_lv);
|
||||
struct lv_segment *cache_seg = first_seg(cache_lv);
|
||||
struct lv_status_cache *status;
|
||||
int cleaner_policy, writeback;
|
||||
int cleaner_policy = 0, writeback;
|
||||
uint64_t dirty_blocks;
|
||||
|
||||
*is_clean = 0;
|
||||
@@ -489,6 +488,9 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
|
||||
//FIXME: use polling to do this...
|
||||
for (;;) {
|
||||
sigint_allow();
|
||||
if (cleaner_policy)
|
||||
/* TODO: Use centralized place */
|
||||
usleep(500000);
|
||||
sigint_restore();
|
||||
if (sigint_caught()) {
|
||||
sigint_clear();
|
||||
@@ -524,13 +526,8 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
|
||||
log_print_unless_silent("Flushing " FMTu64 " blocks for cache %s.",
|
||||
dirty_blocks, display_lvname(cache_lv));
|
||||
|
||||
if (cleaner_policy) {
|
||||
/* TODO: Use centralized place */
|
||||
sigint_allow();
|
||||
usleep(500000);
|
||||
sigint_restore();
|
||||
if (cleaner_policy)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(cache_lv->status & LVM_WRITE)) {
|
||||
log_warn("WARNING: Dirty blocks found on read-only cache volume %s.",
|
||||
@@ -1095,6 +1092,10 @@ int cache_vol_set_params(struct cmd_context *cmd,
|
||||
if (!meta_size) {
|
||||
meta_size = _cache_min_metadata_size(pool_lv->size, chunk_size);
|
||||
|
||||
/* fix bad value from _cache_min_metadata_size */
|
||||
if (meta_size > (pool_lv->size / 2))
|
||||
meta_size = pool_lv->size / 2;
|
||||
|
||||
if (meta_size < min_meta_size)
|
||||
meta_size = min_meta_size;
|
||||
|
||||
|
||||
941
lib/metadata/integrity_manip.c
Normal file
941
lib/metadata/integrity_manip.c
Normal file
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/metadata/metadata.h"
|
||||
#include "lib/locking/locking.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/display/display.h"
|
||||
#include "lib/metadata/segtype.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/config/defaults.h"
|
||||
|
||||
#define DEFAULT_TAG_SIZE 4 /* bytes */
|
||||
#define DEFAULT_MODE 'J'
|
||||
#define DEFAULT_INTERNAL_HASH "crc32c"
|
||||
#define DEFAULT_BLOCK_SIZE 512
|
||||
|
||||
#define ONE_MB_IN_BYTES 1048576
|
||||
#define ONE_GB_IN_BYTES 1073741824
|
||||
|
||||
int lv_is_integrity_origin(const struct logical_volume *lv)
|
||||
{
|
||||
struct seg_list *sl;
|
||||
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
if (!sl->seg || !sl->seg->lv || !sl->seg->origin)
|
||||
continue;
|
||||
if (lv_is_integrity(sl->seg->lv) && (sl->seg->origin == lv))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Every 500M of data needs 4M of metadata.
|
||||
* (From trial and error testing.)
|
||||
*
|
||||
* plus some initial space for journals.
|
||||
* (again from trial and error testing.)
|
||||
*/
|
||||
static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
|
||||
{
|
||||
uint64_t meta_bytes;
|
||||
uint64_t initial_bytes;
|
||||
|
||||
/* Every 500M of data needs 4M of metadata. */
|
||||
meta_bytes = ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES);
|
||||
|
||||
/*
|
||||
* initial space used for journals
|
||||
* lv_size <= 512M -> 4M
|
||||
* lv_size <= 1G -> 8M
|
||||
* lv_size <= 4G -> 32M
|
||||
* lv_size > 4G -> 64M
|
||||
*/
|
||||
if (lv_size_bytes <= (512 * ONE_MB_IN_BYTES))
|
||||
initial_bytes = 4 * ONE_MB_IN_BYTES;
|
||||
else if (lv_size_bytes <= ONE_GB_IN_BYTES)
|
||||
initial_bytes = 8 * ONE_MB_IN_BYTES;
|
||||
else if (lv_size_bytes <= (4ULL * ONE_GB_IN_BYTES))
|
||||
initial_bytes = 32 * ONE_MB_IN_BYTES;
|
||||
else if (lv_size_bytes > (4ULL * ONE_GB_IN_BYTES))
|
||||
initial_bytes = 64 * ONE_MB_IN_BYTES;
|
||||
|
||||
return meta_bytes + initial_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* The user wants external metadata, but did not specify an existing
|
||||
* LV to hold metadata, so create an LV for metadata.
|
||||
*/
|
||||
static int _lv_create_integrity_metadata(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct lvcreate_params *lp,
|
||||
struct logical_volume **meta_lv)
|
||||
{
|
||||
char metaname[NAME_LEN];
|
||||
uint64_t lv_size_bytes, meta_bytes, meta_sectors;
|
||||
struct logical_volume *lv;
|
||||
struct lvcreate_params lp_meta = {
|
||||
.activate = CHANGE_AN,
|
||||
.alloc = ALLOC_INHERIT,
|
||||
.major = -1,
|
||||
.minor = -1,
|
||||
.permission = LVM_READ | LVM_WRITE,
|
||||
.pvh = &vg->pvs,
|
||||
.read_ahead = DM_READ_AHEAD_NONE,
|
||||
.stripes = 1,
|
||||
.vg_name = vg->name,
|
||||
.zero = 0,
|
||||
.wipe_signatures = 0,
|
||||
.suppress_zero_warn = 1,
|
||||
};
|
||||
|
||||
if (lp->lv_name &&
|
||||
dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) {
|
||||
log_error("Failed to create metadata LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp_meta.lv_name = metaname;
|
||||
lp_meta.pvh = lp->pvh;
|
||||
|
||||
lv_size_bytes = (uint64_t)lp->extents * (uint64_t)vg->extent_size * 512;
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
|
||||
meta_sectors = meta_bytes / 512;
|
||||
lp_meta.extents = meta_sectors / vg->extent_size;
|
||||
|
||||
log_print_unless_silent("Creating integrity metadata LV %s with size %s.",
|
||||
metaname, display_size(cmd, meta_sectors));
|
||||
|
||||
dm_list_init(&lp_meta.tags);
|
||||
|
||||
if (!(lp_meta.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!(lv = lv_create_single(vg, &lp_meta))) {
|
||||
log_error("Failed to create integrity metadata LV");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_list_size(&lv->segments) > 1) {
|
||||
log_error("Integrity metadata uses more than one segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*meta_lv = lv;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh)
|
||||
{
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct volume_group *vg = lv->vg;
|
||||
const struct segment_type *segtype;
|
||||
struct lv_segment *seg_top, *seg_image;
|
||||
struct logical_volume *lv_image;
|
||||
struct logical_volume *lv_iorig;
|
||||
struct logical_volume *lv_imeta;
|
||||
struct dm_list allocatable_pvs;
|
||||
struct dm_list *use_pvh;
|
||||
uint64_t lv_size_bytes, meta_bytes, meta_sectors, prev_meta_sectors;
|
||||
uint32_t meta_extents, prev_meta_extents;
|
||||
uint32_t area_count, s;
|
||||
|
||||
if (!lv_is_raid(lv))
|
||||
return_0;
|
||||
|
||||
seg_top = first_seg(lv);
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
area_count = seg_top->area_count;
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (!(lv_imeta = seg_image->integrity_meta_dev)) {
|
||||
log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv_iorig = seg_lv(seg_image, 0))) {
|
||||
log_error("LV %s integrity segment has no origin", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv_size_bytes = lv_iorig->size * 512;
|
||||
meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
|
||||
meta_sectors = meta_bytes / 512;
|
||||
meta_extents = meta_sectors / vg->extent_size;
|
||||
|
||||
prev_meta_sectors = lv_imeta->size;
|
||||
prev_meta_extents = prev_meta_sectors / vg->extent_size;
|
||||
|
||||
if (meta_extents <= prev_meta_extents) {
|
||||
log_debug("extend not needed for imeta LV %s", lv_imeta->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only allow lv_imeta to exist on a single PV (for now),
|
||||
* so the allocatable_pvs is the one PV currently used by
|
||||
* lv_imeta.
|
||||
*/
|
||||
dm_list_init(&allocatable_pvs);
|
||||
|
||||
if (!get_pv_list_for_lv(cmd->mem, lv_imeta, &allocatable_pvs)) {
|
||||
log_error("Failed to build list of PVs for extending %s.", display_lvname(lv_imeta));
|
||||
return 0;
|
||||
}
|
||||
|
||||
use_pvh = &allocatable_pvs;
|
||||
|
||||
if (!lv_extend(lv_imeta, segtype, 1, 0, 0, 0,
|
||||
meta_extents - prev_meta_extents,
|
||||
use_pvh, lv_imeta->alloc, 0)) {
|
||||
log_error("Failed to extend integrity metadata LV %s", lv_imeta->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_remove_integrity_from_raid(struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *iorig_lvs[DEFAULT_RAID_MAX_IMAGES];
|
||||
struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct lv_segment *seg_top, *seg_image;
|
||||
struct logical_volume *lv_image;
|
||||
struct logical_volume *lv_iorig;
|
||||
struct logical_volume *lv_imeta;
|
||||
uint32_t area_count, s;
|
||||
int is_active = lv_is_active(lv);
|
||||
|
||||
seg_top = first_seg(lv);
|
||||
|
||||
if (!seg_is_raid1(seg_top) && !seg_is_raid4(seg_top) &&
|
||||
!seg_is_any_raid5(seg_top) && !seg_is_any_raid6(seg_top) &&
|
||||
!seg_is_any_raid10(seg_top)) {
|
||||
log_error("LV %s segment is unsupported raid for integrity.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
area_count = seg_top->area_count;
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (!(lv_imeta = seg_image->integrity_meta_dev)) {
|
||||
log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv_iorig = seg_lv(seg_image, 0))) {
|
||||
log_error("LV %s integrity segment has no origin", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!remove_seg_from_segs_using_this_lv(seg_image->integrity_meta_dev, seg_image))
|
||||
return_0;
|
||||
|
||||
iorig_lvs[s] = lv_iorig;
|
||||
imeta_lvs[s] = lv_imeta;
|
||||
|
||||
lv_image->status &= ~INTEGRITY;
|
||||
seg_image->integrity_meta_dev = NULL;
|
||||
seg_image->integrity_data_sectors = 0;
|
||||
memset(&seg_image->integrity_settings, 0, sizeof(seg_image->integrity_settings));
|
||||
|
||||
if (!remove_layer_from_lv(lv_image, lv_iorig))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (is_active) {
|
||||
/* vg_write(), suspend_lv(), vg_commit(), resume_lv() */
|
||||
if (!lv_update_and_reload(lv)) {
|
||||
log_error("Failed to update and reload LV after integrity remove.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_iorig = iorig_lvs[s];
|
||||
lv_imeta = imeta_lvs[s];
|
||||
|
||||
if (is_active) {
|
||||
if (!deactivate_lv(cmd, lv_iorig))
|
||||
log_error("Failed to deactivate unused iorig LV %s.", lv_iorig->name);
|
||||
|
||||
if (!deactivate_lv(cmd, lv_imeta))
|
||||
log_error("Failed to deactivate unused imeta LV %s.", lv_imeta->name);
|
||||
}
|
||||
|
||||
lv_imeta->status &= ~INTEGRITY_METADATA;
|
||||
lv_set_visible(lv_imeta);
|
||||
|
||||
if (!lv_remove(lv_iorig))
|
||||
log_error("Failed to remove unused iorig LV %s.", lv_iorig->name);
|
||||
|
||||
if (!lv_remove(lv_imeta))
|
||||
log_error("Failed to remove unused imeta LV %s.", lv_imeta->name);
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int integrity_mode_set(const char *mode, struct integrity_settings *settings)
|
||||
{
|
||||
if (!mode)
|
||||
settings->mode[0] = DEFAULT_MODE;
|
||||
else if (!strcmp(mode, "bitmap") || !strcmp(mode, "B"))
|
||||
settings->mode[0] = 'B';
|
||||
else if (!strcmp(mode, "journal") || !strcmp(mode, "J"))
|
||||
settings->mode[0] = 'J';
|
||||
else {
|
||||
log_error("Invalid raid integrity mode (use \"bitmap\" or \"journal\")");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _set_integrity_block_size(struct cmd_context *cmd, struct logical_volume *lv, int is_active,
|
||||
struct integrity_settings *settings,
|
||||
int lbs_4k, int lbs_512, int pbs_4k, int pbs_512)
|
||||
{
|
||||
char pathname[PATH_MAX];
|
||||
struct device *fs_dev;
|
||||
uint32_t fs_block_size = 0;
|
||||
int rv;
|
||||
|
||||
if (lbs_4k && lbs_512) {
|
||||
log_error("Integrity requires consistent logical block size for LV devices.");
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (settings->block_size &&
|
||||
(settings->block_size != 512 && settings->block_size != 1024 &&
|
||||
settings->block_size != 2048 && settings->block_size != 4096)) {
|
||||
log_error("Invalid integrity block size, possible values are 512, 1024, 2048, 4096");
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (lbs_4k && settings->block_size && (settings->block_size < 4096)) {
|
||||
log_error("Integrity block size %u not allowed with device logical block size 4096.",
|
||||
settings->block_size);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd->name, "lvcreate")) {
|
||||
if (lbs_4k) {
|
||||
settings->block_size = 4096;
|
||||
} else if (lbs_512 && pbs_4k && !pbs_512) {
|
||||
settings->block_size = 4096;
|
||||
} else if (lbs_512) {
|
||||
if (!settings->block_size)
|
||||
settings->block_size = 512;
|
||||
} else if (!lbs_4k && !lbs_512) {
|
||||
if (!settings->block_size)
|
||||
settings->block_size = 512;
|
||||
log_print("Using integrity block size %u with unknown device logical block size.",
|
||||
settings->block_size);
|
||||
} else {
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
} else if (!strcmp(cmd->name, "lvconvert")) {
|
||||
if (dm_snprintf(pathname, sizeof(pathname), "%s%s/%s", cmd->dev_dir,
|
||||
lv->vg->name, lv->name) < 0) {
|
||||
log_error("Path name too long to get LV block size %s", display_lvname(lv));
|
||||
goto_bad;
|
||||
}
|
||||
if (!(fs_dev = dev_cache_get(cmd, pathname, NULL))) {
|
||||
log_error("Device for LV not found to check block size %s", display_lvname(lv));
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_fs_block_size() returns the libblkid BLOCK_SIZE value,
|
||||
* where libblkid has fs-specific code to set BLOCK_SIZE to the
|
||||
* value we need here.
|
||||
*
|
||||
* The term "block size" here may not equate directly to what the fs
|
||||
* calls the block size, e.g. xfs calls this the sector size (and
|
||||
* something different the block size); while ext4 does call this
|
||||
* value the block size, but it's possible values are not the same
|
||||
* as xfs's, and do not seem to relate directly to the device LBS.
|
||||
*/
|
||||
rv = get_fs_block_size(fs_dev, &fs_block_size);
|
||||
if (!rv || !fs_block_size) {
|
||||
int use_bs;
|
||||
|
||||
if (lbs_4k && pbs_4k) {
|
||||
use_bs = 4096;
|
||||
} else if (lbs_512 && pbs_512) {
|
||||
use_bs = 512;
|
||||
} else if (lbs_512 && pbs_4k) {
|
||||
if (settings->block_size == 4096)
|
||||
use_bs = 4096;
|
||||
else
|
||||
use_bs = 512;
|
||||
} else {
|
||||
use_bs = 512;
|
||||
}
|
||||
|
||||
if (settings->block_size && (settings->block_size != use_bs)) {
|
||||
log_error("Cannot use integrity block size %u with unknown file system block size, logical block size %u, physical block size %u.",
|
||||
settings->block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
settings->block_size = use_bs;
|
||||
|
||||
log_print("Using integrity block size %u for unknown file system block size, logical block size %u, physical block size %u.",
|
||||
settings->block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!settings->block_size) {
|
||||
if (is_active && lbs_512) {
|
||||
/* increasing the lbs from 512 to 4k under an active LV could cause problems
|
||||
for an application that expects a given io size/alignment is possible. */
|
||||
settings->block_size = 512;
|
||||
if (fs_block_size > 512)
|
||||
log_print("Limiting integrity block size to 512 because the LV is active.");
|
||||
} else if (fs_block_size <= 4096)
|
||||
settings->block_size = fs_block_size;
|
||||
else
|
||||
settings->block_size = 4096; /* dm-integrity max is 4096 */
|
||||
log_print("Using integrity block size %u for file system block size %u.",
|
||||
settings->block_size, fs_block_size);
|
||||
} else {
|
||||
/* let user specify integrity block size that is less than fs block size */
|
||||
if (settings->block_size > fs_block_size) {
|
||||
log_error("Integrity block size %u cannot be larger than file system block size %u.",
|
||||
settings->block_size, fs_block_size);
|
||||
goto_bad;
|
||||
}
|
||||
log_print("Using integrity block size %u for file system block size %u.",
|
||||
settings->block_size, fs_block_size);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return 1;
|
||||
bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add integrity to each raid image.
|
||||
*
|
||||
* for each rimage_N:
|
||||
* . create and allocate a new linear LV rimage_N_imeta
|
||||
* . move the segments from rimage_N to a new rimage_N_iorig
|
||||
* . add an integrity segment to rimage_N with
|
||||
* origin=rimage_N_iorig, meta_dev=rimage_N_imeta
|
||||
*
|
||||
* Before:
|
||||
* rimage_0
|
||||
* segment1: striped: pv0:A
|
||||
* rimage_1
|
||||
* segment1: striped: pv1:B
|
||||
*
|
||||
* After:
|
||||
* rimage_0
|
||||
* segment1: integrity: rimage_0_iorig, rimage_0_imeta
|
||||
* rimage_1
|
||||
* segment1: integrity: rimage_1_iorig, rimage_1_imeta
|
||||
* rimage_0_iorig
|
||||
* segment1: striped: pv0:A
|
||||
* rimage_1_iorig
|
||||
* segment1: striped: pv1:B
|
||||
* rimage_0_imeta
|
||||
* segment1: striped: pv2:A
|
||||
* rimage_1_imeta
|
||||
* segment1: striped: pv2:B
|
||||
*
|
||||
*/
|
||||
|
||||
int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_settings *settings,
|
||||
struct dm_list *pvh, struct logical_volume *lv_imeta_0)
|
||||
{
|
||||
char imeta_name[NAME_LEN];
|
||||
char *imeta_name_dup;
|
||||
struct lvcreate_params lp;
|
||||
struct dm_list allocatable_pvs;
|
||||
struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *lv_image, *lv_imeta, *lv_iorig;
|
||||
struct lv_segment *seg_top, *seg_image;
|
||||
struct pv_list *pvl;
|
||||
const struct segment_type *segtype;
|
||||
struct integrity_settings *set = NULL;
|
||||
struct dm_list *use_pvh = NULL;
|
||||
uint32_t area_count, s;
|
||||
uint32_t revert_meta_lvs = 0;
|
||||
int lbs_4k = 0, lbs_512 = 0, lbs_unknown = 0;
|
||||
int pbs_4k = 0, pbs_512 = 0, pbs_unknown = 0;
|
||||
int is_active;
|
||||
|
||||
memset(imeta_lvs, 0, sizeof(imeta_lvs));
|
||||
|
||||
is_active = lv_is_active(lv);
|
||||
|
||||
if (dm_list_size(&lv->segments) != 1)
|
||||
return_0;
|
||||
|
||||
if (!dm_list_empty(&lv->segs_using_this_lv)) {
|
||||
log_error("Integrity can only be added to top level raid LV.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv)) {
|
||||
log_error("Integrity cannot be added to snapshot origins.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg_top = first_seg(lv);
|
||||
area_count = seg_top->area_count;
|
||||
|
||||
if (!seg_is_raid1(seg_top) && !seg_is_raid4(seg_top) &&
|
||||
!seg_is_any_raid5(seg_top) && !seg_is_any_raid6(seg_top) &&
|
||||
!seg_is_any_raid10(seg_top)) {
|
||||
log_error("Integrity can only be added to raid1,4,5,6,10.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each rimage, create an _imeta LV for integrity metadata.
|
||||
* Each needs to be zeroed.
|
||||
*/
|
||||
for (s = 0; s < area_count; s++) {
|
||||
struct logical_volume *meta_lv;
|
||||
struct wipe_params wipe = { .do_zero = 1 };
|
||||
|
||||
if (s >= DEFAULT_RAID_MAX_IMAGES)
|
||||
goto_bad;
|
||||
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
|
||||
/*
|
||||
* This function is used to add integrity to new images added
|
||||
* to the raid, in which case old images will already be
|
||||
* integrity.
|
||||
*/
|
||||
if (seg_is_integrity(first_seg(lv_image)))
|
||||
continue;
|
||||
|
||||
if (!seg_is_striped(first_seg(lv_image))) {
|
||||
log_error("raid image must be linear to add integrity");
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use an existing lv_imeta from previous linear+integrity LV.
|
||||
* FIXME: is it guaranteed that lv_image_0 is the existing?
|
||||
*/
|
||||
if (!s && lv_imeta_0) {
|
||||
if (dm_snprintf(imeta_name, sizeof(imeta_name), "%s_imeta", lv_image->name) > 0) {
|
||||
if ((imeta_name_dup = dm_pool_strdup(vg->vgmem, imeta_name)))
|
||||
lv_imeta_0->name = imeta_name_dup;
|
||||
}
|
||||
imeta_lvs[0] = lv_imeta_0;
|
||||
continue;
|
||||
}
|
||||
|
||||
dm_list_init(&allocatable_pvs);
|
||||
|
||||
if (!get_pv_list_for_lv(cmd->mem, lv_image, &allocatable_pvs)) {
|
||||
log_error("Failed to build list of PVs for %s.", display_lvname(lv_image));
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &allocatable_pvs) {
|
||||
unsigned int pbs = 0;
|
||||
unsigned int lbs = 0;
|
||||
|
||||
if (!dev_get_direct_block_sizes(pvl->pv->dev, &pbs, &lbs)) {
|
||||
lbs_unknown++;
|
||||
pbs_unknown++;
|
||||
continue;
|
||||
}
|
||||
if (lbs == 4096)
|
||||
lbs_4k++;
|
||||
else if (lbs == 512)
|
||||
lbs_512++;
|
||||
else
|
||||
lbs_unknown++;
|
||||
if (pbs == 4096)
|
||||
pbs_4k++;
|
||||
else if (pbs == 512)
|
||||
pbs_512++;
|
||||
else
|
||||
pbs_unknown++;
|
||||
}
|
||||
|
||||
use_pvh = &allocatable_pvs;
|
||||
|
||||
/*
|
||||
* allocate a new linear LV NAME_rimage_N_imeta
|
||||
*/
|
||||
memset(&lp, 0, sizeof(lp));
|
||||
lp.lv_name = lv_image->name;
|
||||
lp.pvh = use_pvh;
|
||||
lp.extents = lv_image->size / vg->extent_size;
|
||||
|
||||
if (!_lv_create_integrity_metadata(cmd, vg, &lp, &meta_lv))
|
||||
goto_bad;
|
||||
|
||||
revert_meta_lvs++;
|
||||
|
||||
/* Used below to set up the new integrity segment. */
|
||||
imeta_lvs[s] = meta_lv;
|
||||
|
||||
/*
|
||||
* dm-integrity requires the metadata LV header to be zeroed.
|
||||
*/
|
||||
|
||||
if (!activate_lv(cmd, meta_lv)) {
|
||||
log_error("Failed to activate LV %s to zero", display_lvname(meta_lv));
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!wipe_lv(meta_lv, wipe)) {
|
||||
log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv));
|
||||
if (deactivate_lv(cmd, meta_lv))
|
||||
log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, meta_lv)) {
|
||||
log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
|
||||
goto_bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_active) {
|
||||
/* checking block size of fs on the lv requires the lv to be active */
|
||||
if (!activate_lv(cmd, lv)) {
|
||||
log_error("Failed to activate LV to check block size %s", display_lvname(lv));
|
||||
goto bad;
|
||||
}
|
||||
if (!sync_local_dev_names(cmd))
|
||||
stack;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set settings->block_size which will be copied to segment settings below.
|
||||
* integrity block size chosen based on device logical block size and
|
||||
* file system block size.
|
||||
*/
|
||||
if (!_set_integrity_block_size(cmd, lv, is_active, settings, lbs_4k, lbs_512, pbs_4k, pbs_512)) {
|
||||
if (!is_active && !deactivate_lv(cmd, lv))
|
||||
stack;
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!is_active) {
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Failed to deactivate LV after checking block size %s", display_lvname(lv));
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each rimage, move its segments to a new rimage_iorig and give
|
||||
* the rimage a new integrity segment.
|
||||
*/
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
|
||||
/* Not adding integrity to this image. */
|
||||
if (!imeta_lvs[s])
|
||||
continue;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
|
||||
goto_bad;
|
||||
|
||||
log_debug("Adding integrity to raid image %s", lv_image->name);
|
||||
|
||||
/*
|
||||
* "lv_iorig" is a new LV with new id, but with the segments
|
||||
* from "lv_image". "lv_image" keeps the existing name and id,
|
||||
* but gets a new integrity segment, in place of the segments
|
||||
* that were moved to lv_iorig.
|
||||
*/
|
||||
if (!(lv_iorig = insert_layer_for_lv(cmd, lv_image, INTEGRITY, "_iorig")))
|
||||
goto_bad;
|
||||
|
||||
lv_image->status |= INTEGRITY;
|
||||
|
||||
/*
|
||||
* Set up the new first segment of lv_image as integrity.
|
||||
*/
|
||||
seg_image = first_seg(lv_image);
|
||||
seg_image->segtype = segtype;
|
||||
|
||||
lv_imeta = imeta_lvs[s];
|
||||
lv_imeta->status |= INTEGRITY_METADATA;
|
||||
lv_set_hidden(lv_imeta);
|
||||
seg_image->integrity_data_sectors = lv_image->size;
|
||||
seg_image->integrity_meta_dev = lv_imeta;
|
||||
seg_image->integrity_recalculate = 1;
|
||||
|
||||
memcpy(&seg_image->integrity_settings, settings, sizeof(struct integrity_settings));
|
||||
set = &seg_image->integrity_settings;
|
||||
|
||||
if (!set->mode[0])
|
||||
set->mode[0] = DEFAULT_MODE;
|
||||
|
||||
if (!set->tag_size)
|
||||
set->tag_size = DEFAULT_TAG_SIZE;
|
||||
|
||||
if (!set->block_size)
|
||||
set->block_size = DEFAULT_BLOCK_SIZE;
|
||||
|
||||
if (!set->internal_hash)
|
||||
set->internal_hash = DEFAULT_INTERNAL_HASH;
|
||||
}
|
||||
|
||||
if (is_active) {
|
||||
log_debug("Writing VG and updating LV with new integrity LV %s", lv->name);
|
||||
|
||||
/* vg_write(), suspend_lv(), vg_commit(), resume_lv() */
|
||||
if (!lv_update_and_reload(lv)) {
|
||||
log_error("LV update and reload failed");
|
||||
goto_bad;
|
||||
}
|
||||
revert_meta_lvs = 0;
|
||||
|
||||
} else {
|
||||
log_debug("Writing VG with new integrity LV %s", lv->name);
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
goto_bad;
|
||||
|
||||
revert_meta_lvs = 0;
|
||||
|
||||
/*
|
||||
* This first activation includes "recalculate" which starts the
|
||||
* kernel's recalculating (initialization) process.
|
||||
*/
|
||||
|
||||
log_debug("Activating to start integrity initialization for LV %s", lv->name);
|
||||
|
||||
if (!activate_lv(cmd, lv)) {
|
||||
log_error("Failed to activate integrity LV to initialize.");
|
||||
goto_bad;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that the device is being initialized, update the VG to clear
|
||||
* integrity_recalculate so that subsequent activations will not
|
||||
* include "recalculate" and restart initialization.
|
||||
*/
|
||||
|
||||
log_debug("Writing VG with initialized integrity LV %s", lv->name);
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
lv_image = seg_lv(seg_top, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
seg_image->integrity_recalculate = 0;
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
goto_bad;
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to add integrity.");
|
||||
|
||||
for (s = 0; s < revert_meta_lvs; s++) {
|
||||
if (!lv_remove(imeta_lvs[s]))
|
||||
log_error("New integrity metadata LV may require manual removal.");
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
log_error("New integrity metadata LV may require manual removal.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This should rarely if ever be used. A command that adds integrity
|
||||
* to an LV will activate and then clear the flag. If it fails before
|
||||
* clearing the flag, then this function will be used by a subsequent
|
||||
* activation to clear the flag.
|
||||
*/
|
||||
void lv_clear_integrity_recalculate_metadata(struct logical_volume *lv)
|
||||
{
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *lv_image;
|
||||
struct lv_segment *seg, *seg_image;
|
||||
uint32_t s;
|
||||
|
||||
if (!lv_is_raid(lv) && !lv_is_integrity(lv)) {
|
||||
log_error("Invalid LV type for clearing integrity");
|
||||
return;
|
||||
}
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
if (seg_is_raid(seg)) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
seg_image->integrity_recalculate = 0;
|
||||
}
|
||||
} else if (seg_is_integrity(seg)) {
|
||||
seg->integrity_recalculate = 0;
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||
log_warn("WARNING: failed to clear integrity recalculate flag for %s",
|
||||
display_lvname(lv));
|
||||
}
|
||||
}
|
||||
|
||||
int lv_has_integrity_recalculate_metadata(struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *lv_image;
|
||||
struct lv_segment *seg, *seg_image;
|
||||
uint32_t s;
|
||||
int ret = 0;
|
||||
|
||||
if (!lv_is_raid(lv) && !lv_is_integrity(lv))
|
||||
return 0;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
if (seg_is_raid(seg)) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (!seg_is_integrity(seg_image))
|
||||
continue;
|
||||
if (seg_image->integrity_recalculate)
|
||||
ret = 1;
|
||||
}
|
||||
} else if (seg_is_integrity(seg)) {
|
||||
ret = seg->integrity_recalculate;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lv_raid_has_integrity(struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *lv_image;
|
||||
struct lv_segment *seg, *seg_image;
|
||||
uint32_t s;
|
||||
|
||||
if (!lv_is_raid(lv))
|
||||
return 0;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (seg_is_integrity(seg_image))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lv_get_raid_integrity_settings(struct logical_volume *lv, struct integrity_settings **isettings)
|
||||
{
|
||||
struct logical_volume *lv_image;
|
||||
struct lv_segment *seg, *seg_image;
|
||||
uint32_t s;
|
||||
|
||||
if (!lv_is_raid(lv))
|
||||
return_0;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
lv_image = seg_lv(seg, s);
|
||||
seg_image = first_seg(lv_image);
|
||||
|
||||
if (seg_is_integrity(seg_image)) {
|
||||
*isettings = &seg_image->integrity_settings;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lv_integrity_mismatches(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv,
|
||||
uint64_t *mismatches)
|
||||
{
|
||||
struct lv_with_info_and_seg_status status;
|
||||
|
||||
if (!lv_is_integrity(lv))
|
||||
return_0;
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
status.seg_status.type = SEG_STATUS_NONE;
|
||||
|
||||
status.seg_status.seg = first_seg(lv);
|
||||
|
||||
/* FIXME: why reporter_pool? */
|
||||
if (!(status.seg_status.mem = dm_pool_create("reporter_pool", 1024))) {
|
||||
log_error("Failed to get mem for LV status.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info_with_seg_status(cmd, first_seg(lv), &status, 1, 1)) {
|
||||
log_error("Failed to get device mapper status for %s", display_lvname(lv));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!status.info.exists)
|
||||
goto fail;
|
||||
|
||||
if (status.seg_status.type != SEG_STATUS_INTEGRITY) {
|
||||
log_error("Invalid device mapper status type (%d) for %s",
|
||||
(uint32_t)status.seg_status.type, display_lvname(lv));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*mismatches = status.seg_status.integrity->number_of_mismatches;
|
||||
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
dm_pool_destroy(status.seg_status.mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -385,6 +385,17 @@ dm_percent_t lvseg_percent_with_info_and_seg_status(const struct lv_with_info_an
|
||||
* Esentially rework _target_percent API for segtype.
|
||||
*/
|
||||
switch (s->type) {
|
||||
case SEG_STATUS_INTEGRITY:
|
||||
if (type != PERCENT_GET_DIRTY)
|
||||
p = DM_PERCENT_INVALID;
|
||||
else if (!s->integrity->recalc_sector)
|
||||
p = DM_PERCENT_INVALID;
|
||||
else if (s->integrity->recalc_sector == s->integrity->provided_data_sectors)
|
||||
p = DM_PERCENT_100;
|
||||
else
|
||||
p = dm_make_percent(s->integrity->recalc_sector,
|
||||
s->integrity->provided_data_sectors);
|
||||
break;
|
||||
case SEG_STATUS_CACHE:
|
||||
if (s->cache->fail || s->cache->error)
|
||||
p = DM_PERCENT_INVALID;
|
||||
@@ -405,6 +416,14 @@ dm_percent_t lvseg_percent_with_info_and_seg_status(const struct lv_with_info_an
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SEG_STATUS_WRITECACHE:
|
||||
if (type != PERCENT_GET_DATA)
|
||||
p = DM_PERCENT_INVALID;
|
||||
else {
|
||||
uint64_t used = s->writecache->total_blocks - s->writecache->free_blocks;
|
||||
p = dm_make_percent(used, s->writecache->total_blocks);
|
||||
}
|
||||
break;
|
||||
case SEG_STATUS_RAID:
|
||||
switch (type) {
|
||||
case PERCENT_GET_DIRTY:
|
||||
@@ -585,6 +604,8 @@ struct logical_volume *lv_origin_lv(const struct logical_volume *lv)
|
||||
origin = first_seg(lv)->external_lv;
|
||||
else if (lv_is_writecache(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_integrity(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
|
||||
return origin;
|
||||
}
|
||||
@@ -822,7 +843,7 @@ const char *lv_layer(const struct logical_volume *lv)
|
||||
if (lv_is_vdo_pool(lv))
|
||||
return "vpool";
|
||||
|
||||
if (lv_is_origin(lv) || lv_is_external_origin(lv))
|
||||
if (lv_is_origin(lv) || lv_is_external_origin(lv) || lv_is_writecache_origin(lv))
|
||||
return "real";
|
||||
|
||||
return NULL;
|
||||
@@ -1200,10 +1221,13 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
|
||||
repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
|
||||
else if (lv_is_pool_metadata(lv) ||
|
||||
lv_is_pool_metadata_spare(lv) ||
|
||||
lv_is_raid_metadata(lv))
|
||||
lv_is_raid_metadata(lv) ||
|
||||
lv_is_integrity_metadata(lv))
|
||||
repstr[0] = 'e';
|
||||
else if (lv_is_cache_type(lv) || lv_is_writecache(lv))
|
||||
repstr[0] = 'C';
|
||||
else if (lv_is_integrity(lv))
|
||||
repstr[0] = 'g';
|
||||
else if (lv_is_raid(lv))
|
||||
repstr[0] = (lv_is_not_synced(lv)) ? 'R' : 'r';
|
||||
else if (lv_is_mirror(lv))
|
||||
@@ -1388,6 +1412,9 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
|
||||
} else if (lvdm->seg_status.type == SEG_STATUS_THIN) {
|
||||
if (lvdm->seg_status.thin->fail)
|
||||
repstr[8] = 'F';
|
||||
} else if (lvdm->seg_status.type == SEG_STATUS_WRITECACHE) {
|
||||
if (lvdm->seg_status.writecache->error)
|
||||
repstr[8] = 'E';
|
||||
} else if (lvdm->seg_status.type == SEG_STATUS_UNKNOWN)
|
||||
repstr[8] = 'X'; /* Unknown */
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user