mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-29 16:23:49 +03:00
Compare commits
936 Commits
dev-lvmguy
...
v2_02_180
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb384f8488 | ||
|
|
82feb5f111 | ||
|
|
66990bc7c8 | ||
|
|
6fcb2ba440 | ||
|
|
b8a7f6ba3d | ||
|
|
0851ee5301 | ||
|
|
df8eef7096 | ||
|
|
c1dbb22ba4 | ||
|
|
99cddd67a9 | ||
|
|
814dd84e07 | ||
|
|
d5bcc56eef | ||
|
|
f7ffba204e | ||
|
|
90e419c645 | ||
|
|
49147cbaa7 | ||
|
|
69907e0780 | ||
|
|
b90d4b38e5 | ||
|
|
befdfc245b | ||
|
|
0d78e4c1e9 | ||
|
|
763c65314e | ||
|
|
24aee732a5 | ||
|
|
ba6ed5c90c | ||
|
|
e0c94d883a | ||
|
|
39e3b5d8ac | ||
|
|
39fc98d731 | ||
|
|
5503699c37 | ||
|
|
e0bfc946cb | ||
|
|
9546edeef9 | ||
|
|
716199334c | ||
|
|
4479228d32 | ||
|
|
4afb5971b9 | ||
|
|
dd075e93c1 | ||
|
|
d4fd39f64c | ||
|
|
acb784e2a8 | ||
|
|
8a0af1bec8 | ||
|
|
8bd9a89c14 | ||
|
|
a30e622279 | ||
|
|
76075ff55d | ||
|
|
bfb904af1c | ||
|
|
d88376ca78 | ||
|
|
6283f5ea3f | ||
|
|
43ce357ebc | ||
|
|
d136790bab | ||
|
|
214de62b5d | ||
|
|
e9c0a64fb5 | ||
|
|
7ac8e21f3c | ||
|
|
fdb362b998 | ||
|
|
06accf1395 | ||
|
|
d3dcca639c | ||
|
|
98eb9e5754 | ||
|
|
347c807f86 | ||
|
|
1e5f6887b1 | ||
|
|
81f07c3cca | ||
|
|
885eb2024f | ||
|
|
00f6a8466e | ||
|
|
06b2e5c176 | ||
|
|
caa600a409 | ||
|
|
b9c1cef817 | ||
|
|
4a01e4f389 | ||
|
|
08771bbbbf | ||
|
|
8d9d32b315 | ||
|
|
fdaa7e2e87 | ||
|
|
2beb3009bd | ||
|
|
214235367b | ||
|
|
c516321325 | ||
|
|
27495a3555 | ||
|
|
05ee83579b | ||
|
|
6cd0523337 | ||
|
|
063d065388 | ||
|
|
abba06fb3b | ||
|
|
3759a1f62b | ||
|
|
5c5e449dc5 | ||
|
|
a40d447a02 | ||
|
|
95cf127134 | ||
|
|
595196bc29 | ||
|
|
403c87c1aa | ||
|
|
948f2d9979 | ||
|
|
db8d3bdfa9 | ||
|
|
3a4fe54ca1 | ||
|
|
7f7ec769d9 | ||
|
|
cd369d8a7f | ||
|
|
0c1d3db8db | ||
|
|
6a44dceb48 | ||
|
|
5ac9f8d631 | ||
|
|
6d14d5d16b | ||
|
|
06c789eda1 | ||
|
|
1924426ad1 | ||
|
|
c2a8bbed3b | ||
|
|
9b41efae82 | ||
|
|
0181c77e3f | ||
|
|
033df741e2 | ||
|
|
28c8e95d19 | ||
|
|
9a730233c9 | ||
|
|
0ecf232194 | ||
|
|
3702f39ef3 | ||
|
|
d6f2445996 | ||
|
|
264077907e | ||
|
|
adae8ee1c2 | ||
|
|
7e85361c34 | ||
|
|
fab063cfcb | ||
|
|
9337ff48bc | ||
|
|
a90de76fd8 | ||
|
|
f865e1bf87 | ||
|
|
89f34eaf0c | ||
|
|
76a45424a7 | ||
|
|
c46dbfb14e | ||
|
|
4be1ec3da4 | ||
|
|
c35d3242a8 | ||
|
|
6cd798f556 | ||
|
|
b7fd8ac8eb | ||
|
|
87291a2832 | ||
|
|
61583281e5 | ||
|
|
a60416a13f | ||
|
|
3c9ed33f83 | ||
|
|
73ae68e1c4 | ||
|
|
6029d6d8d8 | ||
|
|
25a66737e3 | ||
|
|
a9f2c1e1f5 | ||
|
|
bc275bcddf | ||
|
|
0253f5a21d | ||
|
|
b2574c2f3a | ||
|
|
3bbdde808a | ||
|
|
fbf64fe730 | ||
|
|
43fb32e761 | ||
|
|
5b86b0e3dc | ||
|
|
f7435cd8c7 | ||
|
|
286c9c78b4 | ||
|
|
a39eaea27d | ||
|
|
5052970da3 | ||
|
|
7ee0a6e44d | ||
|
|
3417d6229d | ||
|
|
c6ca81a38d | ||
|
|
8c453e2e5e | ||
|
|
28d35e5c59 | ||
|
|
64dd656ef7 | ||
|
|
7c852c75c3 | ||
|
|
e296f784c9 | ||
|
|
df2acbbb97 | ||
|
|
ed799404f8 | ||
|
|
3bbc17a670 | ||
|
|
fb0aca86f8 | ||
|
|
99cd7108d3 | ||
|
|
f8745dc23e | ||
|
|
550380c1a4 | ||
|
|
3b3ee66b1f | ||
|
|
b5da4fdfce | ||
|
|
be154e30e8 | ||
|
|
ad756bb708 | ||
|
|
c1abcee142 | ||
|
|
889558fedb | ||
|
|
d25c135806 | ||
|
|
0217c53b24 | ||
|
|
2eba7c7755 | ||
|
|
11ceb77867 | ||
|
|
517d6cc418 | ||
|
|
0e56fa6892 | ||
|
|
0a5edc1f12 | ||
|
|
9640320aea | ||
|
|
ca87674ea4 | ||
|
|
edede1d20f | ||
|
|
093428b067 | ||
|
|
7b8b13c62b | ||
|
|
35ffc3f8eb | ||
|
|
67c02877a1 | ||
|
|
4c7565b65d | ||
|
|
fa8d0b5766 | ||
|
|
79b2961399 | ||
|
|
e2c766d37e | ||
|
|
ac768a9d2b | ||
|
|
83e362cd32 | ||
|
|
0b465d1543 | ||
|
|
d38a2d64f0 | ||
|
|
7616a7f46e | ||
|
|
cbe81a0b05 | ||
|
|
0221ebfd64 | ||
|
|
a7a23e7dd2 | ||
|
|
38b4354494 | ||
|
|
ec0f5c2bf6 | ||
|
|
86c8f0f01f | ||
|
|
7362ed68be | ||
|
|
f5da325d70 | ||
|
|
172d8fb355 | ||
|
|
0cadfdd69d | ||
|
|
842b3074b7 | ||
|
|
6f48741062 | ||
|
|
e2be14e2d5 | ||
|
|
6740c78e83 | ||
|
|
09fcc8eaa8 | ||
|
|
73578e36fa | ||
|
|
3e3cb22f2a | ||
|
|
5c9dcd99fd | ||
|
|
b5d9914628 | ||
|
|
ccab54677c | ||
|
|
bbb8040456 | ||
|
|
4362013872 | ||
|
|
228ed56455 | ||
|
|
413488edc6 | ||
|
|
30a4c7988e | ||
|
|
0a31fb4aa3 | ||
|
|
576dd1fc41 | ||
|
|
3b02b35c3e | ||
|
|
5f780813f2 | ||
|
|
9ad42e5f06 | ||
|
|
d974644db7 | ||
|
|
57bb46c5e7 | ||
|
|
39ce38eb88 | ||
|
|
3c0f5bdd08 | ||
|
|
ae50374811 | ||
|
|
67b80e2d9d | ||
|
|
2b96bb403c | ||
|
|
2ae4a04710 | ||
|
|
e649f71022 | ||
|
|
38f33251b1 | ||
|
|
9a5bd01b0c | ||
|
|
3600caa71d | ||
|
|
1c5c99afce | ||
|
|
2e1869b923 | ||
|
|
a2310e2de0 | ||
|
|
c9729022bf | ||
|
|
8bf92875f7 | ||
|
|
d2840b0ec1 | ||
|
|
bc50dc6e70 | ||
|
|
ed837e6971 | ||
|
|
f4a60fe004 | ||
|
|
822a8b62be | ||
|
|
c016b573ee | ||
|
|
a5e13f2eef | ||
|
|
88fe07ad0a | ||
|
|
49db9b5e0b | ||
|
|
ac18164a52 | ||
|
|
4ebfd8e8eb | ||
|
|
b393fbec00 | ||
|
|
2bb02e24bf | ||
|
|
52656c89fd | ||
|
|
9cab005797 | ||
|
|
dfc320f5b8 | ||
|
|
2688aafefb | ||
|
|
8b755f1e04 | ||
|
|
dc30d4b2f2 | ||
|
|
efad84ebc2 | ||
|
|
b3c41bce3d | ||
|
|
65912ce44d | ||
|
|
977d0a3613 | ||
|
|
90d0ff6636 | ||
|
|
8fd300f7df | ||
|
|
972b535220 | ||
|
|
9fe0be871c | ||
|
|
506ab29bfd | ||
|
|
6abc3f10ae | ||
|
|
11d9b0cae7 | ||
|
|
11436b00e0 | ||
|
|
24e7745d7a | ||
|
|
db0560c1b0 | ||
|
|
1553993ea1 | ||
|
|
39f05855c0 | ||
|
|
d709d8445f | ||
|
|
9687ee2a74 | ||
|
|
8dcc973bbb | ||
|
|
a418f88b76 | ||
|
|
3ea862bdfc | ||
|
|
bfc61a9543 | ||
|
|
de042fa13d | ||
|
|
61153d90e5 | ||
|
|
f564e78d98 | ||
|
|
c863c9581d | ||
|
|
7aba7fe68b | ||
|
|
f6459757af | ||
|
|
c1cd18f21e | ||
|
|
029a76b4f8 | ||
|
|
c365d7de4f | ||
|
|
89935ace29 | ||
|
|
39f24a169c | ||
|
|
ef79d639fe | ||
|
|
cca815d240 | ||
|
|
1b08797419 | ||
|
|
52ebad31ba | ||
|
|
1ddbbb67e0 | ||
|
|
bdf7479449 | ||
|
|
9384b2b5c5 | ||
|
|
2bc896f2a3 | ||
|
|
545ca59468 | ||
|
|
0a2b5d5748 | ||
|
|
65d6118e47 | ||
|
|
513e9e3264 | ||
|
|
475626fb6c | ||
|
|
865a9c5873 | ||
|
|
b904d6653d | ||
|
|
fade45b1d1 | ||
|
|
dd7ac793a0 | ||
|
|
877c2f2ffb | ||
|
|
0931067dc5 | ||
|
|
138225a3a8 | ||
|
|
ab63923d19 | ||
|
|
cdcea0bf55 | ||
|
|
5c878167a2 | ||
|
|
f8f6219513 | ||
|
|
54856b2965 | ||
|
|
e890c37704 | ||
|
|
8a14b8a733 | ||
|
|
5b6e62dc1f | ||
|
|
cdb8400de2 | ||
|
|
1c97fda425 | ||
|
|
ea34dad66f | ||
|
|
c7fdacbc50 | ||
|
|
0fe4f65f65 | ||
|
|
4670e9f698 | ||
|
|
47bfac21ca | ||
|
|
1fec86571f | ||
|
|
f8616ac2d8 | ||
|
|
28a9fcd94b | ||
|
|
dcb5434a7f | ||
|
|
fc3ed8856f | ||
|
|
c492fbb51c | ||
|
|
66f4f8c27f | ||
|
|
ae27461777 | ||
|
|
fcdac700f9 | ||
|
|
f2504257e4 | ||
|
|
1409c4a1c2 | ||
|
|
c42a18d372 | ||
|
|
aee27dc7ba | ||
|
|
7b0a8f47be | ||
|
|
aa833bdd8a | ||
|
|
9b6a62f944 | ||
|
|
c0973e70a5 | ||
|
|
89c65d4f71 | ||
|
|
45e5e702c1 | ||
|
|
6d05859862 | ||
|
|
ae21305ee7 | ||
|
|
a01a8d7172 | ||
|
|
a9b0aa5c17 | ||
|
|
e351f8bc66 | ||
|
|
7e33bd1335 | ||
|
|
ddb5de7a98 | ||
|
|
196579af1f | ||
|
|
44726ed9cb | ||
|
|
1717d4cb17 | ||
|
|
570c6239ee | ||
|
|
217f3f8741 | ||
|
|
da2b155a9d | ||
|
|
4331182964 | ||
|
|
21057676a1 | ||
|
|
e49b114f7e | ||
|
|
8065492046 | ||
|
|
8b26a007b1 | ||
|
|
0da296003d | ||
|
|
34fd818caf | ||
|
|
c2b10daf69 | ||
|
|
e7670d3338 | ||
|
|
b504bb809e | ||
|
|
ae093df3f1 | ||
|
|
d75aa55784 | ||
|
|
96a61337b0 | ||
|
|
28255e3eee | ||
|
|
f328532f05 | ||
|
|
7bce66c5e8 | ||
|
|
6e580465b5 | ||
|
|
37471bb477 | ||
|
|
e4f478d86d | ||
|
|
89f54a5094 | ||
|
|
c29899b910 | ||
|
|
a1e3398ffc | ||
|
|
9d2add1361 | ||
|
|
6c67c7557c | ||
|
|
4343280ebc | ||
|
|
f17c2cf7c6 | ||
|
|
29c6c17121 | ||
|
|
d9a77e8bb4 | ||
|
|
79c4971210 | ||
|
|
5f138f3604 | ||
|
|
e3e5beec74 | ||
|
|
9c71fa0214 | ||
|
|
098c843c50 | ||
|
|
d9ef9eb330 | ||
|
|
748f29b42a | ||
|
|
4507ba3596 | ||
|
|
a7cb76ae94 | ||
|
|
697fa7aa1d | ||
|
|
93fc937429 | ||
|
|
7be54bd687 | ||
|
|
d9e6298edb | ||
|
|
dc8034f5eb | ||
|
|
1cde30eba0 | ||
|
|
6a57ed17a2 | ||
|
|
467adfa082 | ||
|
|
8ae3b244fc | ||
|
|
b03e55a513 | ||
|
|
0d0fab3d2d | ||
|
|
19647d1cd4 | ||
|
|
1563b93691 | ||
|
|
c4c4acfd42 | ||
|
|
0f0eb04edb | ||
|
|
46867a45d2 | ||
|
|
cb2c4542a6 | ||
|
|
38d77898ae | ||
|
|
7a475bef32 | ||
|
|
da7e13ef88 | ||
|
|
acb42ec465 | ||
|
|
00f1b208a1 | ||
|
|
d51429254f | ||
|
|
ac18005de9 | ||
|
|
fa5ba7e42d | ||
|
|
037c234eaa | ||
|
|
73cda0437f | ||
|
|
9731d48691 | ||
|
|
d437bd86ff | ||
|
|
7323557379 | ||
|
|
e878c3fc32 | ||
|
|
27a1a0e5c0 | ||
|
|
1287edf626 | ||
|
|
d81e3f9b06 | ||
|
|
05f954ee9b | ||
|
|
79d214032b | ||
|
|
1693fef529 | ||
|
|
55d83f9f6e | ||
|
|
66400d003d | ||
|
|
a19456b868 | ||
|
|
91965af9b1 | ||
|
|
73189170f5 | ||
|
|
ff3ffe30e4 | ||
|
|
9068de011d | ||
|
|
a7d077b89b | ||
|
|
ace97c9f9c | ||
|
|
7a7b8a7778 | ||
|
|
99bfbbf229 | ||
|
|
bc286910ec | ||
|
|
3a48fb47b7 | ||
|
|
1507956383 | ||
|
|
397b7891ff | ||
|
|
410c992744 | ||
|
|
14abe1e87b | ||
|
|
cafcc5813a | ||
|
|
fe69731d31 | ||
|
|
30975a3328 | ||
|
|
8c02cc9e8f | ||
|
|
4e0c0417ce | ||
|
|
8d7ece126b | ||
|
|
08487a3098 | ||
|
|
e5b40e0488 | ||
|
|
9e7b00a3b9 | ||
|
|
c82ab92d04 | ||
|
|
5c40e81a7e | ||
|
|
f4383a70ba | ||
|
|
aa75e181be | ||
|
|
b4c69320fc | ||
|
|
f2d0eefa77 | ||
|
|
26c58027fb | ||
|
|
f331eb1c0d | ||
|
|
fd6661dfcf | ||
|
|
d727382275 | ||
|
|
67fbe980a7 | ||
|
|
689af32313 | ||
|
|
d68d71013f | ||
|
|
9553dc7761 | ||
|
|
f6f8f0c7fd | ||
|
|
bed869a8a0 | ||
|
|
750fc2e876 | ||
|
|
285413b502 | ||
|
|
d794444715 | ||
|
|
6365f011b0 | ||
|
|
043f58452a | ||
|
|
a082ce2613 | ||
|
|
4c925692f5 | ||
|
|
70ad633638 | ||
|
|
2b3b486a37 | ||
|
|
eae54b67d8 | ||
|
|
90512910e5 | ||
|
|
b1ace8ce19 | ||
|
|
e9cadbe105 | ||
|
|
49a8c786d5 | ||
|
|
06c1f71897 | ||
|
|
3f351466f7 | ||
|
|
7ac7cc0ac8 | ||
|
|
9476cf8cdc | ||
|
|
5f5db7cf41 | ||
|
|
f203d4e206 | ||
|
|
3b7834af17 | ||
|
|
29b2cfba06 | ||
|
|
1bd57b4c1d | ||
|
|
e095586d9e | ||
|
|
0edd89fadc | ||
|
|
a8a579b154 | ||
|
|
0646fd465e | ||
|
|
dd88a0f05c | ||
|
|
6cb2c35d16 | ||
|
|
ee37838b11 | ||
|
|
7421252edc | ||
|
|
a6fdb9d9d7 | ||
|
|
15b6793528 | ||
|
|
b05caca77e | ||
|
|
eb3597acb3 | ||
|
|
112846ce0b | ||
|
|
6134a71a90 | ||
|
|
f92b6f9930 | ||
|
|
73e93ef5e5 | ||
|
|
ca9cbd92c4 | ||
|
|
6481471c9d | ||
|
|
b6e7a0b490 | ||
|
|
f04abd1f8a | ||
|
|
23de09aeb8 | ||
|
|
b2f1254c14 | ||
|
|
ce199db848 | ||
|
|
9be086fbee | ||
|
|
406d6de651 | ||
|
|
16c209c613 | ||
|
|
e643de6e61 | ||
|
|
805bf6ec74 | ||
|
|
6ba94fdd81 | ||
|
|
cc4855acbe | ||
|
|
052f28746d | ||
|
|
b09ea3b6f7 | ||
|
|
749372caf3 | ||
|
|
bc1adc32cb | ||
|
|
6b48868cf0 | ||
|
|
261e6c3df6 | ||
|
|
9bfc8881cb | ||
|
|
32bcdd90ae | ||
|
|
8e5305f630 | ||
|
|
e7f1329cae | ||
|
|
c3bb2b29d4 | ||
|
|
e87fa7c9ce | ||
|
|
1671b83585 | ||
|
|
f5401fbd34 | ||
|
|
552e60b3a1 | ||
|
|
a2d2fe3a8c | ||
|
|
a1195aaa66 | ||
|
|
d67f160200 | ||
|
|
dd6fbcbb69 | ||
|
|
c3642957c5 | ||
|
|
0eb9daf602 | ||
|
|
32febed8d5 | ||
|
|
e40768ac32 | ||
|
|
27399755fd | ||
|
|
e113df129e | ||
|
|
6dff5dc653 | ||
|
|
d90a647802 | ||
|
|
12fba201be | ||
|
|
4f278324c7 | ||
|
|
7239a45b79 | ||
|
|
d94036f8ed | ||
|
|
60b61f2db3 | ||
|
|
afdbb28f72 | ||
|
|
34a9e3d3cd | ||
|
|
7cfe5ab9bc | ||
|
|
83258e3385 | ||
|
|
1b6d0346a3 | ||
|
|
d6cabbbc53 | ||
|
|
3e29c80122 | ||
|
|
db41fe6c5d | ||
|
|
8c7bbcfb0f | ||
|
|
7a9af3cd0e | ||
|
|
e869a52cc4 | ||
|
|
e727da6cf1 | ||
|
|
4d4d5bf323 | ||
|
|
083c221cbe | ||
|
|
34fb5202bd | ||
|
|
edb209776f | ||
|
|
a1cfef9f26 | ||
|
|
102926ed9f | ||
|
|
6e9148e7ab | ||
|
|
2ee105089a | ||
|
|
9194610f42 | ||
|
|
f3c75bb201 | ||
|
|
e16d309d56 | ||
|
|
5baf2de898 | ||
|
|
8ebd45fde7 | ||
|
|
8c7ec44bf0 | ||
|
|
3aedaa7f2a | ||
|
|
38b81e6537 | ||
|
|
a8bcdef4fd | ||
|
|
f41935909f | ||
|
|
02621cffb0 | ||
|
|
5a961d3411 | ||
|
|
7c6fb63041 | ||
|
|
e86910b052 | ||
|
|
c26458339e | ||
|
|
081902b4c1 | ||
|
|
0a3c6bf8c6 | ||
|
|
73b5ee64e7 | ||
|
|
b825987b2f | ||
|
|
c90582344d | ||
|
|
1f01eaa612 | ||
|
|
61d3296f2a | ||
|
|
da37cbd24f | ||
|
|
e4e2abc8bc | ||
|
|
5bbe68cf15 | ||
|
|
35cdd9cf48 | ||
|
|
f771d3f870 | ||
|
|
6210c1ec28 | ||
|
|
c350f96c09 | ||
|
|
366493a1d1 | ||
|
|
dcb2a5a611 | ||
|
|
4d568b709c | ||
|
|
bd0967a4b1 | ||
|
|
bacc942333 | ||
|
|
e2438b5b9f | ||
|
|
b65246499b | ||
|
|
ea96381534 | ||
|
|
943b217797 | ||
|
|
51340888aa | ||
|
|
46cedb105b | ||
|
|
f4675af4cf | ||
|
|
4b02d4e22e | ||
|
|
6d322e68f3 | ||
|
|
5e7d3ad749 | ||
|
|
946f07af3e | ||
|
|
a0ddfad94b | ||
|
|
c70c9f6565 | ||
|
|
d61b1369d0 | ||
|
|
139209ef42 | ||
|
|
111a9fcff5 | ||
|
|
5a846e0929 | ||
|
|
4b9806ab6f | ||
|
|
22b6c482ec | ||
|
|
96801ac085 | ||
|
|
3db51e3f0e | ||
|
|
9b830791ea | ||
|
|
4f4ddb806d | ||
|
|
e6b4b41881 | ||
|
|
0bf1cc2320 | ||
|
|
3a841515af | ||
|
|
17649d4ac8 | ||
|
|
3f9ae846b8 | ||
|
|
81be333e9f | ||
|
|
a1f7a48325 | ||
|
|
5f45cb90a7 | ||
|
|
beee9940a5 | ||
|
|
145ded10c2 | ||
|
|
83e1a0bad8 | ||
|
|
c957d46f1d | ||
|
|
c48d22bd3c | ||
|
|
584ff361df | ||
|
|
86fa0333ff | ||
|
|
3edc25dbdf | ||
|
|
78ffa44fc5 | ||
|
|
643df602c7 | ||
|
|
4002f5e206 | ||
|
|
e932c5da50 | ||
|
|
b96862ee11 | ||
|
|
15ccea7111 | ||
|
|
c5ef76bf27 | ||
|
|
7272fd2210 | ||
|
|
2f4c2a43d4 | ||
|
|
b76c6951aa | ||
|
|
053d35de47 | ||
|
|
2db67a8ea0 | ||
|
|
46393bfca0 | ||
|
|
49d486319f | ||
|
|
75d4d8e9a4 | ||
|
|
2aedc98242 | ||
|
|
6a6c8d7b81 | ||
|
|
a64c73a979 | ||
|
|
700e2a2d25 | ||
|
|
71485ebfc7 | ||
|
|
455b26b8db | ||
|
|
4e8af1d3aa | ||
|
|
14b1e5270d | ||
|
|
4c88c4626d | ||
|
|
717714b24f | ||
|
|
f173274fe4 | ||
|
|
820b1b98fc | ||
|
|
82ae02bc6a | ||
|
|
297d5915c3 | ||
|
|
4a4ea47f70 | ||
|
|
c3e224ad0e | ||
|
|
2208ebfe16 | ||
|
|
2166d7be72 | ||
|
|
d591d04103 | ||
|
|
54154dc6f1 | ||
|
|
0f0f6978e7 | ||
|
|
9e4dc83241 | ||
|
|
b910c34f09 | ||
|
|
b9e4198500 | ||
|
|
5d5807b238 | ||
|
|
46d6f7a639 | ||
|
|
bd893348b4 | ||
|
|
94632eb155 | ||
|
|
7195df5aca | ||
|
|
e4805e4883 | ||
|
|
698483b5a1 | ||
|
|
406b566cfc | ||
|
|
5abf6b7c21 | ||
|
|
76954884c7 | ||
|
|
110dac870c | ||
|
|
1f73cadd2d | ||
|
|
76322d3b3e | ||
|
|
2a01e3d4ca | ||
|
|
925fec6ecb | ||
|
|
e3366787b6 | ||
|
|
10f37345eb | ||
|
|
1f6d79ab48 | ||
|
|
7379a2624b | ||
|
|
2a22576b2d | ||
|
|
e447d7ca5e | ||
|
|
63368a5064 | ||
|
|
b74e7f6a78 | ||
|
|
053314f295 | ||
|
|
7aef59c6c3 | ||
|
|
16fa9d9ed5 | ||
|
|
4daad1cf11 | ||
|
|
3688eeeea0 | ||
|
|
9681d98cc4 | ||
|
|
d3d18e637c | ||
|
|
a42c3a0e90 | ||
|
|
0e177cc7c9 | ||
|
|
4dc8184803 | ||
|
|
7e794b7748 | ||
|
|
e4db42e476 | ||
|
|
c086dfadc3 | ||
|
|
c489dd2e17 | ||
|
|
fbd8b456db | ||
|
|
94d3878efb | ||
|
|
b8caca4652 | ||
|
|
a9812ec9d3 | ||
|
|
02e934c444 | ||
|
|
efa17cae24 | ||
|
|
34eb082bbc | ||
|
|
f70404addb | ||
|
|
8c6fd0933f | ||
|
|
ce83162d7c | ||
|
|
7eae2647c0 | ||
|
|
7bffbe0e2f | ||
|
|
b0398f42ad | ||
|
|
54741aeac5 | ||
|
|
5e88d3a89b | ||
|
|
5b5c5cc618 | ||
|
|
16ef133be2 | ||
|
|
2a6981a697 | ||
|
|
ddbe763eb8 | ||
|
|
aa68b898ff | ||
|
|
b5be7420d9 | ||
|
|
8cf10948bd | ||
|
|
ae6beda12d | ||
|
|
175d06a929 | ||
|
|
ea0463791d | ||
|
|
bbaaf4f1d3 | ||
|
|
e52d2e3bd8 | ||
|
|
115e66e9be | ||
|
|
efb0e7ac6f | ||
|
|
93c02e2532 | ||
|
|
b0618f9011 | ||
|
|
0f0dc1a2a5 | ||
|
|
b978f505ff | ||
|
|
a25f9b2106 | ||
|
|
9d04ecc7b3 | ||
|
|
838592a171 | ||
|
|
8212e1047e | ||
|
|
35b207946a | ||
|
|
9e2a68a981 | ||
|
|
c820b43fc0 | ||
|
|
eab9097b46 | ||
|
|
cc854c0617 | ||
|
|
919744375e | ||
|
|
7c5531b4ca | ||
|
|
fe63c09381 | ||
|
|
02e9876665 | ||
|
|
b5f62a143d | ||
|
|
7a5728fb4c | ||
|
|
97750cd12f | ||
|
|
ebd0fed0ce | ||
|
|
00acae12a4 | ||
|
|
6bf0f04ae2 | ||
|
|
598fcccf45 | ||
|
|
fe69a8d215 | ||
|
|
dd06a0a4a6 | ||
|
|
52cee9dd83 | ||
|
|
55b8204ca3 | ||
|
|
1ac7fde67b | ||
|
|
b9ac1c12d0 | ||
|
|
05f9acdc7f | ||
|
|
f0d1c8429b | ||
|
|
32e747dd31 | ||
|
|
512b2adc77 | ||
|
|
cd3b5e60a8 | ||
|
|
9958c41927 | ||
|
|
763db8aab0 | ||
|
|
b78add3df5 | ||
|
|
d6473b2018 | ||
|
|
2172115379 | ||
|
|
f7fc7bc44a | ||
|
|
e822a9f38d | ||
|
|
0c9e3e8df2 | ||
|
|
3076a839a5 | ||
|
|
f7f2f77dca | ||
|
|
e2fce429cf | ||
|
|
d45a9c0f5b | ||
|
|
0f0baec1f3 | ||
|
|
2354fb3fe4 | ||
|
|
56b527a6fb | ||
|
|
14d0b0bbdd | ||
|
|
014122256b | ||
|
|
1b6dfd4802 | ||
|
|
29300e72ee | ||
|
|
4129cf5090 | ||
|
|
9e8dec2f38 | ||
|
|
5013032845 | ||
|
|
58b763c99c | ||
|
|
7a394575fb | ||
|
|
7a28b243fa | ||
|
|
373372c8ab | ||
|
|
0ba3939542 | ||
|
|
bc29785d09 | ||
|
|
248144d066 | ||
|
|
7e3be7d1ba | ||
|
|
2b6391538c | ||
|
|
3efd1f9c6e | ||
|
|
83d5db056b | ||
|
|
0424410773 | ||
|
|
e9206fb93d | ||
|
|
af21263cb3 | ||
|
|
90ee7783b4 | ||
|
|
52fd66210b | ||
|
|
84aca4201e | ||
|
|
eb710cced1 | ||
|
|
63c50ced89 | ||
|
|
0c68c19c32 | ||
|
|
4b0f6829f6 | ||
|
|
fdcc709ed0 | ||
|
|
adb80816fb | ||
|
|
4a3884245d | ||
|
|
b765288bf2 | ||
|
|
1e80ec8926 | ||
|
|
04186616be | ||
|
|
837bfab75c | ||
|
|
1758614f96 | ||
|
|
44c4fe8e61 | ||
|
|
35df4b10eb | ||
|
|
34618c2d30 | ||
|
|
d809fbb541 | ||
|
|
3f59969c3f | ||
|
|
f32ef63b6c | ||
|
|
0a0cc696ca | ||
|
|
0e7edd1d24 | ||
|
|
38f7fbac64 | ||
|
|
10c76ce35a | ||
|
|
ea63a38f5a | ||
|
|
dcc8f90c58 | ||
|
|
9916d8fa9a | ||
|
|
213cea3aaa | ||
|
|
af781897fa | ||
|
|
6df7917581 | ||
|
|
888dd33148 | ||
|
|
df3ff32fc0 | ||
|
|
d6fcab900b | ||
|
|
de58df390b | ||
|
|
d6f4563103 | ||
|
|
f3ae99dcc0 | ||
|
|
f1cc5b12fd | ||
|
|
327d9d59be | ||
|
|
1b319f39d6 | ||
|
|
146745ad88 | ||
|
|
1f359f7558 | ||
|
|
186a3da998 | ||
|
|
12aff59183 | ||
|
|
6ac1e04b3a | ||
|
|
e14c0cabd9 | ||
|
|
cf13a30eaa | ||
|
|
ae55b1b20a | ||
|
|
71261ae374 | ||
|
|
f5beb58561 | ||
|
|
c795a3b37f | ||
|
|
74fd0dd6c4 | ||
|
|
e02e5b0c5b | ||
|
|
9bd7615fef | ||
|
|
e61313843f | ||
|
|
59145715f1 | ||
|
|
27ef503b35 | ||
|
|
30293baaa0 | ||
|
|
22789563de | ||
|
|
3a639d8144 | ||
|
|
44275c763c | ||
|
|
5f13e33d54 | ||
|
|
2f754b73ff | ||
|
|
554a761db2 | ||
|
|
f005a6e792 | ||
|
|
a994fc5e50 | ||
|
|
73b72b8331 | ||
|
|
486ed10848 | ||
|
|
a781b1c178 | ||
|
|
3ae8adce92 | ||
|
|
9940c2f754 | ||
|
|
a95f656d0d | ||
|
|
32c87d56b1 | ||
|
|
60e3dbd6d5 | ||
|
|
2074094e77 | ||
|
|
090db98828 | ||
|
|
8146548d25 | ||
|
|
b0f4e0fcec | ||
|
|
bdccab07f9 | ||
|
|
7a6e438df8 | ||
|
|
e3965d392c | ||
|
|
096fcb5a6e | ||
|
|
584b4ae38b | ||
|
|
95087c8f96 | ||
|
|
7fa0d52262 | ||
|
|
9f34125d5d | ||
|
|
0ab9e4b6a7 | ||
|
|
f2ee0e7aca | ||
|
|
518a8e8cfb | ||
|
|
d9f9ce1268 | ||
|
|
a15b796146 | ||
|
|
2fd2b197ab | ||
|
|
a02db1c45a | ||
|
|
a65649b45d | ||
|
|
aeb4f2bf3d | ||
|
|
03bcd29481 | ||
|
|
0c46f9cf0c | ||
|
|
8493df8edd | ||
|
|
4cbacf6bac | ||
|
|
5407327bc6 | ||
|
|
200793edc6 | ||
|
|
d73eddcdc0 | ||
|
|
8e8755319c | ||
|
|
d93a2bb741 | ||
|
|
29834b6e91 | ||
|
|
71dbe0fe26 | ||
|
|
918f0a92da | ||
|
|
901c919d22 | ||
|
|
03efec2712 | ||
|
|
3071837e21 | ||
|
|
09c792c206 | ||
|
|
f847fcd31a | ||
|
|
c8fdc5c087 | ||
|
|
962874bfe2 | ||
|
|
47b7d4a733 | ||
|
|
26d97f179f | ||
|
|
d79d919329 | ||
|
|
da9a8fdedc | ||
|
|
288e10cf8b | ||
|
|
b3b1e788e1 | ||
|
|
5de9444202 | ||
|
|
043ff47b05 | ||
|
|
e71c3ff187 | ||
|
|
46ddd5520c | ||
|
|
539a48a328 | ||
|
|
c1e3f96c97 | ||
|
|
d4ce98de4d | ||
|
|
0e42b31dc3 |
101
.gitignore
vendored
101
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
*.5
|
||||
*.7
|
||||
*.8
|
||||
*.8_gen
|
||||
*.a
|
||||
*.d
|
||||
*.o
|
||||
@@ -30,3 +31,103 @@ make.tmpl
|
||||
/cscope.out
|
||||
/tags
|
||||
/tmp/
|
||||
|
||||
|
||||
tools/man-generator
|
||||
tools/man-generator.c
|
||||
|
||||
test/lib/lvchange
|
||||
test/lib/lvconvert
|
||||
test/lib/lvcreate
|
||||
test/lib/lvdisplay
|
||||
test/lib/lvextend
|
||||
test/lib/lvmconfig
|
||||
test/lib/lvmdiskscan
|
||||
test/lib/lvmsadc
|
||||
test/lib/lvmsar
|
||||
test/lib/lvreduce
|
||||
test/lib/lvremove
|
||||
test/lib/lvrename
|
||||
test/lib/lvresize
|
||||
test/lib/lvs
|
||||
test/lib/lvscan
|
||||
test/lib/pvchange
|
||||
test/lib/pvck
|
||||
test/lib/pvcreate
|
||||
test/lib/pvdisplay
|
||||
test/lib/pvmove
|
||||
test/lib/pvremove
|
||||
test/lib/pvresize
|
||||
test/lib/pvs
|
||||
test/lib/pvscan
|
||||
test/lib/vgcfgbackup
|
||||
test/lib/vgcfgrestore
|
||||
test/lib/vgchange
|
||||
test/lib/vgck
|
||||
test/lib/vgconvert
|
||||
test/lib/vgcreate
|
||||
test/lib/vgdisplay
|
||||
test/lib/vgexport
|
||||
test/lib/vgextend
|
||||
test/lib/vgimport
|
||||
test/lib/vgimportclone
|
||||
test/lib/vgmerge
|
||||
test/lib/vgmknodes
|
||||
test/lib/vgreduce
|
||||
test/lib/vgremove
|
||||
test/lib/vgrename
|
||||
test/lib/vgs
|
||||
test/lib/vgscan
|
||||
test/lib/vgsplit
|
||||
test/api/lvtest.t
|
||||
test/api/pe_start.t
|
||||
test/api/percent.t
|
||||
test/api/python_lvm_unit.py
|
||||
test/api/test
|
||||
test/api/thin_percent.t
|
||||
test/api/vglist.t
|
||||
test/api/vgtest.t
|
||||
test/lib/aux
|
||||
test/lib/check
|
||||
test/lib/clvmd
|
||||
test/lib/dm-version-expected
|
||||
test/lib/dmeventd
|
||||
test/lib/dmsetup
|
||||
test/lib/dmstats
|
||||
test/lib/fail
|
||||
test/lib/flavour-ndev-cluster
|
||||
test/lib/flavour-ndev-cluster-lvmpolld
|
||||
test/lib/flavour-ndev-lvmetad
|
||||
test/lib/flavour-ndev-lvmetad-lvmpolld
|
||||
test/lib/flavour-ndev-lvmpolld
|
||||
test/lib/flavour-ndev-vanilla
|
||||
test/lib/flavour-udev-cluster
|
||||
test/lib/flavour-udev-cluster-lvmpolld
|
||||
test/lib/flavour-udev-lvmetad
|
||||
test/lib/flavour-udev-lvmetad-lvmpolld
|
||||
test/lib/flavour-udev-lvmlockd-dlm
|
||||
test/lib/flavour-udev-lvmlockd-sanlock
|
||||
test/lib/flavour-udev-lvmlockd-test
|
||||
test/lib/flavour-udev-lvmpolld
|
||||
test/lib/flavour-udev-vanilla
|
||||
test/lib/fsadm
|
||||
test/lib/get
|
||||
test/lib/inittest
|
||||
test/lib/invalid
|
||||
test/lib/lvm
|
||||
test/lib/lvm-wrapper
|
||||
test/lib/lvmchange
|
||||
test/lib/lvmdbusd.profile
|
||||
test/lib/lvmetad
|
||||
test/lib/lvmpolld
|
||||
test/lib/not
|
||||
test/lib/paths
|
||||
test/lib/paths-common
|
||||
test/lib/runner
|
||||
test/lib/should
|
||||
test/lib/test
|
||||
test/lib/thin-performance.profile
|
||||
test/lib/utils
|
||||
test/lib/version-expected
|
||||
test/unit/dmraid_t.c
|
||||
test/unit/unit-test
|
||||
|
||||
40
Makefile.in
40
Makefile.in
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts device_mapper tools
|
||||
|
||||
ifeq ("@UDEV_RULES@", "yes")
|
||||
SUBDIRS += udev
|
||||
@@ -43,8 +43,7 @@ endif
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = conf include man test scripts \
|
||||
libdaemon lib tools daemons libdm \
|
||||
udev po liblvm python \
|
||||
unit-tests/datastruct unit-tests/mm unit-tests/regex
|
||||
udev po liblvm python device_mapper
|
||||
tools.distclean: test.distclean
|
||||
endif
|
||||
DISTCLEAN_DIRS += lcov_reports*
|
||||
@@ -62,6 +61,9 @@ po: tools daemons
|
||||
man: tools
|
||||
all_man: tools
|
||||
scripts: liblvm libdm
|
||||
test: tools daemons
|
||||
unit-test: lib
|
||||
run-unit-test: unit-test
|
||||
|
||||
lib.device-mapper: include.device-mapper
|
||||
libdm.device-mapper: include.device-mapper
|
||||
@@ -97,7 +99,7 @@ endif
|
||||
DISTCLEAN_TARGETS += cscope.out
|
||||
CLEAN_DIRS += autom4te.cache
|
||||
|
||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
|
||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test run-unit-test: test
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate man.generate: tools
|
||||
@@ -146,7 +148,7 @@ install_system_dirs:
|
||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_RUN_DIR)
|
||||
$(INSTALL_ROOT_DATA) /dev/null $(DESTDIR)$(DEFAULT_CACHE_DIR)/.cache
|
||||
|
||||
install_initscripts:
|
||||
install_initscripts:
|
||||
$(MAKE) -C scripts install_initscripts
|
||||
|
||||
install_systemd_generators:
|
||||
@@ -169,6 +171,7 @@ install_tmpfiles_configuration:
|
||||
|
||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||
libdaemon/client.info libdaemon/server.info \
|
||||
test/unit.info \
|
||||
daemons/clvmd.info \
|
||||
daemons/dmeventd.info \
|
||||
daemons/lvmetad.info \
|
||||
@@ -211,31 +214,6 @@ endif
|
||||
|
||||
endif
|
||||
|
||||
ifeq ("$(TESTING)", "yes")
|
||||
# testing and report generation
|
||||
RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
|
||||
|
||||
.PHONY: unit-test ruby-test test-programs
|
||||
|
||||
# FIXME: put dependencies on libdm and liblvm
|
||||
# FIXME: Should be handled by Makefiles in subdirs, not here at top level.
|
||||
test-programs:
|
||||
cd unit-tests/regex && $(MAKE)
|
||||
cd unit-tests/datastruct && $(MAKE)
|
||||
cd unit-tests/mm && $(MAKE)
|
||||
|
||||
unit-test: test-programs
|
||||
$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS)
|
||||
$(RUBY) report-generators/title_page.rb
|
||||
|
||||
memcheck: test-programs
|
||||
$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS)
|
||||
$(RUBY) report-generators/title_page.rb
|
||||
|
||||
ruby-test:
|
||||
$(RUBY) report-generators/test/ts.rb
|
||||
endif
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
tags:
|
||||
|
||||
13
README
13
README
@@ -8,10 +8,15 @@ 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:
|
||||
https://sourceware.org/git/?p=lvm2.git
|
||||
git clone git://sourceware.org/git/lvm2.git
|
||||
mirrored to:
|
||||
https://github.com/lvmteam/lvm2
|
||||
git clone https://github.com/lvmteam/lvm2.git
|
||||
git clone git@github.com:lvmteam/lvm2.git
|
||||
|
||||
Mailing list for general discussion related to LVM2:
|
||||
linux-lvm@redhat.com
|
||||
@@ -29,6 +34,14 @@ and multipath-tools:
|
||||
dm-devel@redhat.com
|
||||
Subscribe from https://www.redhat.com/mailman/listinfo/dm-devel
|
||||
|
||||
Website:
|
||||
https://sourceware.org/lvm2/
|
||||
|
||||
Report upstream bugs at:
|
||||
https://bugzilla.redhat.com/enter_bug.cgi?product=LVM%20and%20device-mapper
|
||||
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.
|
||||
|
||||
|
||||
62
TESTING
Normal file
62
TESTING
Normal file
@@ -0,0 +1,62 @@
|
||||
LVM2 Test Suite
|
||||
===============
|
||||
|
||||
The codebase contains many tests in the test subdirectory.
|
||||
|
||||
Before running tests
|
||||
--------------------
|
||||
|
||||
Keep in mind the testsuite MUST run under root user.
|
||||
|
||||
It is recommended not to use LVM on the test machine, especially when running
|
||||
tests with udev (`make check_system`.)
|
||||
|
||||
You MUST disable (or mask) any LVM daemons:
|
||||
|
||||
- lvmetad
|
||||
- dmeventd
|
||||
- lvmpolld
|
||||
- lvmdbusd
|
||||
- lvmlockd
|
||||
- clvmd
|
||||
- cmirrord
|
||||
|
||||
For running cluster tests, we are using singlenode locking. Pass
|
||||
`--with-clvmd=singlenode` to configure.
|
||||
|
||||
NOTE: This is useful only for testing, and should not be used in produciton
|
||||
code.
|
||||
|
||||
To run D-Bus daemon tests, existing D-Bus session is required.
|
||||
|
||||
Running tests
|
||||
-------------
|
||||
|
||||
As root run:
|
||||
|
||||
make check
|
||||
|
||||
To run only tests matching a string:
|
||||
|
||||
make check T=test
|
||||
|
||||
To skip tests matching a string:
|
||||
|
||||
make check S=test
|
||||
|
||||
There are other targets and many environment variables can be used to tweak the
|
||||
testsuite - for full list and description run `make -C test help`.
|
||||
|
||||
Installing testsuite
|
||||
--------------------
|
||||
|
||||
It is possible to install and run a testsuite against installed LVM. Run the
|
||||
following:
|
||||
|
||||
make -C test install
|
||||
|
||||
Then lvm2-testsuite binary can be executed to test installed binaries.
|
||||
|
||||
See `lvm2-testsuite --help` for options. The same environment variables can be
|
||||
used as with `make check`.
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.143-git (2017-07-20)
|
||||
1.02.149 (2018-07-19)
|
||||
|
||||
193
WHATS_NEW
193
WHATS_NEW
@@ -1,5 +1,196 @@
|
||||
Version 2.02.174 -
|
||||
Version 2.02.180 - 19th July 2018
|
||||
=================================
|
||||
Never send any discard ioctl with test mode.
|
||||
Fix thin-pool alloc which needs same PV for data and metadata.
|
||||
Extend list of non-memlocked areas with newly linked libs.
|
||||
Enhance vgcfgrestore to check for active LVs in restored VG.
|
||||
lvconvert: provide possible layouts between linear and striped/raid
|
||||
Fix unmonitoring of merging snapshots.
|
||||
Add missing -l description in fsadm man page.
|
||||
Cache can uses metadata format 2 with cleaner policy.
|
||||
Avoid showing internal error in lvs output or pvmoved LVs.
|
||||
Fix check if resized PV can also fit metadata area.
|
||||
Reopen devices RDWR only before writing to avoid udev issues.
|
||||
Change pvresize output confusing when no resize took place.
|
||||
Fix lvmetad hanging on shutdown.
|
||||
Fix mem leak in clvmd and more coverity issues.
|
||||
|
||||
Version 2.02.179 - 18th June 2018
|
||||
=================================
|
||||
Allow forced vgchange to lock type none on clustered VG.
|
||||
Add the report field "shared".
|
||||
Enable automatic metadata consistency repair on a shared VG.
|
||||
Fix pvremove force on a PV with a shared VG.
|
||||
Fixed vgimportclone of a PV with a shared VG.
|
||||
Enable previously disallowed thin/cache commands in shared VGs.
|
||||
Enable metadata-related changes on LVs active with shared lock.
|
||||
Do not continue trying to use a device that cannot be opened.
|
||||
Fix problems opening a device that fails and returns.
|
||||
Use versionsort to fix archive file expiry beyond 100000 files.
|
||||
|
||||
Version 2.02.178 - 13th June 2018
|
||||
=================================
|
||||
|
||||
Version 2.02.178-rc1 - 24th May 2018
|
||||
====================================
|
||||
Add libaio dependency for build.
|
||||
Remove lvm1 and pool format handling and add filter to ignore them.
|
||||
Move some filter checks to after disks are read.
|
||||
Rework disk scanning and when it is used.
|
||||
Add new io layer and shift code to using it.
|
||||
Fix lvconvert's return code on degraded -m raid1 conversion.
|
||||
--enable-testing switch for ./configure has been removed.
|
||||
--with-snapshots switch for ./configure has been removed.
|
||||
--with-mirrors switch for ./configure has been removed.
|
||||
--with-raid switch for ./configure has been removed.
|
||||
--with-thin switch for ./configure has been removed.
|
||||
--with-cache switch for ./configure has been removed.
|
||||
Include new unit-test framework and unit tests.
|
||||
Extend validation of region_size for mirror segment.
|
||||
Reload whole device stack when reinitilizing mirror log.
|
||||
Mirrors without monitoring are WARNING and not blocking on error.
|
||||
Detect too big region_size with clustered mirrors.
|
||||
Fix evaluation of maximal region size for mirror log.
|
||||
Enhance mirror log size estimation and use smaller size when possible.
|
||||
Fix incorrect mirror log size calculation on 32bit arch.
|
||||
Enhance preloading tree creating.
|
||||
Fix regression on acceptance of any LV on lvconvert.
|
||||
Restore usability of thin LV to be again external origin for another thin.
|
||||
Keep systemd vars on change event in 69-dm-lvm-metad.rules for systemd reload.
|
||||
Write systemd and non-systemd rule in 69-dm-lvm-metad.rules, GOTO active one.
|
||||
Add test for activation/volume_list (Sub)LV remnants.
|
||||
Disallow usage of cache format 2 with mq cache policy.
|
||||
Again accept striped LV as COW LV with lvconvert -s (2.02.169).
|
||||
Fix raid target version testing for supported features.
|
||||
Allow activation of pools when thin/cache_check tool is missing.
|
||||
Remove RaidLV on creation failure when rmeta devices can't be activated.
|
||||
Add prioritized_section() to restore cookie boundaries (2.02.177).
|
||||
Enhance error messages when read error happens.
|
||||
Enhance mirror log initialization for old mirror target.
|
||||
Skip private crypto and stratis devices.
|
||||
Skip frozen raid devices from scanning.
|
||||
Activate RAID SubLVs on read_only_volume_list readwrite.
|
||||
Offer convenience type raid5_n converting to raid10.
|
||||
Automatically avoid reading invalid snapshots during device scan.
|
||||
Ensure COW device is writable even for read-only thick snapshots.
|
||||
Support activation of component LVs in read-only mode.
|
||||
Extend internal library to recognize and work with component LV.
|
||||
Skip duplicate check for active LV when prompting for its removal.
|
||||
Activate correct lock holding LV when it is cached.
|
||||
Do not modify archived metadata when removing striped raid.
|
||||
Fix memleak on error path when obtaining lv_raid_data_offset.
|
||||
Fix compatibility size test of extended external origin.
|
||||
Add external_origin visiting in for_each_sub_lv().
|
||||
Ensure cluster commands drop their device cache before locking VG.
|
||||
Do not report LV as remotely active when it's locally exclusive in cluster.
|
||||
Add deprecate messages for usage of mirrors with mirrorlog.
|
||||
Separate reporting of monitoring status and error status.
|
||||
Improve validation of created strings in vgimportclone.
|
||||
Add missing initialisation of mem pool in systemd generator.
|
||||
Do not reopen output streams for multithreaded users of liblvm.
|
||||
Configure ensures /usr/bin dir is checked for dmpd tools.
|
||||
Restore pvmove support for wide-clustered active volumes (2.02.177).
|
||||
Avoid non-exclusive activation of exclusive segment types.
|
||||
Fix trimming sibling PVs when doing a pvmove of raid subLVs.
|
||||
Preserve exclusive activation during thin snaphost merge.
|
||||
Avoid exceeding array bounds in allocation tag processing.
|
||||
Add --lockopt to common options and add option to skip selected locks.
|
||||
|
||||
Version 2.02.177 - 18th December 2017
|
||||
=====================================
|
||||
When writing text metadata content, use complete 4096 byte blocks.
|
||||
Change text format metadata alignment from 512 to 4096 bytes.
|
||||
When writing metadata, consistently skip mdas marked as failed.
|
||||
Refactor and adjust text format metadata alignment calculation.
|
||||
Fix python3 path in lvmdbusd to use value detected by configure.
|
||||
Reduce checks for active LVs in vgchange before background polling.
|
||||
Ensure _node_send_message always uses clean status of thin pool.
|
||||
Fix lvmlockd to use pool lock when accessing _tmeta volume.
|
||||
Report expected sanlock_convert errors only when retries fail.
|
||||
Avoid blocking in sanlock_convert on SH to EX lock conversion.
|
||||
Deactivate missing raid LV legs (_rimage_X-missing_Y_Z) on decativation.
|
||||
Skip read-modify-write when entire block is replaced.
|
||||
Categorise I/O with reason annotations in debug messages.
|
||||
Allow extending of raid LVs created with --nosync after a failed repair.
|
||||
Command will lock memory only when suspending volumes.
|
||||
Merge segments when pvmove is finished.
|
||||
Remove label_verify that has never been used.
|
||||
Ensure very large numbers used as arguments are not casted to lower values.
|
||||
Enhance reading and validation of options stripes and stripes_size.
|
||||
Fix printing of default stripe size when user is not using stripes.
|
||||
Activation code for pvmove automatically discovers holding LVs for resume.
|
||||
Make a pvmove LV locking holder.
|
||||
Do not change critical section counter on resume path without real resume.
|
||||
Enhance activation code to automatically suspend pvmove participants.
|
||||
Prevent conversion of thin volumes to snapshot origin when lvmlockd is used.
|
||||
Correct the steps to change lock type in lvmlockd man page.
|
||||
Retry lock acquisition on recognized sanlock errors.
|
||||
Fix lock manager error codes in lvmlockd.
|
||||
Remove unnecessary single read from lvmdiskscan.
|
||||
Check raid reshape flags in vg_validate().
|
||||
Add support for pvmove of cache and snapshot origins.
|
||||
Avoid using precommitted metadata for suspending pvmove tree.
|
||||
Ehnance pvmove locking.
|
||||
Deactivate activated LVs on error path when pvmove activation fails.
|
||||
Add "io" to log/debug_classes for logging low-level I/O.
|
||||
Eliminate redundant nested VG metadata in VG struct.
|
||||
Avoid importing persistent filter in vgscan/pvscan/vgrename.
|
||||
Fix memleak of string buffer when vgcfgbackup runs in secure mode.
|
||||
Do not print error when clvmd cannot find running clvmd.
|
||||
Prevent start of new merge of snapshot if origin is already being merged.
|
||||
Fix offered type for raid6_n_6 to raid5 conversion (raid5_n).
|
||||
Deactivate sub LVs when removing unused cache-pool.
|
||||
Do not take backup with suspended devices.
|
||||
Avoid RAID4 activation on incompatible kernels under all circumstances.
|
||||
Reject conversion request to striped/raid0 on 2-legged raid4/5.
|
||||
|
||||
Version 2.02.176 - 3rd November 2017
|
||||
====================================
|
||||
Keep Install section only in lvm2-{lvmetad,lvmpolld}.socket systemd unit.
|
||||
Fix segfault in lvm_pv_remove in liblvm. (2.02.173)
|
||||
Do not allow storing VG metadata with LV without any segment.
|
||||
Fix printed message when thin snapshot was already merged.
|
||||
Remove created spare LV when creation of thin-pool failed.
|
||||
Avoid reading ignored metadata when mda gets used again.
|
||||
Fix detection of moved PVs in vgsplit. (2.02.175)
|
||||
Ignore --stripes/--stripesize on RAID takeover
|
||||
Improve used paths for generated systemd units and init shells.
|
||||
Disallow creation of snapshot of mirror/raid subLV (was never supported).
|
||||
Fix regression in more advanced vgname extraction in lvconvert (2.02.169).
|
||||
Allow lvcreate to be used for caching of _tdata LV.
|
||||
Avoid internal error when resizing cache type _tdata LV (not yet supported).
|
||||
Show original converted names when lvconverting LV to pool volume.
|
||||
Move lib code used only by liblvm into metadata-liblvm.c.
|
||||
Distinguish between device not found and excluded by filter.
|
||||
Monitor external origin LVs.
|
||||
Remove the replicator code, including configure --with-replicators.
|
||||
Allow lvcreate --type mirror to work with 100%FREE.
|
||||
Improve selection of resource name for complex volume activation lock.
|
||||
Avoid cutting first character of resource name for activation lock.
|
||||
Support for encrypted devices in fsadm.
|
||||
Improve thin pool overprovisioning and repair warning messages.
|
||||
Fix incorrect adjustment of region size on striped RaidLVs.
|
||||
|
||||
Version 2.02.175 - 6th October 2017
|
||||
===================================
|
||||
Use --help with blockdev when checking for --getsize64 support in fsadm.
|
||||
Dump lvmdbusd debug information with SIGUSR1.
|
||||
Fix metadata corruption in vgsplit and vgmerge intermediate states.
|
||||
Add PV_MOVED_VG PV status flag to mark PVs moving between VGs.
|
||||
Fix lvmdbus hang and recognise unknown VG correctly.
|
||||
Improve error messages when command rules fail.
|
||||
Require LV name with pvmove in a shared VG.
|
||||
Allow shared active mirror LVs with lvmlockd, dlm, and cmirrord.
|
||||
Support lvconvert --repair with cache and cachepool volumes.
|
||||
lvconvert --repair respects --poolmetadataspare option.
|
||||
Mark that we don't plan to develop liblvm2app and python bindings any further.
|
||||
Fix thin pool creation in shared VG. (2.02.173)
|
||||
|
||||
Version 2.02.174 - 13th September 2017
|
||||
======================================
|
||||
Prevent raid1 split with trackchanges in a shared VG.
|
||||
Avoid double unlocking of client & lockspace mutexes in lvmlockd.
|
||||
Fix leaking of file descriptor for non-blocking filebased locking.
|
||||
Fix check for 2nd mda at end of disk fits if using pvcreate --restorefile.
|
||||
Use maximum metadataarea size that fits with pvcreate --restorefile.
|
||||
Always clear cached bootloaderarea when wiping label e.g. in pvcreate.
|
||||
|
||||
49
WHATS_NEW_DM
49
WHATS_NEW_DM
@@ -1,5 +1,52 @@
|
||||
Version 1.02.143 -
|
||||
Version 1.02.149 - 19th July 2018
|
||||
=================================
|
||||
|
||||
Version 1.02.148 - 18th June 2018
|
||||
=================================
|
||||
|
||||
Version 1.02.147 - 13th June 2018
|
||||
=================================
|
||||
|
||||
Version 1.02.147-rc1 - 24th May 2018
|
||||
====================================
|
||||
Reuse uname() result for mirror target.
|
||||
Recognize also mounted btrfs through dm_device_has_mounted_fs().
|
||||
Add missing log_error() into dm_stats_populate() returning 0.
|
||||
Avoid calling dm_stats_populat() for DM devices without any stats regions.
|
||||
Support DM_DEBUG_WITH_LINE_NUMBERS envvar for debug msg with source:line.
|
||||
Configured command for thin pool threshold handling gets whole environment.
|
||||
Fix tests for failing dm_snprintf() in stats code.
|
||||
Parsing mirror status accepts 'userspace' keyword in status.
|
||||
Introduce dm_malloc_aligned for page alignment of buffers.
|
||||
|
||||
Version 1.02.146 - 18th December 2017
|
||||
=====================================
|
||||
Activation tree of thin pool skips duplicated check of pool status.
|
||||
Remove code supporting replicator target.
|
||||
Do not ignore failure of _info_by_dev().
|
||||
Propagate delayed resume for pvmove subvolumes.
|
||||
Suppress integrity encryption keys in 'table' output unless --showkeys supplied.
|
||||
|
||||
Version 1.02.145 - 3rd November 2017
|
||||
====================================
|
||||
Keep Install section only in dm-event.socket systemd unit.
|
||||
Issue a specific error with dmsetup status if device is unknown.
|
||||
Fix RT_LIBS reference in generated libdevmapper.pc for pkg-config
|
||||
|
||||
Version 1.02.144 - 6th October 2017
|
||||
===================================
|
||||
Schedule exit when received SIGTERM in dmeventd.
|
||||
Also try to unmount /boot on blkdeactivate -u if on top of supported device.
|
||||
Use blkdeactivate -r wait in blk-availability systemd service/initscript.
|
||||
Add blkdeactivate -r wait option to wait for MD resync/recovery/reshape.
|
||||
Fix blkdeactivate regression with failing DM/MD devs deactivation (1.02.142).
|
||||
Fix typo in blkdeactivate's '--{dm,lvm,mpath}options' option name.
|
||||
Correct return value testing when get reserved values for reporting.
|
||||
Take -S with dmsetup suspend/resume/clear/wipe_table/remove/deps/status/table.
|
||||
|
||||
Version 1.02.143 - 13th September 2017
|
||||
======================================
|
||||
Restore umask when creation of node fails.
|
||||
Add --concise to dmsetup create for many devices with tables in one command.
|
||||
Accept minor number without major in library when it knows dm major number.
|
||||
Introduce single-line concise table output format: dmsetup table --concise
|
||||
|
||||
@@ -155,7 +155,7 @@ AC_DEFUN([AC_TRY_LDFLAGS],
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 3
|
||||
serial 3
|
||||
|
||||
AC_DEFUN([AX_GCC_BUILTIN], [
|
||||
AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1])
|
||||
|
||||
210
aclocal.m4
vendored
210
aclocal.m4
vendored
@@ -69,32 +69,63 @@ AC_DEFUN([AX_PYTHON_MODULE],[
|
||||
fi
|
||||
])
|
||||
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
dnl serial 11 (pkg-config-0.29)
|
||||
dnl
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
dnl General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
dnl 02111-1307, USA.
|
||||
dnl
|
||||
dnl As a special exception to the GNU General Public License, if you
|
||||
dnl distribute this file as part of a program that contains a
|
||||
dnl configuration script generated by Autoconf, you may include it under
|
||||
dnl the same distribution terms that you use for the rest of that
|
||||
dnl program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
dnl PKG_PREREQ(MIN-VERSION)
|
||||
dnl -----------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Verify that the version of the pkg-config macros are at least
|
||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
|
||||
dnl installed version of pkg-config, this checks the developer's version
|
||||
dnl of pkg.m4 when generating configure.
|
||||
dnl
|
||||
dnl To ensure that this macro is defined, also add:
|
||||
dnl m4_ifndef([PKG_PREREQ],
|
||||
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
|
||||
dnl
|
||||
dnl See the "Since" comment for each macro you use to see what version
|
||||
dnl of the macros you require.
|
||||
m4_defun([PKG_PREREQ],
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29])
|
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||
])dnl PKG_PREREQ
|
||||
|
||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
dnl ----------------------------------
|
||||
dnl Since: 0.16
|
||||
dnl
|
||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||
dnl first found in the path. Checks that the version of pkg-config found
|
||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||
dnl used since that's the first version where most current features of
|
||||
dnl pkg-config existed.
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||
@@ -116,18 +147,19 @@ if test -n "$PKG_CONFIG"; then
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
])dnl PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
# only at the first occurence in configure.ac, so if the first place
|
||||
# it's called might be skipped (such as if it is within an "if", you
|
||||
# have to call PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------------------------------
|
||||
dnl Since: 0.18
|
||||
dnl
|
||||
dnl Check to see whether a particular set of modules exists. Similar to
|
||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
dnl
|
||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
dnl only at the first occurence in configure.ac, so if the first place
|
||||
dnl it's called might be skipped (such as if it is within an "if", you
|
||||
dnl have to call PKG_CHECK_EXISTS manually
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
@@ -137,8 +169,10 @@ m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
dnl ---------------------------------------------
|
||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
|
||||
dnl pkg_failed based on the result.
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
@@ -150,10 +184,11 @@ m4_define([_PKG_CONFIG],
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
])dnl _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
dnl ---------------------------
|
||||
dnl Internal check to see if pkg-config supports short errors.
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
@@ -161,19 +196,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl --------------------------------------------------------------
|
||||
dnl Since: 0.4.0
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
@@ -227,16 +260,40 @@ else
|
||||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
])dnl PKG_CHECK_MODULES
|
||||
|
||||
|
||||
# PKG_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable pkgconfigdir as the location where a module
|
||||
# should install pkg-config .pc files. By default the directory is
|
||||
# $libdir/pkgconfig, but the default can be changed by passing
|
||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
# parameter.
|
||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Checks for existence of MODULES and gathers its build flags with
|
||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
|
||||
dnl and VARIABLE-PREFIX_LIBS from --libs.
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
|
||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
|
||||
dnl configure.ac.
|
||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
_save_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES($@)
|
||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
|
||||
])dnl PKG_CHECK_MODULES_STATIC
|
||||
|
||||
|
||||
dnl PKG_INSTALLDIR([DIRECTORY])
|
||||
dnl -------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable pkgconfigdir as the location where a module
|
||||
dnl should install pkg-config .pc files. By default the directory is
|
||||
dnl $libdir/pkgconfig, but the default can be changed by passing
|
||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
dnl parameter.
|
||||
AC_DEFUN([PKG_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@@ -247,16 +304,18 @@ AC_ARG_WITH([pkgconfigdir],
|
||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_INSTALLDIR
|
||||
])dnl PKG_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
# module should install arch-independent pkg-config .pc files. By
|
||||
# default the directory is $datadir/pkgconfig, but the default can be
|
||||
# changed by passing DIRECTORY. The user can override through the
|
||||
# --with-noarch-pkgconfigdir parameter.
|
||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
|
||||
dnl --------------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
dnl module should install arch-independent pkg-config .pc files. By
|
||||
dnl default the directory is $datadir/pkgconfig, but the default can be
|
||||
dnl changed by passing DIRECTORY. The user can override through the
|
||||
dnl --with-noarch-pkgconfigdir parameter.
|
||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@@ -267,13 +326,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
|
||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_NOARCH_INSTALLDIR
|
||||
])dnl PKG_NOARCH_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# -------------------------------------------
|
||||
# Retrieves the value of the pkg-config variable for the given module.
|
||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------
|
||||
dnl Since: 0.28
|
||||
dnl
|
||||
dnl Retrieves the value of the pkg-config variable for the given module.
|
||||
AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||
@@ -282,7 +343,7 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
])dnl PKG_CHECK_VAR
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
@@ -536,5 +597,4 @@ AC_DEFUN([AM_RUN_LOG],
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
|
||||
(exit $ac_status); }])
|
||||
|
||||
|
||||
m4_include([acinclude.m4])
|
||||
|
||||
862
base/data-struct/radix-tree.c
Normal file
862
base/data-struct/radix-tree.c
Normal file
@@ -0,0 +1,862 @@
|
||||
// Copyright (C) 2018 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 "radix-tree.h"
|
||||
|
||||
#include "base/memory/container_of.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
enum node_type {
|
||||
UNSET = 0,
|
||||
VALUE,
|
||||
VALUE_CHAIN,
|
||||
PREFIX_CHAIN,
|
||||
NODE4,
|
||||
NODE16,
|
||||
NODE48,
|
||||
NODE256
|
||||
};
|
||||
|
||||
struct value {
|
||||
enum node_type type;
|
||||
union radix_value value;
|
||||
};
|
||||
|
||||
// This is used for entries that have a key which is a prefix of another key.
|
||||
struct value_chain {
|
||||
union radix_value value;
|
||||
struct value child;
|
||||
};
|
||||
|
||||
struct prefix_chain {
|
||||
struct value child;
|
||||
unsigned len;
|
||||
uint8_t prefix[0];
|
||||
};
|
||||
|
||||
struct node4 {
|
||||
uint32_t nr_entries;
|
||||
uint8_t keys[4];
|
||||
struct value values[4];
|
||||
};
|
||||
|
||||
struct node16 {
|
||||
uint32_t nr_entries;
|
||||
uint8_t keys[16];
|
||||
struct value values[16];
|
||||
};
|
||||
|
||||
struct node48 {
|
||||
uint32_t nr_entries;
|
||||
uint8_t keys[256];
|
||||
struct value values[48];
|
||||
};
|
||||
|
||||
struct node256 {
|
||||
uint32_t nr_entries;
|
||||
struct value values[256];
|
||||
};
|
||||
|
||||
struct radix_tree {
|
||||
unsigned nr_entries;
|
||||
struct value root;
|
||||
radix_value_dtr dtr;
|
||||
void *dtr_context;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
|
||||
{
|
||||
struct radix_tree *rt = malloc(sizeof(*rt));
|
||||
|
||||
if (rt) {
|
||||
rt->nr_entries = 0;
|
||||
rt->root.type = UNSET;
|
||||
rt->dtr = dtr;
|
||||
rt->dtr_context = dtr_context;
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
static inline void _dtr(struct radix_tree *rt, union radix_value v)
|
||||
{
|
||||
if (rt->dtr)
|
||||
rt->dtr(rt->dtr_context, v);
|
||||
}
|
||||
|
||||
// Returns the number of values removed
|
||||
static unsigned _free_node(struct radix_tree *rt, struct value v)
|
||||
{
|
||||
unsigned i, nr = 0;
|
||||
struct value_chain *vc;
|
||||
struct prefix_chain *pc;
|
||||
struct node4 *n4;
|
||||
struct node16 *n16;
|
||||
struct node48 *n48;
|
||||
struct node256 *n256;
|
||||
|
||||
switch (v.type) {
|
||||
case UNSET:
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
_dtr(rt, v.value);
|
||||
nr = 1;
|
||||
break;
|
||||
|
||||
case VALUE_CHAIN:
|
||||
vc = v.value.ptr;
|
||||
_dtr(rt, vc->value);
|
||||
nr = 1 + _free_node(rt, vc->child);
|
||||
free(vc);
|
||||
break;
|
||||
|
||||
case PREFIX_CHAIN:
|
||||
pc = v.value.ptr;
|
||||
nr = _free_node(rt, pc->child);
|
||||
free(pc);
|
||||
break;
|
||||
|
||||
case NODE4:
|
||||
n4 = (struct node4 *) v.value.ptr;
|
||||
for (i = 0; i < n4->nr_entries; i++)
|
||||
nr += _free_node(rt, n4->values[i]);
|
||||
free(n4);
|
||||
break;
|
||||
|
||||
case NODE16:
|
||||
n16 = (struct node16 *) v.value.ptr;
|
||||
for (i = 0; i < n16->nr_entries; i++)
|
||||
nr += _free_node(rt, n16->values[i]);
|
||||
free(n16);
|
||||
break;
|
||||
|
||||
case NODE48:
|
||||
n48 = (struct node48 *) v.value.ptr;
|
||||
for (i = 0; i < n48->nr_entries; i++)
|
||||
nr += _free_node(rt, n48->values[i]);
|
||||
free(n48);
|
||||
break;
|
||||
|
||||
case NODE256:
|
||||
n256 = (struct node256 *) v.value.ptr;
|
||||
for (i = 0; i < 256; i++)
|
||||
nr += _free_node(rt, n256->values[i]);
|
||||
free(n256);
|
||||
break;
|
||||
}
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
void radix_tree_destroy(struct radix_tree *rt)
|
||||
{
|
||||
_free_node(rt, rt->root);
|
||||
free(rt);
|
||||
}
|
||||
|
||||
unsigned radix_tree_size(struct radix_tree *rt)
|
||||
{
|
||||
return rt->nr_entries;
|
||||
}
|
||||
|
||||
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
|
||||
|
||||
static bool _insert_unset(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
unsigned len = ke - kb;
|
||||
|
||||
if (!len) {
|
||||
// value
|
||||
v->type = VALUE;
|
||||
v->value = rv;
|
||||
rt->nr_entries++;
|
||||
} else {
|
||||
// prefix -> value
|
||||
struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
|
||||
if (!pc)
|
||||
return false;
|
||||
|
||||
pc->child.type = VALUE;
|
||||
pc->child.value = rv;
|
||||
pc->len = len;
|
||||
memcpy(pc->prefix, kb, len);
|
||||
v->type = PREFIX_CHAIN;
|
||||
v->value.ptr = pc;
|
||||
rt->nr_entries++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _insert_value(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
unsigned len = ke - kb;
|
||||
|
||||
if (!len)
|
||||
// overwrite
|
||||
v->value = rv;
|
||||
|
||||
else {
|
||||
// value_chain -> value
|
||||
struct value_chain *vc = zalloc(sizeof(*vc));
|
||||
if (!vc)
|
||||
return false;
|
||||
|
||||
vc->value = v->value;
|
||||
if (!_insert(rt, &vc->child, kb, ke, rv)) {
|
||||
free(vc);
|
||||
return false;
|
||||
}
|
||||
|
||||
v->type = VALUE_CHAIN;
|
||||
v->value.ptr = vc;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct value_chain *vc = v->value.ptr;
|
||||
return _insert(rt, &vc->child, kb, ke, rv);
|
||||
}
|
||||
|
||||
static unsigned min(unsigned lhs, unsigned rhs)
|
||||
{
|
||||
if (lhs <= rhs)
|
||||
return lhs;
|
||||
else
|
||||
return rhs;
|
||||
}
|
||||
|
||||
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct prefix_chain *pc = v->value.ptr;
|
||||
|
||||
if (*kb == pc->prefix[0]) {
|
||||
// There's a common prefix let's split the chain into two and
|
||||
// recurse.
|
||||
struct prefix_chain *pc2;
|
||||
unsigned i, len = min(pc->len, ke - kb);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (kb[i] != pc->prefix[i])
|
||||
break;
|
||||
|
||||
pc2 = zalloc(sizeof(*pc2) + pc->len - i);
|
||||
pc2->len = pc->len - i;
|
||||
memmove(pc2->prefix, pc->prefix + i, pc2->len);
|
||||
pc2->child = pc->child;
|
||||
|
||||
// FIXME: this trashes pc so we can't back out
|
||||
pc->child.type = PREFIX_CHAIN;
|
||||
pc->child.value.ptr = pc2;
|
||||
pc->len = i;
|
||||
|
||||
if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
|
||||
free(pc2);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Stick an n4 in front.
|
||||
struct node4 *n4 = zalloc(sizeof(*n4));
|
||||
if (!n4)
|
||||
return false;
|
||||
|
||||
n4->keys[0] = *kb;
|
||||
if (!_insert(rt, n4->values, kb + 1, ke, rv)) {
|
||||
free(n4);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pc->len) {
|
||||
n4->keys[1] = pc->prefix[0];
|
||||
if (pc->len == 1) {
|
||||
n4->values[1] = pc->child;
|
||||
free(pc);
|
||||
} else {
|
||||
memmove(pc->prefix, pc->prefix + 1, pc->len - 1);
|
||||
pc->len--;
|
||||
n4->values[1] = *v;
|
||||
}
|
||||
n4->nr_entries = 2;
|
||||
} else
|
||||
n4->nr_entries = 1;
|
||||
|
||||
v->type = NODE4;
|
||||
v->value.ptr = n4;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _insert_node4(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct node4 *n4 = v->value.ptr;
|
||||
if (n4->nr_entries == 4) {
|
||||
struct node16 *n16 = zalloc(sizeof(*n16));
|
||||
if (!n16)
|
||||
return false;
|
||||
|
||||
n16->nr_entries = 5;
|
||||
memcpy(n16->keys, n4->keys, sizeof(n4->keys));
|
||||
memcpy(n16->values, n4->values, sizeof(n4->values));
|
||||
|
||||
n16->keys[4] = *kb;
|
||||
if (!_insert(rt, n16->values + 4, kb + 1, ke, rv)) {
|
||||
free(n16);
|
||||
return false;
|
||||
}
|
||||
free(n4);
|
||||
v->type = NODE16;
|
||||
v->value.ptr = n16;
|
||||
} else {
|
||||
n4 = v->value.ptr;
|
||||
if (!_insert(rt, n4->values + n4->nr_entries, kb + 1, ke, rv))
|
||||
return false;
|
||||
|
||||
n4->keys[n4->nr_entries] = *kb;
|
||||
n4->nr_entries++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _insert_node16(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct node16 *n16 = v->value.ptr;
|
||||
|
||||
if (n16->nr_entries == 16) {
|
||||
unsigned i;
|
||||
struct node48 *n48 = zalloc(sizeof(*n48));
|
||||
|
||||
if (!n48)
|
||||
return false;
|
||||
|
||||
n48->nr_entries = 17;
|
||||
memset(n48->keys, 48, sizeof(n48->keys));
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
n48->keys[n16->keys[i]] = i;
|
||||
n48->values[i] = n16->values[i];
|
||||
}
|
||||
|
||||
n48->keys[*kb] = 16;
|
||||
if (!_insert(rt, n48->values + 16, kb + 1, ke, rv)) {
|
||||
free(n48);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(n16);
|
||||
v->type = NODE48;
|
||||
v->value.ptr = n48;
|
||||
} else {
|
||||
if (!_insert(rt, n16->values + n16->nr_entries, kb + 1, ke, rv))
|
||||
return false;
|
||||
n16->keys[n16->nr_entries] = *kb;
|
||||
n16->nr_entries++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _insert_node48(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct node48 *n48 = v->value.ptr;
|
||||
if (n48->nr_entries == 48) {
|
||||
unsigned i;
|
||||
struct node256 *n256 = zalloc(sizeof(*n256));
|
||||
if (!n256)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (n48->keys[i] >= 48)
|
||||
continue;
|
||||
|
||||
n256->values[i] = n48->values[n48->keys[i]];
|
||||
}
|
||||
|
||||
if (!_insert(rt, n256->values + *kb, kb + 1, ke, rv)) {
|
||||
free(n256);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(n48);
|
||||
v->type = NODE256;
|
||||
v->value.ptr = n256;
|
||||
|
||||
} else {
|
||||
if (!_insert(rt, n48->values + n48->nr_entries, kb + 1, ke, rv))
|
||||
return false;
|
||||
|
||||
n48->keys[*kb] = n48->nr_entries;
|
||||
n48->nr_entries++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _insert_node256(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct node256 *n256 = v->value.ptr;
|
||||
bool was_unset = n256->values[*kb].type == UNSET;
|
||||
|
||||
if (!_insert(rt, n256->values + *kb, kb + 1, ke, rv))
|
||||
return false;
|
||||
|
||||
if (was_unset)
|
||||
n256->nr_entries++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: the tree should not be touched if insert fails (eg, OOM)
|
||||
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
if (kb == ke) {
|
||||
if (v->type == UNSET) {
|
||||
v->type = VALUE;
|
||||
v->value = rv;
|
||||
rt->nr_entries++;
|
||||
|
||||
} else if (v->type == VALUE) {
|
||||
v->value = rv;
|
||||
|
||||
} else {
|
||||
struct value_chain *vc = zalloc(sizeof(*vc));
|
||||
if (!vc)
|
||||
return false;
|
||||
|
||||
vc->value = rv;
|
||||
vc->child = *v;
|
||||
v->type = VALUE_CHAIN;
|
||||
v->value.ptr = vc;
|
||||
rt->nr_entries++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (v->type) {
|
||||
case UNSET:
|
||||
return _insert_unset(rt, v, kb, ke, rv);
|
||||
|
||||
case VALUE:
|
||||
return _insert_value(rt, v, kb, ke, rv);
|
||||
|
||||
case VALUE_CHAIN:
|
||||
return _insert_value_chain(rt, v, kb, ke, rv);
|
||||
|
||||
case PREFIX_CHAIN:
|
||||
return _insert_prefix_chain(rt, v, kb, ke, rv);
|
||||
|
||||
case NODE4:
|
||||
return _insert_node4(rt, v, kb, ke, rv);
|
||||
|
||||
case NODE16:
|
||||
return _insert_node16(rt, v, kb, ke, rv);
|
||||
|
||||
case NODE48:
|
||||
return _insert_node48(rt, v, kb, ke, rv);
|
||||
|
||||
case NODE256:
|
||||
return _insert_node256(rt, v, kb, ke, rv);
|
||||
}
|
||||
|
||||
// can't get here
|
||||
return false;
|
||||
}
|
||||
|
||||
struct lookup_result {
|
||||
struct value *v;
|
||||
uint8_t *kb;
|
||||
};
|
||||
|
||||
static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t *ke)
|
||||
{
|
||||
unsigned i;
|
||||
struct value_chain *vc;
|
||||
struct prefix_chain *pc;
|
||||
struct node4 *n4;
|
||||
struct node16 *n16;
|
||||
struct node48 *n48;
|
||||
struct node256 *n256;
|
||||
|
||||
if (kb == ke)
|
||||
return (struct lookup_result) {.v = v, .kb = kb};
|
||||
|
||||
switch (v->type) {
|
||||
case UNSET:
|
||||
case VALUE:
|
||||
break;
|
||||
|
||||
case VALUE_CHAIN:
|
||||
vc = v->value.ptr;
|
||||
return _lookup_prefix(&vc->child, kb, ke);
|
||||
|
||||
case PREFIX_CHAIN:
|
||||
pc = v->value.ptr;
|
||||
if (ke - kb < pc->len)
|
||||
return (struct lookup_result) {.v = v, .kb = kb};
|
||||
|
||||
for (i = 0; i < pc->len; i++)
|
||||
if (kb[i] != pc->prefix[i])
|
||||
return (struct lookup_result) {.v = v, .kb = kb};
|
||||
|
||||
return _lookup_prefix(&pc->child, kb + pc->len, ke);
|
||||
|
||||
case NODE4:
|
||||
n4 = v->value.ptr;
|
||||
for (i = 0; i < n4->nr_entries; i++)
|
||||
if (n4->keys[i] == *kb)
|
||||
return _lookup_prefix(n4->values + i, kb + 1, ke);
|
||||
break;
|
||||
|
||||
case NODE16:
|
||||
// FIXME: use binary search or simd?
|
||||
n16 = v->value.ptr;
|
||||
for (i = 0; i < n16->nr_entries; i++)
|
||||
if (n16->keys[i] == *kb)
|
||||
return _lookup_prefix(n16->values + i, kb + 1, ke);
|
||||
break;
|
||||
|
||||
case NODE48:
|
||||
n48 = v->value.ptr;
|
||||
i = n48->keys[*kb];
|
||||
if (i < 48)
|
||||
return _lookup_prefix(n48->values + i, kb + 1, ke);
|
||||
break;
|
||||
|
||||
case NODE256:
|
||||
n256 = v->value.ptr;
|
||||
return _lookup_prefix(n256->values + *kb, kb + 1, ke);
|
||||
}
|
||||
|
||||
return (struct lookup_result) {.v = v, .kb = kb};
|
||||
}
|
||||
|
||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
|
||||
{
|
||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||
return _insert(rt, lr.v, lr.kb, ke, rv);
|
||||
}
|
||||
|
||||
// Note the degrade functions also free the original node.
|
||||
static void _degrade_to_n4(struct node16 *n16, struct value *result)
|
||||
{
|
||||
struct node4 *n4 = zalloc(sizeof(*n4));
|
||||
|
||||
n4->nr_entries = n16->nr_entries;
|
||||
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
|
||||
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
|
||||
free(n16);
|
||||
|
||||
result->type = NODE4;
|
||||
result->value.ptr = n4;
|
||||
}
|
||||
|
||||
static void _degrade_to_n16(struct node48 *n48, struct value *result)
|
||||
{
|
||||
struct node4 *n16 = zalloc(sizeof(*n16));
|
||||
|
||||
n16->nr_entries = n48->nr_entries;
|
||||
memcpy(n16->keys, n48->keys, n48->nr_entries * sizeof(*n16->keys));
|
||||
memcpy(n16->values, n48->values, n48->nr_entries * sizeof(*n16->values));
|
||||
free(n48);
|
||||
|
||||
result->type = NODE16;
|
||||
result->value.ptr = n16;
|
||||
}
|
||||
|
||||
static void _degrade_to_n48(struct node256 *n256, struct value *result)
|
||||
{
|
||||
unsigned i, count = 0;
|
||||
struct node4 *n48 = zalloc(sizeof(*n48));
|
||||
|
||||
n48->nr_entries = n256->nr_entries;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (n256->values[i].type == UNSET)
|
||||
continue;
|
||||
|
||||
n48->keys[count] = i;
|
||||
n48->values[count] = n256->values[i];
|
||||
count++;
|
||||
}
|
||||
free(n256);
|
||||
|
||||
result->type = NODE48;
|
||||
result->value.ptr = n48;
|
||||
}
|
||||
|
||||
static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
|
||||
{
|
||||
bool r;
|
||||
unsigned i;
|
||||
struct value_chain *vc;
|
||||
struct prefix_chain *pc;
|
||||
struct node4 *n4;
|
||||
struct node16 *n16;
|
||||
struct node48 *n48;
|
||||
struct node256 *n256;
|
||||
|
||||
if (kb == ke) {
|
||||
if (root->type == VALUE) {
|
||||
root->type = UNSET;
|
||||
_dtr(rt, root->value);
|
||||
return true;
|
||||
|
||||
} else if (root->type == VALUE_CHAIN) {
|
||||
vc = root->value.ptr;
|
||||
_dtr(rt, vc->value);
|
||||
memcpy(root, &vc->child, sizeof(*root));
|
||||
free(vc);
|
||||
return true;
|
||||
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (root->type) {
|
||||
case UNSET:
|
||||
case VALUE:
|
||||
// this is a value for a prefix of the key
|
||||
return false;
|
||||
|
||||
case VALUE_CHAIN:
|
||||
vc = root->value.ptr;
|
||||
r = _remove(rt, &vc->child, kb, ke);
|
||||
if (r && (vc->child.type == UNSET)) {
|
||||
memcpy(root, &vc->child, sizeof(*root));
|
||||
free(vc);
|
||||
}
|
||||
return r;
|
||||
|
||||
case PREFIX_CHAIN:
|
||||
pc = root->value.ptr;
|
||||
if (ke - kb < pc->len)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < pc->len; i++)
|
||||
if (kb[i] != pc->prefix[i])
|
||||
return false;
|
||||
|
||||
return _remove(rt, &pc->child, kb + pc->len, ke);
|
||||
|
||||
case NODE4:
|
||||
n4 = root->value.ptr;
|
||||
for (i = 0; i < n4->nr_entries; i++) {
|
||||
if (n4->keys[i] == *kb) {
|
||||
r = _remove(rt, n4->values + i, kb + 1, ke);
|
||||
if (r && n4->values[i].type == UNSET) {
|
||||
n4->nr_entries--;
|
||||
if (i < n4->nr_entries)
|
||||
// slide the entries down
|
||||
memmove(n4->keys + i, n4->keys + i + 1,
|
||||
sizeof(*n4->keys) * (n4->nr_entries - i));
|
||||
if (!n4->nr_entries)
|
||||
root->type = UNSET;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case NODE16:
|
||||
n16 = root->value.ptr;
|
||||
for (i = 0; i < n16->nr_entries; i++) {
|
||||
if (n16->keys[i] == *kb) {
|
||||
r = _remove(rt, n16->values + i, kb + 1, ke);
|
||||
if (r && n16->values[i].type == UNSET) {
|
||||
n16->nr_entries--;
|
||||
if (i < n16->nr_entries)
|
||||
// slide the entries down
|
||||
memmove(n16->keys + i, n16->keys + i + 1,
|
||||
sizeof(*n16->keys) * (n16->nr_entries - i));
|
||||
if (n16->nr_entries <= 4)
|
||||
_degrade_to_n4(n16, root);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case NODE48:
|
||||
n48 = root->value.ptr;
|
||||
i = n48->keys[*kb];
|
||||
if (i < 48) {
|
||||
r = _remove(rt, n48->values + i, kb + 1, ke);
|
||||
if (r && n48->values[i].type == UNSET) {
|
||||
n48->keys[*kb] = 48;
|
||||
n48->nr_entries--;
|
||||
if (n48->nr_entries <= 16)
|
||||
_degrade_to_n16(n48, root);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
return false;
|
||||
|
||||
case NODE256:
|
||||
n256 = root->value.ptr;
|
||||
r = _remove(rt, n256->values + (*kb), kb + 1, ke);
|
||||
if (r && n256->values[*kb].type == UNSET) {
|
||||
n256->nr_entries--;
|
||||
if (n256->nr_entries <= 48)
|
||||
_degrade_to_n48(n256, root);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
|
||||
{
|
||||
if (_remove(rt, &rt->root, key_begin, key_end)) {
|
||||
rt->nr_entries--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _prefix_chain_matches(struct lookup_result *lr, uint8_t *ke)
|
||||
{
|
||||
// It's possible the top node is a prefix chain, and
|
||||
// the remaining key matches part of it.
|
||||
if (lr->v->type == PREFIX_CHAIN) {
|
||||
unsigned i, rlen = ke - lr->kb;
|
||||
struct prefix_chain *pc = lr->v->value.ptr;
|
||||
if (rlen < pc->len) {
|
||||
for (i = 0; i < rlen; i++)
|
||||
if (pc->prefix[i] != lr->kb[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
|
||||
{
|
||||
unsigned count = 0;
|
||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||
if (lr.kb == ke || _prefix_chain_matches(&lr, ke)) {
|
||||
count = _free_node(rt, *lr.v);
|
||||
lr.v->type = UNSET;
|
||||
}
|
||||
|
||||
rt->nr_entries -= count;
|
||||
return count;
|
||||
}
|
||||
|
||||
bool radix_tree_lookup(struct radix_tree *rt,
|
||||
uint8_t *kb, uint8_t *ke, union radix_value *result)
|
||||
{
|
||||
struct value_chain *vc;
|
||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||
if (lr.kb == ke) {
|
||||
switch (lr.v->type) {
|
||||
case VALUE:
|
||||
*result = lr.v->value;
|
||||
return true;
|
||||
|
||||
case VALUE_CHAIN:
|
||||
vc = lr.v->value.ptr;
|
||||
*result = vc->value;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: build up the keys too
|
||||
static bool _iterate(struct value *v, struct radix_tree_iterator *it)
|
||||
{
|
||||
unsigned i;
|
||||
struct value_chain *vc;
|
||||
struct prefix_chain *pc;
|
||||
struct node4 *n4;
|
||||
struct node16 *n16;
|
||||
struct node48 *n48;
|
||||
struct node256 *n256;
|
||||
|
||||
switch (v->type) {
|
||||
case UNSET:
|
||||
// can't happen
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
return it->visit(it, NULL, NULL, v->value);
|
||||
|
||||
case VALUE_CHAIN:
|
||||
vc = v->value.ptr;
|
||||
return it->visit(it, NULL, NULL, vc->value) && _iterate(&vc->child, it);
|
||||
|
||||
case PREFIX_CHAIN:
|
||||
pc = v->value.ptr;
|
||||
return _iterate(&pc->child, it);
|
||||
|
||||
case NODE4:
|
||||
n4 = (struct node4 *) v->value.ptr;
|
||||
for (i = 0; i < n4->nr_entries; i++)
|
||||
if (!_iterate(n4->values + i, it))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case NODE16:
|
||||
n16 = (struct node16 *) v->value.ptr;
|
||||
for (i = 0; i < n16->nr_entries; i++)
|
||||
if (!_iterate(n16->values + i, it))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case NODE48:
|
||||
n48 = (struct node48 *) v->value.ptr;
|
||||
for (i = 0; i < n48->nr_entries; i++)
|
||||
if (!_iterate(n48->values + i, it))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case NODE256:
|
||||
n256 = (struct node256 *) v->value.ptr;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// can't get here
|
||||
return false;
|
||||
}
|
||||
|
||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||
struct radix_tree_iterator *it)
|
||||
{
|
||||
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
|
||||
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
|
||||
_iterate(lr.v, it);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
58
base/data-struct/radix-tree.h
Normal file
58
base/data-struct/radix-tree.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2018 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
|
||||
|
||||
#ifndef BASE_DATA_STRUCT_RADIX_TREE_H
|
||||
#define BASE_DATA_STRUCT_RADIX_TREE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
struct radix_tree;
|
||||
|
||||
union radix_value {
|
||||
void *ptr;
|
||||
uint64_t n;
|
||||
};
|
||||
|
||||
typedef void (*radix_value_dtr)(void *context, union radix_value v);
|
||||
|
||||
// dtr will be called on any deleted entries. dtr may be NULL.
|
||||
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
|
||||
void radix_tree_destroy(struct radix_tree *rt);
|
||||
|
||||
unsigned radix_tree_size(struct radix_tree *rt);
|
||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
|
||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
|
||||
|
||||
// Returns the number of values removed
|
||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
|
||||
|
||||
bool radix_tree_lookup(struct radix_tree *rt,
|
||||
uint8_t *kb, uint8_t *ke, union radix_value *result);
|
||||
|
||||
// The radix tree stores entries in lexicographical order. Which means
|
||||
// we can iterate entries, in order. Or iterate entries with a particular
|
||||
// prefix.
|
||||
struct radix_tree_iterator {
|
||||
// Returns false if the iteration should end.
|
||||
bool (*visit)(struct radix_tree_iterator *it,
|
||||
uint8_t *kb, uint8_t *ke, union radix_value v);
|
||||
};
|
||||
|
||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||
struct radix_tree_iterator *it);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
23
base/memory/container_of.h
Normal file
23
base/memory/container_of.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2018 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
|
||||
|
||||
#ifndef BASE_MEMORY_CONTAINER_OF_H
|
||||
#define BASE_MEMORY_CONTAINER_OF_H
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#define container_of(v, t, head) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
31
base/memory/zalloc.h
Normal file
31
base/memory/zalloc.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2018 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
|
||||
|
||||
#ifndef BASE_MEMORY_ZALLOC_H
|
||||
#define BASE_MEMORY_ZALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static inline void *zalloc(size_t len)
|
||||
{
|
||||
void *ptr = malloc(len);
|
||||
if (ptr)
|
||||
memset(ptr, 0, len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
@@ -611,9 +611,9 @@ log {
|
||||
# Select log messages by class.
|
||||
# Some debugging messages are assigned to a class and only appear in
|
||||
# debug output if the class is listed here. Classes currently
|
||||
# available: memory, devices, activation, allocation, lvmetad,
|
||||
# available: memory, devices, io, activation, allocation, lvmetad,
|
||||
# metadata, cache, locking, lvmpolld. Use "all" to see everything.
|
||||
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
|
||||
debug_classes = [ "memory", "devices", "io", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
|
||||
}
|
||||
|
||||
# Configuration section backup.
|
||||
@@ -702,29 +702,17 @@ global {
|
||||
activation = 1
|
||||
|
||||
# Configuration option global/fallback_to_lvm1.
|
||||
# Try running LVM1 tools if LVM cannot communicate with DM.
|
||||
# This option only applies to 2.4 kernels and is provided to help
|
||||
# switch between device-mapper kernels and LVM1 kernels. The LVM1
|
||||
# tools need to be installed with .lvm1 suffices, e.g. vgscan.lvm1.
|
||||
# They will stop working once the lvm2 on-disk metadata format is used.
|
||||
# This setting is no longer used.
|
||||
# This configuration option has an automatic default value.
|
||||
# fallback_to_lvm1 = @DEFAULT_FALLBACK_TO_LVM1@
|
||||
# fallback_to_lvm1 = 0
|
||||
|
||||
# Configuration option global/format.
|
||||
# The default metadata format that commands should use.
|
||||
# The -M 1|2 option overrides this setting.
|
||||
#
|
||||
# Accepted values:
|
||||
# lvm1
|
||||
# lvm2
|
||||
#
|
||||
# This setting is no longer used.
|
||||
# This configuration option has an automatic default value.
|
||||
# format = "lvm2"
|
||||
|
||||
# Configuration option global/format_libraries.
|
||||
# Shared libraries that process different metadata formats.
|
||||
# If support for LVM1 metadata was compiled as a shared library use
|
||||
# format_libraries = "liblvm2format1.so"
|
||||
# This setting is no longer used.
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option global/segment_libraries.
|
||||
@@ -821,13 +809,6 @@ global {
|
||||
# encountered the internal error. Please only enable for debugging.
|
||||
abort_on_internal_errors = 0
|
||||
|
||||
# Configuration option global/detect_internal_vg_cache_corruption.
|
||||
# Internal verification of VG structures.
|
||||
# Check if CRC matches when a parsed VG is used multiple times. This
|
||||
# is useful to catch unexpected changes to cached VG structures.
|
||||
# Please only enable for debugging.
|
||||
detect_internal_vg_cache_corruption = 0
|
||||
|
||||
# Configuration option global/metadata_read_only.
|
||||
# No operations that change on-disk metadata are permitted.
|
||||
# Additionally, read-only commands that encounter metadata in need of
|
||||
|
||||
384
configure
vendored
384
configure
vendored
@@ -643,6 +643,7 @@ LVMETAD_PIDFILE
|
||||
DMEVENTD_PIDFILE
|
||||
WRITE_INSTALL
|
||||
VALGRIND_POOL
|
||||
USRSBINDIR
|
||||
USE_TRACKING
|
||||
UDEV_HAS_BUILTIN_BLKID
|
||||
UDEV_RULE_EXEC_DETECTION
|
||||
@@ -652,16 +653,16 @@ UDEV_RULES
|
||||
UDEV_PC
|
||||
THIN
|
||||
TESTSUITE_DATA
|
||||
TESTING
|
||||
STATIC_LINK
|
||||
STATICDIR
|
||||
SNAPSHOTS
|
||||
SYSCONFDIR
|
||||
SELINUX_PC
|
||||
SELINUX_LIBS
|
||||
SBINDIR
|
||||
REPLICATORS
|
||||
READLINE_LIBS
|
||||
RT_LIBS
|
||||
RAID
|
||||
PYTHON3DIR
|
||||
PYTHON2DIR
|
||||
PYTHON3_LIBDIRS
|
||||
@@ -674,7 +675,6 @@ PYTHON_BINDINGS
|
||||
PYTHON3
|
||||
PTHREAD_LIBS
|
||||
M_LIBS
|
||||
POOL
|
||||
PKGCONFIG
|
||||
ODIRECT
|
||||
OCFDIR
|
||||
@@ -689,8 +689,6 @@ LVM_MINOR
|
||||
LVM_MAJOR
|
||||
LVM_LIBAPI
|
||||
LVM_VERSION
|
||||
LVM1_FALLBACK
|
||||
LVM1
|
||||
LIB_SUFFIX
|
||||
LDDEPS
|
||||
JOBS
|
||||
@@ -710,6 +708,7 @@ DEFAULT_USE_LVMLOCKD
|
||||
DEFAULT_USE_LVMPOLLD
|
||||
DEFAULT_USE_LVMETAD
|
||||
DEFAULT_USE_BLKID_WIPING
|
||||
DEFAULT_SYS_LOCK_DIR
|
||||
DEFAULT_SYS_DIR
|
||||
DEFAULT_SPARSE_SEGTYPE
|
||||
DEFAULT_RUN_DIR
|
||||
@@ -717,7 +716,6 @@ DEFAULT_RAID10_SEGTYPE
|
||||
DEFAULT_PROFILE_SUBDIR
|
||||
DEFAULT_PID_DIR
|
||||
DEFAULT_MIRROR_SEGTYPE
|
||||
DEFAULT_FALLBACK_TO_LVM1
|
||||
DEFAULT_LOCK_DIR
|
||||
DEFAULT_DM_RUN_DIR
|
||||
DEFAULT_DATA_ALIGNMENT
|
||||
@@ -777,8 +775,6 @@ LOCKD_SANLOCK_LIBS
|
||||
LOCKD_SANLOCK_CFLAGS
|
||||
VALGRIND_LIBS
|
||||
VALGRIND_CFLAGS
|
||||
CUNIT_LIBS
|
||||
CUNIT_CFLAGS
|
||||
GENPNG
|
||||
GENHTML
|
||||
LCOV
|
||||
@@ -880,6 +876,7 @@ infodir
|
||||
docdir
|
||||
oldincludedir
|
||||
includedir
|
||||
runstatedir
|
||||
localstatedir
|
||||
sharedstatedir
|
||||
sysconfdir
|
||||
@@ -911,16 +908,11 @@ with_device_gid
|
||||
with_device_mode
|
||||
with_device_nodes_on
|
||||
with_default_name_mangling
|
||||
enable_lvm1_fallback
|
||||
with_lvm1
|
||||
with_pool
|
||||
with_cluster
|
||||
with_snapshots
|
||||
with_mirrors
|
||||
with_raid
|
||||
with_default_mirror_segtype
|
||||
with_default_raid10_segtype
|
||||
with_replicators
|
||||
with_default_sparse_segtype
|
||||
with_thin
|
||||
with_thin_check
|
||||
@@ -948,7 +940,6 @@ with_cmirrord_pidfile
|
||||
enable_debug
|
||||
with_optimisation
|
||||
enable_profiling
|
||||
enable_testing
|
||||
enable_valgrind_pool
|
||||
enable_devmapper
|
||||
enable_lvmetad
|
||||
@@ -1040,8 +1031,6 @@ DLM_CFLAGS
|
||||
DLM_LIBS
|
||||
SACKPT_CFLAGS
|
||||
SACKPT_LIBS
|
||||
CUNIT_CFLAGS
|
||||
CUNIT_LIBS
|
||||
VALGRIND_CFLAGS
|
||||
VALGRIND_LIBS
|
||||
LOCKD_SANLOCK_CFLAGS
|
||||
@@ -1095,6 +1084,7 @@ datadir='${datarootdir}'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
runstatedir='${localstatedir}/run'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE}'
|
||||
@@ -1347,6 +1337,15 @@ do
|
||||
| -silent | --silent | --silen | --sile | --sil)
|
||||
silent=yes ;;
|
||||
|
||||
-runstatedir | --runstatedir | --runstatedi | --runstated \
|
||||
| --runstate | --runstat | --runsta | --runst | --runs \
|
||||
| --run | --ru | --r)
|
||||
ac_prev=runstatedir ;;
|
||||
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
|
||||
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
|
||||
| --run=* | --ru=* | --r=*)
|
||||
runstatedir=$ac_optarg ;;
|
||||
|
||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||
ac_prev=sbindir ;;
|
||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||
@@ -1484,7 +1483,7 @@ fi
|
||||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||
libdir localedir mandir
|
||||
libdir localedir mandir runstatedir
|
||||
do
|
||||
eval ac_val=\$$ac_var
|
||||
# Remove trailing slashes.
|
||||
@@ -1637,6 +1636,7 @@ Fine tuning of the installation directories:
|
||||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||
--includedir=DIR C header files [PREFIX/include]
|
||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||
@@ -1673,8 +1673,6 @@ Optional Features:
|
||||
speeds up one-time build.
|
||||
--enable-static_link use this to link the tools to their libraries
|
||||
statically (default is dynamic linking
|
||||
--enable-lvm1_fallback use this to fall back and use LVM1 binaries if
|
||||
device-mapper is missing from the kernel
|
||||
--disable-thin_check_needs_check
|
||||
required if thin_check version is < 0.3.0
|
||||
--disable-cache_check_needs_check
|
||||
@@ -1686,7 +1684,6 @@ Optional Features:
|
||||
--enable-cmirrord enable the cluster mirror log daemon
|
||||
--enable-debug enable debugging
|
||||
--enable-profiling gather gcov profiling data
|
||||
--enable-testing enable testing targets in the makefile
|
||||
--enable-valgrind-pool enable valgrind awareness of pools
|
||||
--disable-devmapper disable LVM2 device-mapper interaction
|
||||
--enable-lvmetad enable the LVM Metadata Daemon
|
||||
@@ -1742,20 +1739,14 @@ Optional Packages:
|
||||
create nodes on resume or create [ON=resume]
|
||||
--with-default-name-mangling=MANGLING
|
||||
default name mangling: auto/none/hex [auto]
|
||||
--with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[internal]
|
||||
--with-pool=TYPE GFS pool read-only support: internal/shared/none
|
||||
[internal]
|
||||
--with-cluster=TYPE cluster LVM locking support: internal/shared/none
|
||||
[internal]
|
||||
--with-snapshots=TYPE snapshot support: internal/shared/none [internal]
|
||||
--with-mirrors=TYPE mirror support: internal/shared/none [internal]
|
||||
--with-raid=TYPE raid support: internal/shared/none [internal]
|
||||
--with-default-mirror-segtype=TYPE
|
||||
default mirror segtype: raid1/mirror [raid1]
|
||||
--with-default-raid10-segtype=TYPE
|
||||
default mirror segtype: raid10/mirror [raid10]
|
||||
--with-replicators=TYPE replicator support: internal/shared/none [none]
|
||||
--with-default-sparse-segtype=TYPE
|
||||
default sparse segtype: thin/snapshot [thin]
|
||||
--with-thin=TYPE thin provisioning support: internal/shared/none
|
||||
@@ -1876,9 +1867,6 @@ Some influential environment variables:
|
||||
SACKPT_CFLAGS
|
||||
C compiler flags for SACKPT, overriding pkg-config
|
||||
SACKPT_LIBS linker flags for SACKPT, overriding pkg-config
|
||||
CUNIT_CFLAGS
|
||||
C compiler flags for CUNIT, overriding pkg-config
|
||||
CUNIT_LIBS linker flags for CUNIT, overriding pkg-config
|
||||
VALGRIND_CFLAGS
|
||||
C compiler flags for VALGRIND, overriding pkg-config
|
||||
VALGRIND_LIBS
|
||||
@@ -4367,6 +4355,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
CFLAGS=$save_CFLAGS
|
||||
CXXFLAGS=$save_CXXFLAGS
|
||||
PATH_SBIN="$PATH:/usr/sbin:/sbin"
|
||||
|
||||
|
||||
ac_ext=c
|
||||
@@ -6152,7 +6141,7 @@ fi
|
||||
|
||||
|
||||
for ac_header in assert.h ctype.h dirent.h errno.h fcntl.h float.h \
|
||||
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
|
||||
getopt.h inttypes.h langinfo.h libaio.h libgen.h limits.h locale.h paths.h \
|
||||
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
|
||||
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
|
||||
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||
@@ -8240,9 +8229,14 @@ $as_echo "$ac_cv_flag_HAVE_FULL_RELRO" >&6; }
|
||||
|
||||
################################################################################
|
||||
|
||||
if test "$prefix" = NONE; then
|
||||
datarootdir=${ac_default_prefix}/share
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
test "$exec_prefix" = NONE -a "$prefix" = NONE && exec_prefix=""
|
||||
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
# Let make expand exec_prefix.
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking file owner" >&5
|
||||
@@ -8377,78 +8371,6 @@ cat >>confdefs.h <<_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable lvm1 fallback" >&5
|
||||
$as_echo_n "checking whether to enable lvm1 fallback... " >&6; }
|
||||
# Check whether --enable-lvm1_fallback was given.
|
||||
if test "${enable_lvm1_fallback+set}" = set; then :
|
||||
enableval=$enable_lvm1_fallback; LVM1_FALLBACK=$enableval
|
||||
else
|
||||
LVM1_FALLBACK=no
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1_FALLBACK" >&5
|
||||
$as_echo "$LVM1_FALLBACK" >&6; }
|
||||
|
||||
if test "$LVM1_FALLBACK" = yes; then
|
||||
DEFAULT_FALLBACK_TO_LVM1=1
|
||||
|
||||
$as_echo "#define LVM1_FALLBACK 1" >>confdefs.h
|
||||
|
||||
else
|
||||
DEFAULT_FALLBACK_TO_LVM1=0
|
||||
fi
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define DEFAULT_FALLBACK_TO_LVM1 $DEFAULT_FALLBACK_TO_LVM1
|
||||
_ACEOF
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for lvm1 metadata" >&5
|
||||
$as_echo_n "checking whether to include support for lvm1 metadata... " >&6; }
|
||||
|
||||
# Check whether --with-lvm1 was given.
|
||||
if test "${with_lvm1+set}" = set; then :
|
||||
withval=$with_lvm1; LVM1=$withval
|
||||
else
|
||||
LVM1=internal
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVM1" >&5
|
||||
$as_echo "$LVM1" >&6; }
|
||||
|
||||
case "$LVM1" in
|
||||
none|shared) ;;
|
||||
internal)
|
||||
$as_echo "#define LVM1_INTERNAL 1" >>confdefs.h
|
||||
;;
|
||||
*) as_fn_error $? "--with-lvm1 parameter invalid" "$LINENO" 5 ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for GFS pool metadata" >&5
|
||||
$as_echo_n "checking whether to include support for GFS pool metadata... " >&6; }
|
||||
|
||||
# Check whether --with-pool was given.
|
||||
if test "${with_pool+set}" = set; then :
|
||||
withval=$with_pool; POOL=$withval
|
||||
else
|
||||
POOL=internal
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $POOL" >&5
|
||||
$as_echo "$POOL" >&6; }
|
||||
|
||||
case "$POOL" in
|
||||
none|shared) ;;
|
||||
internal)
|
||||
$as_echo "#define POOL_INTERNAL 1" >>confdefs.h
|
||||
;;
|
||||
*) as_fn_error $? "--with-pool parameter invalid" "$LINENO" 5
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for cluster locking" >&5
|
||||
$as_echo_n "checking whether to include support for cluster locking... " >&6; }
|
||||
@@ -8514,19 +8436,6 @@ $as_echo "#define MIRRORED_INTERNAL 1" >>confdefs.h
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include raid" >&5
|
||||
$as_echo_n "checking whether to include raid... " >&6; }
|
||||
|
||||
# Check whether --with-raid was given.
|
||||
if test "${with_raid+set}" = set; then :
|
||||
withval=$with_raid; RAID=$withval
|
||||
else
|
||||
RAID=internal
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAID" >&5
|
||||
$as_echo "$RAID" >&6; }
|
||||
|
||||
|
||||
# Check whether --with-default-mirror-segtype was given.
|
||||
if test "${with_default_mirror_segtype+set}" = set; then :
|
||||
@@ -8543,15 +8452,10 @@ else
|
||||
DEFAULT_RAID10_SEGTYPE="raid10"
|
||||
fi
|
||||
|
||||
case "$RAID" in
|
||||
none) test "$DEFAULT_MIRROR_SEGTYPE" = "raid1" && DEFAULT_MIRROR_SEGTYPE="mirror"
|
||||
test "$DEFAULT_RAID10_SEGTYPE" = "raid10" && DEFAULT_RAID10_SEGTYPE="mirror" ;;
|
||||
shared) ;;
|
||||
internal)
|
||||
|
||||
|
||||
$as_echo "#define RAID_INTERNAL 1" >>confdefs.h
|
||||
;;
|
||||
*) as_fn_error $? "--with-raid parameter invalid" "$LINENO" 5 ;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
@@ -8566,28 +8470,6 @@ _ACEOF
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include replicators" >&5
|
||||
$as_echo_n "checking whether to include replicators... " >&6; }
|
||||
|
||||
# Check whether --with-replicators was given.
|
||||
if test "${with_replicators+set}" = set; then :
|
||||
withval=$with_replicators; REPLICATORS=$withval
|
||||
else
|
||||
REPLICATORS=none
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $REPLICATORS" >&5
|
||||
$as_echo "$REPLICATORS" >&6; }
|
||||
|
||||
case "$REPLICATORS" in
|
||||
none|shared) ;;
|
||||
internal)
|
||||
$as_echo "#define REPLICATOR_INTERNAL 1" >>confdefs.h
|
||||
;;
|
||||
*) as_fn_error $? "--with-replicators parameter invalid ($REPLICATORS)" "$LINENO" 5 ;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
# Check whether --with-default-sparse-segtype was given.
|
||||
if test "${with_default_sparse_segtype+set}" = set; then :
|
||||
@@ -8687,7 +8569,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -8730,7 +8612,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -8811,7 +8693,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -8854,7 +8736,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -8918,7 +8800,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -8961,7 +8843,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9025,7 +8907,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9068,7 +8950,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9236,7 +9118,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9279,7 +9161,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9372,7 +9254,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9415,7 +9297,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9479,7 +9361,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9522,7 +9404,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9586,7 +9468,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -9629,7 +9511,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -11606,114 +11488,6 @@ $as_echo "$as_me: WARNING: GD.pm perl module is not installed" >&2;}
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable unit testing" >&5
|
||||
$as_echo_n "checking whether to enable unit testing... " >&6; }
|
||||
# Check whether --enable-testing was given.
|
||||
if test "${enable_testing+set}" = set; then :
|
||||
enableval=$enable_testing; TESTING=$enableval
|
||||
else
|
||||
TESTING=no
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TESTING" >&5
|
||||
$as_echo "$TESTING" >&6; }
|
||||
|
||||
if test "$TESTING" = yes; then
|
||||
pkg_config_init
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CUNIT" >&5
|
||||
$as_echo_n "checking for CUNIT... " >&6; }
|
||||
|
||||
if test -n "$CUNIT_CFLAGS"; then
|
||||
pkg_cv_CUNIT_CFLAGS="$CUNIT_CFLAGS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_CUNIT_CFLAGS=`$PKG_CONFIG --cflags "cunit >= 2.0" 2>/dev/null`
|
||||
test "x$?" != "x0" && pkg_failed=yes
|
||||
else
|
||||
pkg_failed=yes
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi
|
||||
if test -n "$CUNIT_LIBS"; then
|
||||
pkg_cv_CUNIT_LIBS="$CUNIT_LIBS"
|
||||
elif test -n "$PKG_CONFIG"; then
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
|
||||
($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
|
||||
ac_status=$?
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
test $ac_status = 0; }; then
|
||||
pkg_cv_CUNIT_LIBS=`$PKG_CONFIG --libs "cunit >= 2.0" 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
|
||||
CUNIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "cunit >= 2.0" 2>&1`
|
||||
else
|
||||
CUNIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "cunit >= 2.0" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$CUNIT_PKG_ERRORS" >&5
|
||||
|
||||
as_fn_error $? "Package requirements (cunit >= 2.0) were not met:
|
||||
|
||||
$CUNIT_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
Alternatively, you may set the environment variables CUNIT_CFLAGS
|
||||
and CUNIT_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details." "$LINENO" 5
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
Alternatively, you may set the environment variables CUNIT_CFLAGS
|
||||
and CUNIT_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.
|
||||
See \`config.log' for more details" "$LINENO" 5; }
|
||||
else
|
||||
CUNIT_CFLAGS=$pkg_cv_CUNIT_CFLAGS
|
||||
CUNIT_LIBS=$pkg_cv_CUNIT_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
|
||||
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
|
||||
@@ -12791,6 +12565,10 @@ $as_echo "$APPLIB" >&6; }
|
||||
test "$APPLIB" = yes \
|
||||
&& LVM2APP_LIB=-llvm2app \
|
||||
|| LVM2APP_LIB=
|
||||
if test "$APPLIB"; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: liblvm2app is deprecated. Use D-Bus API" >&5
|
||||
$as_echo "$as_me: WARNING: liblvm2app is deprecated. Use D-Bus API" >&2;}
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile liblvm2cmd.so" >&5
|
||||
@@ -12821,6 +12599,10 @@ fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_LVMDBUSD" >&5
|
||||
$as_echo "$BUILD_LVMDBUSD" >&6; }
|
||||
if test "$NOTIFYDBUS_SUPPORT" = yes && test "BUILD_LVMDBUSD" = yes; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Building D-Bus support without D-Bus notifications." >&5
|
||||
$as_echo "$as_me: WARNING: Building D-Bus support without D-Bus notifications." >&2;}
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Python wrapper for liblvm2app.so" >&5
|
||||
@@ -13798,7 +13580,7 @@ fi
|
||||
PYTHON3_INCDIRS=`"$PYTHON3_CONFIG" --includes`
|
||||
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
|
||||
PYTHON3DIR=$pythondir
|
||||
PYTHON_BINDINGS=yes
|
||||
test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
@@ -13868,6 +13650,8 @@ $as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Python bindings are deprecated. Use D-Bus API" >&5
|
||||
$as_echo "$as_me: WARNING: Python bindings are deprecated. Use D-Bus API" >&2;}
|
||||
test "$APPLIB" != yes && as_fn_error $? "Python_bindings require --enable-applib" "$LINENO" 5
|
||||
fi
|
||||
|
||||
@@ -14027,9 +13811,6 @@ $as_echo "#define HAVE_CANONICALIZE_FILE_NAME 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
################################################################################
|
||||
test "$exec_prefix" = NONE -a "$prefix" = NONE && exec_prefix=""
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
|
||||
$as_echo_n "checking for dlopen in -ldl... " >&6; }
|
||||
@@ -14081,8 +13862,6 @@ fi
|
||||
|
||||
################################################################################
|
||||
if [ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
-o "$SNAPSHOTS" = shared -o "$MIRRORS" = shared \
|
||||
-o "$RAID" = shared -o "$CACHE" = shared \
|
||||
\) -a "$STATIC_LINK" = yes ]; then
|
||||
as_fn_error $? "Features cannot be 'shared' when building statically" "$LINENO" 5
|
||||
fi
|
||||
@@ -15318,7 +15097,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -15361,7 +15140,7 @@ else
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
for as_dir in $PATH_SBIN
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
@@ -15411,28 +15190,25 @@ _ACEOF
|
||||
|
||||
fi
|
||||
|
||||
SYSCONFDIR="$(eval echo $(eval echo $sysconfdir))"
|
||||
|
||||
lvm_exec_prefix=$exec_prefix
|
||||
test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix
|
||||
test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
|
||||
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
||||
SBINDIR="$(eval echo $(eval echo $sbindir))"
|
||||
LVM_PATH="$SBINDIR/lvm"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define LVM_PATH "$LVM_PATH"
|
||||
_ACEOF
|
||||
|
||||
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
|
||||
CLVMD_PATH="$USRSBINDIR/clvmd"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define CLVMD_PATH "$CLVMD_PATH"
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
||||
FSADM_PATH="$lvm_exec_prefix/sbin/fsadm"
|
||||
FSADM_PATH="$SBINDIR/fsadm"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define FSADM_PATH "$FSADM_PATH"
|
||||
@@ -15462,7 +15238,7 @@ if test "$BUILD_DMEVENTD" = yes; then
|
||||
if test "${with_dmeventd_path+set}" = set; then :
|
||||
withval=$with_dmeventd_path; DMEVENTD_PATH=$withval
|
||||
else
|
||||
DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd"
|
||||
DMEVENTD_PATH="$SBINDIR/dmeventd"
|
||||
fi
|
||||
|
||||
|
||||
@@ -15543,6 +15319,11 @@ cat >>confdefs.h <<_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
# Select default system locking dir, prefer /run/lock over /var/lock
|
||||
DEFAULT_SYS_LOCK_DIR="$RUN_DIR/lock"
|
||||
test -d "$DEFAULT_SYS_LOCK_DIR" || DEFAULT_SYS_LOCK_DIR="/var/lock"
|
||||
|
||||
# Support configurable locking subdir for lvm
|
||||
|
||||
# Check whether --with-default-locking-dir was given.
|
||||
if test "${with_default_locking_dir+set}" = set; then :
|
||||
@@ -15550,8 +15331,7 @@ if test "${with_default_locking_dir+set}" = set; then :
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default lock directory" >&5
|
||||
$as_echo_n "checking for default lock directory... " >&6; }
|
||||
DEFAULT_LOCK_DIR="$RUN_DIR/lock/lvm"
|
||||
test -d "$RUN_DIR/lock" || DEFAULT_LOCK_DIR="/var/lock/lvm"
|
||||
DEFAULT_LOCK_DIR="$DEFAULT_SYS_LOCK_DIR/lvm"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_LOCK_DIR" >&5
|
||||
$as_echo "$DEFAULT_LOCK_DIR" >&6; }
|
||||
fi
|
||||
@@ -15775,13 +15555,11 @@ _ACEOF
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile device_mapper/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/locking/Makefile include/lvm-version.h libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/api/python_lvm_unit.py test/unit/Makefile tools/Makefile udev/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@@ -16491,10 +16269,14 @@ do
|
||||
"daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;;
|
||||
"daemons/dmfilemapd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmfilemapd/Makefile" ;;
|
||||
"daemons/lvmdbusd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/Makefile" ;;
|
||||
"daemons/lvmdbusd/lvmdbusd") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/lvmdbusd" ;;
|
||||
"daemons/lvmdbusd/lvmdb.py") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/lvmdb.py" ;;
|
||||
"daemons/lvmdbusd/lvm_shell_proxy.py") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/lvm_shell_proxy.py" ;;
|
||||
"daemons/lvmdbusd/path.py") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/path.py" ;;
|
||||
"daemons/lvmetad/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmetad/Makefile" ;;
|
||||
"daemons/lvmpolld/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmpolld/Makefile" ;;
|
||||
"daemons/lvmlockd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmlockd/Makefile" ;;
|
||||
"device_mapper/Makefile") CONFIG_FILES="$CONFIG_FILES device_mapper/Makefile" ;;
|
||||
"conf/Makefile") CONFIG_FILES="$CONFIG_FILES conf/Makefile" ;;
|
||||
"conf/example.conf") CONFIG_FILES="$CONFIG_FILES conf/example.conf" ;;
|
||||
"conf/lvmlocal.conf") CONFIG_FILES="$CONFIG_FILES conf/lvmlocal.conf" ;;
|
||||
@@ -16503,16 +16285,8 @@ do
|
||||
"include/.symlinks") CONFIG_FILES="$CONFIG_FILES include/.symlinks" ;;
|
||||
"include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
|
||||
"lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
|
||||
"lib/format1/Makefile") CONFIG_FILES="$CONFIG_FILES lib/format1/Makefile" ;;
|
||||
"lib/format_pool/Makefile") CONFIG_FILES="$CONFIG_FILES lib/format_pool/Makefile" ;;
|
||||
"lib/locking/Makefile") CONFIG_FILES="$CONFIG_FILES lib/locking/Makefile" ;;
|
||||
"lib/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES lib/mirror/Makefile" ;;
|
||||
"lib/replicator/Makefile") CONFIG_FILES="$CONFIG_FILES lib/replicator/Makefile" ;;
|
||||
"include/lvm-version.h") CONFIG_FILES="$CONFIG_FILES include/lvm-version.h" ;;
|
||||
"lib/raid/Makefile") CONFIG_FILES="$CONFIG_FILES lib/raid/Makefile" ;;
|
||||
"lib/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
|
||||
"lib/thin/Makefile") CONFIG_FILES="$CONFIG_FILES lib/thin/Makefile" ;;
|
||||
"lib/cache_segtype/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cache_segtype/Makefile" ;;
|
||||
"libdaemon/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/Makefile" ;;
|
||||
"libdaemon/client/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/client/Makefile" ;;
|
||||
"libdaemon/server/Makefile") CONFIG_FILES="$CONFIG_FILES libdaemon/server/Makefile" ;;
|
||||
@@ -16553,12 +16327,10 @@ do
|
||||
"scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
|
||||
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
|
||||
"test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;;
|
||||
"test/api/python_lvm_unit.py") CONFIG_FILES="$CONFIG_FILES test/api/python_lvm_unit.py" ;;
|
||||
"test/unit/Makefile") CONFIG_FILES="$CONFIG_FILES test/unit/Makefile" ;;
|
||||
"tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
|
||||
"udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;;
|
||||
"unit-tests/datastruct/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/datastruct/Makefile" ;;
|
||||
"unit-tests/regex/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/regex/Makefile" ;;
|
||||
"unit-tests/mm/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/mm/Makefile" ;;
|
||||
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||
esac
|
||||
|
||||
@@ -77,6 +77,7 @@ AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
CFLAGS=$save_CFLAGS
|
||||
CXXFLAGS=$save_CXXFLAGS
|
||||
PATH_SBIN="$PATH:/usr/sbin:/sbin"
|
||||
|
||||
dnl probably no longer needed in 2008, but...
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
@@ -102,7 +103,7 @@ AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
|
||||
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
|
||||
getopt.h inttypes.h langinfo.h libaio.h libgen.h limits.h locale.h paths.h \
|
||||
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
|
||||
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
|
||||
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||
@@ -191,9 +192,15 @@ AC_SUBST(HAVE_FULL_RELRO)
|
||||
################################################################################
|
||||
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||
AC_PREFIX_DEFAULT(/usr)
|
||||
if test "$prefix" = NONE; then
|
||||
datarootdir=${ac_default_prefix}/share
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Clear default exec_prefix - install into /sbin rather than /usr/sbin
|
||||
test "$exec_prefix" = NONE -a "$prefix" = NONE && exec_prefix=""
|
||||
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
# Let make expand exec_prefix.
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the ownership of the files
|
||||
@@ -275,58 +282,6 @@ esac
|
||||
AC_MSG_RESULT($MANGLING)
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour])
|
||||
|
||||
################################################################################
|
||||
dnl -- LVM1 tool fallback option
|
||||
AC_MSG_CHECKING(whether to enable lvm1 fallback)
|
||||
AC_ARG_ENABLE(lvm1_fallback,
|
||||
AC_HELP_STRING([--enable-lvm1_fallback],
|
||||
[use this to fall back and use LVM1 binaries if
|
||||
device-mapper is missing from the kernel]),
|
||||
LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no)
|
||||
AC_MSG_RESULT($LVM1_FALLBACK)
|
||||
|
||||
if test "$LVM1_FALLBACK" = yes; then
|
||||
DEFAULT_FALLBACK_TO_LVM1=1
|
||||
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
|
||||
else
|
||||
DEFAULT_FALLBACK_TO_LVM1=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1],
|
||||
[Fall back to LVM1 by default if device-mapper is missing from the kernel.])
|
||||
|
||||
################################################################################
|
||||
dnl -- format1 inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for lvm1 metadata)
|
||||
AC_ARG_WITH(lvm1,
|
||||
AC_HELP_STRING([--with-lvm1=TYPE],
|
||||
[LVM1 metadata support: internal/shared/none [internal]]),
|
||||
LVM1=$withval, LVM1=internal)
|
||||
|
||||
AC_MSG_RESULT($LVM1)
|
||||
|
||||
case "$LVM1" in
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([LVM1_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for LVM1 metadata.]) ;;
|
||||
*) AC_MSG_ERROR([--with-lvm1 parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- format_pool inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for GFS pool metadata)
|
||||
AC_ARG_WITH(pool,
|
||||
AC_HELP_STRING([--with-pool=TYPE],
|
||||
[GFS pool read-only support: internal/shared/none [internal]]),
|
||||
POOL=$withval, POOL=internal)
|
||||
AC_MSG_RESULT($POOL)
|
||||
|
||||
case "$POOL" in
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([POOL_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for GFS pool metadata.]) ;;
|
||||
*) AC_MSG_ERROR([--with-pool parameter invalid])
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
@@ -377,13 +332,6 @@ esac
|
||||
|
||||
################################################################################
|
||||
dnl -- raid inclusion type
|
||||
AC_MSG_CHECKING(whether to include raid)
|
||||
AC_ARG_WITH(raid,
|
||||
AC_HELP_STRING([--with-raid=TYPE],
|
||||
[raid support: internal/shared/none [internal]]),
|
||||
RAID=$withval, RAID=internal)
|
||||
AC_MSG_RESULT($RAID)
|
||||
|
||||
AC_ARG_WITH(default-mirror-segtype,
|
||||
AC_HELP_STRING([--with-default-mirror-segtype=TYPE],
|
||||
[default mirror segtype: raid1/mirror [raid1]]),
|
||||
@@ -392,14 +340,9 @@ AC_ARG_WITH(default-raid10-segtype,
|
||||
AC_HELP_STRING([--with-default-raid10-segtype=TYPE],
|
||||
[default mirror segtype: raid10/mirror [raid10]]),
|
||||
DEFAULT_RAID10_SEGTYPE=$withval, DEFAULT_RAID10_SEGTYPE="raid10")
|
||||
case "$RAID" in
|
||||
none) test "$DEFAULT_MIRROR_SEGTYPE" = "raid1" && DEFAULT_MIRROR_SEGTYPE="mirror"
|
||||
test "$DEFAULT_RAID10_SEGTYPE" = "raid10" && DEFAULT_RAID10_SEGTYPE="mirror" ;;
|
||||
shared) ;;
|
||||
internal) AC_DEFINE([RAID_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for raid.]) ;;
|
||||
*) AC_MSG_ERROR([--with-raid parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
AC_DEFINE([RAID_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for raid.])
|
||||
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_MIRROR_SEGTYPE], ["$DEFAULT_MIRROR_SEGTYPE"],
|
||||
[Default segtype used for mirror volumes.])
|
||||
@@ -408,22 +351,6 @@ AC_DEFINE_UNQUOTED([DEFAULT_RAID10_SEGTYPE], ["$DEFAULT_RAID10_SEGTYPE"],
|
||||
[Default segtype used for raid10 volumes.])
|
||||
|
||||
################################################################################
|
||||
dnl -- asynchronous volume replicator inclusion type
|
||||
AC_MSG_CHECKING(whether to include replicators)
|
||||
AC_ARG_WITH(replicators,
|
||||
AC_HELP_STRING([--with-replicators=TYPE],
|
||||
[replicator support: internal/shared/none [none]]),
|
||||
REPLICATORS=$withval, REPLICATORS=none)
|
||||
AC_MSG_RESULT($REPLICATORS)
|
||||
|
||||
case "$REPLICATORS" in
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([REPLICATOR_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for replicators.]) ;;
|
||||
*) AC_MSG_ERROR([--with-replicators parameter invalid ($REPLICATORS)]) ;;
|
||||
esac
|
||||
|
||||
|
||||
AC_ARG_WITH(default-sparse-segtype,
|
||||
AC_HELP_STRING([--with-default-sparse-segtype=TYPE],
|
||||
[default sparse segtype: thin/snapshot [thin]]),
|
||||
@@ -478,7 +405,7 @@ case "$THIN" in
|
||||
internal|shared)
|
||||
# Empty means a config way to ignore thin checking
|
||||
if test "$THIN_CHECK_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(THIN_CHECK_CMD, thin_check)
|
||||
AC_PATH_TOOL(THIN_CHECK_CMD, thin_check, [], [$PATH_SBIN])
|
||||
if test -z "$THIN_CHECK_CMD"; then
|
||||
AC_MSG_WARN([thin_check not found in path $PATH])
|
||||
THIN_CHECK_CMD=/usr/sbin/thin_check
|
||||
@@ -502,7 +429,7 @@ case "$THIN" in
|
||||
fi
|
||||
# Empty means a config way to ignore thin dumping
|
||||
if test "$THIN_DUMP_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(THIN_DUMP_CMD, thin_dump)
|
||||
AC_PATH_TOOL(THIN_DUMP_CMD, thin_dump, [], [$PATH_SBIN])
|
||||
test -z "$THIN_DUMP_CMD" && {
|
||||
AC_MSG_WARN(thin_dump not found in path $PATH)
|
||||
THIN_DUMP_CMD=/usr/sbin/thin_dump
|
||||
@@ -511,7 +438,7 @@ case "$THIN" in
|
||||
fi
|
||||
# Empty means a config way to ignore thin repairing
|
||||
if test "$THIN_REPAIR_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(THIN_REPAIR_CMD, thin_repair)
|
||||
AC_PATH_TOOL(THIN_REPAIR_CMD, thin_repair, [], [$PATH_SBIN])
|
||||
test -z "$THIN_REPAIR_CMD" && {
|
||||
AC_MSG_WARN(thin_repair not found in path $PATH)
|
||||
THIN_REPAIR_CMD=/usr/sbin/thin_repair
|
||||
@@ -520,7 +447,7 @@ case "$THIN" in
|
||||
fi
|
||||
# Empty means a config way to ignore thin restoring
|
||||
if test "$THIN_RESTORE_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(THIN_RESTORE_CMD, thin_restore)
|
||||
AC_PATH_TOOL(THIN_RESTORE_CMD, thin_restore, [], [$PATH_SBIN])
|
||||
test -z "$THIN_RESTORE_CMD" && {
|
||||
AC_MSG_WARN(thin_restore not found in path $PATH)
|
||||
THIN_RESTORE_CMD=/usr/sbin/thin_restore
|
||||
@@ -592,7 +519,7 @@ case "$CACHE" in
|
||||
internal|shared)
|
||||
# Empty means a config way to ignore cache checking
|
||||
if test "$CACHE_CHECK_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(CACHE_CHECK_CMD, cache_check)
|
||||
AC_PATH_TOOL(CACHE_CHECK_CMD, cache_check, [], [$PATH_SBIN])
|
||||
if test -z "$CACHE_CHECK_CMD"; then
|
||||
AC_MSG_WARN([cache_check not found in path $PATH])
|
||||
CACHE_CHECK_CMD=/usr/sbin/cache_check
|
||||
@@ -627,7 +554,7 @@ case "$CACHE" in
|
||||
fi
|
||||
# Empty means a config way to ignore cache dumping
|
||||
if test "$CACHE_DUMP_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
|
||||
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump, [], [$PATH_SBIN])
|
||||
test -z "$CACHE_DUMP_CMD" && {
|
||||
AC_MSG_WARN(cache_dump not found in path $PATH)
|
||||
CACHE_DUMP_CMD=/usr/sbin/cache_dump
|
||||
@@ -636,7 +563,7 @@ case "$CACHE" in
|
||||
fi
|
||||
# Empty means a config way to ignore cache repairing
|
||||
if test "$CACHE_REPAIR_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(CACHE_REPAIR_CMD, cache_repair)
|
||||
AC_PATH_TOOL(CACHE_REPAIR_CMD, cache_repair, [], [$PATH_SBIN])
|
||||
test -z "$CACHE_REPAIR_CMD" && {
|
||||
AC_MSG_WARN(cache_repair not found in path $PATH)
|
||||
CACHE_REPAIR_CMD=/usr/sbin/cache_repair
|
||||
@@ -645,7 +572,7 @@ case "$CACHE" in
|
||||
fi
|
||||
# Empty means a config way to ignore cache restoring
|
||||
if test "$CACHE_RESTORE_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(CACHE_RESTORE_CMD, cache_restore)
|
||||
AC_PATH_TOOL(CACHE_RESTORE_CMD, cache_restore, [], [$PATH_SBIN])
|
||||
test -z "$CACHE_RESTORE_CMD" && {
|
||||
AC_MSG_WARN(cache_restore not found in path $PATH)
|
||||
CACHE_RESTORE_CMD=/usr/sbin/cache_restore
|
||||
@@ -1076,20 +1003,6 @@ if test "$PROFILING" = yes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable testing
|
||||
AC_MSG_CHECKING(whether to enable unit testing)
|
||||
AC_ARG_ENABLE(testing,
|
||||
AC_HELP_STRING([--enable-testing],
|
||||
[enable testing targets in the makefile]),
|
||||
TESTING=$enableval, TESTING=no)
|
||||
AC_MSG_RESULT($TESTING)
|
||||
|
||||
if test "$TESTING" = yes; then
|
||||
pkg_config_init
|
||||
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Set LVM2 testsuite data
|
||||
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
|
||||
@@ -1464,6 +1377,8 @@ AC_SUBST([LVM2APP_LIB])
|
||||
test "$APPLIB" = yes \
|
||||
&& LVM2APP_LIB=-llvm2app \
|
||||
|| LVM2APP_LIB=
|
||||
AS_IF([test "$APPLIB"],
|
||||
[AC_MSG_WARN([liblvm2app is deprecated. Use D-Bus API])])
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable cmdlib
|
||||
@@ -1484,6 +1399,8 @@ AC_ARG_ENABLE(dbus-service,
|
||||
AC_HELP_STRING([--enable-dbus-service], [install D-Bus support]),
|
||||
BUILD_LVMDBUSD=$enableval, BUILD_LVMDBUSD=no)
|
||||
AC_MSG_RESULT($BUILD_LVMDBUSD)
|
||||
AS_IF([test "$NOTIFYDBUS_SUPPORT" = yes && test "BUILD_LVMDBUSD" = yes],
|
||||
[AC_MSG_WARN([Building D-Bus support without D-Bus notifications.])])
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable Python liblvm2app bindings
|
||||
@@ -1536,7 +1453,7 @@ if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
||||
PYTHON3_INCDIRS=`"$PYTHON3_CONFIG" --includes`
|
||||
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
|
||||
PYTHON3DIR=$pythondir
|
||||
PYTHON_BINDINGS=yes
|
||||
test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
@@ -1546,6 +1463,7 @@ if test "$BUILD_LVMDBUSD" = yes; then
|
||||
fi
|
||||
|
||||
if test "$PYTHON_BINDINGS" = yes -o "$PYTHON2_BINDINGS" = yes -o "$PYTHON3_BINDINGS" = yes; then
|
||||
AC_MSG_WARN([Python bindings are deprecated. Use D-Bus API])
|
||||
test "$APPLIB" != yes && AC_MSG_ERROR([Python_bindings require --enable-applib])
|
||||
fi
|
||||
|
||||
@@ -1609,10 +1527,6 @@ AC_CHECK_LIB(c, canonicalize_file_name,
|
||||
AC_DEFINE([HAVE_CANONICALIZE_FILE_NAME], 1,
|
||||
[Define to 1 if canonicalize_file_name is available.]))
|
||||
|
||||
################################################################################
|
||||
dnl -- Clear default exec_prefix - install into /sbin rather than /usr/sbin
|
||||
test "$exec_prefix" = NONE -a "$prefix" = NONE && exec_prefix=""
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for dlopen
|
||||
AC_CHECK_LIB(dl, dlopen,
|
||||
@@ -1625,8 +1539,6 @@ AC_CHECK_LIB(dl, dlopen,
|
||||
################################################################################
|
||||
dnl -- Check for shared/static conflicts
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
-o "$SNAPSHOTS" = shared -o "$MIRRORS" = shared \
|
||||
-o "$RAID" = shared -o "$CACHE" = shared \
|
||||
\) -a "$STATIC_LINK" = yes ]]; then
|
||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||
fi
|
||||
@@ -1879,26 +1791,23 @@ if test "$BUILD_DMFILEMAPD" = yes; then
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
AC_PATH_TOOL(MODPROBE_CMD, modprobe)
|
||||
AC_PATH_TOOL(MODPROBE_CMD, modprobe, [], [$PATH_SBIN])
|
||||
|
||||
if test -n "$MODPROBE_CMD"; then
|
||||
AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.])
|
||||
fi
|
||||
|
||||
SYSCONFDIR="$(eval echo $(eval echo $sysconfdir))"
|
||||
|
||||
lvm_exec_prefix=$exec_prefix
|
||||
test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$prefix
|
||||
test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
|
||||
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
||||
SBINDIR="$(eval echo $(eval echo $sbindir))"
|
||||
LVM_PATH="$SBINDIR/lvm"
|
||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
|
||||
CLVMD_PATH="$USRSBINDIR/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
|
||||
|
||||
FSADM_PATH="$lvm_exec_prefix/sbin/fsadm"
|
||||
FSADM_PATH="$SBINDIR/fsadm"
|
||||
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
|
||||
|
||||
################################################################################
|
||||
@@ -1918,7 +1827,7 @@ if test "$BUILD_DMEVENTD" = yes; then
|
||||
AC_HELP_STRING([--with-dmeventd-path=PATH],
|
||||
[dmeventd path [EPREFIX/sbin/dmeventd]]),
|
||||
DMEVENTD_PATH=$withval,
|
||||
DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd")
|
||||
DMEVENTD_PATH="$SBINDIR/dmeventd")
|
||||
AC_DEFINE_UNQUOTED(DMEVENTD_PATH, ["$DMEVENTD_PATH"],
|
||||
[Path to dmeventd binary.])
|
||||
fi
|
||||
@@ -1961,13 +1870,17 @@ AC_ARG_WITH(default-cache-subdir,
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"],
|
||||
[Name of default metadata cache subdirectory.])
|
||||
|
||||
# Select default system locking dir, prefer /run/lock over /var/lock
|
||||
DEFAULT_SYS_LOCK_DIR="$RUN_DIR/lock"
|
||||
test -d "$DEFAULT_SYS_LOCK_DIR" || DEFAULT_SYS_LOCK_DIR="/var/lock"
|
||||
|
||||
# Support configurable locking subdir for lvm
|
||||
AC_ARG_WITH(default-locking-dir,
|
||||
AC_HELP_STRING([--with-default-locking-dir=DIR],
|
||||
[default locking directory [autodetect_lock_dir/lvm]]),
|
||||
DEFAULT_LOCK_DIR=$withval,
|
||||
[AC_MSG_CHECKING(for default lock directory)
|
||||
DEFAULT_LOCK_DIR="$RUN_DIR/lock/lvm"
|
||||
test -d "$RUN_DIR/lock" || DEFAULT_LOCK_DIR="/var/lock/lvm"
|
||||
DEFAULT_LOCK_DIR="$DEFAULT_SYS_LOCK_DIR/lvm"
|
||||
AC_MSG_RESULT($DEFAULT_LOCK_DIR)])
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
|
||||
[Name of default locking directory.])
|
||||
@@ -2054,7 +1967,6 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_FALLBACK_TO_LVM1)
|
||||
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_PID_DIR)
|
||||
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
|
||||
@@ -2062,6 +1974,7 @@ AC_SUBST(DEFAULT_RAID10_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_SYS_DIR)
|
||||
AC_SUBST(DEFAULT_SYS_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
|
||||
AC_SUBST(DEFAULT_USE_LVMETAD)
|
||||
AC_SUBST(DEFAULT_USE_LVMPOLLD)
|
||||
@@ -2084,8 +1997,6 @@ AC_SUBST(JOBS)
|
||||
AC_SUBST(LDDEPS)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LIB_SUFFIX)
|
||||
AC_SUBST(LVM1)
|
||||
AC_SUBST(LVM1_FALLBACK)
|
||||
AC_SUBST(LVM_VERSION)
|
||||
AC_SUBST(LVM_LIBAPI)
|
||||
AC_SUBST(LVM_MAJOR)
|
||||
@@ -2102,7 +2013,6 @@ AC_SUBST(OCF)
|
||||
AC_SUBST(OCFDIR)
|
||||
AC_SUBST(ODIRECT)
|
||||
AC_SUBST(PKGCONFIG)
|
||||
AC_SUBST(POOL)
|
||||
AC_SUBST(M_LIBS)
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PYTHON2)
|
||||
@@ -2118,7 +2028,6 @@ AC_SUBST(PYTHON2DIR)
|
||||
AC_SUBST(PYTHON3DIR)
|
||||
AC_SUBST(QUORUM_CFLAGS)
|
||||
AC_SUBST(QUORUM_LIBS)
|
||||
AC_SUBST(RAID)
|
||||
AC_SUBST(RT_LIBS)
|
||||
AC_SUBST(READLINE_LIBS)
|
||||
AC_SUBST(REPLICATORS)
|
||||
@@ -2126,13 +2035,14 @@ AC_SUBST(SACKPT_CFLAGS)
|
||||
AC_SUBST(SACKPT_LIBS)
|
||||
AC_SUBST(SALCK_CFLAGS)
|
||||
AC_SUBST(SALCK_LIBS)
|
||||
AC_SUBST(SBINDIR)
|
||||
AC_SUBST(SELINUX_LIBS)
|
||||
AC_SUBST(SELINUX_PC)
|
||||
AC_SUBST(SYSCONFDIR)
|
||||
AC_SUBST(SYSTEMD_LIBS)
|
||||
AC_SUBST(SNAPSHOTS)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(TESTING)
|
||||
AC_SUBST(TESTSUITE_DATA)
|
||||
AC_SUBST(THIN)
|
||||
AC_SUBST(THIN_CHECK_CMD)
|
||||
@@ -2150,6 +2060,7 @@ AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(USE_TRACKING)
|
||||
AC_SUBST(USRSBINDIR)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
@@ -2190,10 +2101,14 @@ daemons/dmeventd/plugins/snapshot/Makefile
|
||||
daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/dmfilemapd/Makefile
|
||||
daemons/lvmdbusd/Makefile
|
||||
daemons/lvmdbusd/lvmdbusd
|
||||
daemons/lvmdbusd/lvmdb.py
|
||||
daemons/lvmdbusd/lvm_shell_proxy.py
|
||||
daemons/lvmdbusd/path.py
|
||||
daemons/lvmetad/Makefile
|
||||
daemons/lvmpolld/Makefile
|
||||
daemons/lvmlockd/Makefile
|
||||
device_mapper/Makefile
|
||||
conf/Makefile
|
||||
conf/example.conf
|
||||
conf/lvmlocal.conf
|
||||
@@ -2202,16 +2117,8 @@ conf/metadata_profile_template.profile
|
||||
include/.symlinks
|
||||
include/Makefile
|
||||
lib/Makefile
|
||||
lib/format1/Makefile
|
||||
lib/format_pool/Makefile
|
||||
lib/locking/Makefile
|
||||
lib/mirror/Makefile
|
||||
lib/replicator/Makefile
|
||||
include/lvm-version.h
|
||||
lib/raid/Makefile
|
||||
lib/snapshot/Makefile
|
||||
lib/thin/Makefile
|
||||
lib/cache_segtype/Makefile
|
||||
libdaemon/Makefile
|
||||
libdaemon/client/Makefile
|
||||
libdaemon/server/Makefile
|
||||
@@ -2252,12 +2159,10 @@ scripts/lvmdump.sh
|
||||
scripts/Makefile
|
||||
test/Makefile
|
||||
test/api/Makefile
|
||||
test/api/python_lvm_unit.py
|
||||
test/unit/Makefile
|
||||
tools/Makefile
|
||||
udev/Makefile
|
||||
unit-tests/datastruct/Makefile
|
||||
unit-tests/regex/Makefile
|
||||
unit-tests/mm/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -74,7 +74,7 @@ TARGETS = \
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
|
||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
|
||||
@@ -108,7 +108,6 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
/* Check to see if the VG is in use by LVM1 */
|
||||
status = do_check_lvm1(lockname);
|
||||
do_lock_vg(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
@@ -171,8 +170,10 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
|
||||
/* Check the status of the command and return the error text */
|
||||
if (status) {
|
||||
*retlen = 1 + ((*buf) ? dm_snprintf(*buf, buflen, "%s",
|
||||
strerror(status)) : -1);
|
||||
if (*buf)
|
||||
*retlen = dm_snprintf(*buf, buflen, "%s", strerror(status)) + 1;
|
||||
else
|
||||
*retlen = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
@@ -1105,31 +1105,31 @@ static void be_daemon(int timeout)
|
||||
break;
|
||||
|
||||
default: /* Parent */
|
||||
(void) close(devnull);
|
||||
(void) close(child_pipe[1]);
|
||||
wait_for_child(child_pipe[0], timeout);
|
||||
wait_for_child(child_pipe[0], timeout); /* noreturn */
|
||||
}
|
||||
|
||||
/* Detach ourself from the calling environment */
|
||||
if (close(0) || close(1) || close(2)) {
|
||||
perror("Error closing terminal FDs");
|
||||
exit(4);
|
||||
}
|
||||
setsid();
|
||||
|
||||
if (dup2(devnull, 0) < 0 || dup2(devnull, 1) < 0
|
||||
|| dup2(devnull, 2) < 0) {
|
||||
if ((dup2(devnull, STDIN_FILENO) == -1) ||
|
||||
(dup2(devnull, STDOUT_FILENO) == -1) ||
|
||||
(dup2(devnull, STDERR_FILENO) == -1)) {
|
||||
perror("Error setting terminal FDs to /dev/null");
|
||||
log_error("Error setting terminal FDs to /dev/null: %m");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
if ((devnull > STDERR_FILENO) && close(devnull)) {
|
||||
log_sys_error("close", "/dev/null");
|
||||
exit(7);
|
||||
}
|
||||
|
||||
if (chdir("/")) {
|
||||
log_error("Error setting current directory to /: %m");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
setsid();
|
||||
}
|
||||
|
||||
static int verify_message(char *buf, int len)
|
||||
@@ -1999,6 +1999,9 @@ static int send_message(void *buf, int msglen, const char *csid, int fd,
|
||||
return clops->cluster_send_message(buf, msglen, csid, errtext);
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* Make sure it all goes */
|
||||
for (ptr = 0; ptr < msglen;) {
|
||||
if ((len = write(fd, (char*)buf + ptr, msglen - ptr)) <= 0) {
|
||||
@@ -2151,6 +2154,14 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
|
||||
}
|
||||
|
||||
/* Return 0 if we can talk to an existing clvmd */
|
||||
/*
|
||||
* FIXME:
|
||||
*
|
||||
* This function returns only -1 or 0, but there are
|
||||
* different levels of errors, some of them should stop
|
||||
* further execution of clvmd thus another state is needed
|
||||
* and some error message need to be only informational.
|
||||
*/
|
||||
static int check_local_clvmd(void)
|
||||
{
|
||||
int local_socket;
|
||||
@@ -2170,7 +2181,11 @@ static int check_local_clvmd(void)
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
log_sys_error("connect", "local socket");
|
||||
/* connection failure is expected state */
|
||||
if (errno == ENOENT)
|
||||
log_sys_debug("connect", "local socket");
|
||||
else
|
||||
log_sys_error("connect", "local socket");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -639,16 +639,6 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if a VG is in use by LVM1 so we don't stomp on it */
|
||||
int do_check_lvm1(const char *vgname)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = check_lvm1_vg_inactive(cmd, vgname);
|
||||
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
int do_refresh_cache(void)
|
||||
{
|
||||
DEBUGLOG("Refreshing context\n");
|
||||
@@ -661,10 +651,9 @@ int do_refresh_cache(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_full_scan_done(0);
|
||||
init_ignore_suspended_devices(1);
|
||||
lvmcache_force_next_label_scan();
|
||||
lvmcache_label_scan(cmd);
|
||||
label_scan_destroy(cmd); /* destroys bcache (to close devs), keeps lvmcache */
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
@@ -807,8 +796,7 @@ static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
return;
|
||||
|
||||
strncpy(last_error, message, sizeof(last_error));
|
||||
last_error[sizeof(last_error)-1] = '\0';
|
||||
(void) dm_strncpy(last_error, message, sizeof(last_error));
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
@@ -844,7 +832,7 @@ void lvm_do_backup(const char *vgname)
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, WARN_PV_READ, &consistent);
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, 0, WARN_PV_READ, &consistent);
|
||||
|
||||
if (vg && consistent)
|
||||
check_current_backup(vg);
|
||||
|
||||
@@ -25,7 +25,6 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
extern const char *do_lock_query(char *resource);
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(const char *vgname);
|
||||
extern int do_refresh_cache(void);
|
||||
extern int init_clvm(struct dm_hash_table *excl_uuid);
|
||||
extern void destroy_lvm(void);
|
||||
|
||||
@@ -166,6 +166,9 @@ int cluster_send(struct clog_request *rq)
|
||||
{
|
||||
int r;
|
||||
int found = 0;
|
||||
#if CMIRROR_HAS_CHECKPOINT
|
||||
int count = 0;
|
||||
#endif
|
||||
struct iovec iov;
|
||||
struct clog_cpg *entry;
|
||||
|
||||
@@ -203,8 +206,6 @@ int cluster_send(struct clog_request *rq)
|
||||
|
||||
#if CMIRROR_HAS_CHECKPOINT
|
||||
do {
|
||||
int count = 0;
|
||||
|
||||
r = cpg_mcast_joined(entry->handle, CPG_TYPE_AGREED, &iov, 1);
|
||||
if (r != SA_AIS_ERR_TRY_AGAIN)
|
||||
break;
|
||||
@@ -1630,7 +1631,7 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
|
||||
|
||||
size = ((strlen(uuid) + 1) > CPG_MAX_NAME_LENGTH) ?
|
||||
CPG_MAX_NAME_LENGTH : (strlen(uuid) + 1);
|
||||
strncpy(new->name.value, uuid, size);
|
||||
(void) dm_strncpy(new->name.value, uuid, size);
|
||||
new->name.length = (uint32_t)size;
|
||||
new->luid = luid;
|
||||
|
||||
|
||||
@@ -451,15 +451,19 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
||||
lc->skip_bit_warning = region_count;
|
||||
lc->disk_fd = -1;
|
||||
lc->log_dev_failed = 0;
|
||||
strncpy(lc->uuid, uuid, DM_UUID_LEN);
|
||||
if (!dm_strncpy(lc->uuid, uuid, DM_UUID_LEN)) {
|
||||
LOG_ERROR("Cannot use too long UUID %s.", uuid);
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
lc->luid = luid;
|
||||
|
||||
if (get_log(lc->uuid, lc->luid) ||
|
||||
get_pending_log(lc->uuid, lc->luid)) {
|
||||
LOG_ERROR("[%s/%" PRIu64 "u] Log already exists, unable to create.",
|
||||
SHORT_UUID(lc->uuid), lc->luid);
|
||||
dm_free(lc);
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dm_list_init(&lc->mark_list);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#define _LVM_CLOG_LOGGING_H
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "configure.h"
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define DM_SIGNALED_EXIT 1
|
||||
#define DM_SCHEDULED_EXIT 2
|
||||
static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */
|
||||
|
||||
/* List (un)link macros. */
|
||||
@@ -752,6 +754,7 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
struct thread_status *thread;
|
||||
struct timespec timeout;
|
||||
time_t curr_time;
|
||||
int ret;
|
||||
|
||||
DEBUGLOG("Timeout thread starting.");
|
||||
pthread_cleanup_push(_exit_timeout, NULL);
|
||||
@@ -773,7 +776,10 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
} else {
|
||||
DEBUGLOG("Sending SIGALRM to Thr %x for timeout.",
|
||||
(int) thread->thread);
|
||||
pthread_kill(thread->thread, SIGALRM);
|
||||
ret = pthread_kill(thread->thread, SIGALRM);
|
||||
if (ret && (ret != ESRCH))
|
||||
log_error("Unable to wakeup Thr %x for timeout: %s.",
|
||||
(int) thread->thread, strerror(ret));
|
||||
}
|
||||
_unlock_mutex();
|
||||
}
|
||||
@@ -863,6 +869,7 @@ static int _event_wait(struct thread_status *thread)
|
||||
* This is so that you can break out of waiting on an event,
|
||||
* either for a timeout event, or to cancel the thread.
|
||||
*/
|
||||
sigemptyset(&old);
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGALRM);
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &set, &old) != 0) {
|
||||
@@ -1750,7 +1757,7 @@ static void _init_thread_signals(void)
|
||||
*/
|
||||
static void _exit_handler(int sig __attribute__((unused)))
|
||||
{
|
||||
_exit_now = 1;
|
||||
_exit_now = DM_SIGNALED_EXIT;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -2248,6 +2255,8 @@ int main(int argc, char *argv[])
|
||||
for (;;) {
|
||||
if (_idle_since) {
|
||||
if (_exit_now) {
|
||||
if (_exit_now == DM_SCHEDULED_EXIT)
|
||||
break; /* Only prints shutdown message */
|
||||
log_info("dmeventd detected break while being idle "
|
||||
"for %ld second(s), exiting.",
|
||||
(long) (time(NULL) - _idle_since));
|
||||
@@ -2264,15 +2273,14 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (_exit_now) {
|
||||
_exit_now = 0;
|
||||
} else if (_exit_now == DM_SIGNALED_EXIT) {
|
||||
_exit_now = DM_SCHEDULED_EXIT;
|
||||
/*
|
||||
* When '_exit_now' is set, signal has been received,
|
||||
* but can not simply exit unless all
|
||||
* threads are done processing.
|
||||
*/
|
||||
log_warn("WARNING: There are still devices being monitored.");
|
||||
log_warn("WARNING: Refusing to exit.");
|
||||
log_info("dmeventd received break, scheduling exit.");
|
||||
}
|
||||
_process_request(&fifos);
|
||||
_cleanup_unused_threads();
|
||||
|
||||
@@ -754,11 +754,10 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
/* FIXME Distinguish errors connecting to daemon */
|
||||
if (_do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
|
||||
&msg, dmevh->dso, uuid, dmevh->mask, 0)) {
|
||||
if ((ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE, dmevh->dmeventd_path,
|
||||
&msg, dmevh->dso, uuid, dmevh->mask, 0))) {
|
||||
log_debug("%s: device not registered.", dm_task_get_name(dmt));
|
||||
ret = -ENOENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,23 +16,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SUBDIRS += lvm2
|
||||
|
||||
ifneq ("@MIRRORS@", "none")
|
||||
SUBDIRS += mirror
|
||||
endif
|
||||
|
||||
ifneq ("@SNAPSHOTS@", "none")
|
||||
SUBDIRS += snapshot
|
||||
endif
|
||||
|
||||
ifneq ("@RAID@", "none")
|
||||
SUBDIRS += raid
|
||||
endif
|
||||
|
||||
ifneq ("@THIN@", "none")
|
||||
SUBDIRS += thin
|
||||
endif
|
||||
SUBDIRS += lvm2 snapshot raid thin mirror
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = lvm2 mirror snapshot raid thin
|
||||
|
||||
@@ -62,27 +62,25 @@ struct dso_state {
|
||||
|
||||
DM_EVENT_LOG_FN("thin")
|
||||
|
||||
#define UUID_PREFIX "LVM-"
|
||||
|
||||
static int _run_command(struct dso_state *state)
|
||||
{
|
||||
char val[3][36];
|
||||
char *env[] = { val[0], val[1], val[2], NULL };
|
||||
char val[16];
|
||||
int i;
|
||||
|
||||
/* Mark for possible lvm2 command we are running from dmeventd
|
||||
* lvm2 will not try to talk back to dmeventd while processing it */
|
||||
(void) dm_snprintf(val[0], sizeof(val[0]), "LVM_RUN_BY_DMEVENTD=1");
|
||||
(void) setenv("LVM_RUN_BY_DMEVENTD", "1", 1);
|
||||
|
||||
if (state->data_percent) {
|
||||
/* Prepare some known data to env vars for easy use */
|
||||
(void) dm_snprintf(val[1], sizeof(val[1]), "DMEVENTD_THIN_POOL_DATA=%d",
|
||||
state->data_percent / DM_PERCENT_1);
|
||||
(void) dm_snprintf(val[2], sizeof(val[2]), "DMEVENTD_THIN_POOL_METADATA=%d",
|
||||
state->metadata_percent / DM_PERCENT_1);
|
||||
if (dm_snprintf(val, sizeof(val), "%d",
|
||||
state->data_percent / DM_PERCENT_1) != -1)
|
||||
(void) setenv("DMEVENTD_THIN_POOL_DATA", val, 1);
|
||||
if (dm_snprintf(val, sizeof(val), "%d",
|
||||
state->metadata_percent / DM_PERCENT_1) != -1)
|
||||
(void) setenv("DMEVENTD_THIN_POOL_METADATA", val, 1);
|
||||
} else {
|
||||
/* For an error event it's for a user to check status and decide */
|
||||
env[1] = NULL;
|
||||
log_debug("Error event processing.");
|
||||
}
|
||||
|
||||
@@ -97,7 +95,7 @@ static int _run_command(struct dso_state *state)
|
||||
/* child */
|
||||
(void) close(0);
|
||||
for (i = 3; i < 255; ++i) (void) close(i);
|
||||
execve(state->argv[0], state->argv, env);
|
||||
execvp(state->argv[0], state->argv);
|
||||
_exit(errno);
|
||||
} else if (state->pid == -1) {
|
||||
log_error("Can't fork command %s.", state->cmd_str);
|
||||
|
||||
@@ -802,7 +802,7 @@ bad:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char * _mode_names[] = {
|
||||
static const char * const _mode_names[] = {
|
||||
"inode",
|
||||
"path"
|
||||
};
|
||||
@@ -827,8 +827,10 @@ int main(int argc, char **argv)
|
||||
"mode=%s, path=%s", fm.fd, fm.group_id,
|
||||
_mode_names[fm.mode], fm.path);
|
||||
|
||||
if (!_foreground && !_daemonise(&fm))
|
||||
if (!_foreground && !_daemonise(&fm)) {
|
||||
dm_free(fm.path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return _dmfilemapd(&fm);
|
||||
}
|
||||
|
||||
3
daemons/lvmdbusd/.gitignore
vendored
3
daemons/lvmdbusd/.gitignore
vendored
@@ -1 +1,4 @@
|
||||
path.py
|
||||
lvmdbusd
|
||||
lvmdb.py
|
||||
lvm_shell_proxy.py
|
||||
|
||||
@@ -26,9 +26,7 @@ LVMDBUS_SRCDIR_FILES = \
|
||||
__init__.py \
|
||||
job.py \
|
||||
loader.py \
|
||||
lvmdb.py \
|
||||
main.py \
|
||||
lvm_shell_proxy.py \
|
||||
lv.py \
|
||||
manager.py \
|
||||
objectmanager.py \
|
||||
@@ -40,14 +38,21 @@ LVMDBUS_SRCDIR_FILES = \
|
||||
vg.py
|
||||
|
||||
LVMDBUS_BUILDDIR_FILES = \
|
||||
lvmdb.py \
|
||||
lvm_shell_proxy.py \
|
||||
path.py
|
||||
|
||||
LVMDBUSD = $(srcdir)/lvmdbusd
|
||||
LVMDBUSD = lvmdbusd
|
||||
|
||||
CLEAN_DIRS += __pycache__
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
.PHONY: install_lvmdbusd
|
||||
|
||||
all:
|
||||
test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||
|
||||
install_lvmdbusd:
|
||||
$(INSTALL_DIR) $(sbindir)
|
||||
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||
@@ -63,4 +68,5 @@ install_lvm2: install_lvmdbusd
|
||||
install: install_lvm2
|
||||
|
||||
DISTCLEAN_TARGETS+= \
|
||||
$(LVMDBUS_BUILDDIR_FILES)
|
||||
$(LVMDBUS_BUILDDIR_FILES) \
|
||||
$(LVMDBUSD)
|
||||
|
||||
@@ -158,5 +158,6 @@ def _run_cmd(req):
|
||||
|
||||
|
||||
def cmd_runner(request):
|
||||
t = threading.Thread(target=_run_cmd, args=(request,))
|
||||
t = threading.Thread(target=_run_cmd, args=(request,),
|
||||
name="cmd_runner %s" % str(request.method))
|
||||
t.start()
|
||||
|
||||
@@ -152,7 +152,8 @@ class StateUpdate(object):
|
||||
load(refresh=False, emit_signal=False, need_main_thread=False)
|
||||
|
||||
self.thread = threading.Thread(target=StateUpdate.update_thread,
|
||||
args=(self,))
|
||||
args=(self,),
|
||||
name="StateUpdate.update_thread")
|
||||
|
||||
def load(self, refresh=True, emit_signal=True, cache_refresh=True,
|
||||
log=True, need_main_thread=True):
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .automatedproperties import AutomatedProperties
|
||||
from .utils import job_obj_path_generate, mt_async_result, mt_run_no_wait
|
||||
from .utils import job_obj_path_generate, mt_async_call
|
||||
from . import cfg
|
||||
from .cfg import JOB_INTERFACE
|
||||
import dbus
|
||||
@@ -30,7 +30,7 @@ class WaitingClient(object):
|
||||
# Remove ourselves from waiting client
|
||||
wc.job_state.remove_waiting_client(wc)
|
||||
wc.timer_id = -1
|
||||
mt_async_result(wc.cb, wc.job_state.Complete)
|
||||
mt_async_call(wc.cb, wc.job_state.Complete)
|
||||
wc.job_state = None
|
||||
|
||||
def __init__(self, job_state, tmo, cb, cbe):
|
||||
@@ -55,7 +55,7 @@ class WaitingClient(object):
|
||||
GLib.source_remove(self.timer_id)
|
||||
self.timer_id = -1
|
||||
|
||||
mt_async_result(self.cb, self.job_state.Complete)
|
||||
mt_async_call(self.cb, self.job_state.Complete)
|
||||
self.job_state = None
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ class Job(AutomatedProperties):
|
||||
@Complete.setter
|
||||
def Complete(self, value):
|
||||
self.state.Complete = value
|
||||
mt_run_no_wait(Job._signal_complete, self)
|
||||
mt_async_call(Job._signal_complete, self)
|
||||
|
||||
@property
|
||||
def GetError(self):
|
||||
|
||||
@@ -232,7 +232,6 @@ class LvState(State):
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Attr', 's')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'SnapPercent', 'u')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'MetaDataPercent', 'u')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'CopyPercent', 'u')
|
||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'SyncPercent', 'u')
|
||||
@@ -498,7 +497,7 @@ class Lv(LvCommon):
|
||||
# it is a thin lv
|
||||
if not dbo.IsThinVolume:
|
||||
if optional_size == 0:
|
||||
space = dbo.SizeBytes / 80
|
||||
space = dbo.SizeBytes // 80
|
||||
remainder = space % 512
|
||||
optional_size = space + 512 - remainder
|
||||
|
||||
|
||||
2
daemons/lvmdbusd/lvm_shell_proxy.py → daemons/lvmdbusd/lvm_shell_proxy.py.in
Executable file → Normal file
2
daemons/lvmdbusd/lvm_shell_proxy.py → daemons/lvmdbusd/lvm_shell_proxy.py.in
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!@PYTHON3@
|
||||
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
2
daemons/lvmdbusd/lvmdb.py → daemons/lvmdbusd/lvmdb.py.in
Executable file → Normal file
2
daemons/lvmdbusd/lvmdb.py → daemons/lvmdbusd/lvmdb.py.in
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!@PYTHON3@
|
||||
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
2
daemons/lvmdbusd/lvmdbusd → daemons/lvmdbusd/lvmdbusd.in
Executable file → Normal file
2
daemons/lvmdbusd/lvmdbusd → daemons/lvmdbusd/lvmdbusd.in
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!@PYTHON3@
|
||||
|
||||
# Copyright (C) 2015-2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
@@ -63,6 +63,24 @@ def check_bb_size(value):
|
||||
return v
|
||||
|
||||
|
||||
def install_signal_handlers():
|
||||
# Because of the glib main loop stuff the python signal handler code is
|
||||
# apparently not usable and we need to use the glib calls instead
|
||||
signal_add = None
|
||||
|
||||
if hasattr(GLib, 'unix_signal_add'):
|
||||
signal_add = GLib.unix_signal_add
|
||||
elif hasattr(GLib, 'unix_signal_add_full'):
|
||||
signal_add = GLib.unix_signal_add_full
|
||||
|
||||
if signal_add:
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
|
||||
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
|
||||
else:
|
||||
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
|
||||
|
||||
|
||||
def main():
|
||||
start = time.time()
|
||||
# Add simple command line handling
|
||||
@@ -112,12 +130,7 @@ def main():
|
||||
# List of threads that we start up
|
||||
thread_list = []
|
||||
|
||||
# Install signal handlers
|
||||
for s in [signal.SIGHUP, signal.SIGINT]:
|
||||
try:
|
||||
signal.signal(s, utils.handler)
|
||||
except RuntimeError:
|
||||
pass
|
||||
install_signal_handlers()
|
||||
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
dbus.mainloop.glib.threads_init()
|
||||
@@ -138,7 +151,8 @@ def main():
|
||||
|
||||
# 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))
|
||||
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
|
||||
@@ -176,5 +190,7 @@ def main():
|
||||
for thread in thread_list:
|
||||
thread.join()
|
||||
except KeyboardInterrupt:
|
||||
utils.handler(signal.SIGINT, None)
|
||||
# If we are unable to register signal handler, we will end up here when
|
||||
# the service gets a ^C or a kill -2 <parent pid>
|
||||
utils.handler(signal.SIGINT)
|
||||
return 0
|
||||
|
||||
@@ -79,7 +79,9 @@ class PvState(State):
|
||||
|
||||
self.lv = self._lv_object_list(vg_name)
|
||||
|
||||
if vg_name:
|
||||
# It's possible to have a vg_name and no uuid with the main example
|
||||
# being when the vg_name == '[unknown]'
|
||||
if vg_uuid and vg_name:
|
||||
self.vg_path = cfg.om.get_object_path_by_uuid_lvm_id(
|
||||
vg_uuid, vg_name, vg_obj_path_generate)
|
||||
else:
|
||||
|
||||
@@ -13,7 +13,7 @@ from gi.repository import GLib
|
||||
from .job import Job
|
||||
from . import cfg
|
||||
import traceback
|
||||
from .utils import log_error, mt_async_result
|
||||
from .utils import log_error, mt_async_call
|
||||
|
||||
|
||||
class RequestEntry(object):
|
||||
@@ -116,9 +116,9 @@ class RequestEntry(object):
|
||||
if error_rc == 0:
|
||||
if self.cb:
|
||||
if self._return_tuple:
|
||||
mt_async_result(self.cb, (result, '/'))
|
||||
mt_async_call(self.cb, (result, '/'))
|
||||
else:
|
||||
mt_async_result(self.cb, result)
|
||||
mt_async_call(self.cb, result)
|
||||
else:
|
||||
if self.cb_error:
|
||||
if not error_exception:
|
||||
@@ -129,7 +129,7 @@ class RequestEntry(object):
|
||||
else:
|
||||
error_exception = Exception(error_msg)
|
||||
|
||||
mt_async_result(self.cb_error, error_exception)
|
||||
mt_async_call(self.cb_error, error_exception)
|
||||
else:
|
||||
# We have a job and it's complete, indicate that it's done.
|
||||
self._job.Complete = True
|
||||
|
||||
@@ -20,7 +20,8 @@ from lvmdbusd import cfg
|
||||
# noinspection PyUnresolvedReferences
|
||||
from gi.repository import GLib
|
||||
import threading
|
||||
|
||||
import traceback
|
||||
import signal
|
||||
|
||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||
|
||||
@@ -281,12 +282,47 @@ def log_error(msg, *attributes):
|
||||
_common_log(msg, *attributes)
|
||||
|
||||
|
||||
def dump_threads_stackframe():
|
||||
ident_to_name = {}
|
||||
|
||||
for thread_object in threading.enumerate():
|
||||
ident_to_name[thread_object.ident] = thread_object
|
||||
|
||||
stacks = []
|
||||
for thread_ident, frame in sys._current_frames().items():
|
||||
stack = traceback.format_list(traceback.extract_stack(frame))
|
||||
|
||||
# There is a possibility that a thread gets created after we have
|
||||
# enumerated all threads, so this lookup table may be incomplete, so
|
||||
# account for this
|
||||
if thread_ident in ident_to_name:
|
||||
thread_name = ident_to_name[thread_ident].name
|
||||
else:
|
||||
thread_name = "unknown"
|
||||
|
||||
stacks.append("Thread: %s" % (thread_name))
|
||||
stacks.append("".join(stack))
|
||||
|
||||
log_error("Dumping thread stack frames!\n" + "\n".join(stacks))
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def handler(signum, frame):
|
||||
cfg.run.value = 0
|
||||
log_debug('Signal handler called with signal %d' % signum)
|
||||
if cfg.loop is not None:
|
||||
cfg.loop.quit()
|
||||
def handler(signum):
|
||||
try:
|
||||
if signum == signal.SIGUSR1:
|
||||
dump_threads_stackframe()
|
||||
else:
|
||||
cfg.run.value = 0
|
||||
log_debug('Exiting daemon with signal %d' % signum)
|
||||
if cfg.loop is not None:
|
||||
cfg.loop.quit()
|
||||
except:
|
||||
st = traceback.format_exc()
|
||||
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
|
||||
|
||||
# It's important we report that we handled the exception for the exception
|
||||
# handler to continue to work, especially for signal 10 (SIGUSR1)
|
||||
return True
|
||||
|
||||
|
||||
def pv_obj_path_generate():
|
||||
@@ -534,21 +570,27 @@ def add_no_notify(cmdline):
|
||||
# ensure all dbus library interaction is done from the same thread!
|
||||
|
||||
|
||||
def _async_result(call_back, results):
|
||||
log_debug('Results = %s' % str(results))
|
||||
call_back(results)
|
||||
def _async_handler(call_back, parameters):
|
||||
params_str = ", ".join(str(x) for x in parameters)
|
||||
log_debug('Main thread execution, callback = %s, parameters = (%s)' %
|
||||
(str(call_back), params_str))
|
||||
|
||||
try:
|
||||
if parameters:
|
||||
call_back(*parameters)
|
||||
else:
|
||||
call_back()
|
||||
except:
|
||||
st = traceback.format_exc()
|
||||
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
|
||||
|
||||
|
||||
# Return result in main thread
|
||||
def mt_async_result(call_back, results):
|
||||
GLib.idle_add(_async_result, call_back, results)
|
||||
# Execute the function on the main thread with the provided parameters, do
|
||||
# not return *any* value or wait for the execution to complete!
|
||||
def mt_async_call(function_call_back, *parameters):
|
||||
GLib.idle_add(_async_handler, function_call_back, parameters)
|
||||
|
||||
|
||||
# Take the supplied function and run it on the main thread and not wait for
|
||||
# a result!
|
||||
def mt_run_no_wait(function, param):
|
||||
GLib.idle_add(function, param)
|
||||
|
||||
# Run the supplied function and arguments on the main thread and wait for them
|
||||
# to complete while allowing the ability to get the return value too.
|
||||
#
|
||||
@@ -568,6 +610,7 @@ class MThreadRunner(object):
|
||||
def __init__(self, function, *args):
|
||||
self.f = function
|
||||
self.rc = None
|
||||
self.exception = None
|
||||
self.args = args
|
||||
self.function_complete = False
|
||||
self.cond = threading.Condition(threading.Lock())
|
||||
@@ -577,13 +620,21 @@ class MThreadRunner(object):
|
||||
with self.cond:
|
||||
if not self.function_complete:
|
||||
self.cond.wait()
|
||||
if self.exception:
|
||||
raise self.exception
|
||||
return self.rc
|
||||
|
||||
def _run(self):
|
||||
if len(self.args):
|
||||
self.rc = self.f(*self.args)
|
||||
else:
|
||||
self.rc = self.f()
|
||||
try:
|
||||
if self.args:
|
||||
self.rc = self.f(*self.args)
|
||||
else:
|
||||
self.rc = self.f()
|
||||
except BaseException as be:
|
||||
self.exception = be
|
||||
st = traceback.format_exc()
|
||||
log_error("MThreadRunner: exception \n %s" % st)
|
||||
log_error("Exception will be raised in calling thread!")
|
||||
|
||||
|
||||
def _remove_objects(dbus_objects_rm):
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
|
||||
|
||||
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
|
||||
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
|
||||
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
|
||||
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
|
||||
#define LVMETAD_DISABLE_REASON_REPAIR "REPAIR"
|
||||
|
||||
@@ -200,12 +200,12 @@ struct vg_info {
|
||||
#define GLFL_INVALID 0x00000001
|
||||
#define GLFL_DISABLE 0x00000002
|
||||
#define GLFL_DISABLE_REASON_DIRECT 0x00000004
|
||||
#define GLFL_DISABLE_REASON_LVM1 0x00000008
|
||||
/* 0x00000008 */
|
||||
#define GLFL_DISABLE_REASON_DUPLICATES 0x00000010
|
||||
#define GLFL_DISABLE_REASON_VGRESTORE 0x00000020
|
||||
#define GLFL_DISABLE_REASON_REPAIR 0x00000040
|
||||
|
||||
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_REPAIR | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
|
||||
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_REPAIR | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
|
||||
|
||||
#define VGFL_INVALID 0x00000001
|
||||
|
||||
@@ -2369,8 +2369,6 @@ static response set_global_info(lvmetad_state *s, request r)
|
||||
reason_flags |= GLFL_DISABLE_REASON_DIRECT;
|
||||
if (strstr(reason, LVMETAD_DISABLE_REASON_REPAIR))
|
||||
reason_flags |= GLFL_DISABLE_REASON_REPAIR;
|
||||
if (strstr(reason, LVMETAD_DISABLE_REASON_LVM1))
|
||||
reason_flags |= GLFL_DISABLE_REASON_LVM1;
|
||||
if (strstr(reason, LVMETAD_DISABLE_REASON_DUPLICATES))
|
||||
reason_flags |= GLFL_DISABLE_REASON_DUPLICATES;
|
||||
if (strstr(reason, LVMETAD_DISABLE_REASON_VGRESTORE))
|
||||
@@ -2421,21 +2419,17 @@ static response set_global_info(lvmetad_state *s, request r)
|
||||
|
||||
static response get_global_info(lvmetad_state *s, request r)
|
||||
{
|
||||
char reason[REASON_BUF_SIZE];
|
||||
/* This buffer should be large enough to hold all the possible reasons. */
|
||||
char reason[REASON_BUF_SIZE] = { 0 };
|
||||
char flag_str[64];
|
||||
int pid;
|
||||
|
||||
/* This buffer should be large enough to hold all the possible reasons. */
|
||||
|
||||
memset(reason, 0, sizeof(reason));
|
||||
|
||||
pid = (int)daemon_request_int(r, "pid", 0);
|
||||
|
||||
if (s->flags & GLFL_DISABLE) {
|
||||
snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s%s%s",
|
||||
snprintf(reason, REASON_BUF_SIZE, "%s%s%s%s",
|
||||
(s->flags & GLFL_DISABLE_REASON_DIRECT) ? LVMETAD_DISABLE_REASON_DIRECT "," : "",
|
||||
(s->flags & GLFL_DISABLE_REASON_REPAIR) ? LVMETAD_DISABLE_REASON_REPAIR "," : "",
|
||||
(s->flags & GLFL_DISABLE_REASON_LVM1) ? LVMETAD_DISABLE_REASON_LVM1 "," : "",
|
||||
(s->flags & GLFL_DISABLE_REASON_DUPLICATES) ? LVMETAD_DISABLE_REASON_DUPLICATES "," : "",
|
||||
(s->flags & GLFL_DISABLE_REASON_VGRESTORE) ? LVMETAD_DISABLE_REASON_VGRESTORE "," : "");
|
||||
}
|
||||
@@ -2531,10 +2525,8 @@ inval:
|
||||
|
||||
info = dm_hash_lookup(s->vgid_to_info, uuid);
|
||||
if (!info) {
|
||||
info = malloc(sizeof(struct vg_info));
|
||||
if (!info)
|
||||
if (!(info = dm_zalloc(sizeof(struct vg_info))))
|
||||
goto bad;
|
||||
memset(info, 0, sizeof(struct vg_info));
|
||||
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
|
||||
goto bad;
|
||||
}
|
||||
@@ -2705,9 +2697,8 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
if (!prev_in_progress && this_in_progress) {
|
||||
/* New update is starting (filter token is replaced by update token) */
|
||||
|
||||
memcpy(prev_token, state->token, 128);
|
||||
strncpy(state->token, token, 128);
|
||||
state->token[127] = 0;
|
||||
(void) dm_strncpy(prev_token, state->token, sizeof(prev_token));
|
||||
(void) dm_strncpy(state->token, token, sizeof(state->token));
|
||||
state->update_begin = _monotonic_seconds();
|
||||
state->update_timeout = update_timeout;
|
||||
state->update_pid = pid;
|
||||
@@ -2728,9 +2719,8 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
(int)(_monotonic_seconds() - state->update_begin),
|
||||
state->update_cmd);
|
||||
|
||||
memcpy(prev_token, state->token, 128);
|
||||
strncpy(state->token, token, 128);
|
||||
state->token[127] = 0;
|
||||
(void) dm_strncpy(prev_token, state->token, sizeof(prev_token));
|
||||
(void) dm_strncpy(state->token, token, sizeof(state->token));
|
||||
state->update_begin = _monotonic_seconds();
|
||||
state->update_timeout = update_timeout;
|
||||
state->update_pid = pid;
|
||||
@@ -2762,9 +2752,8 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
(int)(_monotonic_seconds() - state->update_begin),
|
||||
state->update_pid, token);
|
||||
|
||||
memcpy(prev_token, state->token, 128);
|
||||
strncpy(state->token, token, 128);
|
||||
state->token[127] = 0;
|
||||
(void) dm_strncpy(prev_token, state->token, sizeof(prev_token));
|
||||
(void) dm_strncpy(state->token, token, sizeof(state->token));
|
||||
state->update_begin = 0;
|
||||
state->update_timeout = 0;
|
||||
state->update_pid = 0;
|
||||
|
||||
@@ -27,6 +27,8 @@ ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||
LOCK_LIBS += -ldlm_lt
|
||||
endif
|
||||
|
||||
SOURCES2 = lvmlockctl.c
|
||||
|
||||
TARGETS = lvmlockd lvmlockctl
|
||||
|
||||
.PHONY: install_lvmlockd
|
||||
|
||||
@@ -379,7 +379,7 @@ static int setup_dump_socket(void)
|
||||
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
|
||||
if (rv < 0) {
|
||||
rv = -errno;
|
||||
if (!close(s))
|
||||
if (close(s))
|
||||
log_error("failed to close dump socket");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -48,5 +48,7 @@ static inline void lvmlockd_close(daemon_handle h)
|
||||
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
|
||||
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
|
||||
#define EREMOVED 219
|
||||
#define EDEVOPEN 220 /* sanlock failed to open lvmlock LV */
|
||||
#define ELMERR 221
|
||||
|
||||
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||
|
||||
@@ -1009,6 +1009,8 @@ static void add_work_action(struct action *act)
|
||||
pthread_mutex_unlock(&worker_mutex);
|
||||
}
|
||||
|
||||
#define ERR_LVMETAD_NOT_RUNNING -200
|
||||
|
||||
static daemon_reply send_lvmetad(const char *id, ...)
|
||||
{
|
||||
daemon_reply reply;
|
||||
@@ -1029,9 +1031,9 @@ retry:
|
||||
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
|
||||
err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
log_error("lvmetad_open reconnect error %d", err);
|
||||
log_debug("lvmetad_open reconnect error %d", err);
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
reply.error = err;
|
||||
reply.error = ERR_LVMETAD_NOT_RUNNING;
|
||||
va_end(ap);
|
||||
return reply;
|
||||
} else {
|
||||
@@ -1265,6 +1267,15 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
* caches, and tell lvmetad to set global invalid to 0.
|
||||
*/
|
||||
|
||||
/*
|
||||
* lvmetad not running:
|
||||
* Even if we have not previously found lvmetad running,
|
||||
* we attempt to connect and invalidate in case it has
|
||||
* been started while lvmlockd is running. We don't
|
||||
* want to allow lvmetad to be used with invalid data if
|
||||
* it happens to be enabled and started after lvmlockd.
|
||||
*/
|
||||
|
||||
if (inval_meta && (r->type == LD_RT_VG)) {
|
||||
daemon_reply reply;
|
||||
char *uuid;
|
||||
@@ -1284,8 +1295,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
"version = " FMTd64, (int64_t)new_version,
|
||||
NULL);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("set_vg_info in lvmetad failed %d", reply.error);
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
if (reply.error != ERR_LVMETAD_NOT_RUNNING)
|
||||
log_error("set_vg_info in lvmetad failed %d", reply.error);
|
||||
}
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
@@ -1300,8 +1313,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
"global_invalid = " FMTd64, INT64_C(1),
|
||||
NULL);
|
||||
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("set_global_info in lvmetad failed %d", reply.error);
|
||||
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
if (reply.error != ERR_LVMETAD_NOT_RUNNING)
|
||||
log_error("set_global_info in lvmetad failed %d", reply.error);
|
||||
}
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
@@ -1389,12 +1404,11 @@ static int res_convert(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
rv = lm_convert(ls, r, act->mode, act, r_version);
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s res_convert lm error %d", ls->name, r->name, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
log_debug("S %s R %s res_convert lm done", ls->name, r->name);
|
||||
log_debug("S %s R %s res_convert rv %d", ls->name, r->name, rv);
|
||||
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
if (lk->mode == LD_LK_EX && act->mode == LD_LK_SH) {
|
||||
r->sh_count = 1;
|
||||
@@ -2652,10 +2666,16 @@ out_act:
|
||||
ls->drop_vg = drop_vg;
|
||||
if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
|
||||
global_dlm_lockspace_exists = 0;
|
||||
/* Avoid a name collision of the same lockspace is added again before this thread is cleaned up. */
|
||||
memset(tmp_name, 0, sizeof(tmp_name));
|
||||
snprintf(tmp_name, MAX_NAME, "REM:%s", ls->name);
|
||||
memcpy(ls->name, tmp_name, MAX_NAME);
|
||||
|
||||
/*
|
||||
* Avoid a name collision of the same lockspace is added again before
|
||||
* this thread is cleaned up. We just set ls->name to a "junk" value
|
||||
* for the short period until the struct is freed. We could make it
|
||||
* blank or fill it with garbage, but instead set it to REM:<name>
|
||||
* to make it easier to follow progress of freeing is via log_debug.
|
||||
*/
|
||||
dm_strncpy(tmp_name, ls->name, sizeof(tmp_name));
|
||||
snprintf(ls->name, sizeof(ls->name), "REM:%s", tmp_name);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
/* worker_thread will join this thread, and free the ls */
|
||||
@@ -3533,11 +3553,15 @@ static int setup_worker_thread(void)
|
||||
|
||||
static void close_worker_thread(void)
|
||||
{
|
||||
int perrno;
|
||||
|
||||
pthread_mutex_lock(&worker_mutex);
|
||||
worker_stop = 1;
|
||||
pthread_cond_signal(&worker_cond);
|
||||
pthread_mutex_unlock(&worker_mutex);
|
||||
pthread_join(worker_thread, NULL);
|
||||
|
||||
if ((perrno = pthread_join(worker_thread, NULL)))
|
||||
log_error("pthread_join worker_thread error %d", perrno);
|
||||
}
|
||||
|
||||
/* client_mutex is locked */
|
||||
@@ -3666,7 +3690,17 @@ static int client_send_result(struct client *cl, struct action *act)
|
||||
if (!gl_lsname_dlm[0])
|
||||
strcat(result_flags, "NO_GL_LS,");
|
||||
} else {
|
||||
strcat(result_flags, "NO_GL_LS,");
|
||||
int found_lm = 0;
|
||||
|
||||
if (lm_support_dlm() && lm_is_running_dlm())
|
||||
found_lm++;
|
||||
if (lm_support_sanlock() && lm_is_running_sanlock())
|
||||
found_lm++;
|
||||
|
||||
if (!found_lm)
|
||||
strcat(result_flags, "NO_GL_LS,NO_LM");
|
||||
else
|
||||
strcat(result_flags, "NO_GL_LS");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3763,7 +3797,8 @@ static int client_send_result(struct client *cl, struct action *act)
|
||||
if (dump_fd >= 0) {
|
||||
/* To avoid deadlock, send data here after the reply. */
|
||||
send_dump_buf(dump_fd, dump_len);
|
||||
close(dump_fd);
|
||||
if (close(dump_fd))
|
||||
log_error("failed to close dump socket %d", dump_fd);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -3836,8 +3871,9 @@ static int add_lock_action(struct action *act)
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
if (ls_name[0])
|
||||
ls = find_lockspace_name(ls_name);
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
if (!ls) {
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
if (act->op == LD_OP_UPDATE && act->rt == LD_RT_VG) {
|
||||
log_debug("lockspace \"%s\" not found ignored for vg update", ls_name);
|
||||
return -ENOLS;
|
||||
@@ -4754,8 +4790,8 @@ static void *client_thread_main(void *arg_in)
|
||||
} else {
|
||||
pthread_mutex_unlock(&cl->mutex);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&client_mutex);
|
||||
} else
|
||||
pthread_mutex_unlock(&client_mutex);
|
||||
}
|
||||
out:
|
||||
return NULL;
|
||||
@@ -4779,11 +4815,15 @@ static int setup_client_thread(void)
|
||||
|
||||
static void close_client_thread(void)
|
||||
{
|
||||
int perrno;
|
||||
|
||||
pthread_mutex_lock(&client_mutex);
|
||||
client_stop = 1;
|
||||
pthread_cond_signal(&client_cond);
|
||||
pthread_mutex_unlock(&client_mutex);
|
||||
pthread_join(client_thread, NULL);
|
||||
|
||||
if ((perrno = pthread_join(client_thread, NULL)))
|
||||
log_error("pthread_join client_thread error %d", perrno);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5823,7 +5863,7 @@ static int main_loop(daemon_state *ds_arg)
|
||||
pthread_mutex_init(&lvmetad_mutex, NULL);
|
||||
lvmetad_handle = lvmetad_open(NULL);
|
||||
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0)
|
||||
log_error("lvmetad_open error %d", lvmetad_handle.error);
|
||||
log_debug("lvmetad_open error %d", lvmetad_handle.error);
|
||||
else
|
||||
lvmetad_connected = 1;
|
||||
|
||||
@@ -5831,8 +5871,13 @@ static int main_loop(daemon_state *ds_arg)
|
||||
* Attempt to rejoin lockspaces and adopt locks from a previous
|
||||
* instance of lvmlockd that left behind lockspaces/locks.
|
||||
*/
|
||||
if (adopt_opt)
|
||||
adopt_locks();
|
||||
if (adopt_opt) {
|
||||
/* FIXME: implement this without lvmetad */
|
||||
if (!lvmetad_connected)
|
||||
log_error("Cannot adopt locks without lvmetad running.");
|
||||
else
|
||||
adopt_locks();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
rv = poll(pollfd, pollfd_maxi + 1, -1);
|
||||
|
||||
@@ -508,7 +508,7 @@ lockrv:
|
||||
}
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
||||
return rv;
|
||||
return -ELMERR;
|
||||
}
|
||||
|
||||
if (rdd->vb) {
|
||||
@@ -581,6 +581,7 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
|
||||
rv = -ELMERR;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -654,6 +655,7 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
0, NULL, NULL, NULL);
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
|
||||
rv = -ELMERR;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -697,7 +699,7 @@ int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||
return 0;
|
||||
|
||||
memset(ls_nodes_path, 0, sizeof(ls_nodes_path));
|
||||
snprintf(ls_nodes_path, PATH_MAX-1, "%s/%s/nodes",
|
||||
snprintf(ls_nodes_path, PATH_MAX, "%s/%s/nodes",
|
||||
DLM_LOCKSPACES_PATH, ls->name);
|
||||
|
||||
if (!(ls_dir = opendir(ls_nodes_path)))
|
||||
|
||||
@@ -294,6 +294,36 @@ out:
|
||||
return host_id;
|
||||
}
|
||||
|
||||
/* Prepare valid /dev/mapper/vgname-lvname with all the mangling */
|
||||
static int build_dm_path(char *path, size_t path_len,
|
||||
const char *vg_name, const char *lv_name)
|
||||
{
|
||||
struct dm_pool *mem;
|
||||
char *dm_name;
|
||||
int rv = 0;
|
||||
|
||||
if (!(mem = dm_pool_create("namepool", 1024))) {
|
||||
log_error("Failed to create mempool.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!(dm_name = dm_build_dm_name(mem, vg_name, lv_name, NULL))) {
|
||||
log_error("Failed to build dm name for %s/%s.", vg_name, lv_name);
|
||||
rv = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((dm_snprintf(path, path_len, "%s/%s", dm_dir(), dm_name) < 0)) {
|
||||
log_error("Failed to create path %s/%s.", dm_dir(), dm_name);
|
||||
rv = -EINVAL;
|
||||
}
|
||||
|
||||
fail:
|
||||
dm_pool_destroy(mem);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* vgcreate
|
||||
*
|
||||
@@ -336,7 +366,8 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
if (strlen(lock_lv_name) + strlen(lock_args_version) + 2 > MAX_ARGS)
|
||||
return -EARGS;
|
||||
|
||||
snprintf(disk.path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
if ((rv = build_dm_path(disk.path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
|
||||
return rv;
|
||||
|
||||
log_debug("S %s init_vg_san path %s", ls_name, disk.path);
|
||||
|
||||
@@ -356,12 +387,19 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
log_debug("sanlock daemon version %08x proto %08x",
|
||||
daemon_version, daemon_proto);
|
||||
|
||||
align_size = sanlock_align(&disk);
|
||||
if (align_size <= 0) {
|
||||
log_error("S %s init_vg_san bad disk align size %d %s",
|
||||
ls_name, align_size, disk.path);
|
||||
return -EARGS;
|
||||
}
|
||||
rv = sanlock_align(&disk);
|
||||
if (rv <= 0) {
|
||||
if (rv == -EACCES) {
|
||||
log_error("S %s init_vg_san sanlock error -EACCES: no permission to access %s",
|
||||
ls_name, disk.path);
|
||||
return -EDEVOPEN;
|
||||
} else {
|
||||
log_error("S %s init_vg_san sanlock error %d trying to get align size of %s",
|
||||
ls_name, rv, disk.path);
|
||||
return -EARGS;
|
||||
}
|
||||
} else
|
||||
align_size = rv;
|
||||
|
||||
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
|
||||
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
||||
@@ -506,7 +544,8 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
|
||||
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
rd.rs.num_disks = 1;
|
||||
snprintf(rd.rs.disks[0].path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
if ((rv = build_dm_path(rd.rs.disks[0].path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
|
||||
return rv;
|
||||
|
||||
align_size = sanlock_align(&rd.rs.disks[0]);
|
||||
if (align_size <= 0) {
|
||||
@@ -605,7 +644,8 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
return rv;
|
||||
}
|
||||
|
||||
snprintf(disk.path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
if ((rv = build_dm_path(disk.path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
|
||||
return rv;
|
||||
|
||||
log_debug("S %s rename_vg_san path %s", ls_name, disk.path);
|
||||
|
||||
@@ -1062,10 +1102,10 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
* and appending "lockctl" to get /path/to/lvmlockctl.
|
||||
*/
|
||||
memset(killpath, 0, sizeof(killpath));
|
||||
snprintf(killpath, SANLK_PATH_LEN - 1, "%slockctl", LVM_PATH);
|
||||
snprintf(killpath, SANLK_PATH_LEN, "%slockctl", LVM_PATH);
|
||||
|
||||
memset(killargs, 0, sizeof(killargs));
|
||||
snprintf(killargs, SANLK_PATH_LEN - 1, "--kill %s", ls->vg_name);
|
||||
snprintf(killargs, SANLK_PATH_LEN, "--kill %s", ls->vg_name);
|
||||
|
||||
rv = check_args_version(ls->vg_args, VG_LOCK_ARGS_MAJOR);
|
||||
if (rv < 0) {
|
||||
@@ -1081,8 +1121,8 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
snprintf(disk_path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s",
|
||||
ls->vg_name, lock_lv_name);
|
||||
if ((ret = build_dm_path(disk_path, SANLK_PATH_LEN, ls->vg_name, lock_lv_name)))
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* When a vg is started, the internal sanlock lv should be
|
||||
@@ -1453,6 +1493,12 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
|
||||
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, &opt);
|
||||
|
||||
/*
|
||||
* errors: translate the sanlock error number to an lvmlockd error.
|
||||
* We don't want to return an sanlock-specific error number from
|
||||
* this function to code that doesn't recognize sanlock error numbers.
|
||||
*/
|
||||
|
||||
if (rv == -EAGAIN) {
|
||||
/*
|
||||
* It appears that sanlock_acquire returns EAGAIN when we request
|
||||
@@ -1521,6 +1567,26 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (rv == SANLK_AIO_TIMEOUT) {
|
||||
/*
|
||||
* sanlock got an i/o timeout when trying to acquire the
|
||||
* lease on disk.
|
||||
*/
|
||||
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
|
||||
*retry = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (rv == SANLK_DBLOCK_LVER || rv == SANLK_DBLOCK_MBAL) {
|
||||
/*
|
||||
* There was contention with another host for the lease,
|
||||
* and we lost.
|
||||
*/
|
||||
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
|
||||
*retry = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
|
||||
/*
|
||||
* The lock is held by a failed host, and will eventually
|
||||
@@ -1571,15 +1637,25 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
if (rv == -ENOSPC)
|
||||
rv = -ELOCKIO;
|
||||
|
||||
return rv;
|
||||
/*
|
||||
* generic error number for sanlock errors that we are not
|
||||
* catching above.
|
||||
*/
|
||||
return -ELMERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* sanlock acquire success (rv 0)
|
||||
*/
|
||||
|
||||
if (rds->vb) {
|
||||
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_san get_lvb error %d", ls->name, r->name, rv);
|
||||
memset(rds->vb, 0, sizeof(struct val_blk));
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
/* the lock is still acquired, the vb values considered invalid */
|
||||
rv = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1632,6 +1708,7 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s convert_san set_lvb error %d",
|
||||
ls->name, r->name, rv);
|
||||
return -ELMERR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1644,14 +1721,35 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||
if (daemon_test)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Don't block waiting for a failed lease to expire since it causes
|
||||
* sanlock_convert to block for a long time, which would prevent this
|
||||
* thread from processing other lock requests.
|
||||
*
|
||||
* FIXME: SANLK_CONVERT_OWNER_NOWAIT is the same as SANLK_ACQUIRE_OWNER_NOWAIT.
|
||||
* Change to use the CONVERT define when the latest sanlock version has it.
|
||||
*/
|
||||
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
|
||||
|
||||
rv = sanlock_convert(lms->sock, -1, flags, rs);
|
||||
if (rv == -EAGAIN) {
|
||||
/* FIXME: When could this happen? Should something different be done? */
|
||||
log_error("S %s R %s convert_san EAGAIN", ls->name, r->name);
|
||||
if (!rv)
|
||||
return 0;
|
||||
|
||||
switch (rv) {
|
||||
case -EAGAIN:
|
||||
case SANLK_ACQUIRE_IDLIVE:
|
||||
case SANLK_ACQUIRE_OWNED:
|
||||
case SANLK_ACQUIRE_OWNED_RETRY:
|
||||
case SANLK_ACQUIRE_OTHER:
|
||||
case SANLK_AIO_TIMEOUT:
|
||||
case SANLK_DBLOCK_LVER:
|
||||
case SANLK_DBLOCK_MBAL:
|
||||
/* expected errors from known/normal cases like lock contention or io timeouts */
|
||||
log_debug("S %s R %s convert_san error %d", ls->name, r->name, rv);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (rv < 0) {
|
||||
default:
|
||||
log_error("S %s R %s convert_san convert error %d", ls->name, r->name, rv);
|
||||
rv = -ELMERR;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -1688,6 +1786,7 @@ static int release_rename(struct lockspace *ls, struct resource *r)
|
||||
rv = sanlock_release(lms->sock, -1, SANLK_REL_RENAME, 2, res_args);
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s unlock_san release rename error %d", ls->name, r->name, rv);
|
||||
rv = -ELMERR;
|
||||
}
|
||||
|
||||
free(res_args);
|
||||
@@ -1744,6 +1843,7 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s unlock_san set_lvb error %d",
|
||||
ls->name, r->name, rv);
|
||||
return -ELMERR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1762,6 +1862,8 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
|
||||
if (rv == -EIO)
|
||||
rv = -ELOCKIO;
|
||||
else if (rv < 0)
|
||||
rv = -ELMERR;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2013-2014 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -14,11 +14,10 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = cache.c
|
||||
|
||||
LIB_SHARED = liblvm2cache.$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
SOURCES=\
|
||||
vdo/status.c
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
install: install_lvm2_plugin
|
||||
LIB_NAME = libdevicemapper
|
||||
LIB_STATIC = $(LIB_NAME).a
|
||||
248
device_mapper/vdo/status.c
Normal file
248
device_mapper/vdo/status.c
Normal file
@@ -0,0 +1,248 @@
|
||||
#include "target.h"
|
||||
|
||||
// For DM_ARRAY_SIZE!
|
||||
#include "libdevmapper.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static char *_tok_cpy(const char *b, const char *e)
|
||||
{
|
||||
char *new = malloc((e - b) + 1);
|
||||
char *ptr = new;
|
||||
|
||||
if (new) {
|
||||
while (b != e)
|
||||
*ptr++ = *b++;
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static bool _tok_eq(const char *b, const char *e, const char *str)
|
||||
{
|
||||
while (b != e) {
|
||||
if (!*str || *b != *str)
|
||||
return false;
|
||||
|
||||
b++;
|
||||
str++;
|
||||
}
|
||||
|
||||
return !*str;
|
||||
}
|
||||
|
||||
static bool _parse_operating_mode(const char *b, const char *e, void *context)
|
||||
{
|
||||
static struct {
|
||||
const char *str;
|
||||
enum vdo_operating_mode mode;
|
||||
} _table[] = {
|
||||
{"recovering", VDO_MODE_RECOVERING},
|
||||
{"read-only", VDO_MODE_READ_ONLY},
|
||||
{"normal", VDO_MODE_NORMAL}
|
||||
};
|
||||
|
||||
enum vdo_operating_mode *r = context;
|
||||
unsigned i;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_table); i++) {
|
||||
if (_tok_eq(b, e, _table[i].str)) {
|
||||
*r = _table[i].mode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _parse_compression_state(const char *b, const char *e, void *context)
|
||||
{
|
||||
static struct {
|
||||
const char *str;
|
||||
enum vdo_compression_state state;
|
||||
} _table[] = {
|
||||
{"online", VDO_COMPRESSION_ONLINE},
|
||||
{"offline", VDO_COMPRESSION_OFFLINE}
|
||||
};
|
||||
|
||||
enum vdo_compression_state *r = context;
|
||||
unsigned i;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_table); i++) {
|
||||
if (_tok_eq(b, e, _table[i].str)) {
|
||||
*r = _table[i].state;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _parse_recovering(const char *b, const char *e, void *context)
|
||||
{
|
||||
bool *r = context;
|
||||
|
||||
if (_tok_eq(b, e, "recovering"))
|
||||
*r = true;
|
||||
|
||||
else if (_tok_eq(b, e, "-"))
|
||||
*r = false;
|
||||
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _parse_index_state(const char *b, const char *e, void *context)
|
||||
{
|
||||
static struct {
|
||||
const char *str;
|
||||
enum vdo_index_state state;
|
||||
} _table[] = {
|
||||
{"error", VDO_INDEX_ERROR},
|
||||
{"closed", VDO_INDEX_CLOSED},
|
||||
{"opening", VDO_INDEX_OPENING},
|
||||
{"closing", VDO_INDEX_CLOSING},
|
||||
{"offline", VDO_INDEX_OFFLINE},
|
||||
{"online", VDO_INDEX_ONLINE},
|
||||
{"unknown", VDO_INDEX_UNKNOWN}
|
||||
};
|
||||
|
||||
enum vdo_index_state *r = context;
|
||||
unsigned i;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_table); i++) {
|
||||
if (_tok_eq(b, e, _table[i].str)) {
|
||||
*r = _table[i].state;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _parse_uint64(const char *b, const char *e, void *context)
|
||||
{
|
||||
uint64_t *r = context, n;
|
||||
|
||||
n = 0;
|
||||
while (b != e) {
|
||||
if (!isdigit(*b))
|
||||
return false;
|
||||
|
||||
n = (n * 10) + (*b - '0');
|
||||
b++;
|
||||
}
|
||||
|
||||
*r = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *_eat_space(const char *b, const char *e)
|
||||
{
|
||||
while (b != e && isspace(*b))
|
||||
b++;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static const char *_next_tok(const char *b, const char *e)
|
||||
{
|
||||
const char *te = b;
|
||||
while (te != e && !isspace(*te))
|
||||
te++;
|
||||
|
||||
return te == b ? NULL : te;
|
||||
}
|
||||
|
||||
static void _set_error(struct vdo_status_parse_result *result, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
static void _set_error(struct vdo_status_parse_result *result, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(result->error, sizeof(result->error), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static bool _parse_field(const char **b, const char *e,
|
||||
bool (*p_fn)(const char *, const char *, void *),
|
||||
void *field, const char *field_name,
|
||||
struct vdo_status_parse_result *result)
|
||||
{
|
||||
const char *te;
|
||||
|
||||
te = _next_tok(*b, e);
|
||||
if (!te) {
|
||||
_set_error(result, "couldn't get token for '%s'", field_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!p_fn(*b, te, field)) {
|
||||
_set_error(result, "couldn't parse '%s'", field_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
*b = _eat_space(te, e);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool vdo_status_parse(const char *input, struct vdo_status_parse_result *result)
|
||||
{
|
||||
const char *b = b = input;
|
||||
const char *e = input + strlen(input);
|
||||
const char *te;
|
||||
struct vdo_status *s = malloc(sizeof(*s));
|
||||
|
||||
if (!s) {
|
||||
_set_error(result, "out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
b = _eat_space(b, e);
|
||||
te = _next_tok(b, e);
|
||||
if (!te) {
|
||||
_set_error(result, "couldn't get token for device");
|
||||
free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
s->device = _tok_cpy(b, te);
|
||||
if (!s->device) {
|
||||
_set_error(result, "out of memory");
|
||||
free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
b = _eat_space(te, e);
|
||||
|
||||
#define XX(p, f, fn) if (!_parse_field(&b, e, p, f, fn, result)) goto bad;
|
||||
XX(_parse_operating_mode, &s->operating_mode, "operating mode");
|
||||
XX(_parse_recovering, &s->recovering, "recovering");
|
||||
XX(_parse_index_state, &s->index_state, "index state");
|
||||
XX(_parse_compression_state, &s->compression_state, "compression state");
|
||||
XX(_parse_uint64, &s->used_blocks, "used blocks");
|
||||
XX(_parse_uint64, &s->total_blocks, "total blocks");
|
||||
#undef XX
|
||||
|
||||
if (b != e) {
|
||||
_set_error(result, "too many tokens");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
result->status = s;
|
||||
return true;
|
||||
|
||||
bad:
|
||||
free(s->device);
|
||||
free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
68
device_mapper/vdo/target.h
Normal file
68
device_mapper/vdo/target.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef DEVICE_MAPPER_VDO_TARGET_H
|
||||
#define DEVICE_MAPPER_VDO_TARGET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
enum vdo_operating_mode {
|
||||
VDO_MODE_RECOVERING,
|
||||
VDO_MODE_READ_ONLY,
|
||||
VDO_MODE_NORMAL
|
||||
};
|
||||
|
||||
enum vdo_compression_state {
|
||||
VDO_COMPRESSION_ONLINE,
|
||||
VDO_COMPRESSION_OFFLINE
|
||||
};
|
||||
|
||||
enum vdo_index_state {
|
||||
VDO_INDEX_ERROR,
|
||||
VDO_INDEX_CLOSED,
|
||||
VDO_INDEX_OPENING,
|
||||
VDO_INDEX_CLOSING,
|
||||
VDO_INDEX_OFFLINE,
|
||||
VDO_INDEX_ONLINE,
|
||||
VDO_INDEX_UNKNOWN
|
||||
};
|
||||
|
||||
struct vdo_status {
|
||||
char *device;
|
||||
enum vdo_operating_mode operating_mode;
|
||||
bool recovering;
|
||||
enum vdo_index_state index_state;
|
||||
enum vdo_compression_state compression_state;
|
||||
uint64_t used_blocks;
|
||||
uint64_t total_blocks;
|
||||
};
|
||||
|
||||
void vdo_status_destroy(struct vdo_status *s);
|
||||
|
||||
#define VDO_MAX_ERROR 256
|
||||
|
||||
struct vdo_status_parse_result {
|
||||
char error[VDO_MAX_ERROR];
|
||||
struct vdo_status *status;
|
||||
};
|
||||
|
||||
// Parses the status line from the kernel target.
|
||||
bool vdo_status_parse(const char *input, struct vdo_status_parse_result *result);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
338
doc/lvm-disk-reading.txt
Normal file
338
doc/lvm-disk-reading.txt
Normal file
@@ -0,0 +1,338 @@
|
||||
LVM disk reading
|
||||
|
||||
Reading disks happens in two phases. The first is a discovery phase,
|
||||
which determines what's on the disks. The second is a working phase,
|
||||
which does a particular job for the command.
|
||||
|
||||
|
||||
Phase 1: Discovery
|
||||
------------------
|
||||
|
||||
Read all the disks on the system to find out:
|
||||
- What are the LVM devices?
|
||||
- What VG's exist on those devices?
|
||||
|
||||
This phase is called "label scan" (although it reads and scans everything,
|
||||
not just the label.) It stores the information it discovers (what LVM
|
||||
devices exist, and what VGs exist on them) in lvmcache. The devs/VGs info
|
||||
in lvmcache is the starting point for phase two.
|
||||
|
||||
|
||||
Phase 1 in outline:
|
||||
|
||||
For each device:
|
||||
|
||||
a. Read the first <N> KB of the device. (N is configurable.)
|
||||
|
||||
b. Look for the lvm label_header in the first four sectors,
|
||||
if none exists, it's not an lvm device, so quit looking at it.
|
||||
(By default, label_header is in the second sector.)
|
||||
|
||||
c. Look at the pv_header, which follows the label_header.
|
||||
This tells us the location of VG metadata on the device.
|
||||
There can be 0, 1 or 2 copies of VG metadata. The first
|
||||
is always at the start of the device, the second (if used)
|
||||
is at the end.
|
||||
|
||||
d. Look at the first mda_header (location came from pv_header
|
||||
in the previous step). This is by default in sector 8,
|
||||
4096 bytes from the start of the device. This tells us the
|
||||
location of the actual VG metadata text.
|
||||
|
||||
e. Look at the first copy of the text VG metadata (location came
|
||||
from mda_header in the previous step). This is by default
|
||||
in sector 9, 4608 bytes from the start of the device.
|
||||
The VG metadata is only partially analyzed to create a basic
|
||||
summary of the VG.
|
||||
|
||||
f. Store an "info" entry in lvmcache for this device,
|
||||
indicating that it is an lvm device, and store a "vginfo"
|
||||
entry in lvmcache indicating the name of the VG seen
|
||||
in the metadata in step e.
|
||||
|
||||
g. If the pv_header in step c shows a second mda_header
|
||||
location at the end of the device, then read that as
|
||||
in step d, and repeat steps e-f for it.
|
||||
|
||||
At the end of phase 1, lvmcache will have a list of devices
|
||||
that belong to LVM, and a list of VG names that exist on
|
||||
those devices. Each device (info struct) is associated
|
||||
with the VG (vginfo struct) it is used in.
|
||||
|
||||
|
||||
Phase 1 in code:
|
||||
|
||||
The most relevant functions are listed for each step in the outline.
|
||||
|
||||
lvmcache_label_scan()
|
||||
label_scan()
|
||||
|
||||
. dev_cache_scan()
|
||||
choose which devices on the system to look at
|
||||
|
||||
. for each dev in dev_cache: bcache prefetch/read
|
||||
|
||||
. _process_block() to process data from bcache
|
||||
_find_lvm_header() checks if this is an lvm dev by looking at label_header
|
||||
_text_read() via ops->read() looks at mda/pv/vg data to populate lvmcache
|
||||
|
||||
. _read_mda_header_and_metadata()
|
||||
raw_read_mda_header()
|
||||
|
||||
. _read_mda_header_and_metadata()
|
||||
read_metadata_location()
|
||||
text_read_metadata_summary()
|
||||
config_file_read_fd()
|
||||
_read_vgsummary() via ops->read_vgsummary()
|
||||
|
||||
. _text_read(): lvmcache_add()
|
||||
[adds this device to list of lvm devices]
|
||||
_read_mda_header_and_metadata(): lvmcache_update_vgname_and_id()
|
||||
[adds the VG name to list of VGs]
|
||||
|
||||
|
||||
Phase 2: Work
|
||||
-------------
|
||||
|
||||
This phase carries out the operation requested by the command that was
|
||||
run.
|
||||
|
||||
Whereas the first phase is based on iterating through each device on the
|
||||
system, this phase is based on iterating through each VG name. The list
|
||||
of VG names comes from phase 1, which stored the list in lvmcache to be
|
||||
used by phase 2.
|
||||
|
||||
Some commands may need to iterate through all VG names, while others may
|
||||
need to iterate through just one or two.
|
||||
|
||||
This phase includes locking each VG as work is done on it, so that two
|
||||
commands do not interfere with each other.
|
||||
|
||||
|
||||
Phase 2 in outline:
|
||||
|
||||
For each VG name:
|
||||
|
||||
a. Lock the VG.
|
||||
|
||||
b. Repeat the phase 1 scan steps for each device in this VG.
|
||||
The phase 1 information in lvmcache may have changed because no VG lock
|
||||
was held during phase 1. So, repeat the phase 1 steps, but only for the
|
||||
devices in this VG. N.B. for commands that are just reporting data,
|
||||
we skip this step if the data from phase 1 was complete and consistent.
|
||||
|
||||
c. Get the list of on-disk metadata locations for this VG.
|
||||
Phase 1 created this list in lvmcache to be used here. At this
|
||||
point we copy it out of lvmcache. In the simple/common case,
|
||||
this is a list of devices in the VG. But, some devices may
|
||||
have 0 or 2 metadata locations instead of the default 1, so it
|
||||
is not always equal to the list of devices. We want to read
|
||||
every copy of the metadata for this VG.
|
||||
|
||||
d. For each metadata location on each device in the VG
|
||||
(the list from the previous step):
|
||||
|
||||
1) Look at the mda_header. The location of the mda_header was saved
|
||||
in the lvmcache info struct by phase 1 (where it came from the
|
||||
pv_header.) The mda_header tells us where the text VG metadata is
|
||||
located.
|
||||
|
||||
2) Look at the text VG metadata. The location came from mda_header
|
||||
in the previous step. The VG metadata is fully analyzed and used
|
||||
to create an in-memory 'struct volume_group'.
|
||||
|
||||
e. Compare the copies of VG metadata that were found in each location.
|
||||
If some copies are older, choose the newest one to use, and update
|
||||
any older copies.
|
||||
|
||||
f. Update details about the devices/VG in lvmcache.
|
||||
|
||||
g. Pass the 'vg' struct to the command-specific code to work with.
|
||||
|
||||
|
||||
Phase 2 in code:
|
||||
|
||||
The most relevant functions are listed for each step in the outline.
|
||||
|
||||
For each VG name:
|
||||
process_each_vg()
|
||||
|
||||
. vg_read()
|
||||
lock_vol()
|
||||
|
||||
. vg_read()
|
||||
lvmcache_label_rescan_vg() (if needed)
|
||||
[insert phase 1 steps for scanning devs, but only devs in this vg]
|
||||
|
||||
. vg_read()
|
||||
create_instance()
|
||||
_text_create_text_instance()
|
||||
_create_vg_text_instance()
|
||||
lvmcache_fid_add_mdas_vg()
|
||||
[Copies mda locations from info->mdas where it was saved
|
||||
by phase 1, into fid->metadata_areas_in_use. This is
|
||||
the key connection between phase 1 and phase 2.]
|
||||
|
||||
. dm_list_iterate_items(mda, &fid->metadata_areas_in_use)
|
||||
|
||||
. _vg_read_raw() via ops->vg_read()
|
||||
raw_read_mda_header()
|
||||
|
||||
. _vg_read_raw()
|
||||
text_read_metadata()
|
||||
config_file_read_fd()
|
||||
_read_vg() via ops->read_vg()
|
||||
|
||||
. return the 'vg' struct from vg_read() and use it to do
|
||||
command-specific work
|
||||
|
||||
|
||||
|
||||
Filter i/o
|
||||
----------
|
||||
|
||||
Some filters must be applied before reading a device, and other filters
|
||||
must be applied after reading a device. In all cases, the filters must be
|
||||
applied before lvm processes the device, i.e. before it looks for an lvm
|
||||
label.
|
||||
|
||||
1. Some filters need to be applied prior to reading any devices
|
||||
because the purpose of the filter is to avoid submitting any
|
||||
io on the excluded devices. The regex filter is the primary
|
||||
example. Other filters benefit from being applied prior to
|
||||
reading devices because they can tell which devices to
|
||||
exclude without doing io to the device. An example of this
|
||||
is the mpath filter.
|
||||
|
||||
2. Some filters need to be applied after reading a device because
|
||||
they are based on data/signatures seen on the device.
|
||||
The partitioned filter is an example of this; lvm needs to
|
||||
read a device to see if it has a partition table before it can
|
||||
know whether to exclude the device from further processing.
|
||||
|
||||
We apply filters from 1 before reading devices, and we apply filters from
|
||||
2 after populating bcache, but before processing the device (i.e. before
|
||||
checking for an lvm label, which is the first step in processing.)
|
||||
|
||||
The current implementation of this makes filters return -EAGAIN if they
|
||||
want to read the device, but bcache data is not yet available. This will
|
||||
happen when filtering runs prior to populating bcache. In this case the
|
||||
device is flagged. After bcache is populated, the filters are reapplied
|
||||
to the flagged devices. The filters which need to look at device content
|
||||
are now able to get it from bcache. Devices that do not pass filters at
|
||||
this point are excluded just like devices which were excluded earlier.
|
||||
|
||||
(Some filters from 2 can be skipped by consulting udev for the information
|
||||
instead of reading the device. This is not entirely reliable, so it is
|
||||
disabled by default with the config setting external_device_info_source.
|
||||
It may be worthwhile to change the filters to use the udev info as a hint,
|
||||
or only use udev info for filtering in reporting commands where
|
||||
inaccuracies are not a big problem.)
|
||||
|
||||
|
||||
|
||||
I/O Performance
|
||||
---------------
|
||||
|
||||
. 400 loop devices used as PVs
|
||||
. 40 VGs each with 10 PVs
|
||||
. each VG has one active LV
|
||||
. each of the 10 PVs in vg0 has an artificial 100 ms read delay
|
||||
. read/write/io_submit are system call counts using strace
|
||||
. old is lvm 2.2.175
|
||||
. new is lvm 2.2.178 (shortly before)
|
||||
|
||||
|
||||
Command: pvs
|
||||
------------
|
||||
old: 0m17.422s
|
||||
new: 0m0.331s
|
||||
|
||||
old: read 7773 write 497
|
||||
new: read 2807 write 495 io_submit 448
|
||||
|
||||
|
||||
Command: vgs
|
||||
------------
|
||||
old: 0m20.383s
|
||||
new: 0m0.325s
|
||||
|
||||
old: read 10684 write 129
|
||||
new: read 2807 write 129 io_submit 448
|
||||
|
||||
|
||||
Command: vgck vg0
|
||||
-----------------
|
||||
old: 0m16.212s
|
||||
new: 0m1.290s
|
||||
|
||||
old: read 6372 write 4
|
||||
new: read 2807 write 4 io_submit 458
|
||||
|
||||
|
||||
Command: lvcreate -n test -l1 -an vg0
|
||||
-------------------------------------
|
||||
old: 0m29.271s
|
||||
new: 0m1.351s
|
||||
|
||||
old: read 6503 write 39
|
||||
new: read 2808 write 9 io_submit 488
|
||||
|
||||
|
||||
Command: lvremove vg0/test
|
||||
--------------------------
|
||||
old: 0m29.262s
|
||||
new: 0m1.348s
|
||||
|
||||
old: read 6502 write 36
|
||||
new: read 2807 write 6 io_submit 488
|
||||
|
||||
|
||||
io_submit sources
|
||||
-----------------
|
||||
|
||||
vgs:
|
||||
reads:
|
||||
- 400 for each PV
|
||||
- 40 for each LV
|
||||
- 8 for other devs on the system
|
||||
|
||||
vgck vg0:
|
||||
reads:
|
||||
- 400 for each PV
|
||||
- 40 for each LV
|
||||
- 10 for each PV in vg0 (rescan)
|
||||
- 8 for other devs on the system
|
||||
|
||||
lvcreate -n test -l1 -an vg0
|
||||
reads:
|
||||
- 400 for each PV
|
||||
- 40 for each LV
|
||||
- 10 for each PV in vg0 (rescan)
|
||||
- 8 for other devs on the system
|
||||
writes:
|
||||
- 10 for metadata on each PV in vg0
|
||||
- 10 for precommit on each PV in vg0
|
||||
- 10 for commit on each PV in vg0
|
||||
|
||||
|
||||
|
||||
With lvmetad
|
||||
------------
|
||||
|
||||
Command: pvs
|
||||
------------
|
||||
old: 0m5.405s
|
||||
new: 0m1.404s
|
||||
|
||||
Command: vgs
|
||||
------------
|
||||
old: 0m0.222s
|
||||
new: 0m0.223s
|
||||
|
||||
Command: lvcreate -n test -l1 -an vg0
|
||||
-------------------------------------
|
||||
old: 0m10.128s
|
||||
new: 0m1.137s
|
||||
|
||||
|
||||
158
doc/refactoring.txt
Normal file
158
doc/refactoring.txt
Normal file
@@ -0,0 +1,158 @@
|
||||
Over time, I'd like to refactor the LVM code into these high level modules.
|
||||
|
||||
|
||||
+-------------------------------------------+
|
||||
| |
|
||||
| User Interface |
|
||||
| |
|
||||
| |
|
||||
+-------------------+-----------------------+
|
||||
|
|
||||
+--------------------v-----------------------+
|
||||
| |
|
||||
| LVM Core |
|
||||
| |
|
||||
| |
|
||||
+----+----------------+-----------------+----+
|
||||
| | |
|
||||
+-----v-----+ +-----v------+ +------v----+
|
||||
| | | | | |
|
||||
| Device | | Metadata | | System |
|
||||
| Mapper | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
| | | | | |
|
||||
+-----------+ +------------+ +-----------+
|
||||
|
||||
+---------------------------------------------------------+
|
||||
|
||||
|
||||
+------------------------------------+
|
||||
| |
|
||||
| Base |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+------------------------------------+
|
||||
|
||||
Going from the bottom up we have:
|
||||
|
||||
Base
|
||||
----
|
||||
|
||||
This holds all our general purpose code such as data structures, regex engine,
|
||||
memory allocators. In fact pretty much everything in libdevmapper apart from
|
||||
the dm code and config.
|
||||
|
||||
This can be used by any code in the system, which is why I've drawn a line
|
||||
between it and the code above rather than using arrows.
|
||||
|
||||
If anyone can come up with a better name please do. I'm trying to stay away
|
||||
from 'utils'.
|
||||
|
||||
|
||||
Device mapper
|
||||
-------------
|
||||
|
||||
As well as the low level dm-ioctl driving code we need to have all our dm 'best
|
||||
practise' stuff in here. For instance this is the code that decides to use the
|
||||
mirror target to move some data around; that knows to suspend a thin volume
|
||||
before taking a snapshot of it. This module is going to have a lot more code
|
||||
in it than the current libdevmapper.
|
||||
|
||||
It should not know anything about the LVM abstractions or metadata (no PVs, LVs
|
||||
or VGs). It just knows about the dm world.
|
||||
|
||||
Code in here is only allowed to use base.
|
||||
|
||||
|
||||
Metadata model
|
||||
--------------
|
||||
|
||||
Here we have all the format handling, labelling, config parsing etc. We try
|
||||
and put *everything* to do with LVM in here that doesn't actually require dm.
|
||||
|
||||
|
||||
System
|
||||
------
|
||||
|
||||
Code that interfaces with the system (udev etc).
|
||||
|
||||
|
||||
LVM Core
|
||||
--------
|
||||
|
||||
[terrible name]
|
||||
|
||||
This ties together the last 3 units. It should just be glue. We need to be
|
||||
strict about pushing code down from here to keep this as small as possible.
|
||||
|
||||
|
||||
User interface
|
||||
--------------
|
||||
|
||||
Self explanatory.
|
||||
|
||||
|
||||
Headers
|
||||
-------
|
||||
|
||||
Headers will be included using sub directories to make it clearer where they
|
||||
are in the tree.
|
||||
|
||||
eg,
|
||||
#include "base/mm/pool.h"
|
||||
#include "base/data-struct/list.h"
|
||||
#include "dm/thin-provisioning.h"
|
||||
#include "core/pvmove.h"
|
||||
|
||||
|
||||
Getting there
|
||||
=============
|
||||
|
||||
+-------------------------------------------+
|
||||
| |
|
||||
| |
|
||||
| Tools |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+---------+------------------------------+--+
|
||||
| |
|
||||
| +---------------v---------------------------+
|
||||
| | |
|
||||
| | |
|
||||
| | Lib |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| +----------------+--------------------------+
|
||||
| |
|
||||
| |
|
||||
+-----v-------------------------------v-----+
|
||||
| |
|
||||
| |
|
||||
| libdevmapper |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
+-------------------------------------------+
|
||||
|
||||
This is where I see us now.
|
||||
|
||||
'base' should be easy to factor out, it's just the non-dm part of libdevmapper
|
||||
(ie. the bulk of it). But we have the problem that libdevmapper is a public
|
||||
interface to get round.
|
||||
|
||||
'lib' is where the bulk of our code currently is. Dependency-wise the code is
|
||||
a bit like a ball of string. So splitting it up is going to take time. We can
|
||||
probably pull code pretty quickly into the 'metadata model' dir. But factoring
|
||||
out the dm best practises stuff is going to require splitting at least
|
||||
files, and probably functions. Certainly not something that can be done in one
|
||||
go. System should just be a question of cherry picking functions.
|
||||
|
||||
I'm not too familiar with the tools dir. Hopefully it just corresponds with
|
||||
the User Interface module and doesn't contain any business logic.
|
||||
53
doc/release-notes/2.02.178
Normal file
53
doc/release-notes/2.02.178
Normal file
@@ -0,0 +1,53 @@
|
||||
Version 2.02.178
|
||||
================
|
||||
|
||||
There are going to be some large changes to the lvm2 codebase
|
||||
over the next year or so. Starting with this release. These
|
||||
changes should be internal rather than having a big effect on
|
||||
the command line. Inevitably these changes will increase the
|
||||
chance of bugs, so please be on the alert.
|
||||
|
||||
|
||||
Remove support for obsolete metadata formats
|
||||
--------------------------------------------
|
||||
|
||||
Support for the GFS pool format, and format used by the
|
||||
original 1990's version of LVM1 have been removed.
|
||||
|
||||
Use asynchronous IO
|
||||
-------------------
|
||||
|
||||
Almost all IO uses libaio now.
|
||||
|
||||
Rewrite label scanning
|
||||
----------------------
|
||||
|
||||
Dave Teigland has reworked the label scanning and metadata reading
|
||||
logic to minimise the amount of IOs issued. Combined with the aio changes
|
||||
this can greatly improve scanning speed for some systems.
|
||||
|
||||
./configure options
|
||||
-------------------
|
||||
|
||||
We're going to try and remove as many options from ./configure as we
|
||||
can. Each option multiplies the number of possible configurations
|
||||
that we should test (this testing is currently not occurring).
|
||||
|
||||
The first batch to be removed are:
|
||||
|
||||
--enable-testing
|
||||
--with-snapshots
|
||||
--with-mirrors
|
||||
--with-raid
|
||||
--with-thin
|
||||
--with-cache
|
||||
|
||||
Stable targets that are in the upstream kernel will just be supported.
|
||||
|
||||
In future optional target flags will be given in two situations:
|
||||
|
||||
1) The target is experimental, or not upstream at all (eg, vdo).
|
||||
2) The target is deprecated and support will be removed at some future date.
|
||||
|
||||
This decision could well be contentious, so could distro maintainers feel
|
||||
free to comment.
|
||||
257
doc/unit-tests.txt
Normal file
257
doc/unit-tests.txt
Normal file
@@ -0,0 +1,257 @@
|
||||
Building unit tests
|
||||
===================
|
||||
|
||||
make unit-unit/unit-test
|
||||
|
||||
|
||||
Running unit tests
|
||||
==================
|
||||
|
||||
The tests leave no artifacts at the moment, so you can just run
|
||||
unit-test/unit-test from wherever you want.
|
||||
|
||||
./unit-test <list|run> [pattern]
|
||||
|
||||
Listing tests
|
||||
-------------
|
||||
|
||||
Every test has a symbolic path associated with it. Just like file paths they
|
||||
are split into components separated by '/'s. The 'list' command will show you
|
||||
a tree of these tests, along with some description text.
|
||||
|
||||
|
||||
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list
|
||||
base
|
||||
data-struct
|
||||
bitset
|
||||
and ................................................. and all bits
|
||||
equal ............................................... equality
|
||||
get_next ............................................ get next set bit
|
||||
list
|
||||
splice .............................................. joining lists together
|
||||
string
|
||||
asprint ............................................. tests asprint
|
||||
strncpy ............................................. tests string copying
|
||||
device
|
||||
bcache
|
||||
block-size-multiple-page ............................ block size must be a multiple of page size
|
||||
block-size-positive ................................. block size must be positive
|
||||
blocks-get-evicted .................................. block get evicted with many reads
|
||||
cache-blocks-positive ............................... nr cache blocks must be positive
|
||||
create-destroy ...................................... simple create/destroy
|
||||
flush-waits ......................................... flush waits for all dirty
|
||||
get-reads ........................................... bcache_get() triggers read
|
||||
prefetch-never-waits ................................ too many prefetches does not trigger a wait
|
||||
prefetch-reads ...................................... prefetch issues a read
|
||||
read-multiple-files ................................. read from multiple files
|
||||
reads-cached ........................................ repeated reads are cached
|
||||
writeback-occurs .................................... dirty data gets written back
|
||||
zero-flag-dirties ................................... zeroed data counts as dirty
|
||||
formatting
|
||||
percent
|
||||
0 ................................................... Pretty printing of percentages near 0%
|
||||
100 ................................................. Pretty printing of percentages near 100%
|
||||
regex
|
||||
fingerprints .......................................... not sure
|
||||
matching .............................................. test the matcher with a variety of regexes
|
||||
dm
|
||||
target
|
||||
mirror
|
||||
status .............................................. parsing mirror status
|
||||
metadata
|
||||
config
|
||||
cascade ............................................... cascade
|
||||
clone ................................................. duplicating a config tree
|
||||
parse ................................................. parsing various
|
||||
|
||||
|
||||
An optional 'pattern' argument may be specified to select subsets of tests.
|
||||
This pattern is a posix regex and does a substring match, so you will need to
|
||||
use anchors if you particularly want the match at the beginning or end of the
|
||||
string.
|
||||
|
||||
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list data-struct
|
||||
base
|
||||
data-struct
|
||||
bitset
|
||||
and ................................................. and all bits
|
||||
equal ............................................... equality
|
||||
get_next ............................................ get next set bit
|
||||
list
|
||||
splice .............................................. joining lists together
|
||||
string
|
||||
asprint ............................................. tests asprint
|
||||
strncpy ............................................. tests string copying
|
||||
|
||||
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list s$
|
||||
base
|
||||
device
|
||||
bcache
|
||||
flush-waits ......................................... flush waits for all dirty
|
||||
get-reads ........................................... bcache_get() triggers read
|
||||
prefetch-never-waits ................................ too many prefetches does not trigger a wait
|
||||
prefetch-reads ...................................... prefetch issues a read
|
||||
read-multiple-files ................................. read from multiple files
|
||||
writeback-occurs .................................... dirty data gets written back
|
||||
zero-flag-dirties ................................... zeroed data counts as dirty
|
||||
regex
|
||||
fingerprints .......................................... not sure
|
||||
dm
|
||||
target
|
||||
mirror
|
||||
status .............................................. parsing mirror status
|
||||
|
||||
|
||||
Running tests
|
||||
=============
|
||||
|
||||
'make run-unit-test' from the top level will run all unit tests. But I tend to
|
||||
run it by hand to I can select just the tests I'm working on.
|
||||
|
||||
Use the 'run' command to run the tests. Currently all logging goes to stderr,
|
||||
so the test runner prints a line at the start of the test and a line
|
||||
indicating success or failure at the end.
|
||||
|
||||
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run bcache/block-size
|
||||
[RUN ] /base/device/bcache/block-size-multiple-page
|
||||
bcache block size must be a multiple of page size
|
||||
bcache block size must be a multiple of page size
|
||||
bcache block size must be a multiple of page size
|
||||
bcache block size must be a multiple of page size
|
||||
[ OK] /base/device/bcache/block-size-multiple-page
|
||||
|
||||
[RUN ] /base/device/bcache/block-size-positive
|
||||
bcache must have a non zero block size
|
||||
[ OK] /base/device/bcache/block-size-positive
|
||||
|
||||
|
||||
2/2 tests passed
|
||||
|
||||
|
||||
ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run data-struct
|
||||
[RUN ] /base/data-struct/bitset/and
|
||||
[ OK] /base/data-struct/bitset/and
|
||||
|
||||
[RUN ] /base/data-struct/bitset/equal
|
||||
[ OK] /base/data-struct/bitset/equal
|
||||
|
||||
[RUN ] /base/data-struct/bitset/get_next
|
||||
[ OK] /base/data-struct/bitset/get_next
|
||||
|
||||
[RUN ] /base/data-struct/list/splice
|
||||
[ OK] /base/data-struct/list/splice
|
||||
|
||||
[RUN ] /base/data-struct/string/asprint
|
||||
[ OK] /base/data-struct/string/asprint
|
||||
|
||||
[RUN ] /base/data-struct/string/strncpy
|
||||
[ OK] /base/data-struct/string/strncpy
|
||||
|
||||
|
||||
6/6 tests passed
|
||||
|
||||
|
||||
Writing tests
|
||||
=============
|
||||
|
||||
[See unit-test/framework.h and unit-test/units.h for the details]
|
||||
|
||||
Tests are grouped together into 'suites', all tests in a suite share a
|
||||
'fixture'. A fixture is a void * to any object you want; use it to set up any
|
||||
common environment that you need for the tests to run (eg, creating a dm_pool).
|
||||
|
||||
Test suites have nothing to do with the test paths, you can have tests from
|
||||
different suites with similar paths, the runner sorts things for you.
|
||||
|
||||
Put your tests in a file in unit-test/, with '_t' at the end of the name
|
||||
(convention only, nothing relies on this).
|
||||
|
||||
#include "units.h"
|
||||
|
||||
Then write any fixtures you need:
|
||||
|
||||
eg,
|
||||
static void *_mem_init(void) {
|
||||
struct dm_pool *mem = dm_pool_create("bitset test", 1024);
|
||||
if (!mem) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void _mem_exit(void *mem)
|
||||
{
|
||||
dm_pool_destroy(mem);
|
||||
}
|
||||
|
||||
Then write your tests, which should take the void * that was returned by your
|
||||
fixture. Use the T_ASSERT* macros to indicate failure.
|
||||
|
||||
eg,
|
||||
static void test_equal(void *fixture)
|
||||
{
|
||||
struct dm_pool *mem = fixture;
|
||||
dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
|
||||
dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
|
||||
|
||||
int i, j;
|
||||
for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
|
||||
dm_bit_set(bs1, i);
|
||||
dm_bit_set(bs2, i);
|
||||
}
|
||||
|
||||
T_ASSERT(dm_bitset_equal(bs1, bs2));
|
||||
T_ASSERT(dm_bitset_equal(bs2, bs1));
|
||||
|
||||
for (i = 0; i < NR_BITS; i++) {
|
||||
bit_flip(bs1, i);
|
||||
T_ASSERT(!dm_bitset_equal(bs1, bs2));
|
||||
T_ASSERT(!dm_bitset_equal(bs2, bs1));
|
||||
|
||||
T_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
|
||||
bit_flip(bs1, i);
|
||||
}
|
||||
}
|
||||
|
||||
At the end of your test file you should write a function that builds one or
|
||||
more test suites and adds them to the list of all suites that is passed in. I
|
||||
tend to write a little macro (T) to save typing the same test path repeatedly.
|
||||
|
||||
eg,
|
||||
#define T(path, desc, fn) register_test(ts, "/base/data-struct/bitset/" path, desc, fn)
|
||||
|
||||
void bitset_tests(struct dm_list *all_tests)
|
||||
{
|
||||
struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
|
||||
if (!ts) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
T("get_next", "get next set bit", test_get_next);
|
||||
T("equal", "equality", test_equal);
|
||||
T("and", "and all bits", test_and);
|
||||
|
||||
dm_list_add(all_tests, &ts->list);
|
||||
}
|
||||
|
||||
Then you need to declare your registration function and call it in units.h.
|
||||
|
||||
|
||||
// Declare the function that adds tests suites here ...
|
||||
...
|
||||
void bitset_tests(struct dm_list *suites);
|
||||
...
|
||||
|
||||
// ... and call it in here.
|
||||
static inline void register_all_tests(struct dm_list *suites)
|
||||
{
|
||||
...
|
||||
bitset_tests(suites);
|
||||
...
|
||||
}
|
||||
|
||||
Finally add your test file to the Makefile.in and rerun configure.
|
||||
|
||||
104
doc/vdo.md
Normal file
104
doc/vdo.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# VDO - Compression and deduplication.
|
||||
|
||||
Currently device stacking looks like this:
|
||||
|
||||
Physical x [multipath] x [partition] x [mdadm] x [LUKS] x [LVS] x [LUKS] x [FS|Database|...]
|
||||
|
||||
Adding VDO:
|
||||
|
||||
Physical x [multipath] x [partition] x [mdadm] x [LUKS] x [LVS] x [LUKS] x VDO x [LVS] x [FS|Database|...]
|
||||
|
||||
## Where VDO fits (and where it does not):
|
||||
|
||||
### Backing devices for VDO volumes:
|
||||
|
||||
1. Physical x [multipath] x [partition] x [mdadm],
|
||||
2. LUKS over (1) - full disk encryption.
|
||||
3. LVs (raids|mirror|stripe|linear) x [cache] over (1).
|
||||
4. LUKS over (3) - especially when using raids.
|
||||
|
||||
Usual limitations apply:
|
||||
|
||||
- Never layer LUKS over another LUKS - it makes no sense.
|
||||
- LUKS is better over the raids, than under.
|
||||
|
||||
Devices which are not best suitable as backing device:
|
||||
|
||||
- thin volumes - at the moment it is not possible to take snapshot of active VDO volume on top of thin volume.
|
||||
|
||||
### Using VDO as a PV:
|
||||
|
||||
1. under tdata
|
||||
- The best fit - it will deduplicate additional redundancies among all
|
||||
snapshots and will reduce the footprint.
|
||||
- Risks: Resize! dmevent will not be able to handle resizing of tpool ATM.
|
||||
2. under corig
|
||||
- This is useful to keep the most frequently used data in cache
|
||||
uncompressed or without deduplication if that happens to be a bottleneck.
|
||||
- Cache may fit better under VDO device, depending on compressibility and
|
||||
amount of duplicates, as
|
||||
- compression will reduce amount of data, thus effectively increasing
|
||||
size of cache,
|
||||
- and deduplication may emphasize hotspots.
|
||||
- Performance testing of your particular workload is strongly recommended.
|
||||
3. under (multiple) linear LVs - e.g. used for VMs.
|
||||
|
||||
### And where VDO does not fit:
|
||||
|
||||
- *never* use VDO under LUKS volumes
|
||||
- these are random data and do not compress nor deduplicate well,
|
||||
- *never* use VDO under cmeta and tmeta LVs
|
||||
- these are random data and do not compress nor deduplicate well,
|
||||
- under raids
|
||||
- raid{4,5,6} scrambles data, so they do not deduplicate well,
|
||||
- raid{1,4,5,6,10} also causes amount of data grow, so more (duplicit in
|
||||
case of raid{1,10}) work has to be done in order to find less duplicates.
|
||||
|
||||
### And where it could be useful:
|
||||
|
||||
- under snapshot CoW device - when there are multiple of those it could deduplicate
|
||||
|
||||
## Development
|
||||
|
||||
### Things to decide
|
||||
|
||||
- under integrity devices
|
||||
- VDO should work well for data blocks,
|
||||
- but hashes are mostly unique and not compressible - were it possible it
|
||||
would make sense to have separate imeta and idata volumes for integrity
|
||||
devices.
|
||||
|
||||
### Future Integration of VDO into LVM:
|
||||
|
||||
One issue is using both LUKS and RAID under VDO. We have two options:
|
||||
|
||||
- use mdadm x LUKS x VDO+LV
|
||||
- use LV RAID x LUKS x VDO+LV
|
||||
|
||||
In both cases dmeventd will not be able to resize the volume at the moment.
|
||||
|
||||
Another issue is duality of VDO - it can be used as a top level LV (with a
|
||||
filesystem on top) but it can be used as "pool" for multiple devices too.
|
||||
|
||||
This will be solved in similar way thin pools allow multiple volumes.
|
||||
|
||||
Also VDO, has two sizes - its physical size and virtual size - and when
|
||||
overprovisioning, just like tpool, we face same problems - VDO can get full,
|
||||
without exposing it to a FS. dmeventd monitoring will be needed.
|
||||
|
||||
Another possible RFE is to split data and metadata - keep data on HDD and metadata on SSD.
|
||||
|
||||
## Issues / Testing
|
||||
|
||||
- fstrim/discard pass down - does it work with VDO?
|
||||
- VDO can run in synchronous vs. asynchronous mode:
|
||||
- synchronous for devices where write is safe after it is confirmed. Some
|
||||
devices are lying.
|
||||
- asynchronous for devices requiring flush.
|
||||
- Multiple devices under VDO - need to find and expose common properties, or
|
||||
not allow grouping them together. (This is same for all volumes with more
|
||||
physical devices below.)
|
||||
- pvmove changing characteristics of underlying device.
|
||||
- autoactivation during boot?
|
||||
- Q: can we use VDO for RootFS? Dracut!
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
@top_srcdir@/lib/config/defaults.h
|
||||
@top_srcdir@/lib/datastruct/btree.h
|
||||
@top_srcdir@/lib/datastruct/str_list.h
|
||||
@top_srcdir@/lib/device/bcache.h
|
||||
@top_srcdir@/lib/device/dev-cache.h
|
||||
@top_srcdir@/lib/device/dev-ext-udev-constants.h
|
||||
@top_srcdir@/lib/device/dev-type.h
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* include/configure.h.in. Generated from configure.in by autoheader. */
|
||||
/* include/configure.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 to use libblkid detection of signatures when wiping. */
|
||||
#undef BLKID_WIPING_SUPPORT
|
||||
@@ -72,10 +72,6 @@
|
||||
/* Default system configuration directory. */
|
||||
#undef DEFAULT_ETC_DIR
|
||||
|
||||
/* Fall back to LVM1 by default if device-mapper is missing from the kernel.
|
||||
*/
|
||||
#undef DEFAULT_FALLBACK_TO_LVM1
|
||||
|
||||
/* Name of default locking directory. */
|
||||
#undef DEFAULT_LOCK_DIR
|
||||
|
||||
@@ -249,6 +245,9 @@
|
||||
/* Define to 1 if you have the <langinfo.h> header file. */
|
||||
#undef HAVE_LANGINFO_H
|
||||
|
||||
/* Define to 1 if you have the <libaio.h> header file. */
|
||||
#undef HAVE_LIBAIO_H
|
||||
|
||||
/* Define to 1 if you have the <libcman.h> header file. */
|
||||
#undef HAVE_LIBCMAN_H
|
||||
|
||||
@@ -347,9 +346,6 @@
|
||||
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||
#undef HAVE_PTRDIFF_T
|
||||
|
||||
/* Define to 1 if the compiler has the `__builtin_clz` builtin. */
|
||||
#undef HAVE___BUILTIN_CLZ
|
||||
|
||||
/* Define to 1 if you have the <readline/history.h> header file. */
|
||||
#undef HAVE_READLINE_HISTORY_H
|
||||
|
||||
@@ -478,9 +474,16 @@
|
||||
/* Define to 1 if you have the `strtoull' function. */
|
||||
#undef HAVE_STRTOULL
|
||||
|
||||
/* Define to 1 if `st_blocks' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_BLOCKS
|
||||
|
||||
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_RDEV
|
||||
|
||||
/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use
|
||||
`HAVE_STRUCT_STAT_ST_BLOCKS' instead. */
|
||||
#undef HAVE_ST_BLOCKS
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
@@ -552,6 +555,9 @@
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#undef HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/vfs.h> header file. */
|
||||
#undef HAVE_SYS_VFS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
@@ -591,6 +597,9 @@
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to 1 if the system has the `__builtin_clz' built-in function */
|
||||
#undef HAVE___BUILTIN_CLZ
|
||||
|
||||
/* Internalization package */
|
||||
#undef INTL_PACKAGE
|
||||
|
||||
@@ -607,13 +616,6 @@
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
|
||||
/* Define to 1 if 'lvm' should fall back to using LVM1 binaries if
|
||||
device-mapper is missing from the kernel */
|
||||
#undef LVM1_FALLBACK
|
||||
|
||||
/* Define to 1 to include built-in support for LVM1 metadata. */
|
||||
#undef LVM1_INTERNAL
|
||||
|
||||
/* Path to lvmetad pidfile. */
|
||||
#undef LVMETAD_PIDFILE
|
||||
|
||||
@@ -676,18 +678,12 @@
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 to include built-in support for GFS pool metadata. */
|
||||
#undef POOL_INTERNAL
|
||||
|
||||
/* Define to 1 to include built-in support for raid. */
|
||||
#undef RAID_INTERNAL
|
||||
|
||||
/* Define to 1 to include the LVM readline shell. */
|
||||
#undef READLINE_SUPPORT
|
||||
|
||||
/* Define to 1 to include built-in support for replicators. */
|
||||
#undef REPLICATOR_INTERNAL
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
|
||||
@@ -16,38 +16,6 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
ifeq ("@LVM1@", "shared")
|
||||
SUBDIRS = format1
|
||||
endif
|
||||
|
||||
ifeq ("@POOL@", "shared")
|
||||
SUBDIRS += format_pool
|
||||
endif
|
||||
|
||||
ifeq ("@SNAPSHOTS@", "shared")
|
||||
SUBDIRS += snapshot
|
||||
endif
|
||||
|
||||
ifeq ("@MIRRORS@", "shared")
|
||||
SUBDIRS += mirror
|
||||
endif
|
||||
|
||||
ifeq ("@RAID@", "shared")
|
||||
SUBDIRS += raid
|
||||
endif
|
||||
|
||||
ifeq ("@REPLICATORS@", "shared")
|
||||
SUBDIRS += replicator
|
||||
endif
|
||||
|
||||
ifeq ("@THIN@", "shared")
|
||||
SUBDIRS += thin
|
||||
endif
|
||||
|
||||
ifeq ("@CACHE@", "shared")
|
||||
SUBDIRS += cache_segtype
|
||||
endif
|
||||
|
||||
ifeq ("@CLUSTER@", "shared")
|
||||
SUBDIRS += locking
|
||||
endif
|
||||
@@ -55,10 +23,13 @@ endif
|
||||
SOURCES =\
|
||||
activate/activate.c \
|
||||
cache/lvmcache.c \
|
||||
cache_segtype/cache.c \
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
datastruct/btree.c \
|
||||
datastruct/str_list.c \
|
||||
device/bcache.c \
|
||||
device/bcache-utils.c \
|
||||
device/dev-cache.c \
|
||||
device/dev-ext.c \
|
||||
device/dev-io.c \
|
||||
@@ -67,6 +38,7 @@ SOURCES =\
|
||||
device/dev-type.c \
|
||||
device/dev-luks.c \
|
||||
device/dev-dasd.c \
|
||||
device/dev-lvm1-pool.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
unknown/unknown.c \
|
||||
@@ -81,6 +53,7 @@ SOURCES =\
|
||||
filters/filter-type.c \
|
||||
filters/filter-usable.c \
|
||||
filters/filter-internal.c \
|
||||
filters/filter-signature.c \
|
||||
format_text/archive.c \
|
||||
format_text/archiver.c \
|
||||
format_text/export.c \
|
||||
@@ -100,17 +73,18 @@ SOURCES =\
|
||||
metadata/lv_manip.c \
|
||||
metadata/merge.c \
|
||||
metadata/metadata.c \
|
||||
metadata/metadata-liblvm.c \
|
||||
metadata/mirror.c \
|
||||
metadata/pool_manip.c \
|
||||
metadata/pv.c \
|
||||
metadata/pv_manip.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/raid_manip.c \
|
||||
metadata/replicator_manip.c \
|
||||
metadata/segtype.c \
|
||||
metadata/snapshot_manip.c \
|
||||
metadata/thin_manip.c \
|
||||
metadata/vg.c \
|
||||
mirror/mirrored.c \
|
||||
misc/crc.c \
|
||||
misc/lvm-exec.c \
|
||||
misc/lvm-file.c \
|
||||
@@ -124,59 +98,19 @@ SOURCES =\
|
||||
mm/memlock.c \
|
||||
notify/lvmnotify.c \
|
||||
properties/prop_common.c \
|
||||
raid/raid.c \
|
||||
report/properties.c \
|
||||
report/report.c \
|
||||
snapshot/snapshot.c \
|
||||
striped/striped.c \
|
||||
thin/thin.c \
|
||||
uuid/uuid.c \
|
||||
zero/zero.c
|
||||
|
||||
ifeq ("@LVM1@", "internal")
|
||||
SOURCES +=\
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
format1/import-extents.c \
|
||||
format1/layout.c \
|
||||
format1/lvm1-label.c \
|
||||
format1/vg_number.c
|
||||
endif
|
||||
|
||||
ifeq ("@POOL@", "internal")
|
||||
SOURCES +=\
|
||||
format_pool/disk_rep.c \
|
||||
format_pool/format_pool.c \
|
||||
format_pool/import_export.c \
|
||||
format_pool/pool_label.c
|
||||
endif
|
||||
|
||||
ifeq ("@CLUSTER@", "internal")
|
||||
SOURCES += locking/cluster_locking.c
|
||||
endif
|
||||
|
||||
ifeq ("@SNAPSHOTS@", "internal")
|
||||
SOURCES += snapshot/snapshot.c
|
||||
endif
|
||||
|
||||
ifeq ("@MIRRORS@", "internal")
|
||||
SOURCES += mirror/mirrored.c
|
||||
endif
|
||||
|
||||
ifeq ("@RAID@", "internal")
|
||||
SOURCES += raid/raid.c
|
||||
endif
|
||||
|
||||
ifeq ("@REPLICATORS@", "internal")
|
||||
SOURCES += replicator/replicator.c
|
||||
endif
|
||||
|
||||
ifeq ("@THIN@", "internal")
|
||||
SOURCES += thin/thin.c
|
||||
endif
|
||||
|
||||
ifeq ("@CACHE@", "internal")
|
||||
SOURCES += cache_segtype/cache.c
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
SOURCES +=\
|
||||
activate/dev_manager.c \
|
||||
@@ -209,15 +143,7 @@ LIB_STATIC = $(LIB_NAME).a
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS =\
|
||||
format1 \
|
||||
format_pool \
|
||||
snapshot \
|
||||
mirror \
|
||||
notify \
|
||||
raid \
|
||||
replicator \
|
||||
thin \
|
||||
cache_segtype \
|
||||
locking
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "config.h"
|
||||
#include "segtype.h"
|
||||
#include "sharedlib.h"
|
||||
#include "lvmcache.h"
|
||||
#include "metadata.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
@@ -35,19 +37,6 @@
|
||||
|
||||
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
|
||||
|
||||
int lvm1_present(struct cmd_context *cmd)
|
||||
{
|
||||
static char path[PATH_MAX];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
|
||||
< 0) {
|
||||
log_error("LVM1 proc global snprintf failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (path_exists(path)) ? 1 : 0;
|
||||
}
|
||||
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
struct dm_list *modules)
|
||||
{
|
||||
@@ -323,12 +312,6 @@ int lvs_in_vg_opened(const struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/******
|
||||
int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
*******/
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive,
|
||||
const struct logical_volume *lv, const struct logical_volume *lv_pre)
|
||||
{
|
||||
@@ -612,7 +595,7 @@ int module_present(struct cmd_context *cmd, const char *target_name)
|
||||
#endif
|
||||
struct stat st;
|
||||
char path[PATH_MAX];
|
||||
int i = dm_snprintf(path, (sizeof(path) - 1), "%smodule/dm_%s",
|
||||
int i = dm_snprintf(path, sizeof(path), "%smodule/dm_%s",
|
||||
dm_sysfs_dir(), target_name);
|
||||
|
||||
if (i > 0) {
|
||||
@@ -1012,8 +995,10 @@ int lv_raid_data_offset(const struct logical_volume *lv, uint64_t *data_offset)
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!(r = dev_manager_raid_status(dm, lv, &status)))
|
||||
stack;
|
||||
if (!(r = dev_manager_raid_status(dm, lv, &status))) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*data_offset = status->data_offset;
|
||||
|
||||
@@ -1549,8 +1534,11 @@ static int _lv_is_active(const struct logical_volume *lv,
|
||||
if (skip_cluster_query)
|
||||
goto out;
|
||||
|
||||
if ((r = cluster_lock_held(lv->lvid.s, "", &e)) >= 0)
|
||||
if ((r = cluster_lock_held(lv->lvid.s, "", &e)) >= 0) {
|
||||
if (l && e)
|
||||
r = 0; /* exclusive locally */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If lock query is not supported (due to interfacing with old
|
||||
@@ -1668,7 +1656,10 @@ static struct dm_event_handler *_create_dm_event_handler(struct cmd_context *cmd
|
||||
if (!(dmevh = dm_event_handler_create()))
|
||||
return_NULL;
|
||||
|
||||
if (dm_event_handler_set_dmeventd_path(dmevh, find_config_tree_str(cmd, dmeventd_executable_CFG, NULL)))
|
||||
if (!cmd->default_settings.dmeventd_executable)
|
||||
cmd->default_settings.dmeventd_executable = find_config_tree_str(cmd, dmeventd_executable_CFG, NULL);
|
||||
|
||||
if (dm_event_handler_set_dmeventd_path(dmevh, cmd->default_settings.dmeventd_executable))
|
||||
goto_bad;
|
||||
|
||||
if (dso && dm_event_handler_set_dso(dmevh, dso))
|
||||
@@ -1684,21 +1675,18 @@ static struct dm_event_handler *_create_dm_event_handler(struct cmd_context *cmd
|
||||
|
||||
bad:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath)
|
||||
char *get_monitor_dso_path(struct cmd_context *cmd, int id)
|
||||
{
|
||||
char *path;
|
||||
const char *libpath = find_config_tree_str(cmd, id, NULL);
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Failed to allocate dmeventd library path.");
|
||||
return NULL;
|
||||
}
|
||||
get_shared_library_path(cmd, libpath, path, sizeof(path));
|
||||
|
||||
get_shared_library_path(cmd, libpath, path, PATH_MAX);
|
||||
|
||||
return path;
|
||||
return dm_strdup(path);
|
||||
}
|
||||
|
||||
static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
@@ -1707,7 +1695,7 @@ static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_vo
|
||||
|
||||
if (lv_is_thin_pool(lv))
|
||||
layer = "tpool"; /* Monitor "tpool" for the "thin pool". */
|
||||
else if (lv_is_origin(lv))
|
||||
else if (lv_is_origin(lv) || lv_is_external_origin(lv))
|
||||
layer = "real"; /* Monitor "real" for "snapshot-origin". */
|
||||
else
|
||||
layer = NULL;
|
||||
@@ -1715,13 +1703,18 @@ static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_vo
|
||||
return build_dm_uuid(cmd->mem, lv, layer);
|
||||
}
|
||||
|
||||
static int _device_registered_with_dmeventd(struct cmd_context *cmd, const struct logical_volume *lv, int *pending, const char **dso)
|
||||
static int _device_registered_with_dmeventd(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv,
|
||||
const char **dso,
|
||||
int *pending, int *monitored)
|
||||
{
|
||||
char *uuid;
|
||||
enum dm_event_mask evmask = 0;
|
||||
enum dm_event_mask evmask;
|
||||
struct dm_event_handler *dmevh;
|
||||
int r;
|
||||
|
||||
*pending = 0;
|
||||
*monitored = 0;
|
||||
|
||||
if (!(uuid = _build_target_uuid(cmd, lv)))
|
||||
return_0;
|
||||
@@ -1729,9 +1722,20 @@ static int _device_registered_with_dmeventd(struct cmd_context *cmd, const struc
|
||||
if (!(dmevh = _create_dm_event_handler(cmd, uuid, NULL, 0, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
if (dm_event_get_registered_device(dmevh, 0)) {
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return 0;
|
||||
if ((r = dm_event_get_registered_device(dmevh, 0))) {
|
||||
if (r == -ENOENT) {
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
/* FIXME: why do we care which 'dso' is monitoring? */
|
||||
if (dso && (*dso = dm_event_handler_get_dso(dmevh)) &&
|
||||
!(*dso = dm_pool_strdup(cmd->mem, *dso))) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
evmask = dm_event_handler_get_event_mask(dmevh);
|
||||
@@ -1740,21 +1744,25 @@ static int _device_registered_with_dmeventd(struct cmd_context *cmd, const struc
|
||||
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
|
||||
}
|
||||
|
||||
if (dso && (*dso = dm_event_handler_get_dso(dmevh)) && !(*dso = dm_pool_strdup(cmd->mem, *dso)))
|
||||
log_error("Failed to duplicate dso name.");
|
||||
|
||||
*monitored = evmask;
|
||||
r = 1;
|
||||
out:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return evmask;
|
||||
return r;
|
||||
}
|
||||
|
||||
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
|
||||
const struct logical_volume *lv, int *pending)
|
||||
const struct logical_volume *lv,
|
||||
int *pending, int *monitored)
|
||||
{
|
||||
char *uuid;
|
||||
enum dm_event_mask evmask = 0;
|
||||
enum dm_event_mask evmask;
|
||||
struct dm_event_handler *dmevh;
|
||||
int r;
|
||||
|
||||
*pending = 0;
|
||||
*monitored = 0;
|
||||
|
||||
if (!dso)
|
||||
return_0;
|
||||
@@ -1765,9 +1773,13 @@ int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
|
||||
if (!(dmevh = _create_dm_event_handler(cmd, uuid, dso, 0, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
if (dm_event_get_registered_device(dmevh, 0)) {
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return 0;
|
||||
if ((r = dm_event_get_registered_device(dmevh, 0))) {
|
||||
if (r == -ENOENT) {
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
evmask = dm_event_handler_get_event_mask(dmevh);
|
||||
@@ -1776,9 +1788,12 @@ int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
|
||||
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
|
||||
}
|
||||
|
||||
*monitored = evmask;
|
||||
r = 1;
|
||||
out:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return evmask;
|
||||
return r;
|
||||
}
|
||||
|
||||
int target_register_events(struct cmd_context *cmd, const char *dso, const struct logical_volume *lv,
|
||||
@@ -1806,7 +1821,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_very_verbose("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
|
||||
log_verbose("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1821,7 +1836,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
const struct lv_activate_opts *laopts, int monitor)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
int i, pending = 0, monitored;
|
||||
int i, pending = 0, monitored = 0;
|
||||
int r = 1;
|
||||
struct dm_list *snh, *snht;
|
||||
struct lv_segment *seg;
|
||||
@@ -1829,6 +1844,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
int (*monitor_fn) (struct lv_segment *s, int e);
|
||||
uint32_t s;
|
||||
static const struct lv_activate_opts zlaopts = { 0 };
|
||||
struct lv_activate_opts mirr_laopts = { .origin_only = 1 };
|
||||
struct lvinfo info;
|
||||
const char *dso = NULL;
|
||||
int new_unmonitor;
|
||||
@@ -1891,7 +1907,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
* In case of a snapshot device, we monitor lv->snapshot->lv,
|
||||
* not the actual LV itself.
|
||||
*/
|
||||
if (lv_is_cow(lv) && (laopts->no_merging || !lv_is_merging_cow(lv))) {
|
||||
if (lv_is_cow(lv) && (laopts->no_merging || !lv_is_merging_cow(lv) ||
|
||||
lv_has_target_type(lv->vg->cmd->mem, lv, NULL, TARGET_NAME_SNAPSHOT))) {
|
||||
if (!(r = monitor_dev_for_events(cmd, lv->snapshot->lv, NULL, monitor)))
|
||||
stack;
|
||||
return r;
|
||||
@@ -1930,9 +1947,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
continue;
|
||||
if (!monitor_dev_for_events(cmd, seg_lv(seg, s), NULL,
|
||||
monitor)) {
|
||||
log_error("Failed to %smonitor %s",
|
||||
monitor ? "" : "un",
|
||||
display_lvname(seg_lv(seg, s)));
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
@@ -1949,6 +1964,13 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (seg->external_lv &&
|
||||
!monitor_dev_for_events(cmd, seg->external_lv,
|
||||
(!monitor) ? laopts : NULL, monitor)) {
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (seg->metadata_lv &&
|
||||
!monitor_dev_for_events(cmd, seg->metadata_lv, NULL, monitor)) {
|
||||
stack;
|
||||
@@ -1960,11 +1982,21 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
!seg->segtype->ops->target_monitored) /* doesn't support registration */
|
||||
continue;
|
||||
|
||||
if (!monitor)
|
||||
if (!monitor) {
|
||||
/* When unmonitoring, obtain existing dso being used. */
|
||||
monitored = _device_registered_with_dmeventd(cmd, seg_is_snapshot(seg) ? seg->cow : seg->lv, &pending, &dso);
|
||||
else
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
if (!_device_registered_with_dmeventd(cmd, seg_is_snapshot(seg) ? seg->cow : seg->lv,
|
||||
&dso, &pending, &monitored)) {
|
||||
log_warn("WARNING: Failed to %smonitor %s.",
|
||||
monitor ? "" : "un",
|
||||
display_lvname(seg_is_snapshot(seg) ? seg->cow : seg->lv));
|
||||
return 0;
|
||||
}
|
||||
} else if (!seg->segtype->ops->target_monitored(seg, &pending, &monitored)) {
|
||||
log_warn("WARNING: Failed to %smonitor %s.",
|
||||
monitor ? "" : "un",
|
||||
display_lvname(seg->lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: We should really try again if pending */
|
||||
monitored = (pending) ? 0 : monitored;
|
||||
@@ -1976,7 +2008,9 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
if (monitored)
|
||||
log_verbose("%s already monitored.", display_lvname(lv));
|
||||
else if (seg->segtype->ops->target_monitor_events) {
|
||||
log_verbose("Monitoring %s%s", display_lvname(lv), test_mode() ? " [Test mode: skipping this]" : "");
|
||||
log_very_verbose("Monitoring %s with %s.%s", display_lvname(lv),
|
||||
seg->segtype->dso,
|
||||
test_mode() ? " [Test mode: skipping this]" : "");
|
||||
monitor_fn = seg->segtype->ops->target_monitor_events;
|
||||
}
|
||||
} else {
|
||||
@@ -1998,26 +2032,42 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
|
||||
if (new_unmonitor) {
|
||||
if (!target_register_events(cmd, dso, seg_is_snapshot(seg) ? seg->cow : lv, 0, 0, 10)) {
|
||||
log_error("%s: segment unmonitoring failed.",
|
||||
display_lvname(lv));
|
||||
|
||||
log_warn("WARNING: %s: segment unmonitoring failed.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
} else if (monitor_fn) {
|
||||
/* FIXME specify events */
|
||||
if (!monitor_fn(seg, 0)) {
|
||||
log_error("%s: %s segment monitoring function failed.",
|
||||
display_lvname(lv), lvseg_name(seg));
|
||||
log_warn("WARNING: %s: %s segment monitoring function failed.",
|
||||
display_lvname(lv), lvseg_name(seg));
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (!vg_write_lock_held() && lv_is_mirror(lv)) {
|
||||
mirr_laopts.exclusive = lv_is_active_exclusive_locally(lv) ? 1 : 0;
|
||||
/*
|
||||
* Commands vgchange and lvchange do use read-only lock when changing
|
||||
* monitoring (--monitor y|n). All other use cases hold 'write-lock'
|
||||
* so they skip this dm mirror table refreshing step.
|
||||
*/
|
||||
if (!_lv_activate_lv(lv, &mirr_laopts)) {
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check [un]monitor results */
|
||||
/* Try a couple times if pending, but not forever... */
|
||||
for (i = 0;; i++) {
|
||||
pending = 0;
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
if (!seg->segtype->ops->target_monitored(seg, &pending, &monitored)) {
|
||||
stack;
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
if (!pending || i >= 40)
|
||||
break;
|
||||
log_very_verbose("%s %smonitoring still pending: waiting...",
|
||||
@@ -2030,8 +2080,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
}
|
||||
|
||||
if (!r && !error_message_produced())
|
||||
log_error("%sonitoring %s failed.", monitor ? "M" : "Not m",
|
||||
display_lvname(lv));
|
||||
log_warn("WARNING: %sonitoring %s failed.", monitor ? "M" : "Not m",
|
||||
display_lvname(lv));
|
||||
return r;
|
||||
#else
|
||||
return 1;
|
||||
@@ -2062,6 +2112,12 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data)
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!lv_is_visible(lv) && (lv_pre = find_lv(detached->lv_pre->vg, lv->name)) &&
|
||||
lv_is_visible(lv_pre)) {
|
||||
if (!_lv_preload(lv_pre, detached->laopts, detached->flush_required))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* FIXME: condition here should be far more limiting to really
|
||||
* detect detached LVs */
|
||||
if ((lv_pre = find_lv(detached->lv_pre->vg, lv->name))) {
|
||||
@@ -2082,16 +2138,76 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
const struct logical_volume *pvmove_lv = NULL;
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
const struct logical_volume *lv_pre_to_free = NULL;
|
||||
struct logical_volume *lv_pre_tmp;
|
||||
struct logical_volume *lv_pre_tmp, *lv_tmp;
|
||||
struct seg_list *sl;
|
||||
struct lv_segment *snap_seg;
|
||||
struct lvinfo info;
|
||||
int r = 0, lockfs = 0, flush_required = 0;
|
||||
struct detached_lv_data detached;
|
||||
struct dm_pool *mem = NULL;
|
||||
struct dm_list suspend_lvs;
|
||||
struct lv_list *lvl;
|
||||
const union lvid *lvid = (const union lvid *) lvid_s;
|
||||
const char *vgid = (const char *)lvid->id[0].uuid;
|
||||
struct volume_group *vg;
|
||||
struct volume_group *vg_pre;
|
||||
int found;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!cmd->is_clvmd)
|
||||
goto skip_read;
|
||||
|
||||
if (lv && lv_pre)
|
||||
goto skip_read;
|
||||
|
||||
if (!(vg = lvmcache_get_saved_vg(vgid, 0))) {
|
||||
log_debug("lv_suspend did not find saved_vg %.8s so reading", vgid);
|
||||
if (!(vg = vg_read_by_vgid(cmd, vgid, 0))) {
|
||||
log_error("lv_suspend could not read vgid %.8s", vgid);
|
||||
goto out;
|
||||
}
|
||||
log_debug("lv_suspend using read vg %s %d %p", vg->name, vg->seqno, vg);
|
||||
} else {
|
||||
log_debug("lv_suspend using saved_vg %s %d %p", vg->name, vg->seqno, vg);
|
||||
}
|
||||
|
||||
if (!(vg_pre = lvmcache_get_saved_vg(vgid, 1))) {
|
||||
log_debug("lv_suspend did not find pre saved_vg %.8s so reading", vgid);
|
||||
if (!(vg_pre = vg_read_by_vgid(cmd, vgid, 1))) {
|
||||
log_error("lv_suspend could not read pre vgid %.8s", vgid);
|
||||
goto out;
|
||||
}
|
||||
log_debug("lv_suspend using pre read vg %s %d %p", vg_pre->name, vg_pre->seqno, vg_pre);
|
||||
} else {
|
||||
log_debug("lv_suspend using pre saved_vg %s %d %p", vg_pre->name, vg_pre->seqno, vg_pre);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that vg and vg_pre returned by vg_read_by_vgid will
|
||||
* not be the same as saved_vg_old/saved_vg_new that would
|
||||
* be returned by lvmcache_get_saved_vg() because the saved_vg's
|
||||
* are copies of the vg struct that is created by _vg_read.
|
||||
* (Should we grab and use the saved_vg to use here instead of
|
||||
* the vg returned by vg_read_by_vgid?)
|
||||
*/
|
||||
|
||||
if ((vg->status & EXPORTED_VG) || (vg_pre->status & EXPORTED_VG)) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lv = lv_to_free = find_lv_in_vg_by_lvid(vg, lvid);
|
||||
lv_pre = lv_pre_to_free = find_lv_in_vg_by_lvid(vg_pre, lvid);
|
||||
|
||||
if (!lv || !lv_pre) {
|
||||
log_error("lv_suspend could not find lv %p lv_pre %p vg %p vg_pre %p vgid %s",
|
||||
lv, lv_pre, vg, vg_pre, vgid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
skip_read:
|
||||
/* lv comes from committed metadata */
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
@@ -2116,6 +2232,19 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Save old and new (current and precommitted) versions of the
|
||||
* VG metadata for lv_resume() to use, since lv_resume can't
|
||||
* read metadata given that devices are suspended. lv_resume()
|
||||
* will resume LVs using the old/current metadata if the vg_commit
|
||||
* did happen (or failed), and it will resume LVs using the
|
||||
* new/precommitted metadata if the vg_commit succeeded.
|
||||
*/
|
||||
if (cmd->is_clvmd) {
|
||||
lvmcache_save_vg(lv->vg, 0);
|
||||
lvmcache_save_vg(lv_pre->vg, 1);
|
||||
}
|
||||
|
||||
if (!info.exists || info.suspended) {
|
||||
if (!error_if_not_suspended) {
|
||||
r = 1;
|
||||
@@ -2125,9 +2254,6 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!lv_read_replicator_vgs(lv))
|
||||
goto_out;
|
||||
|
||||
lv_calculate_readahead(lv, NULL);
|
||||
|
||||
/*
|
||||
@@ -2157,6 +2283,12 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
if (!_lv_preload(lv_pre_tmp, laopts, &flush_required))
|
||||
goto_out;
|
||||
|
||||
/* Suspending 1st. LV above PVMOVE suspends whole tree */
|
||||
dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) {
|
||||
lv = sl->seg->lv;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!_lv_preload(lv_pre, laopts, &flush_required))
|
||||
/* FIXME Revert preloading */
|
||||
@@ -2194,7 +2326,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
* NOTE: Mirror repair requires noflush for proper repair!
|
||||
* TODO: Relax this limiting condition further */
|
||||
if (!flush_required &&
|
||||
(lv_is_pvmove(lv) ||
|
||||
(lv_is_pvmove(lv) || pvmove_lv ||
|
||||
(!lv_is_mirror(lv) && !lv_is_thin_pool(lv) && !lv_is_thin_volume(lv)))) {
|
||||
log_debug("Requiring flush for LV %s.", display_lvname(lv));
|
||||
flush_required = 1;
|
||||
@@ -2204,10 +2336,6 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
/* FIXME Consider aborting here */
|
||||
stack;
|
||||
|
||||
critical_section_inc(cmd, "suspending");
|
||||
if (pvmove_lv)
|
||||
critical_section_inc(cmd, "suspending pvmove LV");
|
||||
|
||||
if (!laopts->origin_only &&
|
||||
(lv_is_origin(lv_pre) || lv_is_cow(lv_pre)))
|
||||
lockfs = 1;
|
||||
@@ -2219,40 +2347,68 @@ 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;
|
||||
|
||||
/*
|
||||
* Suspending an LV directly above a PVMOVE LV also
|
||||
* suspends other LVs using that same PVMOVE LV.
|
||||
* FIXME Remove this and delay the 'clear node' until
|
||||
* after the code knows whether there's a different
|
||||
* inactive table to load or not instead so lv_suspend
|
||||
* can be called separately for each LV safely.
|
||||
*/
|
||||
if ((lv_pre->vg->status & PRECOMMITTED) &&
|
||||
lv_is_locked(lv_pre) && find_pvmove_lv_in_lv(lv_pre)) {
|
||||
if (!_lv_suspend_lv(lv_pre, laopts, lockfs, flush_required)) {
|
||||
critical_section_dec(cmd, "failed precommitted suspend");
|
||||
if (pvmove_lv)
|
||||
critical_section_dec(cmd, "failed precommitted suspend (pvmove)");
|
||||
critical_section_inc(cmd, "suspending");
|
||||
|
||||
if (!lv_is_locked(lv) && lv_is_locked(lv_pre) &&
|
||||
(pvmove_lv = find_pvmove_lv_in_lv(lv_pre))) {
|
||||
/*
|
||||
* When starting PVMOVE, suspend participating LVs first
|
||||
* with committed metadata by looking at precommited pvmove list.
|
||||
* In committed metadata these LVs are not connected in any way.
|
||||
*
|
||||
* TODO: prepare list of LVs needed to be suspended and pass them
|
||||
* via 'struct laopts' directly to _lv_suspend_lv() and handle this
|
||||
* with a single 'dmtree' call.
|
||||
*/
|
||||
if (!(mem = dm_pool_create("suspend_lvs", 128)))
|
||||
goto_out;
|
||||
|
||||
/* Prepare list of all LVs for suspend ahead */
|
||||
dm_list_init(&suspend_lvs);
|
||||
dm_list_iterate_items(sl, &pvmove_lv->segs_using_this_lv) {
|
||||
lv_tmp = sl->seg->lv;
|
||||
if (lv_is_cow(lv_tmp))
|
||||
/* Never suspend COW, always has to be origin */
|
||||
lv_tmp = origin_from_cow(lv_tmp);
|
||||
found = 0;
|
||||
dm_list_iterate_items(lvl, &suspend_lvs)
|
||||
if (strcmp(lvl->lv->name, lv_tmp->name) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
continue; /* LV is already in the list */
|
||||
if (!(lvl = dm_pool_alloc(mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed.");
|
||||
goto out;
|
||||
}
|
||||
/* Look for precommitted LV name in commmitted VG */
|
||||
if (!(lvl->lv = find_lv(lv->vg, lv_tmp->name))) {
|
||||
log_error(INTERNAL_ERROR "LV %s missing from preload metadata.",
|
||||
display_lvname(lv_tmp));
|
||||
goto out;
|
||||
}
|
||||
dm_list_add(&suspend_lvs, &lvl->list);
|
||||
}
|
||||
} else {
|
||||
/* Normal suspend */
|
||||
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 */
|
||||
if (!_lv_suspend_lv(lv, laopts, lockfs, flush_required)) {
|
||||
critical_section_dec(cmd, "failed suspend");
|
||||
if (pvmove_lv)
|
||||
critical_section_dec(cmd, "failed suspend (pvmove)");
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (mem)
|
||||
dm_pool_destroy(mem);
|
||||
if (lv_pre_to_free)
|
||||
release_vg(lv_pre_to_free->vg);
|
||||
if (lv_to_free) {
|
||||
lv_release_replicator_vgs(lv_to_free);
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -2274,20 +2430,76 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned o
|
||||
return _lv_suspend(cmd, lvid_s, &laopts, 0, lv, lv_pre);
|
||||
}
|
||||
|
||||
static int _check_suspended_lv(struct logical_volume *lv, void *data)
|
||||
{
|
||||
struct lvinfo info;
|
||||
|
||||
if (lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) && info.exists && info.suspended) {
|
||||
log_debug("Found suspended LV %s in critical section().", display_lvname(lv));
|
||||
return 0; /* There is suspended subLV in the tree */
|
||||
}
|
||||
|
||||
if (lv_layer(lv) && lv_info(lv->vg->cmd, lv, 1, &info, 0, 0) && info.exists && info.suspended) {
|
||||
log_debug("Found suspended layered LV %s in critical section().", display_lvname(lv));
|
||||
return 0; /* There is suspended subLV in the tree */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct lv_activate_opts *laopts, int error_if_not_active,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct dm_list *snh;
|
||||
struct volume_group *vg = NULL;
|
||||
struct logical_volume *lv_found = NULL;
|
||||
const union lvid *lvid;
|
||||
const char *vgid;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
/*
|
||||
* When called in clvmd, lvid_s is set and lv is not. We need to
|
||||
* get the VG metadata without reading disks because devs are
|
||||
* suspended. lv_suspend() saved old and new VG metadata for us
|
||||
* to use here. If vg_commit() happened, lvmcache_get_saved_vg_latest
|
||||
* will return the new metadata for us to use in resuming LVs.
|
||||
* If vg_commit() did not happen, lvmcache_get_saved_vg_latest
|
||||
* returns the old metadata which we use to resume LVs.
|
||||
*/
|
||||
if (!lv && lvid_s) {
|
||||
lvid = (const union lvid *) lvid_s;
|
||||
vgid = (const char *)lvid->id[0].uuid;
|
||||
|
||||
if ((vg = lvmcache_get_saved_vg_latest(vgid))) {
|
||||
log_debug_activation("Resuming LVID %s found saved vg seqno %d %s", lvid_s, vg->seqno, vg->name);
|
||||
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_debug_activation("Resuming LVID %s found saved LV %s", lvid_s, display_lvname(lv_found));
|
||||
lv = lv_found;
|
||||
} else
|
||||
log_debug_activation("Resuming LVID %s did not find saved LV", lvid_s);
|
||||
} else
|
||||
log_debug_activation("Resuming LVID %s did not find saved VG", lvid_s);
|
||||
|
||||
/*
|
||||
* resume must have been called without a preceding suspend,
|
||||
* so we need to read the vg.
|
||||
*/
|
||||
|
||||
if (!lv) {
|
||||
log_debug_activation("Resuming LVID %s reading VG", lvid_s);
|
||||
if (!(lv_found = lv_from_lvid(cmd, lvid_s, 0))) {
|
||||
log_debug_activation("Resuming LVID %s failed to read VG", lvid_s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lv = lv_found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
|
||||
laopts->origin_only = 0;
|
||||
@@ -2313,12 +2525,28 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!info.exists || !info.suspended) {
|
||||
if (error_if_not_active)
|
||||
goto_out;
|
||||
r = 1;
|
||||
if (!info.suspended)
|
||||
critical_section_dec(cmd, "already resumed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ATM only thin-pool with origin-only suspend does not really suspend anything
|
||||
* it's used only for message passing to thin-pool */
|
||||
if (laopts->origin_only && lv_is_thin_pool(lv))
|
||||
critical_section_dec(cmd, "resumed");
|
||||
|
||||
if (!info.suspended && critical_section()) {
|
||||
/* Validation check if any subLV is suspended */
|
||||
if (!laopts->origin_only && lv_is_origin(lv)) {
|
||||
/* Check all snapshots for this origin LV */
|
||||
dm_list_iterate(snh, &lv->snapshot_segs)
|
||||
if (!_check_suspended_lv(dm_list_struct_base(snh, struct lv_segment, origin_list)->cow, NULL))
|
||||
goto needs_resume; /* Found suspended snapshot */
|
||||
}
|
||||
if ((r = for_each_sub_lv((struct logical_volume *)lv, &_check_suspended_lv, NULL)))
|
||||
goto out; /* Nothing was found suspended */
|
||||
} else {
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
needs_resume:
|
||||
laopts->read_only = _passes_readonly_filter(cmd, lv);
|
||||
laopts->resuming = 1;
|
||||
|
||||
@@ -2332,9 +2560,6 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -2436,14 +2661,21 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!lv_read_replicator_vgs(lv))
|
||||
goto_out;
|
||||
|
||||
if (!monitor_dev_for_events(cmd, lv, &laopts, 0))
|
||||
stack;
|
||||
|
||||
critical_section_inc(cmd, "deactivating");
|
||||
r = _lv_deactivate(lv);
|
||||
|
||||
/*
|
||||
* Remove any transiently activated error
|
||||
* devices which arean't used any more.
|
||||
*/
|
||||
if (r && lv_is_raid(lv) && !lv_deactivate_any_missing_subdevs(lv)) {
|
||||
log_error("Failed to remove temporary SubLVs from %s",
|
||||
display_lvname(lv));
|
||||
r = 0;
|
||||
}
|
||||
critical_section_dec(cmd, "deactivated");
|
||||
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists) {
|
||||
@@ -2453,10 +2685,8 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
r = 0;
|
||||
}
|
||||
out:
|
||||
if (lv_to_free) {
|
||||
lv_release_replicator_vgs(lv_to_free);
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -2504,6 +2734,15 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto out;
|
||||
|
||||
if (!laopts->exclusive &&
|
||||
(lv_is_origin(lv) ||
|
||||
seg_only_exclusive(first_seg(lv)))) {
|
||||
log_error(INTERNAL_ERROR "Trying non-exlusive activation of %s with "
|
||||
"a volume type %s requiring exclusive activation.",
|
||||
display_lvname(lv), lvseg_name(first_seg(lv)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (filter && !_passes_activation_filter(cmd, lv)) {
|
||||
log_verbose("Not activating %s since it does not pass "
|
||||
"activation filter.", display_lvname(lv));
|
||||
@@ -2549,7 +2788,12 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (filter)
|
||||
/* Component LV activation is enforced to be 'read-only' */
|
||||
/* TODO: should not apply for LVs in maintenance mode */
|
||||
if (!lv_is_visible(lv) && lv_is_component(lv)) {
|
||||
laopts->read_only = 1;
|
||||
laopts->component_lv = lv;
|
||||
} else if (filter)
|
||||
laopts->read_only = _passes_readonly_filter(cmd, lv);
|
||||
|
||||
log_debug_activation("Activating %s%s%s%s%s.", display_lvname(lv),
|
||||
@@ -2565,15 +2809,12 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
* Nothing to do?
|
||||
*/
|
||||
if (info.exists && !info.suspended && info.live_table &&
|
||||
(info.read_only == read_only_lv(lv, laopts))) {
|
||||
(info.read_only == read_only_lv(lv, laopts, NULL))) {
|
||||
r = 1;
|
||||
log_debug_activation("LV %s is already active.", display_lvname(lv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!lv_read_replicator_vgs(lv))
|
||||
goto_out;
|
||||
|
||||
lv_calculate_readahead(lv, NULL);
|
||||
|
||||
critical_section_inc(cmd, "activating");
|
||||
@@ -2585,10 +2826,8 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
stack;
|
||||
|
||||
out:
|
||||
if (lv_to_free) {
|
||||
lv_release_replicator_vgs(lv_to_free);
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -2680,10 +2919,8 @@ static int _lv_remove_any_missing_subdevs(struct logical_volume *lv)
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->area_count != 1)
|
||||
return_0;
|
||||
if (dm_snprintf(name, sizeof(name), "%s-%s-missing_%u_0", seg->lv->vg->name, seg->lv->name, seg_no) < 0)
|
||||
return 0;
|
||||
return_0;
|
||||
if (!_remove_dm_dev_by_name(name))
|
||||
return 0;
|
||||
|
||||
@@ -2743,3 +2980,112 @@ void activation_exit(void)
|
||||
dev_manager_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _component_cb(struct logical_volume *lv, void *data)
|
||||
{
|
||||
struct logical_volume **component_lv = (struct logical_volume **) data;
|
||||
|
||||
if (lv_is_locked(lv) || lv_is_pvmove(lv) ||/* ignoring */
|
||||
/* thin-pool is special and it's using layered device */
|
||||
(lv_is_thin_pool(lv) && pool_is_active(lv)))
|
||||
return -1;
|
||||
|
||||
if (lv_is_active(lv)) {
|
||||
if (!lv_is_component(lv) || lv_is_visible(lv))
|
||||
return -1; /* skip whole subtree */
|
||||
|
||||
log_debug_activation("Found active component LV %s.", display_lvname(lv));
|
||||
*component_lv = lv;
|
||||
return 0; /* break any further processing */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds out for any LV if any of its component LVs are active.
|
||||
* Function first checks if an existing LV is visible and active eventually
|
||||
* it's lock holding LV is already active. In such case sub LV cannot be
|
||||
* actived alone and no further checking is needed.
|
||||
*
|
||||
* Returns active component LV if there is such.
|
||||
*/
|
||||
const struct logical_volume *lv_component_is_active(const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *component_lv = NULL;
|
||||
const struct logical_volume *holder_lv = lv_lock_holder(lv);
|
||||
|
||||
if ((holder_lv != lv) && lv_is_active(holder_lv))
|
||||
return NULL; /* Lock holding LV is active, do not check components */
|
||||
|
||||
if (_component_cb((struct logical_volume *) lv, &holder_lv) == 1)
|
||||
(void) for_each_sub_lv((struct logical_volume *) lv, _component_cb,
|
||||
(void*) &component_lv);
|
||||
|
||||
return component_lv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds out if any LV above is active, as stacked device tree can be composed of
|
||||
* chained set of LVs.
|
||||
*
|
||||
* Returns active holder LV if there is such.
|
||||
*/
|
||||
const struct logical_volume *lv_holder_is_active(const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *holder;
|
||||
const struct seg_list *sl;
|
||||
|
||||
if (lv_is_locked(lv) || lv_is_pvmove(lv))
|
||||
return NULL; /* Skip pvmove/locked LV tracking */
|
||||
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
/* Recursive call for upper-stack holder */
|
||||
if ((holder = lv_holder_is_active(sl->seg->lv)))
|
||||
return holder;
|
||||
|
||||
if (lv_is_active(sl->seg->lv)) {
|
||||
log_debug_activation("Found active holder LV %s.", display_lvname(sl->seg->lv));
|
||||
return sl->seg->lv;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _deactivate_sub_lv_cb(struct logical_volume *lv, void *data)
|
||||
{
|
||||
struct logical_volume **slv = data;
|
||||
|
||||
if (lv_is_thin_pool(lv) || lv_is_external_origin(lv))
|
||||
return -1;
|
||||
|
||||
if (!deactivate_lv(lv->vg->cmd, lv)) {
|
||||
*slv = lv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deactivates LV toghether with explicit deactivation call made also for all its component LVs.
|
||||
*/
|
||||
int deactivate_lv_with_sub_lv(const struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *flv;
|
||||
|
||||
if (!deactivate_lv(lv->vg->cmd, lv)) {
|
||||
log_error("Cannot deactivate logical volume %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!for_each_sub_lv((struct logical_volume *)lv, _deactivate_sub_lv_cb, &flv)) {
|
||||
log_error("Cannot deactivate subvolume %s of logical volume %s.",
|
||||
display_lvname(flv), display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -83,6 +83,7 @@ struct lv_activate_opts {
|
||||
* flags are persistent in udev db for any spurious event
|
||||
* that follows. */
|
||||
unsigned resuming; /* Set when resuming after a suspend. */
|
||||
const struct logical_volume *component_lv;
|
||||
};
|
||||
|
||||
void set_activation(int activation, int silent);
|
||||
@@ -90,7 +91,6 @@ int activation(void);
|
||||
|
||||
int driver_version(char *version, size_t size);
|
||||
int library_version(char *version, size_t size);
|
||||
int lvm1_present(struct cmd_context *cmd);
|
||||
|
||||
int module_present(struct cmd_context *cmd, const char *target_name);
|
||||
int target_present_version(struct cmd_context *cmd, const char *target_name,
|
||||
@@ -198,6 +198,11 @@ int lv_is_active_exclusive(const struct logical_volume *lv);
|
||||
int lv_is_active_exclusive_locally(const struct logical_volume *lv);
|
||||
int lv_is_active_exclusive_remotely(const struct logical_volume *lv);
|
||||
|
||||
/* Check is any component LV is active */
|
||||
const struct logical_volume *lv_component_is_active(const struct logical_volume *lv);
|
||||
const struct logical_volume *lv_holder_is_active(const struct logical_volume *lv);
|
||||
int deactivate_lv_with_sub_lv(const struct logical_volume *lv);
|
||||
|
||||
int lv_has_target_type(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
const char *layer, const char *target_type);
|
||||
|
||||
@@ -206,9 +211,9 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
|
||||
#ifdef DMEVENTD
|
||||
# include "libdevmapper-event.h"
|
||||
char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath);
|
||||
char *get_monitor_dso_path(struct cmd_context *cmd, int id);
|
||||
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
|
||||
const struct logical_volume *lv, int *pending);
|
||||
const struct logical_volume *lv, int *pending, int *monitored);
|
||||
int target_register_events(struct cmd_context *cmd, const char *dso, const struct logical_volume *lv,
|
||||
int evmask __attribute__((unused)), int set, int timeout);
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#define MAX_TARGET_PARAMSIZE 50000
|
||||
#define LVM_UDEV_NOSCAN_FLAG DM_SUBSYSTEM_UDEV_FLAG0
|
||||
#define CRYPT_TEMP "CRYPT-TEMP"
|
||||
#define STRATIS "stratis-"
|
||||
|
||||
typedef enum {
|
||||
PRELOAD,
|
||||
@@ -72,10 +74,17 @@ struct dev_manager {
|
||||
struct lv_layer {
|
||||
const struct logical_volume *lv;
|
||||
const char *old_name;
|
||||
int visible_component;
|
||||
};
|
||||
|
||||
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts)
|
||||
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer)
|
||||
{
|
||||
if (layer && lv_is_cow(lv))
|
||||
return 0; /* Keep snapshot's COW volume writable */
|
||||
|
||||
if (lv_is_raid_image(lv) || lv_is_raid_metadata(lv))
|
||||
return 0; /* Keep RAID SubLvs writable */
|
||||
|
||||
return (laopts->read_only || !(lv->status & LVM_WRITE));
|
||||
}
|
||||
|
||||
@@ -169,7 +178,8 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
}
|
||||
|
||||
/* Validate target_name segtype from DM table with lvm2 metadata segtype */
|
||||
if (strcmp(segtype->name, target_name) &&
|
||||
if (!lv_is_locked(seg->lv) &&
|
||||
strcmp(segtype->name, target_name) &&
|
||||
/* If kernel's type isn't an exact match is it compatible? */
|
||||
(!segtype->ops->target_status_compatible ||
|
||||
!segtype->ops->target_status_compatible(target_name))) {
|
||||
@@ -441,15 +451,21 @@ static int _ignore_suspended_snapshot_component(struct device *dev)
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!target_type || !strcmp(target_type, TARGET_NAME_SNAPSHOT)) {
|
||||
|
||||
if (!target_type)
|
||||
continue;
|
||||
|
||||
if (!strcmp(target_type, TARGET_NAME_SNAPSHOT)) {
|
||||
if (!params || sscanf(params, "%d:%d %d:%d", &major1, &minor1, &major2, &minor2) != 4) {
|
||||
log_error("Incorrect snapshot table found.");
|
||||
log_warn("WARNING: Incorrect snapshot table found for %d:%d.",
|
||||
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
goto out;
|
||||
}
|
||||
r = r || _device_is_suspended(major1, minor1) || _device_is_suspended(major2, minor2);
|
||||
} else if (!strcmp(target_type, TARGET_NAME_SNAPSHOT_ORIGIN)) {
|
||||
if (!params || sscanf(params, "%d:%d", &major1, &minor1) != 2) {
|
||||
log_error("Incorrect snapshot-origin table found.");
|
||||
log_warn("WARNING: Incorrect snapshot-origin table found for %d:%d.",
|
||||
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
goto out;
|
||||
}
|
||||
r = r || _device_is_suspended(major1, minor1);
|
||||
@@ -484,7 +500,7 @@ static int _ignore_unusable_thins(struct device *dev)
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!params || sscanf(params, "%d:%d", &major, &minor) != 2) {
|
||||
log_error("Failed to get thin-pool major:minor for thin device %d:%d.",
|
||||
log_warn("WARNING: Cannot get thin-pool major:minor for thin device %d:%d.",
|
||||
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
goto out;
|
||||
}
|
||||
@@ -514,6 +530,47 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _ignore_invalid_snapshot(const char *params)
|
||||
{
|
||||
struct dm_status_snapshot *s;
|
||||
struct dm_pool *mem;
|
||||
int r = 0;
|
||||
|
||||
if (!(mem = dm_pool_create("invalid snapshots", 128)))
|
||||
return_0;
|
||||
|
||||
if (!dm_get_status_snapshot(mem, params, &s))
|
||||
stack;
|
||||
else
|
||||
r = s->invalid;
|
||||
|
||||
dm_pool_destroy(mem);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _ignore_frozen_raid(struct device *dev, const char *params)
|
||||
{
|
||||
struct dm_status_raid *s;
|
||||
struct dm_pool *mem;
|
||||
int r = 0;
|
||||
|
||||
if (!(mem = dm_pool_create("frozen raid", 128)))
|
||||
return_0;
|
||||
|
||||
if (!dm_get_status_raid(mem, params, &s))
|
||||
stack;
|
||||
else if (s->sync_action && !strcmp(s->sync_action, "frozen")) {
|
||||
log_warn("WARNING: %s frozen raid device (%d:%d) needs inspection.",
|
||||
dev_name(dev), (int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
r = 1;
|
||||
}
|
||||
|
||||
dm_pool_destroy(mem);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_is_usable
|
||||
* @dev
|
||||
@@ -583,12 +640,26 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
}
|
||||
}
|
||||
|
||||
if (check.check_reserved && uuid &&
|
||||
(!strncmp(uuid, CRYPT_TEMP, sizeof(CRYPT_TEMP) - 1) ||
|
||||
!strncmp(uuid, STRATIS, sizeof(STRATIS) - 1))) {
|
||||
/* Skip private crypto devices */
|
||||
log_debug_activation("%s: Reserved uuid %s on %s device %s not usable.",
|
||||
dev_name(dev), uuid,
|
||||
uuid[0] == 'C' ? "crypto" : "stratis",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME Also check for mpath no paths */
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (check.check_blocked && target_type && !strcmp(target_type, TARGET_NAME_MIRROR)) {
|
||||
if (!target_type)
|
||||
continue;
|
||||
|
||||
if (check.check_blocked && !strcmp(target_type, TARGET_NAME_MIRROR)) {
|
||||
if (ignore_lvm_mirrors()) {
|
||||
log_debug_activation("%s: Scanning mirror devices is disabled.", dev_name(dev));
|
||||
goto out;
|
||||
@@ -622,21 +693,33 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
* correctly, not just snapshots but any cobimnation possible
|
||||
* in a stack - use proper dm tree to check this instead.
|
||||
*/
|
||||
if (check.check_suspended && target_type &&
|
||||
if (check.check_suspended &&
|
||||
(!strcmp(target_type, TARGET_NAME_SNAPSHOT) || !strcmp(target_type, TARGET_NAME_SNAPSHOT_ORIGIN)) &&
|
||||
_ignore_suspended_snapshot_component(dev)) {
|
||||
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strcmp(target_type, TARGET_NAME_SNAPSHOT) &&
|
||||
_ignore_invalid_snapshot(params)) {
|
||||
log_debug_activation("%s: Invalid %s device %s not usable.", dev_name(dev), target_type, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strncmp(target_type, TARGET_NAME_RAID, 4) && _ignore_frozen_raid(dev, params)) {
|
||||
log_debug_activation("%s: Frozen %s device %s not usable.",
|
||||
dev_name(dev), target_type, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* TODO: extend check struct ? */
|
||||
if (target_type && !strcmp(target_type, TARGET_NAME_THIN) &&
|
||||
if (!strcmp(target_type, TARGET_NAME_THIN) &&
|
||||
!_ignore_unusable_thins(dev)) {
|
||||
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target_type && strcmp(target_type, TARGET_NAME_ERROR))
|
||||
if (strcmp(target_type, TARGET_NAME_ERROR))
|
||||
only_error_target = 0;
|
||||
} while (next);
|
||||
|
||||
@@ -1590,7 +1673,8 @@ int dev_manager_mknodes(const struct logical_volume *lv)
|
||||
return_0;
|
||||
|
||||
if (dminfo.exists) {
|
||||
if (_lv_has_mknode(lv))
|
||||
/* read-only component LV is also made visible */
|
||||
if (_lv_has_mknode(lv) || (dminfo.read_only && lv_is_component(lv)))
|
||||
r = _dev_manager_lv_mknodes(lv);
|
||||
} else
|
||||
r = _dev_manager_lv_rmnodes(lv);
|
||||
@@ -1652,7 +1736,8 @@ static int _check_udev_fallback(struct cmd_context *cmd)
|
||||
#endif /* UDEV_SYNC_SUPPORT */
|
||||
|
||||
static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
const char *layer, int noscan, int temporary)
|
||||
const char *layer, int noscan, int temporary,
|
||||
int visible_component)
|
||||
{
|
||||
uint16_t udev_flags = 0;
|
||||
|
||||
@@ -1668,7 +1753,7 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_vol
|
||||
* If not, create just the /dev/mapper content.
|
||||
*/
|
||||
/* FIXME: add target's method for this */
|
||||
if (lv_is_new_thin_pool(lv))
|
||||
if (lv_is_new_thin_pool(lv) || visible_component)
|
||||
/* New thin-pool is regular LV with -tpool UUID suffix. */
|
||||
udev_flags |= DM_UDEV_DISABLE_DISK_RULES_FLAG |
|
||||
DM_UDEV_DISABLE_OTHER_RULES_FLAG;
|
||||
@@ -1717,6 +1802,114 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_vol
|
||||
return udev_flags;
|
||||
}
|
||||
|
||||
static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
const struct logical_volume *lv, int origin_only);
|
||||
|
||||
static int _check_holder(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
const struct logical_volume *lv, uint32_t major,
|
||||
const char *d_name)
|
||||
{
|
||||
const char *default_uuid_prefix = dm_uuid_prefix();
|
||||
const size_t default_uuid_prefix_len = strlen(default_uuid_prefix);
|
||||
const char *name;
|
||||
const char *uuid;
|
||||
struct dm_info info;
|
||||
struct dm_task *dmt;
|
||||
struct logical_volume *lv_det;
|
||||
union lvid id;
|
||||
int dev, r = 0;
|
||||
|
||||
errno = 0;
|
||||
dev = strtoll(d_name + 3, NULL, 10);
|
||||
if (errno) {
|
||||
log_error("Failed to parse dm device minor number from %s.", d_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dmt = _setup_task_run(DM_DEVICE_INFO, &info, NULL, NULL, NULL,
|
||||
major, dev, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (info.exists) {
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
name = dm_task_get_name(dmt);
|
||||
|
||||
log_debug_activation("Checking holder of %s %s (" FMTu32 ":" FMTu32 ") %s.",
|
||||
display_lvname(lv), uuid, info.major, info.minor,
|
||||
name);
|
||||
|
||||
/* Skip common uuid prefix */
|
||||
if (!strncmp(default_uuid_prefix, uuid, default_uuid_prefix_len))
|
||||
uuid += default_uuid_prefix_len;
|
||||
|
||||
if (!strncmp(uuid, (char*)&lv->vg->id, sizeof(lv->vg->id)) &&
|
||||
!dm_tree_find_node_by_uuid(dtree, uuid)) {
|
||||
dm_strncpy((char*)&id, uuid, 2 * sizeof(struct id) + 1);
|
||||
|
||||
/* If UUID is not yet in dtree, look for matching LV */
|
||||
if (!(lv_det = find_lv_in_vg_by_lvid(lv->vg, &id))) {
|
||||
log_error("Cannot find holder with device name %s in VG %s.",
|
||||
name, lv->vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv_det))
|
||||
lv_det = origin_from_cow(lv_det);
|
||||
log_debug_activation("Found holder %s of %s.",
|
||||
display_lvname(lv_det),
|
||||
display_lvname(lv));
|
||||
if (!_add_lv_to_dtree(dm, dtree, lv_det, 0))
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add exiting devices which holds given LV device open.
|
||||
* This is used in case when metadata already do not contain information
|
||||
* i.e. PVMOVE is being finished and final table is going to be resumed.
|
||||
*/
|
||||
static int _add_holders_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
const struct logical_volume *lv, struct dm_info *info)
|
||||
{
|
||||
const char *sysfs_dir = dm_sysfs_dir();
|
||||
char sysfs_path[PATH_MAX];
|
||||
struct dirent *dirent;
|
||||
DIR *d;
|
||||
int r = 0;
|
||||
|
||||
/* Sysfs path of holders */
|
||||
if (dm_snprintf(sysfs_path, sizeof(sysfs_path), "%sblock/dm-" FMTu32
|
||||
"/holders", sysfs_dir, info->minor) < 0) {
|
||||
log_error("sysfs_path dm_snprintf failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(d = opendir(sysfs_path))) {
|
||||
log_sys_error("opendir", sysfs_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(d)))
|
||||
/* Expects minor is added to 'dm-' prefix */
|
||||
if (!strncmp(dirent->d_name, "dm-", 3) &&
|
||||
!_check_holder(dm, dtree, lv, info->major, dirent->d_name))
|
||||
goto_out;
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (closedir(d))
|
||||
log_sys_debug("closedir", "holders");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
const struct logical_volume *lv, const char *layer)
|
||||
{
|
||||
@@ -1758,7 +1951,8 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
}
|
||||
|
||||
if (info.exists && !dm_tree_add_dev_with_udev_flags(dtree, info.major, info.minor,
|
||||
_get_udev_flags(dm, lv, layer, 0, 0))) {
|
||||
_get_udev_flags(dm, lv, layer,
|
||||
0, 0, 0))) {
|
||||
log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree.",
|
||||
info.major, info.minor);
|
||||
return 0;
|
||||
@@ -1771,83 +1965,14 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add replicator devices
|
||||
*
|
||||
* Using _add_dev_to_dtree() directly instead of _add_lv_to_dtree()
|
||||
* to avoid extra checks with extensions.
|
||||
*/
|
||||
static int _add_partial_replicator_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *rlv = first_seg(lv)->replicator;
|
||||
struct replicator_device *rdev;
|
||||
struct replicator_site *rsite;
|
||||
struct dm_tree_node *rep_node, *rdev_node;
|
||||
const char *uuid;
|
||||
|
||||
if (!lv_is_active_replicator_dev(lv)) {
|
||||
if (!_add_dev_to_dtree(dm, dtree, lv->rdevice->lv,
|
||||
NULL))
|
||||
/*
|
||||
* Find holders of existing active LV where name starts with 'pvmove',
|
||||
* but it's not anymore PVMOVE LV and also it's not PVMOVE _mimage
|
||||
*/
|
||||
if (info.exists && !lv_is_pvmove(lv) &&
|
||||
!strchr(lv->name, '_') && !strncmp(lv->name, "pvmove", 6))
|
||||
if (!_add_holders_to_dtree(dm, dtree, lv, &info))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add _rlog and replicator device */
|
||||
if (!_add_dev_to_dtree(dm, dtree, first_seg(rlv)->rlog_lv, NULL))
|
||||
return_0;
|
||||
|
||||
if (!_add_dev_to_dtree(dm, dtree, rlv, NULL))
|
||||
return_0;
|
||||
|
||||
if (!(uuid = build_dm_uuid(dm->mem, rlv, NULL)))
|
||||
return_0;
|
||||
|
||||
rep_node = dm_tree_find_node_by_uuid(dtree, uuid);
|
||||
|
||||
/* Add all related devices for replicator */
|
||||
dm_list_iterate_items(rsite, &rlv->rsites)
|
||||
dm_list_iterate_items(rdev, &rsite->rdevices) {
|
||||
if (rsite->state == REPLICATOR_STATE_ACTIVE) {
|
||||
/* Add _rimage LV */
|
||||
if (!_add_dev_to_dtree(dm, dtree, rdev->lv, NULL))
|
||||
return_0;
|
||||
|
||||
/* Add replicator-dev LV, except of the already added one */
|
||||
if ((lv != rdev->replicator_dev->lv) &&
|
||||
!_add_dev_to_dtree(dm, dtree,
|
||||
rdev->replicator_dev->lv, NULL))
|
||||
return_0;
|
||||
|
||||
/* If replicator exists - try connect existing heads */
|
||||
if (rep_node) {
|
||||
uuid = build_dm_uuid(dm->mem,
|
||||
rdev->replicator_dev->lv,
|
||||
NULL);
|
||||
if (!uuid)
|
||||
return_0;
|
||||
|
||||
rdev_node = dm_tree_find_node_by_uuid(dtree, uuid);
|
||||
if (rdev_node)
|
||||
dm_tree_node_set_presuspend_node(rdev_node,
|
||||
rep_node);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rdev->rsite->vg_name)
|
||||
continue;
|
||||
|
||||
if (!_add_dev_to_dtree(dm, dtree, rdev->lv, NULL))
|
||||
return_0;
|
||||
|
||||
if (rdev->slog &&
|
||||
!_add_dev_to_dtree(dm, dtree, rdev->slog, NULL))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1859,13 +1984,60 @@ struct pool_cb_data {
|
||||
int skip_zero; /* to skip zeroed device header (check first 64B) */
|
||||
int exec; /* which binary to call */
|
||||
int opts;
|
||||
struct {
|
||||
unsigned maj;
|
||||
unsigned min;
|
||||
unsigned patch;
|
||||
} version;
|
||||
const char *global;
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple version of check function calling 'tool -V'
|
||||
*
|
||||
* Returns 1 if the tool's version is equal or better to given.
|
||||
* Otherwise it returns 0.
|
||||
*/
|
||||
static int _check_tool_version(struct cmd_context *cmd, const char *tool,
|
||||
unsigned maj, unsigned min, unsigned patch)
|
||||
{
|
||||
const char *argv[] = { tool, "-V", NULL };
|
||||
struct pipe_data pdata;
|
||||
FILE *f;
|
||||
char buf[128] = { 0 };
|
||||
char *nl;
|
||||
unsigned v_maj, v_min, v_patch;
|
||||
int ret = 0;
|
||||
|
||||
if (!(f = pipe_open(cmd, argv, 0, &pdata))) {
|
||||
log_warn("WARNING: Cannot read output from %s.", argv[0]);
|
||||
} else {
|
||||
if (fgets(buf, sizeof(buf) - 1, f) &&
|
||||
(sscanf(buf, "%u.%u.%u", &v_maj, &v_min, &v_patch) == 3)) {
|
||||
if ((v_maj > maj) ||
|
||||
((v_maj == maj) &&
|
||||
((v_min > min) ||
|
||||
(v_min == min && v_patch >= patch))))
|
||||
ret = 1;
|
||||
|
||||
if ((nl = strchr(buf, '\n')))
|
||||
nl[0] = 0; /* cut newline away */
|
||||
|
||||
log_verbose("Found version of %s %s is %s then requested %u.%u.%u.",
|
||||
argv[0], buf, ret ? "better" : "older", maj, min, patch);
|
||||
} else
|
||||
log_warn("WARNING: Cannot parse output '%s' from %s.", buf, argv[0]);
|
||||
|
||||
(void) pipe_close(&pdata);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _pool_callback(struct dm_tree_node *node,
|
||||
dm_node_callback_t type, void *cb_data)
|
||||
{
|
||||
int ret, status, fd;
|
||||
int ret, status = 0, fd;
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const struct pool_cb_data *data = cb_data;
|
||||
@@ -1873,12 +2045,45 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
const struct logical_volume *mlv = first_seg(pool_lv)->metadata_lv;
|
||||
long buf[64 / sizeof(long)]; /* buffer for short disk header (64B) */
|
||||
int args = 0;
|
||||
char *mpath;
|
||||
const char *argv[19] = { /* Max supported 15 args */
|
||||
find_config_tree_str_allow_empty(pool_lv->vg->cmd, data->exec, NULL) /* argv[0] */
|
||||
find_config_tree_str_allow_empty(pool_lv->vg->cmd, data->exec, NULL)
|
||||
};
|
||||
|
||||
if (!*argv[0])
|
||||
return 1; /* Checking disabled */
|
||||
if (!*argv[0]) /* *_check tool is unconfigured/disabled with "" setting */
|
||||
return 1;
|
||||
|
||||
if (!(mpath = lv_dmpath_dup(data->dm->mem, mlv))) {
|
||||
log_error("Failed to build device path for checking pool metadata %s.",
|
||||
display_lvname(mlv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->skip_zero) {
|
||||
if ((fd = open(mpath, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", mpath);
|
||||
return 0;
|
||||
}
|
||||
/* let's assume there is no problem to read 64 bytes */
|
||||
if (read(fd, buf, sizeof(buf)) < (int)sizeof(buf)) {
|
||||
log_sys_error("read", mpath);
|
||||
if (close(fd))
|
||||
log_sys_error("close", mpath);
|
||||
return 0;
|
||||
}
|
||||
for (ret = 0; ret < (int) DM_ARRAY_SIZE(buf); ++ret)
|
||||
if (buf[ret])
|
||||
break;
|
||||
|
||||
if (close(fd))
|
||||
log_sys_error("close", mpath);
|
||||
|
||||
if (ret == (int) DM_ARRAY_SIZE(buf)) {
|
||||
log_debug_activation("Metadata checking skipped, detected empty disk header on %s.",
|
||||
mpath);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
|
||||
@@ -1900,39 +2105,23 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(argv[++args] = lv_dmpath_dup(data->dm->mem, mlv))) {
|
||||
log_error("Failed to build pool metadata path.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->skip_zero) {
|
||||
if ((fd = open(argv[args], O_RDONLY)) < 0) {
|
||||
log_sys_error("open", argv[args]);
|
||||
return 0;
|
||||
}
|
||||
/* let's assume there is no problem to read 64 bytes */
|
||||
if (read(fd, buf, sizeof(buf)) < (int)sizeof(buf)) {
|
||||
log_sys_error("read", argv[args]);
|
||||
if (close(fd))
|
||||
log_sys_error("close", argv[args]);
|
||||
return 0;
|
||||
}
|
||||
for (ret = 0; ret < (int) DM_ARRAY_SIZE(buf); ++ret)
|
||||
if (buf[ret])
|
||||
break;
|
||||
|
||||
if (close(fd))
|
||||
log_sys_error("close", argv[args]);
|
||||
|
||||
if (ret == (int) DM_ARRAY_SIZE(buf)) {
|
||||
log_debug_activation("%s skipped, detect empty disk header on %s.",
|
||||
argv[0], argv[args]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
argv[++args] = mpath;
|
||||
|
||||
if (!(ret = exec_cmd(pool_lv->vg->cmd, (const char * const *)argv,
|
||||
&status, 0))) {
|
||||
if (status == ENOENT) {
|
||||
log_warn("WARNING: Check is skipped, please install recommended missing binary %s!",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((data->version.maj || data->version.min || data->version.patch) &&
|
||||
!_check_tool_version(pool_lv->vg->cmd, argv[0],
|
||||
data->version.maj, data->version.min, data->version.patch)) {
|
||||
log_warn("WARNING: Check is skipped, please upgrade installed version of %s!",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
switch (type) {
|
||||
case DM_NODE_CALLBACK_PRELOADED:
|
||||
log_err_once("Check of pool %s failed (status:%d). "
|
||||
@@ -1990,6 +2179,10 @@ static int _pool_register_callback(struct dev_manager *dm,
|
||||
data->exec = global_cache_check_executable_CFG;
|
||||
data->opts = global_cache_check_options_CFG;
|
||||
data->global = "cache";
|
||||
if (first_seg(first_seg(lv)->pool_lv)->cache_metadata_format > 1) {
|
||||
data->version.maj = 0;
|
||||
data->version.min = 7;
|
||||
}
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
|
||||
return 0;
|
||||
@@ -2017,6 +2210,10 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
struct lv_segment *seg;
|
||||
struct dm_tree_node *node;
|
||||
const char *uuid;
|
||||
const struct logical_volume *plv;
|
||||
|
||||
if (lv_is_pvmove(lv) && (dm->track_pvmove_deps == 2))
|
||||
return 1; /* Avoid rechecking of already seen pvmove LV */
|
||||
|
||||
if (lv_is_cache_pool(lv)) {
|
||||
if (!dm_list_empty(&lv->segs_using_this_lv)) {
|
||||
@@ -2137,11 +2334,14 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return_0;
|
||||
|
||||
/* Add any LVs referencing a PVMOVE LV unless told not to. */
|
||||
if (dm->track_pvmove_deps && lv_is_pvmove(lv)) {
|
||||
dm->track_pvmove_deps = 0;
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv)
|
||||
if (!_add_lv_to_dtree(dm, dtree, sl->seg->lv, origin_only))
|
||||
if ((dm->track_pvmove_deps == 1) && lv_is_pvmove(lv)) {
|
||||
dm->track_pvmove_deps = 2; /* Mark as already seen */
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
/* If LV is snapshot COW - whole snapshot needs reload */
|
||||
plv = lv_is_cow(sl->seg->lv) ? origin_from_cow(sl->seg->lv) : sl->seg->lv;
|
||||
if (!_add_lv_to_dtree(dm, dtree, plv, 0))
|
||||
return_0;
|
||||
}
|
||||
dm->track_pvmove_deps = 1;
|
||||
}
|
||||
|
||||
@@ -2156,11 +2356,6 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
}
|
||||
}
|
||||
|
||||
/* Adding LV head of replicator adds all other related devs */
|
||||
if (lv_is_replicator_dev(lv) &&
|
||||
!_add_partial_replicator_to_dtree(dm, dtree, lv))
|
||||
return_0;
|
||||
|
||||
/* Add any LVs used by segments in this LV */
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->external_lv && dm->track_external_lv_deps &&
|
||||
@@ -2524,64 +2719,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
struct lv_activate_opts *laopts,
|
||||
const char *layer);
|
||||
|
||||
/* Add all replicators' LVs */
|
||||
static int _add_replicator_dev_target_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
struct lv_segment *seg,
|
||||
struct lv_activate_opts *laopts)
|
||||
{
|
||||
struct replicator_device *rdev;
|
||||
struct replicator_site *rsite;
|
||||
|
||||
/* For inactive replicator add linear mapping */
|
||||
if (!lv_is_active_replicator_dev(seg->lv)) {
|
||||
if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->rdevice->lv, laopts, NULL))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add rlog and replicator nodes */
|
||||
if (!seg->replicator ||
|
||||
!first_seg(seg->replicator)->rlog_lv ||
|
||||
!_add_new_lv_to_dtree(dm, dtree,
|
||||
first_seg(seg->replicator)->rlog_lv,
|
||||
laopts, NULL) ||
|
||||
!_add_new_lv_to_dtree(dm, dtree, seg->replicator, laopts, NULL))
|
||||
return_0;
|
||||
|
||||
/* Activation of one replicator_dev node activates all other nodes */
|
||||
dm_list_iterate_items(rsite, &seg->replicator->rsites) {
|
||||
dm_list_iterate_items(rdev, &rsite->rdevices) {
|
||||
if (rdev->lv &&
|
||||
!_add_new_lv_to_dtree(dm, dtree, rdev->lv,
|
||||
laopts, NULL))
|
||||
return_0;
|
||||
|
||||
if (rdev->slog &&
|
||||
!_add_new_lv_to_dtree(dm, dtree, rdev->slog,
|
||||
laopts, NULL))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
/* Add remaining replicator-dev nodes in the second loop
|
||||
* to avoid multiple retries for inserting all elements */
|
||||
dm_list_iterate_items(rsite, &seg->replicator->rsites) {
|
||||
if (rsite->state != REPLICATOR_STATE_ACTIVE)
|
||||
continue;
|
||||
dm_list_iterate_items(rdev, &rsite->rdevices) {
|
||||
if (rdev->replicator_dev->lv == seg->lv)
|
||||
continue;
|
||||
if (!rdev->replicator_dev->lv ||
|
||||
!_add_new_lv_to_dtree(dm, dtree,
|
||||
rdev->replicator_dev->lv,
|
||||
laopts, NULL))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_new_external_lv_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
struct logical_volume *external_lv,
|
||||
@@ -2682,11 +2819,6 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
lv_layer(seg->pool_lv)))
|
||||
return_0;
|
||||
|
||||
if (seg_is_replicator_dev(seg)) {
|
||||
if (!_add_replicator_dev_target_to_dtree(dm, dtree, seg, laopts))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* Add any LVs used by this segment */
|
||||
for (s = 0; s < seg->area_count; ++s) {
|
||||
if ((seg_type(seg, s) == AREA_LV) &&
|
||||
@@ -2824,6 +2956,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
}
|
||||
|
||||
lvlayer->lv = lv;
|
||||
lvlayer->visible_component = (laopts->component_lv == lv) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Add LV to dtree.
|
||||
@@ -2837,10 +2970,11 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
if (!(dnode = dm_tree_add_new_dev_with_udev_flags(dtree, name, dlid,
|
||||
layer ? UINT32_C(0) : (uint32_t) lv->major,
|
||||
layer ? UINT32_C(0) : (uint32_t) lv->minor,
|
||||
read_only_lv(lv, laopts),
|
||||
read_only_lv(lv, laopts, layer),
|
||||
((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
|
||||
lvlayer,
|
||||
_get_udev_flags(dm, lv, layer, laopts->noscan, laopts->temporary))))
|
||||
_get_udev_flags(dm, lv, layer, laopts->noscan, laopts->temporary,
|
||||
lvlayer->visible_component))))
|
||||
return_0;
|
||||
|
||||
/* Store existing name so we can do rename later */
|
||||
@@ -2984,7 +3118,7 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
if (_lv_has_mknode(lvlayer->lv)) {
|
||||
if (_lv_has_mknode(lvlayer->lv) || lvlayer->visible_component) {
|
||||
if (!_dev_manager_lv_mknodes(lvlayer->lv))
|
||||
r = 0;
|
||||
continue;
|
||||
@@ -3156,8 +3290,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
|
||||
goto_out;
|
||||
|
||||
//if (action == PRELOAD) { log_debug("SLEEP"); sleep(7); }
|
||||
|
||||
if ((dm_tree_node_size_changed(root) < 0))
|
||||
dm->flush_required = 1;
|
||||
/* Currently keep the code require flush for any
|
||||
|
||||
@@ -27,7 +27,7 @@ struct dm_info;
|
||||
struct device;
|
||||
struct lv_seg_status;
|
||||
|
||||
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts);
|
||||
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer);
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
|
||||
@@ -441,7 +441,7 @@ static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
|
||||
const char *lv_name, const char *dev, const char *old_lv_name,
|
||||
int check_udev)
|
||||
{
|
||||
if (critical_section()) {
|
||||
if (prioritized_section()) {
|
||||
if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
|
||||
old_lv_name, check_udev))
|
||||
return_0;
|
||||
@@ -487,7 +487,7 @@ int fs_rename_lv(const struct logical_volume *lv, const char *dev,
|
||||
|
||||
void fs_unlock(void)
|
||||
{
|
||||
if (!critical_section()) {
|
||||
if (!prioritized_section()) {
|
||||
log_debug_activation("Syncing device names");
|
||||
/* Wait for all processed udev devices */
|
||||
if (!dm_udev_wait(_fs_cookie))
|
||||
|
||||
1497
lib/cache/lvmcache.c
vendored
1497
lib/cache/lvmcache.c
vendored
File diff suppressed because it is too large
Load Diff
48
lib/cache/lvmcache.h
vendored
48
lib/cache/lvmcache.h
vendored
@@ -59,21 +59,17 @@ struct lvmcache_vgsummary {
|
||||
const char *lock_type;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
int zero_offset;
|
||||
int seqno;
|
||||
};
|
||||
|
||||
int lvmcache_init(void);
|
||||
int lvmcache_init(struct cmd_context *cmd);
|
||||
void lvmcache_allow_reads_with_lvmetad(void);
|
||||
|
||||
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
|
||||
|
||||
/*
|
||||
* lvmcache_label_scan() will scan labels the first time it's
|
||||
* called, but not on subsequent calls, unless
|
||||
* lvmcache_force_next_label_scan() is called first
|
||||
* to force the next lvmcache_label_scan() to scan again.
|
||||
*/
|
||||
void lvmcache_force_next_label_scan(void);
|
||||
int lvmcache_label_scan(struct cmd_context *cmd);
|
||||
int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid, int open_rw);
|
||||
|
||||
/* Add/delete a device */
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
@@ -82,6 +78,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
uint32_t vgstatus);
|
||||
int lvmcache_add_orphan_vginfo(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,
|
||||
@@ -105,10 +102,8 @@ struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
|
||||
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
|
||||
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
|
||||
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
|
||||
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
|
||||
unsigned *scan_done_once, uint64_t *label_sector);
|
||||
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
|
||||
const char *devname);
|
||||
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
|
||||
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname);
|
||||
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
|
||||
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
|
||||
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
|
||||
@@ -134,20 +129,16 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
|
||||
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid);
|
||||
|
||||
/* Returns cached volume group metadata. */
|
||||
struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid, unsigned precommitted);
|
||||
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
|
||||
void lvmcache_commit_metadata(const char *vgname);
|
||||
|
||||
int lvmcache_pvid_is_locked(const char *pvid);
|
||||
int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid,
|
||||
const char *id, int id_len);
|
||||
int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
|
||||
int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
|
||||
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
|
||||
struct physical_volume *pv,
|
||||
int scan_label_only);
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv);
|
||||
int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
|
||||
void lvmcache_del_mdas(struct lvmcache_info *info);
|
||||
void lvmcache_del_das(struct lvmcache_info *info);
|
||||
@@ -164,6 +155,8 @@ uint32_t lvmcache_ext_flags(struct lvmcache_info *info);
|
||||
|
||||
const struct format_type *lvmcache_fmt(struct lvmcache_info *info);
|
||||
struct label *lvmcache_get_label(struct lvmcache_info *info);
|
||||
struct label *lvmcache_get_dev_label(struct device *dev);
|
||||
int lvmcache_has_dev_info(struct device *dev);
|
||||
|
||||
void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv,
|
||||
const struct format_type *fmt);
|
||||
@@ -187,7 +180,6 @@ int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo,
|
||||
uint64_t lvmcache_device_size(struct lvmcache_info *info);
|
||||
void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size);
|
||||
struct device *lvmcache_device(struct lvmcache_info *info);
|
||||
void lvmcache_make_valid(struct lvmcache_info *info);
|
||||
int lvmcache_is_orphan(struct lvmcache_info *info);
|
||||
int lvmcache_uncertain_ownership(struct lvmcache_info *info);
|
||||
unsigned lvmcache_mda_count(struct lvmcache_info *info);
|
||||
@@ -196,6 +188,8 @@ uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
|
||||
|
||||
int lvmcache_found_duplicate_pvs(void);
|
||||
|
||||
void lvmcache_pvscan_duplicate_check(struct cmd_context *cmd);
|
||||
|
||||
int lvmcache_get_unused_duplicate_devs(struct cmd_context *cmd, struct dm_list *head);
|
||||
|
||||
int vg_has_duplicate_pvs(struct volume_group *vg);
|
||||
@@ -215,4 +209,20 @@ void lvmcache_remove_unchosen_duplicate(struct device *dev);
|
||||
|
||||
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
|
||||
|
||||
int lvmcache_get_vg_devs(struct cmd_context *cmd,
|
||||
struct lvmcache_vginfo *vginfo,
|
||||
struct dm_list *devs);
|
||||
void lvmcache_set_independent_location(const char *vgname);
|
||||
|
||||
int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
|
||||
/*
|
||||
* These are clvmd-specific functions and are not related to lvmcache.
|
||||
* FIXME: rename these with a clvm_ prefix in place of lvmcache_
|
||||
*/
|
||||
void lvmcache_save_vg(struct volume_group *vg, int precommitted);
|
||||
struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted);
|
||||
struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid);
|
||||
void lvmcache_drop_saved_vgid(const char *vgid);
|
||||
|
||||
#endif
|
||||
|
||||
547
lib/cache/lvmetad.c
vendored
547
lib/cache/lvmetad.c
vendored
@@ -37,9 +37,7 @@ static const char *_lvmetad_socket = NULL;
|
||||
static struct cmd_context *_lvmetad_cmd = NULL;
|
||||
static int64_t _lvmetad_update_timeout;
|
||||
|
||||
static int _found_lvm1_metadata = 0;
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg, const char *vgid, struct format_type *fmt);
|
||||
|
||||
static uint64_t _monotonic_seconds(void)
|
||||
{
|
||||
@@ -551,6 +549,7 @@ static int _token_update(int *replaced_update)
|
||||
daemon_reply reply;
|
||||
const char *token_expected;
|
||||
const char *prev_token;
|
||||
const char *reply_str;
|
||||
int update_pid;
|
||||
int ending_our_update;
|
||||
|
||||
@@ -567,13 +566,14 @@ static int _token_update(int *replaced_update)
|
||||
}
|
||||
|
||||
update_pid = (int)daemon_reply_int(reply, "update_pid", 0);
|
||||
reply_str = daemon_reply_str(reply, "response", "");
|
||||
|
||||
/*
|
||||
* A mismatch can only happen when this command attempts to set the
|
||||
* token to filter:<hash> at the end of its update, but the update has
|
||||
* been preempted in lvmetad by a new one (from update_pid).
|
||||
*/
|
||||
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
|
||||
if (!strcmp(reply_str, "token_mismatch")) {
|
||||
token_expected = daemon_reply_str(reply, "expected", "");
|
||||
|
||||
ending_our_update = strcmp(_lvmetad_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
|
||||
@@ -599,7 +599,7 @@ static int _token_update(int *replaced_update)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
if (strcmp(reply_str, "OK")) {
|
||||
log_error("Failed response from lvmetad for token update.");
|
||||
daemon_reply_destroy(reply);
|
||||
return 0;
|
||||
@@ -626,6 +626,7 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
|
||||
{
|
||||
const char *token_expected;
|
||||
const char *action;
|
||||
const char *reply_str;
|
||||
int action_modifies = 0;
|
||||
int daemon_in_update;
|
||||
int we_are_in_update;
|
||||
@@ -670,8 +671,8 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
|
||||
/*
|
||||
* Errors related to token mismatch.
|
||||
*/
|
||||
|
||||
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
|
||||
reply_str = daemon_reply_str(reply, "response", "");
|
||||
if (!strcmp(reply_str, "token_mismatch")) {
|
||||
|
||||
token_expected = daemon_reply_str(reply, "expected", "");
|
||||
update_pid = (int)daemon_reply_int(reply, "update_pid", 0);
|
||||
@@ -769,14 +770,14 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
|
||||
*/
|
||||
|
||||
/* All OK? */
|
||||
if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
if (!strcmp(reply_str, "OK")) {
|
||||
if (found)
|
||||
*found = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Unknown device permitted? */
|
||||
if (found && !strcmp(daemon_reply_str(reply, "response", ""), "unknown")) {
|
||||
if (found && !strcmp(reply_str, "unknown")) {
|
||||
log_very_verbose("Request to %s %s%sin lvmetad did not find any matching object.",
|
||||
action, object, *object ? " " : "");
|
||||
*found = 0;
|
||||
@@ -784,7 +785,7 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
|
||||
}
|
||||
|
||||
/* Multiple VGs with the same name were found. */
|
||||
if (found && !strcmp(daemon_reply_str(reply, "response", ""), "multiple")) {
|
||||
if (found && !strcmp(reply_str, "multiple")) {
|
||||
log_very_verbose("Request to %s %s%sin lvmetad found multiple matching objects.",
|
||||
action, object, *object ? " " : "");
|
||||
if (found)
|
||||
@@ -1090,14 +1091,17 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
* invalidated the cached vg.
|
||||
*/
|
||||
if (rescan) {
|
||||
if (!(vg2 = lvmetad_pvscan_vg(cmd, vg))) {
|
||||
if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg, vgid, fmt))) {
|
||||
log_debug_lvmetad("VG %s from lvmetad not found during rescan.", vgname);
|
||||
fid = NULL;
|
||||
release_vg(vg);
|
||||
vg = NULL;
|
||||
goto out;
|
||||
}
|
||||
fid->ref_count++;
|
||||
release_vg(vg);
|
||||
fid->ref_count--;
|
||||
fmt->ops->destroy_instance(fid);
|
||||
vg = vg2;
|
||||
fid = vg2->fid;
|
||||
}
|
||||
@@ -1105,14 +1109,14 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
goto_out; /* FIXME: use an error path that disables lvmetad */
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
goto_out; /* FIXME: use an error path that disables lvmetad */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1281,7 +1285,7 @@ int lvmetad_vg_update_finish(struct volume_group *vg)
|
||||
if (pvl->pv->dev && !lvmetad_pv_found(vg->cmd, &pvl->pv->id, pvl->pv->dev,
|
||||
vgu->fid ? vgu->fid->fmt : pvl->pv->fmt,
|
||||
pvl->pv->label_sector, NULL, NULL, NULL))
|
||||
return 0;
|
||||
return_0;
|
||||
}
|
||||
|
||||
vg->lvmetad_update_pending = 0;
|
||||
@@ -1516,7 +1520,7 @@ int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct _extract_dl_baton {
|
||||
struct extract_dl_baton {
|
||||
int i;
|
||||
struct dm_config_tree *cft;
|
||||
struct dm_config_node *pre_sib;
|
||||
@@ -1524,7 +1528,7 @@ struct _extract_dl_baton {
|
||||
|
||||
static int _extract_mda(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct _extract_dl_baton *b = baton;
|
||||
struct extract_dl_baton *b = baton;
|
||||
struct dm_config_node *cn;
|
||||
char id[32];
|
||||
|
||||
@@ -1545,7 +1549,7 @@ static int _extract_mda(struct metadata_area *mda, void *baton)
|
||||
|
||||
static int _extract_disk_location(const char *name, struct disk_locn *dl, void *baton)
|
||||
{
|
||||
struct _extract_dl_baton *b = baton;
|
||||
struct extract_dl_baton *b = baton;
|
||||
struct dm_config_node *cn;
|
||||
char id[32];
|
||||
|
||||
@@ -1580,7 +1584,7 @@ static int _extract_ba(struct disk_locn *ba, void *baton)
|
||||
static int _extract_mdas(struct lvmcache_info *info, struct dm_config_tree *cft,
|
||||
struct dm_config_node *pre_sib)
|
||||
{
|
||||
struct _extract_dl_baton baton = { .cft = cft };
|
||||
struct extract_dl_baton baton = { .cft = cft };
|
||||
|
||||
if (!lvmcache_foreach_mda(info, &_extract_mda, &baton))
|
||||
return 0;
|
||||
@@ -1607,7 +1611,7 @@ int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct devi
|
||||
struct dm_config_tree *pvmeta, *vgmeta;
|
||||
const char *status = NULL, *vgname = NULL;
|
||||
int64_t changed = 0;
|
||||
int result;
|
||||
int result, seqno_after;
|
||||
|
||||
if (!lvmetad_used() || test_mode())
|
||||
return 1;
|
||||
@@ -1672,10 +1676,12 @@ int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct devi
|
||||
|
||||
result = _lvmetad_handle_reply(reply, "pv_found", uuid, NULL);
|
||||
|
||||
if (vg && result &&
|
||||
(daemon_reply_int(reply, "seqno_after", -1) != vg->seqno ||
|
||||
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
|
||||
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
|
||||
if (vg && result) {
|
||||
seqno_after = daemon_reply_int(reply, "seqno_after", -1);
|
||||
if ((seqno_after != (int) vg->seqno) ||
|
||||
(seqno_after != daemon_reply_int(reply, "seqno_before", -1)))
|
||||
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
|
||||
}
|
||||
|
||||
if (result && found_vgnames) {
|
||||
status = daemon_reply_str(reply, "status", NULL);
|
||||
@@ -1756,6 +1762,7 @@ int lvmetad_pv_gone_by_dev(struct device *dev)
|
||||
*/
|
||||
|
||||
struct _lvmetad_pvscan_baton {
|
||||
struct cmd_context *cmd;
|
||||
struct volume_group *vg;
|
||||
struct format_instance *fid;
|
||||
};
|
||||
@@ -1766,7 +1773,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
struct volume_group *vg;
|
||||
|
||||
if (mda_is_ignored(mda) ||
|
||||
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
|
||||
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
|
||||
return 1;
|
||||
|
||||
/* FIXME Also ensure contents match etc. */
|
||||
@@ -1778,6 +1785,33 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: handle errors and do proper comparison of metadata from each area
|
||||
* like vg_read and fall back to real vg_read from disk if there's any problem.
|
||||
*/
|
||||
|
||||
static int _lvmetad_pvscan_vg_single(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct _lvmetad_pvscan_baton *b = baton;
|
||||
struct volume_group *vg = NULL;
|
||||
|
||||
if (mda_is_ignored(mda))
|
||||
return 1;
|
||||
|
||||
if (!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
|
||||
return 1;
|
||||
|
||||
if (!b->vg)
|
||||
b->vg = vg;
|
||||
else if (vg->seqno > b->vg->seqno) {
|
||||
release_vg(b->vg);
|
||||
b->vg = vg;
|
||||
} else
|
||||
release_vg(vg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lock manager may detect that the vg cached in lvmetad is out of date,
|
||||
* due to something like an lvcreate from another host.
|
||||
@@ -1787,41 +1821,41 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
* the VG, and that PV may have been reused for another VG.
|
||||
*/
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *vgid, struct format_type *fmt)
|
||||
{
|
||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
struct label *label;
|
||||
struct volume_group *vg_ret = NULL;
|
||||
struct dm_config_tree *vgmeta_ret = NULL;
|
||||
struct dm_config_tree *vgmeta;
|
||||
struct pv_list *pvl, *pvl_new;
|
||||
struct device_list *devl, *devl_new, *devlsafe;
|
||||
struct device_list *devl, *devlsafe;
|
||||
struct dm_list pvs_scan;
|
||||
struct dm_list pvs_drop;
|
||||
struct dm_list pvs_new;
|
||||
struct lvmcache_vginfo *vginfo = NULL;
|
||||
struct lvmcache_info *info = NULL;
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
struct volume_group *save_vg;
|
||||
struct dm_config_tree *save_meta;
|
||||
struct device *save_dev = NULL;
|
||||
uint32_t save_seqno = 0;
|
||||
int missing_devs = 0;
|
||||
int check_new_pvs = 0;
|
||||
int found_new_pvs = 0;
|
||||
int retried_reads = 0;
|
||||
int found;
|
||||
|
||||
save_vg = NULL;
|
||||
save_meta = NULL;
|
||||
save_dev = NULL;
|
||||
save_seqno = 0;
|
||||
|
||||
dm_list_init(&pvs_scan);
|
||||
dm_list_init(&pvs_drop);
|
||||
dm_list_init(&pvs_new);
|
||||
|
||||
log_debug_lvmetad("Rescanning VG %s (seqno %u).", vg->name, vg->seqno);
|
||||
log_debug_lvmetad("Rescan VG %s to update lvmetad (seqno %u).", vg->name, vg->seqno);
|
||||
|
||||
/*
|
||||
* Another host may have added a PV to the VG, and some
|
||||
* commands do not always populate their lvmcache with
|
||||
* all devs from lvmetad, so they would fail to find
|
||||
* the new PV when scanning the VG. So make sure this
|
||||
* command knows about all PVs from lvmetad.
|
||||
* Make sure this command knows about all PVs from lvmetad.
|
||||
*/
|
||||
lvmcache_seed_infos_from_lvmetad(cmd);
|
||||
|
||||
@@ -1836,54 +1870,111 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
dm_list_add(&pvs_scan, &devl->list);
|
||||
}
|
||||
|
||||
scan_more:
|
||||
/*
|
||||
* Rescan labels/metadata only from devs that we previously
|
||||
* saw in the VG. If we find below that there are new PVs
|
||||
* in the VG, we'll have to rescan all devices to find which
|
||||
* device(s) are now being used.
|
||||
*/
|
||||
log_debug_lvmetad("Rescan VG %s scanning data from devs in previous metadata.", vg->name);
|
||||
|
||||
label_scan_devs(cmd, cmd->full_filter, &pvs_scan);
|
||||
|
||||
/*
|
||||
* Run the equivalent of lvmetad_pvscan_single on each dev in the VG.
|
||||
* Check if any pvs_scan entries are no longer PVs.
|
||||
* In that case, label_read/_find_label_header will have
|
||||
* found no label_header, and would have dropped the
|
||||
* info struct for the device from lvmcache. So, if
|
||||
* we look up the info struct here and don't find it,
|
||||
* we can infer it's no longer a PV.
|
||||
*
|
||||
* FIXME: we should record specific results from the
|
||||
* label_read and then check specifically for whatever
|
||||
* result means "no label was found", rather than going
|
||||
* about this indirectly via the lvmcache side effects.
|
||||
*/
|
||||
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
|
||||
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
|
||||
/* Another host removed this PV from the VG. */
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no label).",
|
||||
vg->name, dev_name(devl->dev));
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
}
|
||||
}
|
||||
|
||||
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
|
||||
fic.context.vg_ref.vg_name = vg->name;
|
||||
fic.context.vg_ref.vg_id = vgid;
|
||||
|
||||
retry_reads:
|
||||
|
||||
if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
|
||||
/* FIXME: are there only internal reasons for failures here? */
|
||||
log_error("Reading VG %s failed to create format instance.", vg->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: not sure if this is necessary */
|
||||
fid->ref_count++;
|
||||
|
||||
baton.fid = fid;
|
||||
baton.cmd = cmd;
|
||||
|
||||
/*
|
||||
* FIXME: this vg_read path does not have the ability to repair
|
||||
* any problems with the VG, e.g. VG on one dev has an older
|
||||
* seqno. When vg_read() is reworked, we need to fall back
|
||||
* to using that from here (and vg_read's from lvmetad) when
|
||||
* there is a problem. Perhaps by disabling lvmetad when a
|
||||
* VG problem is detected, causing commands to fully fall
|
||||
* back to disk, which will repair the VG. Then lvmetad can
|
||||
* be repopulated and re-enabled (possibly automatically.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Do a low level vg_read on each dev, verify the vg returned
|
||||
* from metadata on each device is for the VG being read
|
||||
* (the PV may have been removed from the VG being read and
|
||||
* added to a different one), and return this vg to the caller
|
||||
* as the current vg to use.
|
||||
*
|
||||
* The label scan above will have saved in lvmcache which
|
||||
* vg each device is used in, so we could figure that part
|
||||
* out without doing the vg_read.
|
||||
*/
|
||||
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s scanning %s.", vg->name, dev_name(devl->dev));
|
||||
|
||||
if (!label_read(devl->dev, &label, 0)) {
|
||||
/* Another host removed this PV from the VG. */
|
||||
log_debug_lvmetad("Rescan VG %s found %s was removed.", vg->name, dev_name(devl->dev));
|
||||
|
||||
if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
|
||||
lvmcache_del(info);
|
||||
log_debug_lvmetad("Rescan VG %s getting metadata from %s.",
|
||||
vg->name, dev_name(devl->dev));
|
||||
|
||||
/*
|
||||
* The info struct for this dev knows what and where
|
||||
* the mdas are for this dev (the label scan saved
|
||||
* the mda locations for this dev on the lvmcache info struct).
|
||||
*/
|
||||
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no info).",
|
||||
vg->name, dev_name(devl->dev));
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
|
||||
baton.vg = NULL;
|
||||
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
if (!baton.fid)
|
||||
return_NULL;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
log_debug_lvmetad("Ignoring obsolete format on PV %s in VG %s.", dev_name(devl->dev), vg->name);
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read VG metadata from this dev's mdas.
|
||||
*/
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_vg_single, &baton);
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG by another host
|
||||
* since we last read the VG.
|
||||
*/
|
||||
if (!baton.vg) {
|
||||
log_debug_lvmetad("Rescan VG %s did not find %s.", vg->name, dev_name(devl->dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no metadata).",
|
||||
vg->name, dev_name(devl->dev));
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
@@ -1893,10 +1984,15 @@ scan_more:
|
||||
* different VG since we last read the VG.
|
||||
*/
|
||||
if (strcmp(baton.vg->name, vg->name)) {
|
||||
log_debug_lvmetad("Rescan VG %s found different VG %s on PV %s.",
|
||||
vg->name, baton.vg->name, dev_name(devl->dev));
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (other VG %s).",
|
||||
vg->name, dev_name(devl->dev), baton.vg->name);
|
||||
release_vg(baton.vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
log_error("VG export to config tree failed");
|
||||
release_vg(baton.vg);
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1906,20 +2002,35 @@ scan_more:
|
||||
* read from each other dev.
|
||||
*/
|
||||
|
||||
if (!save_seqno)
|
||||
save_seqno = baton.vg->seqno;
|
||||
if (save_vg && (save_seqno != baton.vg->seqno)) {
|
||||
/* FIXME: fall back to vg_read to correct this. */
|
||||
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
|
||||
vg->name, dev_name(save_dev), save_seqno,
|
||||
dev_name(devl->dev), baton.vg->seqno);
|
||||
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
log_error("VG export to config tree failed");
|
||||
release_vg(baton.vg);
|
||||
return NULL;
|
||||
/* Use the most recent */
|
||||
if (save_seqno < baton.vg->seqno) {
|
||||
release_vg(save_vg);
|
||||
dm_config_destroy(save_meta);
|
||||
save_vg = baton.vg;
|
||||
save_meta = vgmeta;
|
||||
save_seqno = baton.vg->seqno;
|
||||
save_dev = devl->dev;
|
||||
} else {
|
||||
release_vg(baton.vg);
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!vgmeta_ret) {
|
||||
vgmeta_ret = vgmeta;
|
||||
if (!save_vg) {
|
||||
save_vg = baton.vg;
|
||||
save_meta = vgmeta;
|
||||
save_seqno = baton.vg->seqno;
|
||||
save_dev = devl->dev;
|
||||
} else {
|
||||
struct dm_config_node *meta1 = vgmeta_ret->root;
|
||||
struct dm_config_node *meta1 = save_meta->root;
|
||||
struct dm_config_node *meta2 = vgmeta->root;
|
||||
struct dm_config_node *sib1 = meta1->sib;
|
||||
struct dm_config_node *sib2 = meta2->sib;
|
||||
@@ -1944,73 +2055,128 @@ scan_more:
|
||||
meta2->sib = NULL;
|
||||
|
||||
if (compare_config(meta1, meta2)) {
|
||||
/* FIXME: fall back to vg_read to correct this. */
|
||||
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
|
||||
vg->name, dev_name(save_dev), save_seqno,
|
||||
dev_name(devl->dev), baton.vg->seqno);
|
||||
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
|
||||
log_error("VG %s metadata comparison failed for device %s vs %s",
|
||||
vg->name, dev_name(devl->dev), save_dev ? dev_name(save_dev) : "none");
|
||||
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
|
||||
_log_debug_inequality(vg->name, save_meta->root, vgmeta->root);
|
||||
|
||||
meta1->sib = sib1;
|
||||
meta2->sib = sib2;
|
||||
dm_config_destroy(vgmeta);
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
|
||||
/* no right choice, just use the previous copy */
|
||||
release_vg(baton.vg);
|
||||
return NULL;
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
meta1->sib = sib1;
|
||||
meta2->sib = sib2;
|
||||
release_vg(baton.vg);
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for any new PVs in the VG metadata that were not in our
|
||||
* previous version of the VG. Add them to pvs_new to be
|
||||
* scanned in this loop just like the old PVs.
|
||||
*/
|
||||
if (!check_new_pvs) {
|
||||
check_new_pvs = 1;
|
||||
dm_list_iterate_items(pvl_new, &baton.vg->pvs) {
|
||||
found = 0;
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl_new->pv->dev != pvl->pv->dev)
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
/* FIXME: see above */
|
||||
fid->ref_count--;
|
||||
|
||||
/*
|
||||
* Look for any new PVs in the VG metadata that were not in our
|
||||
* previous version of the VG.
|
||||
*
|
||||
* (Don't look for new PVs after a rescan and retry.)
|
||||
*/
|
||||
found_new_pvs = 0;
|
||||
|
||||
if (save_vg && !retried_reads) {
|
||||
dm_list_iterate_items(pvl_new, &save_vg->pvs) {
|
||||
found = 0;
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl_new->pv->dev != pvl->pv->dev)
|
||||
continue;
|
||||
if (!pvl_new->pv->dev) {
|
||||
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
|
||||
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
|
||||
stack;
|
||||
log_error("Device not found for PV %s in VG %s", uuid, vg->name);
|
||||
missing_devs++;
|
||||
continue;
|
||||
}
|
||||
if (!(devl_new = dm_pool_zalloc(cmd->mem, sizeof(*devl_new))))
|
||||
return_NULL;
|
||||
devl_new->dev = pvl_new->pv->dev;
|
||||
dm_list_add(&pvs_new, &devl_new->list);
|
||||
log_debug_lvmetad("Rescan VG %s found %s was added.", vg->name, dev_name(devl_new->dev));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* PV in new VG metadata not found in old VG metadata.
|
||||
* There's a good chance we don't know about this new
|
||||
* PV or what device it's on; a label scan is needed
|
||||
* of all devices so we know which device the VG is
|
||||
* now using.
|
||||
*/
|
||||
if (!found) {
|
||||
found_new_pvs++;
|
||||
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
|
||||
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
|
||||
stack;
|
||||
log_debug_lvmetad("Rescan VG %s found new PV %s.", vg->name, uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release_vg(baton.vg);
|
||||
if (!save_vg && retried_reads) {
|
||||
log_error("VG %s not found after rescanning devices.", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the same scanning above for any new PVs.
|
||||
* Do a full rescan of devices, then look up which devices the
|
||||
* scan found for this VG name, and select those devices to
|
||||
* read metadata from in the loop above (rather than the list
|
||||
* of devices we created from our last copy of the vg metadata.)
|
||||
*
|
||||
* Case 1: VG we knew is no longer on any of the devices we knew it
|
||||
* to be on (save_vg is NULL, which means the metadata wasn't found
|
||||
* when reading mdas on each of the initial pvs_scan devices).
|
||||
* Rescan all devs and then retry reading metadata from the devs that
|
||||
* the scan finds associated with this VG.
|
||||
*
|
||||
* Case 2: VG has new PVs but we don't know what devices they are
|
||||
* so rescan all devs and then retry reading metadata from the devs
|
||||
* that the scan finds associated with this VG.
|
||||
*
|
||||
* (N.B. after a retry, we don't check for found_new_pvs.)
|
||||
*/
|
||||
if (!dm_list_empty(&pvs_new)) {
|
||||
dm_list_init(&pvs_scan);
|
||||
dm_list_splice(&pvs_scan, &pvs_new);
|
||||
dm_list_init(&pvs_new);
|
||||
log_debug_lvmetad("Rescan VG %s found new PVs to scan.", vg->name);
|
||||
goto scan_more;
|
||||
}
|
||||
if (!save_vg || found_new_pvs) {
|
||||
if (!save_vg)
|
||||
log_debug_lvmetad("Rescan VG %s did not find VG on previous devs.", vg->name);
|
||||
if (found_new_pvs)
|
||||
log_debug_lvmetad("Rescan VG %s scanning all devs to find new PVs.", vg->name);
|
||||
|
||||
if (missing_devs) {
|
||||
if (vgmeta_ret)
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
return_NULL;
|
||||
label_scan(cmd);
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, NULL))) {
|
||||
log_error("VG %s vg info not found after rescanning devices.", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set pvs_scan to devs that the label scan found
|
||||
* in the VG and retry the metadata reading loop.
|
||||
*/
|
||||
dm_list_init(&pvs_scan);
|
||||
|
||||
if (!lvmcache_get_vg_devs(cmd, vginfo, &pvs_scan)) {
|
||||
log_error("VG %s info devs not found after rescanning devices.", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s has %d PVs after label scan.",
|
||||
vg->name, dm_list_size(&pvs_scan));
|
||||
|
||||
if (save_vg)
|
||||
release_vg(save_vg);
|
||||
if (save_meta)
|
||||
dm_config_destroy(save_meta);
|
||||
save_vg = NULL;
|
||||
save_meta = NULL;
|
||||
save_dev = NULL;
|
||||
save_seqno = 0;
|
||||
found_new_pvs = 0;
|
||||
retried_reads = 1;
|
||||
goto retry_reads;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2019,52 +2185,50 @@ scan_more:
|
||||
dm_list_iterate_items(devl, &pvs_drop) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
log_debug_lvmetad("Rescan VG %s dropping %s.", vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev))
|
||||
return_NULL;
|
||||
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad.", vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
|
||||
/* FIXME: use an error path that disables lvmetad */
|
||||
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the VG in lvmetad.
|
||||
* Update lvmetad with the newly read version of the VG.
|
||||
* When the seqno is unchanged the cached VG can be left.
|
||||
*/
|
||||
if (vgmeta_ret) {
|
||||
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
|
||||
log_error("VG import from config tree failed");
|
||||
lvmcache_fmt(info)->ops->destroy_instance(fid);
|
||||
goto out;
|
||||
if (save_vg && (save_seqno != vg->seqno)) {
|
||||
dm_list_iterate_items(devl, &pvs_scan) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad to replace.",
|
||||
vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
|
||||
/* FIXME: use an error path that disables lvmetad */
|
||||
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
|
||||
}
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
|
||||
vg->name, vg->seqno, save_seqno);
|
||||
|
||||
/*
|
||||
* Update lvmetad with the newly read version of the VG.
|
||||
* When the seqno is unchanged the cached VG can be left.
|
||||
* If this vg_update fails the cached metadata in
|
||||
* lvmetad will remain invalid.
|
||||
*/
|
||||
if (save_seqno != vg->seqno) {
|
||||
dm_list_iterate_items(devl, &pvs_scan) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
log_debug_lvmetad("Rescan VG %s dropping to replace %s.", vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev))
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
|
||||
vg->name, vg->seqno, save_seqno);
|
||||
|
||||
/*
|
||||
* If this vg_update fails the cached metadata in
|
||||
* lvmetad will remain invalid.
|
||||
*/
|
||||
vg_ret->lvmetad_update_pending = 1;
|
||||
if (!lvmetad_vg_update_finish(vg_ret))
|
||||
log_error("Failed to update lvmetad with new VG meta");
|
||||
save_vg->lvmetad_update_pending = 1;
|
||||
if (!lvmetad_vg_update_finish(save_vg)) {
|
||||
/* FIXME: use an error path that disables lvmetad */
|
||||
log_error("Failed to update lvmetad with new VG meta");
|
||||
}
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
}
|
||||
out:
|
||||
if (vg_ret)
|
||||
log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
|
||||
return vg_ret;
|
||||
if (!save_vg && fid)
|
||||
fmt->ops->destroy_instance(fid);
|
||||
if (save_meta)
|
||||
dm_config_destroy(save_meta);
|
||||
if (save_vg)
|
||||
log_debug_lvmetad("Rescan VG %s done (new seqno %u).", save_vg->name, save_vg->seqno);
|
||||
return save_vg;
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
@@ -2074,9 +2238,12 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
const struct format_type *fmt;
|
||||
/* Create a dummy instance. */
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
|
||||
log_debug_lvmetad("Scan metadata from dev %s", dev_name(dev));
|
||||
|
||||
if (!lvmetad_used()) {
|
||||
log_error("Cannot proceed since lvmetad is not active.");
|
||||
return 0;
|
||||
@@ -2087,39 +2254,35 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!label_read(dev, &label, 0)) {
|
||||
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
|
||||
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
|
||||
log_print_unless_silent("No PV info found on %s for PVID %s.", dev_name(dev), dev->pvid);
|
||||
if (!lvmetad_pv_gone_by_dev(dev))
|
||||
goto_bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (!(label = lvmcache_get_label(info))) {
|
||||
log_print_unless_silent("No PV label found for %s.", dev_name(dev));
|
||||
if (!lvmetad_pv_gone_by_dev(dev))
|
||||
goto_bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fmt = lvmcache_fmt(info);
|
||||
|
||||
baton.cmd = cmd;
|
||||
baton.vg = NULL;
|
||||
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
baton.fid = fmt->ops->create_instance(fmt, &fic);
|
||||
|
||||
if (!baton.fid)
|
||||
goto_bad;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
|
||||
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
|
||||
_found_lvm1_metadata = 1;
|
||||
/*
|
||||
* return 1 (success) so that we'll continue to populate lvmetad
|
||||
* instead of leaving the update incomplete.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
|
||||
if (!baton.vg)
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
fmt->ops->destroy_instance(baton.fid);
|
||||
|
||||
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
|
||||
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, fmt,
|
||||
label->sector, baton.vg, found_vgnames, changed_vgnames)) {
|
||||
release_vg(baton.vg);
|
||||
goto_bad;
|
||||
@@ -2185,6 +2348,15 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
|
||||
replacing_other_update = 1;
|
||||
}
|
||||
|
||||
label_scan(cmd);
|
||||
|
||||
lvmcache_pvscan_duplicate_check(cmd);
|
||||
|
||||
if (lvmcache_found_duplicate_pvs()) {
|
||||
log_warn("WARNING: Scan found duplicate PVs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Scanning all devices to update lvmetad.");
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
|
||||
@@ -2268,11 +2440,9 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
|
||||
}
|
||||
|
||||
/*
|
||||
* If lvmetad is disabled, and no lvm1 metadata was seen and no
|
||||
* duplicate PVs were seen, then re-enable lvmetad.
|
||||
* If lvmetad is disabled, and no duplicate PVs were seen, then re-enable lvmetad.
|
||||
*/
|
||||
if (lvmetad_is_disabled(cmd, &reason) &&
|
||||
!lvmcache_found_duplicate_pvs() && !_found_lvm1_metadata) {
|
||||
if (lvmetad_is_disabled(cmd, &reason) && !lvmcache_found_duplicate_pvs()) {
|
||||
log_debug_lvmetad("Enabling lvmetad which was previously disabled.");
|
||||
lvmetad_clear_disabled(cmd);
|
||||
}
|
||||
@@ -2367,11 +2537,18 @@ static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *p
|
||||
*/
|
||||
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
log_debug_devs("device %d:%d open to update udev",
|
||||
/*
|
||||
* FIXME: this is diabled as part of removing dev_opens
|
||||
* to integrate bcache. If this is really needed, we
|
||||
* can do a separate open/close here.
|
||||
*/
|
||||
log_debug_devs("SKIP device %d:%d open to update udev",
|
||||
(int)MAJOR(devt), (int)MINOR(devt));
|
||||
|
||||
#if 0
|
||||
struct device *dev;
|
||||
|
||||
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
|
||||
log_error("_update_pv_in_udev no dev found");
|
||||
return;
|
||||
@@ -2384,6 +2561,7 @@ static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2555,6 +2733,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
*/
|
||||
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
|
||||
|
||||
log_debug_lvmetad("Rescan all devices to validate global cache.");
|
||||
|
||||
/*
|
||||
* Update the local lvmetad cache so it correctly reflects any
|
||||
* changes made on remote hosts. (It's possible that this command
|
||||
@@ -2623,7 +2803,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Validating global lvmetad cache finished");
|
||||
log_debug_lvmetad("Rescanned all devices");
|
||||
}
|
||||
|
||||
int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid)
|
||||
@@ -2878,9 +3058,6 @@ int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason)
|
||||
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_REPAIR)) {
|
||||
*reason = "a repair command was run";
|
||||
|
||||
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_LVM1)) {
|
||||
*reason = "LVM1 metadata was found";
|
||||
|
||||
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_DUPLICATES)) {
|
||||
*reason = "duplicate PVs were found";
|
||||
|
||||
|
||||
76
lib/cache/lvmetad.h
vendored
76
lib/cache/lvmetad.h
vendored
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "config-util.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct volume_group;
|
||||
struct cmd_context;
|
||||
struct dm_config_tree;
|
||||
@@ -163,38 +165,48 @@ void lvmetad_clear_disabled(struct cmd_context *cmd);
|
||||
|
||||
# else /* LVMETAD_SUPPORT */
|
||||
|
||||
# define lvmetad_disconnect() do { } while (0)
|
||||
# define lvmetad_connect(cmd) (0)
|
||||
# define lvmetad_make_unused(cmd) do { } while (0)
|
||||
# define lvmetad_used() (0)
|
||||
# define lvmetad_set_socket(a) do { } while (0)
|
||||
# define lvmetad_socket_present() (0)
|
||||
# define lvmetad_pidfile_present() (0)
|
||||
# define lvmetad_set_token(a) do { } while (0)
|
||||
# define lvmetad_release_token() do { } while (0)
|
||||
# define lvmetad_vg_update(vg) (1)
|
||||
# define lvmetad_vg_update_pending(vg) (1)
|
||||
# define lvmetad_vg_update_finish(vg) (1)
|
||||
# define lvmetad_vg_remove_pending(vg) (1)
|
||||
# define lvmetad_vg_remove_finish(vg) (1)
|
||||
# define lvmetad_pv_found(cmd, pvid, dev, fmt, label_sector, vg, found_vgnames, changed_vgnames) (1)
|
||||
# define lvmetad_pv_gone(devno, pv_name) (1)
|
||||
# define lvmetad_pv_gone_by_dev(dev) (1)
|
||||
# define lvmetad_pv_list_to_lvmcache(cmd) (1)
|
||||
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
|
||||
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
||||
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
||||
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
|
||||
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
|
||||
# define lvmetad_pvscan_single(cmd, dev, found_vgnames, changed_vgnames) (0)
|
||||
# define lvmetad_pvscan_all_devs(cmd, do_wait) (0)
|
||||
# define lvmetad_vg_clear_outdated_pvs(vg) do { } while (0)
|
||||
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
|
||||
# define lvmetad_vg_is_foreign(cmd, vgname, vgid) (0)
|
||||
# define lvmetad_token_matches(cmd) (1)
|
||||
# define lvmetad_is_disabled(cmd, reason) (0)
|
||||
# define lvmetad_set_disabled(cmd, reason) do { } while (0)
|
||||
# define lvmetad_clear_disabled(cmd) do { } while (0)
|
||||
static inline int lvmetad_connect(struct cmd_context *cmd) {return 0;}
|
||||
static inline void lvmetad_disconnect(void) {}
|
||||
static inline void lvmetad_make_unused(struct cmd_context *cmd) {}
|
||||
static inline int lvmetad_used(void) {return 0;}
|
||||
static inline void lvmetad_set_socket(const char *thing) {}
|
||||
static inline int lvmetad_socket_present(void) {return 0;}
|
||||
static inline int lvmetad_pidfile_present(void) {return 0;}
|
||||
static inline void lvmetad_set_token(const struct dm_config_value *filter) {}
|
||||
static inline void lvmetad_release_token(void) {}
|
||||
static inline int lvmetad_vg_update_pending(struct volume_group *vg) {return 1;}
|
||||
static inline int lvmetad_vg_update_finish(struct volume_group *vg) {return 1;}
|
||||
static inline int lvmetad_vg_remove_pending(struct volume_group *vg) {return 1;}
|
||||
static inline int lvmetad_vg_remove_finish(struct volume_group *vg) {return 1;}
|
||||
static inline int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct device *dev,
|
||||
const struct format_type *fmt, uint64_t label_sector,
|
||||
struct volume_group *vg,
|
||||
struct dm_list *found_vgnames,
|
||||
struct dm_list *changed_vgnames) {return 1;}
|
||||
static inline int lvmetad_pv_gone(dev_t devno, const char *pv_name) {return 1;}
|
||||
static inline int lvmetad_pv_gone_by_dev(struct device *dev) {return 1;}
|
||||
static inline int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd) {return 1;}
|
||||
static inline int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found) {return 0;}
|
||||
static inline int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *found) {return 0;}
|
||||
static inline int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd) {return 1;}
|
||||
static inline int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids) {return 0;}
|
||||
static inline struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
|
||||
const char *vgname, const char *vgid) {return NULL;}
|
||||
static inline int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
struct dm_list *found_vgnames,
|
||||
struct dm_list *changed_vgnames) {return 0;}
|
||||
|
||||
static inline int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait) {return 0;}
|
||||
|
||||
static inline int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg) {return 0;}
|
||||
static inline void lvmetad_validate_global_cache(struct cmd_context *cmd, int force) {}
|
||||
static inline int lvmetad_token_matches(struct cmd_context *cmd) {return 1;}
|
||||
|
||||
static inline int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid) {return 0;}
|
||||
|
||||
static inline int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason) {return 0;}
|
||||
static inline void lvmetad_set_disabled(struct cmd_context *cmd, const char *reason) {}
|
||||
static inline void lvmetad_clear_disabled(struct cmd_context *cmd) {}
|
||||
|
||||
# endif /* LVMETAD_SUPPORT */
|
||||
|
||||
|
||||
@@ -36,16 +36,9 @@
|
||||
#include "sharedlib.h"
|
||||
#endif
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
#include "format1.h"
|
||||
#endif
|
||||
|
||||
#ifdef POOL_INTERNAL
|
||||
#include "format_pool.h"
|
||||
#endif
|
||||
|
||||
#include <locale.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
@@ -54,7 +47,7 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static const size_t linebuffer_size = 4096;
|
||||
static const size_t _linebuffer_size = 4096;
|
||||
|
||||
/*
|
||||
* Copy the input string, removing invalid characters.
|
||||
@@ -283,6 +276,8 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
||||
debug_classes |= LOG_CLASS_LVMPOLLD;
|
||||
else if (!strcasecmp(cv->v.str, "dbus"))
|
||||
debug_classes |= LOG_CLASS_DBUS;
|
||||
else if (!strcasecmp(cv->v.str, "io"))
|
||||
debug_classes |= LOG_CLASS_IO;
|
||||
else
|
||||
log_verbose("Unrecognised value for log/debug_classes: %s", cv->v.str);
|
||||
}
|
||||
@@ -564,7 +559,7 @@ static int _process_config(struct cmd_context *cmd)
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
dm_set_dev_dir(cmd->dev_dir);
|
||||
|
||||
if (!dm_set_uuid_prefix("LVM-"))
|
||||
if (!dm_set_uuid_prefix(UUID_PREFIX))
|
||||
return_0;
|
||||
#endif
|
||||
|
||||
@@ -685,9 +680,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
if (find_config_tree_bool(cmd, report_two_word_unknown_device_CFG, NULL))
|
||||
init_unknown_device_name("unknown device");
|
||||
|
||||
init_detect_internal_vg_cache_corruption
|
||||
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
|
||||
|
||||
if (!_init_system_id(cmd))
|
||||
return_0;
|
||||
|
||||
@@ -1061,7 +1053,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_FILTERS 9
|
||||
#define MAX_FILTERS 10
|
||||
|
||||
static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
{
|
||||
@@ -1142,10 +1134,17 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/* signature filter. Required. */
|
||||
if (!(filters[nr_filt] = signature_filter_create(cmd->dev_types))) {
|
||||
log_error("Failed to create signature device filter");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/* md component filter. Optional, non-critical. */
|
||||
if (find_config_tree_bool(cmd, devices_md_component_detection_CFG, NULL)) {
|
||||
init_md_filtering(1);
|
||||
if ((filters[nr_filt] = md_filter_create(cmd->dev_types)))
|
||||
if ((filters[nr_filt] = md_filter_create(cmd, cmd->dev_types)))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
@@ -1341,20 +1340,6 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
const struct dm_config_node *cn;
|
||||
#endif
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
if (!(fmt = init_lvm1_format(cmd)))
|
||||
return 0;
|
||||
fmt->library = NULL;
|
||||
dm_list_add(&cmd->formats, &fmt->list);
|
||||
#endif
|
||||
|
||||
#ifdef POOL_INTERNAL
|
||||
if (!(fmt = init_pool_format(cmd)))
|
||||
return 0;
|
||||
fmt->library = NULL;
|
||||
dm_list_add(&cmd->formats, &fmt->list);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs if not static */
|
||||
if (!is_static() &&
|
||||
@@ -1477,6 +1462,7 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
struct segment_type *segtype;
|
||||
struct segtype_library seglib = { .cmd = cmd, .lib = NULL };
|
||||
struct segment_type *(*init_segtype_array[])(struct cmd_context *cmd) = {
|
||||
init_linear_segtype,
|
||||
init_striped_segtype,
|
||||
init_zero_segtype,
|
||||
init_error_segtype,
|
||||
@@ -1501,11 +1487,6 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
dm_list_add(&cmd->segtypes, &segtype->list);
|
||||
}
|
||||
|
||||
#ifdef REPLICATOR_INTERNAL
|
||||
if (!init_replicator_segtype(cmd, &seglib))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifdef RAID_INTERNAL
|
||||
if (!init_raid_segtypes(cmd, &seglib))
|
||||
return 0;
|
||||
@@ -1653,7 +1634,6 @@ static void _init_rand(struct cmd_context *cmd)
|
||||
|
||||
static void _init_globals(struct cmd_context *cmd)
|
||||
{
|
||||
init_full_scan_done(0);
|
||||
init_mirror_in_sync(0);
|
||||
}
|
||||
|
||||
@@ -1784,6 +1764,8 @@ void destroy_config_context(struct cmd_context *cmd)
|
||||
/*
|
||||
* A "config context" is a very light weight toolcontext that
|
||||
* is only used for reading config settings from lvm.conf.
|
||||
*
|
||||
* FIXME: this needs to go back to parametrized create_toolcontext()
|
||||
*/
|
||||
struct cmd_context *create_config_context(void)
|
||||
{
|
||||
@@ -1800,6 +1782,9 @@ struct cmd_context *create_config_context(void)
|
||||
if (!(cmd->libmem = dm_pool_create("library", 4 * 1024)))
|
||||
goto_out;
|
||||
|
||||
if (!(cmd->mem = dm_pool_create("command", 4 * 1024)))
|
||||
goto out;
|
||||
|
||||
dm_list_init(&cmd->config_files);
|
||||
dm_list_init(&cmd->tags);
|
||||
|
||||
@@ -1830,7 +1815,7 @@ out:
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
const char *system_dir,
|
||||
unsigned set_buffering,
|
||||
unsigned threaded,
|
||||
@@ -1857,7 +1842,8 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
log_error("Failed to allocate command context");
|
||||
return NULL;
|
||||
}
|
||||
cmd->is_long_lived = is_long_lived;
|
||||
cmd->is_long_lived = is_clvmd;
|
||||
cmd->is_clvmd = is_clvmd;
|
||||
cmd->threaded = threaded ? 1 : 0;
|
||||
cmd->handles_missing_pvs = 0;
|
||||
cmd->handles_unknown_segments = 0;
|
||||
@@ -1876,9 +1862,15 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
|
||||
#ifndef VALGRIND_POOL
|
||||
/* Set in/out stream buffering before glibc */
|
||||
if (set_buffering) {
|
||||
if (set_buffering
|
||||
#ifdef SYS_gettid
|
||||
/* For threaded programs no changes of streams */
|
||||
/* On linux gettid() is implemented only via syscall */
|
||||
&& (syscall(SYS_gettid) == getpid())
|
||||
#endif
|
||||
) {
|
||||
/* Allocate 2 buffers */
|
||||
if (!(cmd->linebuffer = dm_malloc(2 * linebuffer_size))) {
|
||||
if (!(cmd->linebuffer = dm_malloc(2 * _linebuffer_size))) {
|
||||
log_error("Failed to allocate line buffer.");
|
||||
goto out;
|
||||
}
|
||||
@@ -1889,7 +1881,7 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
(flags & O_ACCMODE) != O_WRONLY) {
|
||||
if (!reopen_standard_stream(&stdin, "r"))
|
||||
goto_out;
|
||||
if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) {
|
||||
if (setvbuf(stdin, cmd->linebuffer, _IOLBF, _linebuffer_size)) {
|
||||
log_sys_error("setvbuf", "");
|
||||
goto out;
|
||||
}
|
||||
@@ -1900,14 +1892,14 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
(flags & O_ACCMODE) != O_RDONLY) {
|
||||
if (!reopen_standard_stream(&stdout, "w"))
|
||||
goto_out;
|
||||
if (setvbuf(stdout, cmd->linebuffer + linebuffer_size,
|
||||
_IOLBF, linebuffer_size)) {
|
||||
if (setvbuf(stdout, cmd->linebuffer + _linebuffer_size,
|
||||
_IOLBF, _linebuffer_size)) {
|
||||
log_sys_error("setvbuf", "");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* Buffers are used for lines without '\n' */
|
||||
} else
|
||||
} else if (!set_buffering)
|
||||
/* Without buffering, must not use stdin/stdout */
|
||||
init_silent(1);
|
||||
#endif
|
||||
@@ -1980,6 +1972,10 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (!_init_formats(cmd))
|
||||
goto_out;
|
||||
|
||||
if (!lvmcache_init(cmd))
|
||||
goto_out;
|
||||
|
||||
/* FIXME: move into lvmcache_init */
|
||||
if (!init_lvmcache_orphans(cmd))
|
||||
goto_out;
|
||||
|
||||
@@ -2001,7 +1997,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (set_filters && !init_filters(cmd, 1))
|
||||
goto_out;
|
||||
|
||||
cmd->default_settings.cache_vgmetadata = 1;
|
||||
cmd->current_settings = cmd->default_settings;
|
||||
|
||||
cmd->initialized.config = 1;
|
||||
@@ -2115,6 +2110,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
|
||||
activation_release();
|
||||
lvmcache_destroy(cmd, 0, 0);
|
||||
label_scan_destroy(cmd);
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
@@ -2201,6 +2197,9 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_formats(cmd))
|
||||
return_0;
|
||||
|
||||
if (!lvmcache_init(cmd))
|
||||
return_0;
|
||||
|
||||
if (!init_lvmcache_orphans(cmd))
|
||||
return_0;
|
||||
|
||||
@@ -2234,6 +2233,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
archive_exit(cmd);
|
||||
backup_exit(cmd);
|
||||
lvmcache_destroy(cmd, 0, 0);
|
||||
label_scan_destroy(cmd);
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
|
||||
@@ -42,6 +42,7 @@ struct config_info {
|
||||
int cache_vgmetadata;
|
||||
const char *msg_prefix;
|
||||
const char *fmt_name;
|
||||
const char *dmeventd_executable;
|
||||
uint64_t unit_factor;
|
||||
int cmd_name; /* Show command name? */
|
||||
mode_t umask;
|
||||
@@ -153,6 +154,7 @@ struct cmd_context {
|
||||
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
|
||||
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
|
||||
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
|
||||
unsigned force_access_clustered:1;
|
||||
unsigned lockd_gl_disable:1;
|
||||
unsigned lockd_vg_disable:1;
|
||||
unsigned lockd_lv_disable:1;
|
||||
@@ -160,9 +162,17 @@ struct cmd_context {
|
||||
unsigned lockd_vg_rescan:1;
|
||||
unsigned lockd_vg_default_sh:1;
|
||||
unsigned lockd_vg_enforce_sh:1;
|
||||
unsigned lockd_lv_sh:1;
|
||||
unsigned vg_notify:1;
|
||||
unsigned lv_notify:1;
|
||||
unsigned pv_notify:1;
|
||||
unsigned activate_component:1; /* command activates component LV */
|
||||
unsigned process_component_lvs:1; /* command processes also component LVs */
|
||||
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
|
||||
unsigned pvscan_cache_single:1;
|
||||
unsigned can_use_one_scan:1;
|
||||
unsigned is_clvmd:1;
|
||||
unsigned use_full_md_check:1;
|
||||
|
||||
/*
|
||||
* Filtering.
|
||||
@@ -228,7 +238,7 @@ struct cmd_context {
|
||||
* system_dir may be NULL to use the default value.
|
||||
* The environment variable LVM_SYSTEM_DIR always takes precedence.
|
||||
*/
|
||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
const char *system_dir,
|
||||
unsigned set_buffering,
|
||||
unsigned threaded,
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-file.h"
|
||||
#include "memlock.h"
|
||||
#include "label.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -494,7 +495,7 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
|
||||
* and function avoids parsing of mda into config tree which
|
||||
* remains unmodified and should not be used.
|
||||
*/
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
int checksum_only, int no_dup_node_check)
|
||||
@@ -532,17 +533,28 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
log_error("Failed to allocate circular buffer.");
|
||||
return 0;
|
||||
}
|
||||
if (!dev_read_circular(dev, (uint64_t) offset, size,
|
||||
(uint64_t) offset2, size2, buf)) {
|
||||
|
||||
if (!dev_read_bytes(dev, offset, size, buf))
|
||||
goto out;
|
||||
|
||||
if (size2) {
|
||||
if (!dev_read_bytes(dev, offset2, size2, buf + size))
|
||||
goto out;
|
||||
}
|
||||
|
||||
fb = buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* The checksum passed in is the checksum from the mda_header
|
||||
* preceding this metadata. They should always match.
|
||||
* FIXME: handle case where mda_header checksum is bad,
|
||||
* but the checksum calculated here is correct.
|
||||
*/
|
||||
if (checksum_fn && checksum !=
|
||||
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
|
||||
(const uint8_t *)(fb + size), size2))) {
|
||||
log_error("%s: Checksum error", dev_name(dev));
|
||||
log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -601,7 +613,7 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
}
|
||||
}
|
||||
|
||||
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
|
||||
r = config_file_read_fd(cft, cf->dev, DEV_IO_MDA_CONTENT, 0, (size_t) info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0, 0, 0);
|
||||
|
||||
if (!cf->keep_open) {
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
#define _LVM_CONFIG_H
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "device.h"
|
||||
|
||||
/* 16 bits: 3 bits for major, 4 bits for minor, 9 bits for patchlevel */
|
||||
/* FIXME Max LVM version supported: 7.15.511. Extend bits when needed. */
|
||||
#define vsn(major, minor, patchlevel) (major << 13 | minor << 9 | patchlevel)
|
||||
|
||||
struct device;
|
||||
struct cmd_context;
|
||||
|
||||
typedef enum {
|
||||
@@ -239,7 +239,7 @@ config_source_t config_get_source_type(struct dm_config_tree *cft);
|
||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size);
|
||||
|
||||
struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open);
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
int skip_parse, int no_dup_node_check);
|
||||
|
||||
@@ -705,11 +705,11 @@ cfg(log_activation_CFG, "activation", log_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(
|
||||
|
||||
cfg(log_activate_file_CFG, "activate_file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
|
||||
|
||||
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sactivation#Sallocation#Slvmetad#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
|
||||
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sio#Sactivation#Sallocation#Slvmetad#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
|
||||
"Select log messages by class.\n"
|
||||
"Some debugging messages are assigned to a class and only appear in\n"
|
||||
"debug output if the class is listed here. Classes currently\n"
|
||||
"available: memory, devices, activation, allocation, lvmetad,\n"
|
||||
"available: memory, devices, io, activation, allocation, lvmetad,\n"
|
||||
"metadata, cache, locking, lvmpolld. Use \"all\" to see everything.\n")
|
||||
|
||||
cfg(backup_backup_CFG, "backup", backup_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_BACKUP_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
@@ -767,26 +767,14 @@ cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, D
|
||||
"is not present in the kernel, disabling this should suppress\n"
|
||||
"the error messages.\n")
|
||||
|
||||
cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), "@DEFAULT_FALLBACK_TO_LVM1@", 0, NULL,
|
||||
"Try running LVM1 tools if LVM cannot communicate with DM.\n"
|
||||
"This option only applies to 2.4 kernels and is provided to help\n"
|
||||
"switch between device-mapper kernels and LVM1 kernels. The LVM1\n"
|
||||
"tools need to be installed with .lvm1 suffices, e.g. vgscan.lvm1.\n"
|
||||
"They will stop working once the lvm2 on-disk metadata format is used.\n")
|
||||
cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(1, 0, 18), NULL, 0, NULL,
|
||||
"This setting is no longer used.\n")
|
||||
|
||||
cfg(global_format_CFG, "format", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_FORMAT, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"The default metadata format that commands should use.\n"
|
||||
"The -M 1|2 option overrides this setting.\n"
|
||||
"#\n"
|
||||
"Accepted values:\n"
|
||||
" lvm1\n"
|
||||
" lvm2\n"
|
||||
"#\n")
|
||||
"This setting is no longer used.\n")
|
||||
|
||||
cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Shared libraries that process different metadata formats.\n"
|
||||
"If support for LVM1 metadata was compiled as a shared library use\n"
|
||||
"format_libraries = \"liblvm2format1.so\"\n")
|
||||
"This setting is no longer used.")
|
||||
|
||||
cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, 0, NULL, NULL)
|
||||
|
||||
@@ -868,11 +856,8 @@ cfg(global_abort_on_internal_errors_CFG, "abort_on_internal_errors", global_CFG_
|
||||
"Treat any internal errors as fatal errors, aborting the process that\n"
|
||||
"encountered the internal error. Please only enable for debugging.\n")
|
||||
|
||||
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION, vsn(2, 2, 96), NULL, 0, NULL,
|
||||
"Internal verification of VG structures.\n"
|
||||
"Check if CRC matches when a parsed VG is used multiple times. This\n"
|
||||
"is useful to catch unexpected changes to cached VG structures.\n"
|
||||
"Please only enable for debugging.\n")
|
||||
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 96), NULL, vsn(2, 2, 174), NULL,
|
||||
"No longer used.\n")
|
||||
|
||||
cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_METADATA_READ_ONLY, vsn(2, 2, 75), NULL, 0, NULL,
|
||||
"No operations that change on-disk metadata are permitted.\n"
|
||||
|
||||
@@ -179,7 +179,6 @@
|
||||
#define DEFAULT_LOGLEVEL 0
|
||||
#define DEFAULT_INDENT 1
|
||||
#define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
|
||||
#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
|
||||
#define DEFAULT_UNITS "r"
|
||||
#define DEFAULT_SUFFIX 1
|
||||
#define DEFAULT_HOSTTAGS 0
|
||||
|
||||
272
lib/device/bcache-utils.c
Normal file
272
lib/device/bcache-utils.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 "bcache.h"
|
||||
|
||||
// FIXME: need to define this in a common place (that doesn't pull in deps)
|
||||
#ifndef SECTOR_SHIFT
|
||||
#define SECTOR_SHIFT 9
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static void byte_range_to_block_range(struct bcache *cache, uint64_t start, size_t len,
|
||||
block_address *bb, block_address *be)
|
||||
{
|
||||
block_address block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
||||
*bb = start / block_size;
|
||||
*be = (start + len + block_size - 1) / block_size;
|
||||
}
|
||||
|
||||
static uint64_t _min(uint64_t lhs, uint64_t rhs)
|
||||
{
|
||||
if (rhs < lhs)
|
||||
return rhs;
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
void bcache_prefetch_bytes(struct bcache *cache, int fd, 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);
|
||||
bb++;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
bool bcache_read_bytes(struct bcache *cache, int fd, 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);
|
||||
|
||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_get(cache, fd, bb, 0, &b))
|
||||
return false;
|
||||
|
||||
size_t blen = _min(block_size - block_offset, len);
|
||||
memcpy(data, ((unsigned char *) b->data) + block_offset, blen);
|
||||
bcache_put(b);
|
||||
|
||||
block_offset = 0;
|
||||
len -= blen;
|
||||
data = ((unsigned char *) data) + blen;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
// Writing bytes and zeroing bytes are very similar, so we factor out
|
||||
// this common code.
|
||||
|
||||
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);
|
||||
|
||||
struct updater {
|
||||
struct bcache *cache;
|
||||
partial_update_fn partial_fn;
|
||||
whole_update_fn whole_fn;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static bool _update_bytes(struct updater *u, int fd, uint64_t start, size_t len)
|
||||
{
|
||||
struct bcache *cache = u->cache;
|
||||
block_address bb, be;
|
||||
uint64_t block_size = bcache_block_sectors(cache) << SECTOR_SHIFT;
|
||||
uint64_t block_offset = start % block_size;
|
||||
uint64_t nr_whole;
|
||||
|
||||
byte_range_to_block_range(cache, start, len, &bb, &be);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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))
|
||||
return false;
|
||||
|
||||
len -= blen;
|
||||
if (!len)
|
||||
return true;
|
||||
|
||||
bb++;
|
||||
}
|
||||
|
||||
// Now we write out a set of whole blocks
|
||||
nr_whole = len / block_size;
|
||||
if (!u->whole_fn(u, fd, bb, bb + nr_whole))
|
||||
return false;
|
||||
|
||||
bb += nr_whole;
|
||||
len -= nr_whole * block_size;
|
||||
|
||||
if (!len)
|
||||
return true;
|
||||
|
||||
// Finally we write a partial end block
|
||||
return u->partial_fn(u, fd, bb, 0, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static bool _write_partial(struct updater *u, int fd, block_address bb,
|
||||
uint64_t offset, size_t len)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b))
|
||||
return false;
|
||||
|
||||
memcpy(((unsigned char *) b->data) + offset, u->data, len);
|
||||
u->data = ((unsigned char *) u->data) + len;
|
||||
|
||||
bcache_put(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _write_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||
{
|
||||
struct block *b;
|
||||
uint64_t block_size = bcache_block_sectors(u->cache) << SECTOR_SHIFT;
|
||||
|
||||
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))
|
||||
return false;
|
||||
memcpy(b->data, u->data, block_size);
|
||||
u->data = ((unsigned char *) u->data) + block_size;
|
||||
bcache_put(b);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_write_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, void *data)
|
||||
{
|
||||
struct updater u;
|
||||
|
||||
u.cache = cache;
|
||||
u.partial_fn = _write_partial;
|
||||
u.whole_fn = _write_whole;
|
||||
u.data = data;
|
||||
|
||||
return _update_bytes(&u, fd, start, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static bool _zero_partial(struct updater *u, int fd, block_address bb, uint64_t offset, size_t len)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
if (!bcache_get(u->cache, fd, bb, GF_DIRTY, &b))
|
||||
return false;
|
||||
|
||||
memset(((unsigned char *) b->data) + offset, 0, len);
|
||||
bcache_put(b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _zero_whole(struct updater *u, int fd, block_address bb, block_address be)
|
||||
{
|
||||
struct block *b;
|
||||
|
||||
for (; bb != be; bb++) {
|
||||
if (!bcache_get(u->cache, fd, bb, GF_ZERO, &b))
|
||||
return false;
|
||||
bcache_put(b);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len)
|
||||
{
|
||||
struct updater u;
|
||||
|
||||
u.cache = cache;
|
||||
u.partial_fn = _zero_partial;
|
||||
u.whole_fn = _zero_whole;
|
||||
u.data = NULL;
|
||||
|
||||
return _update_bytes(&u, fd, start, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
static bool _set_partial(struct updater *u, int fd, 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))
|
||||
return false;
|
||||
|
||||
memset(((unsigned char *) b->data) + offset, val, len);
|
||||
bcache_put(b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _set_whole(struct updater *u, int fd, 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))
|
||||
return false;
|
||||
memset((unsigned char *) b->data, val, len);
|
||||
bcache_put(b);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, uint8_t val)
|
||||
{
|
||||
struct updater u;
|
||||
|
||||
u.cache = cache;
|
||||
u.partial_fn = _set_partial;
|
||||
u.whole_fn = _set_whole;
|
||||
u.data = &val;
|
||||
|
||||
return _update_bytes(&u, fd, start, len);
|
||||
}
|
||||
|
||||
1147
lib/device/bcache.c
Normal file
1147
lib/device/bcache.c
Normal file
File diff suppressed because it is too large
Load Diff
163
lib/device/bcache.h
Normal file
163
lib/device/bcache.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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
|
||||
*/
|
||||
|
||||
#ifndef BCACHE_H
|
||||
#define BCACHE_H
|
||||
|
||||
#include "libdevmapper.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
|
||||
};
|
||||
|
||||
typedef uint64_t block_address;
|
||||
typedef uint64_t sector_t;
|
||||
|
||||
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,
|
||||
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);
|
||||
};
|
||||
|
||||
struct io_engine *create_async_io_engine(void);
|
||||
struct io_engine *create_sync_io_engine(void);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
struct bcache;
|
||||
struct block {
|
||||
/* clients may only access these three fields */
|
||||
int fd;
|
||||
uint64_t index;
|
||||
void *data;
|
||||
|
||||
struct bcache *cache;
|
||||
struct dm_list list;
|
||||
struct dm_list hash;
|
||||
|
||||
unsigned flags;
|
||||
unsigned ref_count;
|
||||
int error;
|
||||
enum dir io_dir;
|
||||
};
|
||||
|
||||
/*
|
||||
* Ownership of engine passes. Engine will be destroyed even if this fails.
|
||||
*/
|
||||
struct bcache *bcache_create(sector_t block_size, unsigned nr_cache_blocks,
|
||||
struct io_engine *engine);
|
||||
void bcache_destroy(struct bcache *cache);
|
||||
|
||||
enum bcache_get_flags {
|
||||
/*
|
||||
* The block will be zeroed before get_block returns it. This
|
||||
* potentially avoids a read if the block is not already in the cache.
|
||||
* GF_DIRTY is implicit.
|
||||
*/
|
||||
GF_ZERO = (1 << 0),
|
||||
|
||||
/*
|
||||
* Indicates the caller is intending to change the data in the block, a
|
||||
* writeback will occur after the block is released.
|
||||
*/
|
||||
GF_DIRTY = (1 << 1)
|
||||
};
|
||||
|
||||
sector_t bcache_block_sectors(struct bcache *cache);
|
||||
unsigned bcache_nr_cache_blocks(struct bcache *cache);
|
||||
unsigned bcache_max_prefetches(struct bcache *cache);
|
||||
|
||||
/*
|
||||
* Use the prefetch method to take advantage of asynchronous IO. For example,
|
||||
* if you wanted to read a block from many devices concurrently you'd do
|
||||
* something like this:
|
||||
*
|
||||
* dm_list_iterate_items (dev, &devices)
|
||||
* bcache_prefetch(cache, dev->fd, block);
|
||||
*
|
||||
* dm_list_iterate_items (dev, &devices) {
|
||||
* if (!bcache_get(cache, dev->fd, block, &b))
|
||||
* fail();
|
||||
*
|
||||
* process_block(b);
|
||||
* }
|
||||
*
|
||||
* It's slightly sub optimal, since you may not run the gets in the order that
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool bcache_get(struct bcache *cache, int fd, block_address index,
|
||||
unsigned flags, struct block **result);
|
||||
void bcache_put(struct block *b);
|
||||
|
||||
/*
|
||||
* flush() does not attempt to writeback locked blocks. flush will fail
|
||||
* (return false), if any unlocked dirty data cannot be written back.
|
||||
*/
|
||||
bool bcache_flush(struct bcache *cache);
|
||||
|
||||
/*
|
||||
* Removes a block from the cache.
|
||||
*
|
||||
* If the block is dirty it will be written back first. If the writeback fails
|
||||
* false will be returned.
|
||||
*
|
||||
* If the block is currently held false will be returned.
|
||||
*/
|
||||
bool bcache_invalidate(struct bcache *cache, int fd, 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);
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
@@ -73,7 +73,6 @@ static void _dev_init(struct device *dev, int max_error_count)
|
||||
dev->ext.src = DEV_EXT_NONE;
|
||||
|
||||
dm_list_init(&dev->aliases);
|
||||
dm_list_init(&dev->open_list);
|
||||
}
|
||||
|
||||
void dev_destroy_file(struct device *dev)
|
||||
@@ -275,10 +274,8 @@ static int _compare_paths(const char *path0, const char *path1)
|
||||
if (slash1 < slash0)
|
||||
return 1;
|
||||
|
||||
strncpy(p0, path0, sizeof(p0) - 1);
|
||||
p0[sizeof(p0) - 1] = '\0';
|
||||
strncpy(p1, path1, sizeof(p1) - 1);
|
||||
p1[sizeof(p1) - 1] = '\0';
|
||||
(void) dm_strncpy(p0, path0, sizeof(p0));
|
||||
(void) dm_strncpy(p1, path1, sizeof(p1));
|
||||
s0 = p0 + 1;
|
||||
s1 = p1 + 1;
|
||||
|
||||
@@ -336,10 +333,8 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
|
||||
/* Is name already there? */
|
||||
dm_list_iterate_items(strl, &dev->aliases) {
|
||||
if (!strcmp(strl->str, path)) {
|
||||
log_debug_devs("%s: Already in device cache", path);
|
||||
if (!strcmp(strl->str, path))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sl->str = path;
|
||||
@@ -347,13 +342,7 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
if (!dm_list_empty(&dev->aliases)) {
|
||||
oldpath = dm_list_item(dev->aliases.n, struct dm_str_list)->str;
|
||||
prefer_old = _compare_paths(path, oldpath);
|
||||
log_debug_devs("%s: Aliased to %s in device cache%s (%d:%d)",
|
||||
path, oldpath, prefer_old ? "" : " (preferred name)",
|
||||
(int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
||||
|
||||
} else
|
||||
log_debug_devs("%s: Added to device cache (%d:%d)", path,
|
||||
(int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
||||
}
|
||||
|
||||
if (prefer_old)
|
||||
dm_list_add(&dev->aliases, &sl->list);
|
||||
@@ -669,6 +658,29 @@ struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid)
|
||||
return dm_hash_lookup(_cache.lvid_index, lvid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scanning code calls this when it fails to open a device using
|
||||
* this path. The path is dropped from dev-cache. In the next
|
||||
* dev_cache_scan it may be added again, but it could be for a
|
||||
* different device.
|
||||
*/
|
||||
|
||||
void dev_cache_failed_path(struct device *dev, const char *path)
|
||||
{
|
||||
struct device *dev_by_path;
|
||||
struct dm_str_list *strl;
|
||||
|
||||
if ((dev_by_path = (struct device *) dm_hash_lookup(_cache.names, path)))
|
||||
dm_hash_remove(_cache.names, path);
|
||||
|
||||
dm_list_iterate_items(strl, &dev->aliases) {
|
||||
if (!strcmp(strl->str, path)) {
|
||||
dm_list_del(&strl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Either creates a new dev, or adds an alias to
|
||||
* an existing dev.
|
||||
@@ -676,6 +688,8 @@ struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid)
|
||||
static int _insert_dev(const char *path, dev_t d)
|
||||
{
|
||||
struct device *dev;
|
||||
struct device *dev_by_devt;
|
||||
struct device *dev_by_path;
|
||||
static dev_t loopfile_count = 0;
|
||||
int loopfile = 0;
|
||||
char *path_copy;
|
||||
@@ -688,8 +702,26 @@ static int _insert_dev(const char *path, dev_t d)
|
||||
loopfile = 1;
|
||||
}
|
||||
|
||||
/* is this device already registered ? */
|
||||
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) d))) {
|
||||
dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) d);
|
||||
dev_by_path = (struct device *) dm_hash_lookup(_cache.names, path);
|
||||
dev = dev_by_devt;
|
||||
|
||||
/*
|
||||
* Existing device, existing path points to the same device.
|
||||
*/
|
||||
if (dev_by_devt && dev_by_path && (dev_by_devt == dev_by_path)) {
|
||||
log_debug_devs("Found dev %d:%d %s - exists. %.8s",
|
||||
(int)MAJOR(d), (int)MINOR(d), path, dev->pvid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* No device or path found, add devt to cache.devices, add name to cache.names.
|
||||
*/
|
||||
if (!dev_by_devt && !dev_by_path) {
|
||||
log_debug_devs("Found dev %d:%d %s - new.",
|
||||
(int)MAJOR(d), (int)MINOR(d), path);
|
||||
|
||||
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) d))) {
|
||||
/* create new device */
|
||||
if (loopfile) {
|
||||
@@ -704,30 +736,126 @@ static int _insert_dev(const char *path, dev_t d)
|
||||
_free(dev);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dm_hash_lookup(_cache.names, path) == dev) {
|
||||
/* Hash already has matching entry present */
|
||||
log_debug("Path already cached %s.", path);
|
||||
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
|
||||
log_error("Failed to duplicate path string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!loopfile && !_add_alias(dev, path_copy)) {
|
||||
log_error("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(_cache.names, path_copy, dev)) {
|
||||
log_error("Couldn't add name to hash in dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
|
||||
log_error("Failed to duplicate path string.");
|
||||
return 0;
|
||||
/*
|
||||
* Existing device, path is new, add path as a new alias for the device.
|
||||
*/
|
||||
if (dev_by_devt && !dev_by_path) {
|
||||
log_debug_devs("Found dev %d:%d %s - new alias.",
|
||||
(int)MAJOR(d), (int)MINOR(d), path);
|
||||
|
||||
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
|
||||
log_error("Failed to duplicate path string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!loopfile && !_add_alias(dev, path_copy)) {
|
||||
log_error("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(_cache.names, path_copy, dev)) {
|
||||
log_error("Couldn't add name to hash in dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!loopfile && !_add_alias(dev, path_copy)) {
|
||||
log_error("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
/*
|
||||
* No existing device, but path exists and previously pointed
|
||||
* to a different device.
|
||||
*/
|
||||
if (!dev_by_devt && dev_by_path) {
|
||||
log_debug_devs("Found dev %d:%d %s - new device, path was previously %d:%d.",
|
||||
(int)MAJOR(d), (int)MINOR(d), path,
|
||||
(int)MAJOR(dev_by_path->dev), (int)MINOR(dev_by_path->dev));
|
||||
|
||||
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) d))) {
|
||||
/* create new device */
|
||||
if (loopfile) {
|
||||
if (!(dev = dev_create_file(path, NULL, NULL, 0)))
|
||||
return_0;
|
||||
} else if (!(dev = _dev_create(d)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
|
||||
log_error("Couldn't insert device into binary tree.");
|
||||
_free(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
|
||||
log_error("Failed to duplicate path string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!loopfile && !_add_alias(dev, path_copy)) {
|
||||
log_error("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_hash_remove(_cache.names, path);
|
||||
|
||||
if (!dm_hash_insert(_cache.names, path_copy, dev)) {
|
||||
log_error("Couldn't add name to hash in dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(_cache.names, path_copy, dev)) {
|
||||
log_error("Couldn't add name to hash in dev cache.");
|
||||
return 0;
|
||||
/*
|
||||
* Existing device, and path exists and previously pointed to
|
||||
* a different device.
|
||||
*/
|
||||
if (dev_by_devt && dev_by_path) {
|
||||
log_debug_devs("Found dev %d:%d %s - existing device, path was previously %d:%d.",
|
||||
(int)MAJOR(d), (int)MINOR(d), path,
|
||||
(int)MAJOR(dev_by_path->dev), (int)MINOR(dev_by_path->dev));
|
||||
|
||||
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
|
||||
log_error("Failed to duplicate path string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!loopfile && !_add_alias(dev, path_copy)) {
|
||||
log_error("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_hash_remove(_cache.names, path);
|
||||
|
||||
if (!dm_hash_insert(_cache.names, path_copy, dev)) {
|
||||
log_error("Couldn't add name to hash in dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
log_error("Found dev %d:%d %s - failed to use.", (int)MAJOR(d), (int)MINOR(d), path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_join(const char *dir, const char *name)
|
||||
@@ -939,12 +1067,20 @@ static int _insert_udev_dir(struct udev *udev, const char *dir)
|
||||
struct udev_device *device;
|
||||
int r = 1;
|
||||
|
||||
if (!(udev_enum = udev_enumerate_new(udev)))
|
||||
goto bad;
|
||||
if (!(udev_enum = udev_enumerate_new(udev))) {
|
||||
log_error("Failed to udev_enumerate_new.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (udev_enumerate_add_match_subsystem(udev_enum, "block") ||
|
||||
udev_enumerate_scan_devices(udev_enum))
|
||||
goto bad;
|
||||
if (udev_enumerate_add_match_subsystem(udev_enum, "block")) {
|
||||
log_error("Failed to udev_enumerate_add_match_subsystem.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (udev_enumerate_scan_devices(udev_enum)) {
|
||||
log_error("Failed to udev_enumerate_scan_devices.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report any missing information as "log_very_verbose" only, do not
|
||||
@@ -981,13 +1117,10 @@ static int _insert_udev_dir(struct udev *udev, const char *dir)
|
||||
udev_device_unref(device);
|
||||
}
|
||||
|
||||
out:
|
||||
udev_enumerate_unref(udev_enum);
|
||||
return r;
|
||||
|
||||
bad:
|
||||
log_error("Failed to enumerate udev device list.");
|
||||
udev_enumerate_unref(udev_enum);
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _insert_dirs(struct dm_list *dirs)
|
||||
@@ -1062,10 +1195,8 @@ static int _insert(const char *path, const struct stat *info,
|
||||
if (rec && !_insert_dir(path))
|
||||
return_0;
|
||||
} else { /* add a device */
|
||||
if (!S_ISBLK(info->st_mode)) {
|
||||
log_debug_devs("%s: Not a block device", path);
|
||||
if (!S_ISBLK(info->st_mode))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_insert_dev(path, info->st_rdev))
|
||||
return_0;
|
||||
@@ -1074,12 +1205,13 @@ static int _insert(const char *path, const struct stat *info,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _full_scan(int dev_scan)
|
||||
void dev_cache_scan(void)
|
||||
{
|
||||
struct dir_list *dl;
|
||||
|
||||
log_debug_devs("Creating list of system devices.");
|
||||
|
||||
if (_cache.has_scanned && !dev_scan)
|
||||
return;
|
||||
_cache.has_scanned = 1;
|
||||
|
||||
_insert_dirs(&_cache.dirs);
|
||||
|
||||
@@ -1087,9 +1219,6 @@ static void _full_scan(int dev_scan)
|
||||
|
||||
dm_list_iterate_items(dl, &_cache.files)
|
||||
_insert_file(dl->dir);
|
||||
|
||||
_cache.has_scanned = 1;
|
||||
init_full_scan_done(1);
|
||||
}
|
||||
|
||||
int dev_cache_has_scanned(void)
|
||||
@@ -1097,14 +1226,6 @@ int dev_cache_has_scanned(void)
|
||||
return _cache.has_scanned;
|
||||
}
|
||||
|
||||
void dev_cache_scan(int do_scan)
|
||||
{
|
||||
if (!do_scan)
|
||||
_cache.has_scanned = 1;
|
||||
else
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
static int _init_preferred_names(struct cmd_context *cmd)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
@@ -1168,7 +1289,6 @@ out:
|
||||
int dev_cache_init(struct cmd_context *cmd)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
|
||||
if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
|
||||
return_0;
|
||||
@@ -1370,11 +1490,25 @@ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
{
|
||||
struct stat buf;
|
||||
struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
int info_available = 0;
|
||||
int ret = 1;
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
@@ -1397,15 +1531,30 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
_insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev());
|
||||
d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
if (!d) {
|
||||
_full_scan(0);
|
||||
dev_cache_scan();
|
||||
d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!d || (f && !(d->flags & DEV_REGULAR) && !(f->passes_filter(f, d))))
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
|
||||
if (f && !(d->flags & DEV_REGULAR)) {
|
||||
ret = f->passes_filter(f, d);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
log_debug_devs("get device by name defer filter %s", dev_name(d));
|
||||
d->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (f && !(d->flags & DEV_REGULAR) && !ret)
|
||||
return NULL;
|
||||
|
||||
log_debug_devs("Using %s", dev_name(d));
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -1432,6 +1581,7 @@ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
|
||||
const char *sysfs_dir;
|
||||
struct stat info;
|
||||
struct device *d = _dev_cache_seek_devt(dev);
|
||||
int ret;
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
@@ -1447,31 +1597,40 @@ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
|
||||
}
|
||||
|
||||
if (lstat(path, &info)) {
|
||||
log_debug("No sysfs entry for %d:%d.",
|
||||
(int)MAJOR(dev), (int)MINOR(dev));
|
||||
log_debug("No sysfs entry for %d:%d errno %d at %s.",
|
||||
(int)MAJOR(dev), (int)MINOR(dev), errno, path);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_full_scan(0);
|
||||
dev_cache_scan();
|
||||
d = _dev_cache_seek_devt(dev);
|
||||
}
|
||||
|
||||
return (d && (!f || (d->flags & DEV_REGULAR) ||
|
||||
f->passes_filter(f, d))) ? d : NULL;
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
if (d->flags & DEV_REGULAR)
|
||||
return d;
|
||||
|
||||
if (!f)
|
||||
return d;
|
||||
|
||||
ret = f->passes_filter(f, d);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
log_debug_devs("get device by number defer filter %s", dev_name(d));
|
||||
d->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return d;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dev_cache_full_scan(struct dev_filter *f)
|
||||
{
|
||||
if (f && f->wipe) {
|
||||
f->wipe(f); /* might call _full_scan(1) */
|
||||
if (!full_scan_done())
|
||||
_full_scan(1);
|
||||
} else
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused)
|
||||
{
|
||||
struct dev_iter *di = dm_malloc(sizeof(*di));
|
||||
|
||||
@@ -1480,13 +1639,6 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dev_scan && !trust_cache()) {
|
||||
/* Flag gets reset between each command */
|
||||
if (!full_scan_done())
|
||||
dev_cache_full_scan(f);
|
||||
} else
|
||||
_full_scan(0);
|
||||
|
||||
di->current = btree_first(_cache.devices);
|
||||
di->filter = f;
|
||||
if (di->filter)
|
||||
@@ -1511,13 +1663,27 @@ static struct device *_iter_next(struct dev_iter *iter)
|
||||
|
||||
struct device *dev_iter_get(struct dev_iter *iter)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
int ret;
|
||||
|
||||
while (iter->current) {
|
||||
struct device *d = _iter_next(iter);
|
||||
if (!iter->filter || (d->flags & DEV_REGULAR) ||
|
||||
iter->filter->passes_filter(iter->filter, d)) {
|
||||
log_debug_devs("Using %s", dev_name(d));
|
||||
return d;
|
||||
ret = 1;
|
||||
|
||||
f = iter->filter;
|
||||
|
||||
if (f && !(d->flags & DEV_REGULAR)) {
|
||||
ret = f->passes_filter(f, d);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
log_debug_devs("get device by iter defer filter %s", dev_name(d));
|
||||
d->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!f || (d->flags & DEV_REGULAR) || ret)
|
||||
return d;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -46,15 +46,14 @@ int dev_cache_exit(void);
|
||||
*/
|
||||
int dev_cache_check_for_open_devices(void);
|
||||
|
||||
/* Trigger(1) or avoid(0) a scan */
|
||||
void dev_cache_scan(int do_scan);
|
||||
void dev_cache_scan(void);
|
||||
int dev_cache_has_scanned(void);
|
||||
void dev_cache_full_scan(struct dev_filter *f);
|
||||
|
||||
int dev_cache_add_dir(const char *path);
|
||||
int dev_cache_add_loopfile(const char *path);
|
||||
__attribute__((nonnull(1)))
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
const char *dev_cache_filtered_reason(const char *name);
|
||||
|
||||
// TODO
|
||||
struct device *dev_cache_get_by_devt(dev_t device, struct dev_filter *f);
|
||||
@@ -65,10 +64,12 @@ void dev_set_preferred_name(struct dm_str_list *sl, struct device *dev);
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
struct dev_iter;
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
|
||||
void dev_iter_destroy(struct dev_iter *iter);
|
||||
struct device *dev_iter_get(struct dev_iter *iter);
|
||||
|
||||
void dev_reset_error_count(struct cmd_context *cmd);
|
||||
|
||||
void dev_cache_failed_path(struct device *dev, const char *path);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -100,8 +100,6 @@ const char *dev_ext_name(struct device *dev)
|
||||
return _ext_registry[dev->ext.src].name;
|
||||
}
|
||||
|
||||
static const char *_ext_attached_msg = "External handle attached to device";
|
||||
|
||||
struct dev_ext *dev_ext_get(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
@@ -110,10 +108,10 @@ struct dev_ext *dev_ext_get(struct device *dev)
|
||||
handle_ptr = dev->ext.handle;
|
||||
|
||||
if (!(ext = _ext_registry[dev->ext.src].dev_ext_get(dev)))
|
||||
log_error("Failed to get external handle for device %s [%s].",
|
||||
log_error("%s: Failed to get external handle [%s].",
|
||||
dev_name(dev), dev_ext_name(dev));
|
||||
else if (handle_ptr != dev->ext.handle)
|
||||
log_debug_devs("%s %s [%s:%p]", _ext_attached_msg, dev_name(dev),
|
||||
log_debug_devs("%s: External handle [%s:%p] attached", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
|
||||
return ext;
|
||||
@@ -131,10 +129,10 @@ int dev_ext_release(struct device *dev)
|
||||
handle_ptr = dev->ext.handle;
|
||||
|
||||
if (!(r = _ext_registry[dev->ext.src].dev_ext_release(dev)))
|
||||
log_error("Failed to release external handle for device %s [%s:%p].",
|
||||
log_error("%s: Failed to release external handle [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
else
|
||||
log_debug_devs("External handle detached from device %s [%s:%p]",
|
||||
log_debug_devs("%s: External handle [%s:%p] detached",
|
||||
dev_name(dev), dev_ext_name(dev), handle_ptr);
|
||||
|
||||
return r;
|
||||
@@ -143,7 +141,7 @@ int dev_ext_release(struct device *dev)
|
||||
int dev_ext_enable(struct device *dev, dev_ext_t src)
|
||||
{
|
||||
if (dev->ext.enabled && (dev->ext.src != src) && !dev_ext_release(dev)) {
|
||||
log_error("Failed to enable external handle for device %s [%s].",
|
||||
log_error("%s: Failed to enable external handle [%s].",
|
||||
dev_name(dev), _ext_registry[src].name);
|
||||
return 0;
|
||||
}
|
||||
@@ -160,7 +158,7 @@ int dev_ext_disable(struct device *dev)
|
||||
return 1;
|
||||
|
||||
if (!dev_ext_release(dev)) {
|
||||
log_error("Failed to disable external handle for device %s [%s].",
|
||||
log_error("%s: Failed to disable external handle [%s].",
|
||||
dev_name(dev), dev_ext_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "lib.h"
|
||||
#include "device.h"
|
||||
#include "metadata.h"
|
||||
#include "lvmcache.h"
|
||||
#include "memlock.h"
|
||||
#include "locking.h"
|
||||
|
||||
@@ -53,14 +52,31 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static DM_LIST_INIT(_open_devices);
|
||||
static unsigned _dev_size_seqno = 1;
|
||||
|
||||
static const char *_reasons[] = {
|
||||
"dev signatures",
|
||||
"PV labels",
|
||||
"VG metadata header",
|
||||
"VG metadata content",
|
||||
"extra VG metadata header",
|
||||
"extra VG metadata content",
|
||||
"LVM1 metadata",
|
||||
"pool metadata",
|
||||
"LV content",
|
||||
"logging",
|
||||
};
|
||||
|
||||
static const char *_reason_text(dev_io_reason_t reason)
|
||||
{
|
||||
return _reasons[(unsigned) reason];
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* The standard io loop that keeps submitting an io until it's
|
||||
* all gone.
|
||||
*---------------------------------------------------------------*/
|
||||
static int _io(struct device_area *where, char *buffer, int should_write)
|
||||
static int _io(struct device_area *where, char *buffer, int should_write, dev_io_reason_t reason)
|
||||
{
|
||||
int fd = dev_fd(where->dev);
|
||||
ssize_t n = 0;
|
||||
@@ -72,6 +88,11 @@ static int _io(struct device_area *where, char *buffer, int should_write)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_io("%s %s:%8" PRIu64 " bytes (sync) at %" PRIu64 "%s (for %s)",
|
||||
should_write ? "Write" : "Read ", dev_name(where->dev),
|
||||
where->size, (uint64_t) where->start,
|
||||
(should_write && test_mode()) ? " (test mode - suppressed)" : "", _reason_text(reason));
|
||||
|
||||
/*
|
||||
* Skip all writes in test mode.
|
||||
*/
|
||||
@@ -142,7 +163,7 @@ int dev_get_block_size(struct device *dev, unsigned int *physical_block_size, un
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
log_debug_devs("%s: block size is %u bytes", name, dev->block_size);
|
||||
log_debug_devs("%s: Block size is %u bytes", name, dev->block_size);
|
||||
}
|
||||
|
||||
#ifdef BLKPBSZGET
|
||||
@@ -153,7 +174,7 @@ int dev_get_block_size(struct device *dev, unsigned int *physical_block_size, un
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
log_debug_devs("%s: physical block size is %u bytes", name, dev->phys_block_size);
|
||||
log_debug_devs("%s: Physical block size is %u bytes", name, dev->phys_block_size);
|
||||
}
|
||||
#elif defined (BLKSSZGET)
|
||||
/* if we can't get physical block size, just use logical block size instead */
|
||||
@@ -163,22 +184,20 @@ int dev_get_block_size(struct device *dev, unsigned int *physical_block_size, un
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
log_debug_devs("%s: physical block size can't be determined, using logical "
|
||||
"block size of %u bytes", name, dev->phys_block_size);
|
||||
log_debug_devs("%s: Physical block size can't be determined: Using logical block size of %u bytes", name, dev->phys_block_size);
|
||||
}
|
||||
#else
|
||||
/* if even BLKSSZGET is not available, use default 512b */
|
||||
if (dev->phys_block_size == -1) {
|
||||
dev->phys_block_size = 512;
|
||||
log_debug_devs("%s: physical block size can't be determined, using block "
|
||||
"size of %u bytes instead", name, dev->phys_block_size);
|
||||
log_debug_devs("%s: Physical block size can't be determined: Using block size of %u bytes instead", name, dev->phys_block_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
*physical_block_size = (unsigned int) dev->phys_block_size;
|
||||
*block_size = (unsigned int) dev->block_size;
|
||||
out:
|
||||
if (needs_open && !dev_close(dev))
|
||||
if (needs_open && !dev_close_immediate(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
@@ -207,11 +226,12 @@ static void _widen_region(unsigned int block_size, struct device_area *region,
|
||||
}
|
||||
|
||||
static int _aligned_io(struct device_area *where, char *buffer,
|
||||
int should_write)
|
||||
int should_write, dev_io_reason_t reason)
|
||||
{
|
||||
char *bounce, *bounce_buf;
|
||||
unsigned int physical_block_size = 0;
|
||||
unsigned int block_size = 0;
|
||||
unsigned buffer_was_widened = 0;
|
||||
uintptr_t mask;
|
||||
struct device_area widened;
|
||||
int r = 0;
|
||||
@@ -222,14 +242,18 @@ static int _aligned_io(struct device_area *where, char *buffer,
|
||||
|
||||
if (!block_size)
|
||||
block_size = lvm_getpagesize();
|
||||
mask = block_size - 1;
|
||||
|
||||
_widen_region(block_size, where, &widened);
|
||||
|
||||
/* Do we need to use a bounce buffer? */
|
||||
mask = block_size - 1;
|
||||
if (!memcmp(where, &widened, sizeof(widened)) &&
|
||||
!((uintptr_t) buffer & mask))
|
||||
return _io(where, buffer, should_write);
|
||||
/* Did we widen the buffer? When writing, this means means read-modify-write. */
|
||||
if (where->size != widened.size || where->start != widened.start) {
|
||||
buffer_was_widened = 1;
|
||||
log_debug_io("Widening request for %" PRIu64 " bytes at %" PRIu64 " to %" PRIu64 " bytes at %" PRIu64 " on %s (for %s)",
|
||||
where->size, (uint64_t) where->start, widened.size, (uint64_t) widened.start, dev_name(where->dev), _reason_text(reason));
|
||||
} else if (!((uintptr_t) buffer & mask))
|
||||
/* Perform the I/O directly. */
|
||||
return _io(where, buffer, should_write, reason);
|
||||
|
||||
/* Allocate a bounce buffer with an extra block */
|
||||
if (!(bounce_buf = bounce = dm_malloc((size_t) widened.size + block_size))) {
|
||||
@@ -243,10 +267,12 @@ static int _aligned_io(struct device_area *where, char *buffer,
|
||||
if (((uintptr_t) bounce) & mask)
|
||||
bounce = (char *) ((((uintptr_t) bounce) + mask) & ~mask);
|
||||
|
||||
/* channel the io through the bounce buffer */
|
||||
if (!_io(&widened, bounce, 0)) {
|
||||
/* Do we need to read into the bounce buffer? */
|
||||
if ((!should_write || buffer_was_widened) &&
|
||||
!_io(&widened, bounce, 0, reason)) {
|
||||
if (!should_write)
|
||||
goto_out;
|
||||
/* FIXME Handle errors properly! */
|
||||
/* FIXME pre-extend the file */
|
||||
memset(bounce, '\n', widened.size);
|
||||
}
|
||||
@@ -256,7 +282,7 @@ static int _aligned_io(struct device_area *where, char *buffer,
|
||||
(size_t) where->size);
|
||||
|
||||
/* ... then we write */
|
||||
if (!(r = _io(&widened, bounce, 1)))
|
||||
if (!(r = _io(&widened, bounce, 1, reason)))
|
||||
stack;
|
||||
|
||||
goto out;
|
||||
@@ -302,6 +328,8 @@ static int _dev_get_size_file(struct device *dev, uint64_t *size)
|
||||
static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
int fd = dev->bcache_fd;
|
||||
int do_close = 0;
|
||||
|
||||
if (dev->size_seqno == _dev_size_seqno) {
|
||||
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
|
||||
@@ -310,12 +338,16 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
if (fd <= 0) {
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
fd = dev_fd(dev);
|
||||
do_close = 1;
|
||||
}
|
||||
|
||||
if (ioctl(dev_fd(dev), BLKGETSIZE64, size) < 0) {
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||
if (!dev_close(dev))
|
||||
if (do_close && !dev_close_immediate(dev))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
@@ -324,29 +356,35 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
dev->size = *size;
|
||||
dev->size_seqno = _dev_size_seqno;
|
||||
|
||||
if (!dev_close(dev))
|
||||
log_sys_error("close", name);
|
||||
|
||||
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
|
||||
|
||||
if (do_close && !dev_close_immediate(dev))
|
||||
log_sys_error("close", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead)
|
||||
{
|
||||
long read_ahead_long;
|
||||
int fd = dev->bcache_fd;
|
||||
int do_close = 0;
|
||||
|
||||
if (dev->read_ahead != -1) {
|
||||
*read_ahead = (uint32_t) dev->read_ahead;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
if (fd <= 0) {
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
fd = dev_fd(dev);
|
||||
do_close = 1;
|
||||
}
|
||||
|
||||
if (ioctl(dev->fd, BLKRAGET, &read_ahead_long) < 0) {
|
||||
if (ioctl(fd, BLKRAGET, &read_ahead_long) < 0) {
|
||||
log_sys_error("ioctl BLKRAGET", dev_name(dev));
|
||||
if (!dev_close(dev))
|
||||
if (do_close && !dev_close_immediate(dev))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -357,8 +395,8 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead)
|
||||
log_very_verbose("%s: read_ahead is %u sectors",
|
||||
dev_name(dev), *read_ahead);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
if (do_close && !dev_close_immediate(dev))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -373,18 +411,20 @@ static int _dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64
|
||||
discard_range[0] = offset_bytes;
|
||||
discard_range[1] = size_bytes;
|
||||
|
||||
log_debug_devs("Discarding %" PRIu64 " bytes offset %" PRIu64 " bytes on %s.",
|
||||
size_bytes, offset_bytes, dev_name(dev));
|
||||
if (ioctl(dev->fd, BLKDISCARD, &discard_range) < 0) {
|
||||
log_debug_devs("Discarding %" PRIu64 " bytes offset %" PRIu64 " bytes on %s. %s",
|
||||
size_bytes, offset_bytes, dev_name(dev),
|
||||
test_mode() ? " (test mode - suppressed)" : "");
|
||||
|
||||
if (!test_mode() && ioctl(dev->fd, BLKDISCARD, &discard_range) < 0) {
|
||||
log_error("%s: BLKDISCARD ioctl at offset %" PRIu64 " size %" PRIu64 " failed: %s.",
|
||||
dev_name(dev), offset_bytes, size_bytes, strerror(errno));
|
||||
if (!dev_close(dev))
|
||||
if (!dev_close_immediate(dev))
|
||||
stack;
|
||||
/* It doesn't matter if discard failed, so return success. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
if (!dev_close_immediate(dev))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
@@ -463,11 +503,12 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dev->open_count && !need_excl) {
|
||||
log_debug_devs("%s already opened read-only. Upgrading "
|
||||
if (dev->open_count && !need_excl)
|
||||
log_debug_devs("%s: Already opened read-only. Upgrading "
|
||||
"to read-write.", dev_name(dev));
|
||||
dev->open_count++;
|
||||
}
|
||||
|
||||
/* dev_close_immediate will decrement this */
|
||||
dev->open_count++;
|
||||
|
||||
dev_close_immediate(dev);
|
||||
// FIXME: dev with DEV_ALLOCED is released
|
||||
@@ -562,8 +603,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
if ((flags & O_CREAT) && !(flags & O_TRUNC))
|
||||
dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
|
||||
|
||||
dm_list_add(&_open_devices, &dev->open_list);
|
||||
|
||||
log_debug_devs("Opened %s %s%s%s", dev_name(dev),
|
||||
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
|
||||
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
|
||||
@@ -600,17 +639,12 @@ int dev_open_readonly_quiet(struct device *dev)
|
||||
|
||||
int dev_test_excl(struct device *dev)
|
||||
{
|
||||
int flags;
|
||||
int r;
|
||||
int flags = 0;
|
||||
|
||||
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
|
||||
flags |= O_EXCL;
|
||||
flags |= O_RDWR;
|
||||
|
||||
r = dev_open_flags(dev, flags, 1, 1);
|
||||
if (r)
|
||||
dev_close_immediate(dev);
|
||||
|
||||
return r;
|
||||
return dev_open_flags(dev, flags, 1, 1);
|
||||
}
|
||||
|
||||
static void _close(struct device *dev)
|
||||
@@ -620,7 +654,6 @@ static void _close(struct device *dev)
|
||||
dev->fd = -1;
|
||||
dev->phys_block_size = -1;
|
||||
dev->block_size = -1;
|
||||
dm_list_del(&dev->open_list);
|
||||
|
||||
log_debug_devs("Closed %s", dev_name(dev));
|
||||
|
||||
@@ -630,7 +663,6 @@ static void _close(struct device *dev)
|
||||
|
||||
static int _dev_close(struct device *dev, int immediate)
|
||||
{
|
||||
|
||||
if (dev->fd < 0) {
|
||||
log_error("Attempt to close device '%s' "
|
||||
"which is not open.", dev_name(dev));
|
||||
@@ -649,9 +681,7 @@ static int _dev_close(struct device *dev, int immediate)
|
||||
log_debug_devs("%s: Immediate close attempt while still referenced",
|
||||
dev_name(dev));
|
||||
|
||||
/* Close unless device is known to belong to a locked VG */
|
||||
if (immediate ||
|
||||
(dev->open_count < 1 && !lvmcache_pvid_is_locked(dev->pvid)))
|
||||
if (immediate || (dev->open_count < 1))
|
||||
_close(dev);
|
||||
|
||||
return 1;
|
||||
@@ -667,18 +697,6 @@ int dev_close_immediate(struct device *dev)
|
||||
return _dev_close(dev, 1);
|
||||
}
|
||||
|
||||
void dev_close_all(void)
|
||||
{
|
||||
struct dm_list *doh, *doht;
|
||||
struct device *dev;
|
||||
|
||||
dm_list_iterate_safe(doh, doht, &_open_devices) {
|
||||
dev = dm_list_struct_base(doh, struct device, open_list);
|
||||
if (dev->open_count < 1)
|
||||
_close(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int _dev_is_valid(struct device *dev)
|
||||
{
|
||||
return (dev->max_error_count == NO_DEV_ERROR_COUNT_LIMIT ||
|
||||
@@ -693,7 +711,7 @@ static void _dev_inc_error_count(struct device *dev)
|
||||
dev->max_error_count, dev_name(dev));
|
||||
}
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer)
|
||||
{
|
||||
struct device_area where;
|
||||
int ret;
|
||||
@@ -708,9 +726,7 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
where.start = offset;
|
||||
where.size = len;
|
||||
|
||||
// fprintf(stderr, "READ: %s, %lld, %d\n", dev_name(dev), offset, len);
|
||||
|
||||
ret = _aligned_io(&where, buffer, 0);
|
||||
ret = _aligned_io(&where, buffer, 0, reason);
|
||||
if (!ret)
|
||||
_dev_inc_error_count(dev);
|
||||
|
||||
@@ -723,9 +739,9 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
* 'buf' should be len+len2.
|
||||
*/
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, char *buf)
|
||||
uint64_t offset2, size_t len2, dev_io_reason_t reason, char *buf)
|
||||
{
|
||||
if (!dev_read(dev, offset, len, buf)) {
|
||||
if (!dev_read(dev, offset, len, reason, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
@@ -737,7 +753,7 @@ int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
if (!len2)
|
||||
return 1;
|
||||
|
||||
if (!dev_read(dev, offset2, len2, buf + len)) {
|
||||
if (!dev_read(dev, offset2, len2, reason, buf + len)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
@@ -751,14 +767,14 @@ int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
*/
|
||||
|
||||
/* FIXME pre-extend the file */
|
||||
int dev_append(struct device *dev, size_t len, char *buffer)
|
||||
int dev_append(struct device *dev, size_t len, dev_io_reason_t reason, char *buffer)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dev->open_count)
|
||||
return_0;
|
||||
|
||||
r = dev_write(dev, dev->end, len, buffer);
|
||||
r = dev_write(dev, dev->end, len, reason, buffer);
|
||||
dev->end += (uint64_t) len;
|
||||
|
||||
#ifndef O_DIRECT_SUPPORT
|
||||
@@ -767,7 +783,7 @@ int dev_append(struct device *dev, size_t len, char *buffer)
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer)
|
||||
{
|
||||
struct device_area where;
|
||||
int ret;
|
||||
@@ -778,20 +794,25 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
if (!_dev_is_valid(dev))
|
||||
return 0;
|
||||
|
||||
if (!len) {
|
||||
log_error(INTERNAL_ERROR "Attempted to write 0 bytes to %s at " FMTu64, dev_name(dev), offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
where.dev = dev;
|
||||
where.start = offset;
|
||||
where.size = len;
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
ret = _aligned_io(&where, buffer, 1);
|
||||
ret = _aligned_io(&where, buffer, 1, reason);
|
||||
if (!ret)
|
||||
_dev_inc_error_count(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, int value)
|
||||
{
|
||||
size_t s;
|
||||
char buffer[4096] __attribute__((aligned(8)));
|
||||
@@ -810,7 +831,7 @@ int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
|
||||
memset(buffer, value, sizeof(buffer));
|
||||
while (1) {
|
||||
s = len > sizeof(buffer) ? sizeof(buffer) : len;
|
||||
if (!dev_write(dev, offset, s, buffer))
|
||||
if (!dev_write(dev, offset, s, reason, buffer))
|
||||
break;
|
||||
|
||||
len -= s;
|
||||
|
||||
@@ -18,27 +18,22 @@
|
||||
#define LUKS_SIGNATURE "LUKS\xba\xbe"
|
||||
#define LUKS_SIGNATURE_SIZE 6
|
||||
|
||||
int dev_is_luks(struct device *dev, uint64_t *offset_found)
|
||||
int dev_is_luks(struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
char buf[LUKS_SIGNATURE_SIZE];
|
||||
int ret = -1;
|
||||
|
||||
if (!dev_open_readonly(dev)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
if (!scan_bcache)
|
||||
return -EAGAIN;
|
||||
|
||||
if (offset_found)
|
||||
*offset_found = 0;
|
||||
|
||||
if (!dev_read(dev, 0, LUKS_SIGNATURE_SIZE, buf))
|
||||
if (!dev_read_bytes(dev, 0, LUKS_SIGNATURE_SIZE, buf))
|
||||
goto_out;
|
||||
|
||||
ret = memcmp(buf, LUKS_SIGNATURE, LUKS_SIGNATURE_SIZE) ? 0 : 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
174
lib/device/dev-lvm1-pool.c
Normal file
174
lib/device/dev-lvm1-pool.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.h"
|
||||
#include "dev-type.h"
|
||||
#include "xlate.h"
|
||||
|
||||
/*
|
||||
* These lvm1 structs just used NAME_LEN in the previous format1 lvm2 code, but
|
||||
* NAME_LEN was defined as 128 in generic lvm2 code that was not lvm1-specific
|
||||
* and not disk-format-specific.
|
||||
*/
|
||||
|
||||
#define LVM1_NAME_LEN 128
|
||||
|
||||
struct data_area {
|
||||
uint32_t base;
|
||||
uint32_t size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pv_disk {
|
||||
int8_t id[2];
|
||||
uint16_t version; /* lvm version */
|
||||
struct data_area pv_on_disk;
|
||||
struct data_area vg_on_disk;
|
||||
struct data_area pv_uuidlist_on_disk;
|
||||
struct data_area lv_on_disk;
|
||||
struct data_area pe_on_disk;
|
||||
int8_t pv_uuid[LVM1_NAME_LEN];
|
||||
int8_t vg_name[LVM1_NAME_LEN];
|
||||
int8_t system_id[LVM1_NAME_LEN]; /* for vgexport/vgimport */
|
||||
uint32_t pv_major;
|
||||
uint32_t pv_number;
|
||||
uint32_t pv_status;
|
||||
uint32_t pv_allocatable;
|
||||
uint32_t pv_size;
|
||||
uint32_t lv_cur;
|
||||
uint32_t pe_size;
|
||||
uint32_t pe_total;
|
||||
uint32_t pe_allocated;
|
||||
|
||||
/* only present on version == 2 pv's */
|
||||
uint32_t pe_start;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
int dev_is_lvm1(struct device *dev, char *buf, int buflen)
|
||||
{
|
||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||
uint32_t version;
|
||||
int ret;
|
||||
|
||||
version = xlate16(pvd->version);
|
||||
|
||||
if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
|
||||
(version == 1 || version == 2))
|
||||
ret = 1;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define POOL_MAGIC 0x011670
|
||||
#define POOL_NAME_SIZE 256
|
||||
|
||||
#define NSPMajorVersion 4
|
||||
#define NSPMinorVersion 1
|
||||
#define NSPUpdateLevel 3
|
||||
|
||||
/* When checking for version matching, the first two numbers **
|
||||
** are important for metadata formats, a.k.a pool labels. **
|
||||
** All the numbers are important when checking if the user **
|
||||
** space tools match up with the kernel module............. */
|
||||
|
||||
#define POOL_VERSION (NSPMajorVersion << 16 | \
|
||||
NSPMinorVersion << 8 | \
|
||||
NSPUpdateLevel)
|
||||
|
||||
struct pool_disk {
|
||||
uint64_t pl_magic; /* Pool magic number */
|
||||
uint64_t pl_pool_id; /* Unique pool identifier */
|
||||
char pl_pool_name[POOL_NAME_SIZE]; /* Name of pool */
|
||||
uint32_t pl_version; /* Pool version */
|
||||
uint32_t pl_subpools; /* Number of subpools in this pool */
|
||||
uint32_t pl_sp_id; /* Subpool number within pool */
|
||||
uint32_t pl_sp_devs; /* Number of data partitions in this subpool */
|
||||
uint32_t pl_sp_devid; /* Partition number within subpool */
|
||||
uint32_t pl_sp_type; /* Partition type */
|
||||
uint64_t pl_blocks; /* Number of blocks in this partition */
|
||||
uint32_t pl_striping; /* Striping size within subpool */
|
||||
/*
|
||||
* If the number of DMEP devices is zero, then the next field **
|
||||
* ** (pl_sp_dmepid) becomes the subpool ID for redirection. In **
|
||||
* ** other words, if this subpool does not have the capability **
|
||||
* ** to do DMEP, then it must specify which subpool will do it **
|
||||
* ** in it's place
|
||||
*/
|
||||
|
||||
/*
|
||||
* While the next 3 field are no longer used, they must stay to keep **
|
||||
* ** backward compatibility...........................................
|
||||
*/
|
||||
uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */
|
||||
uint32_t pl_sp_dmepid; /* Dmep device number within subpool */
|
||||
uint32_t pl_sp_weight; /* if dmep dev, pref to using it */
|
||||
|
||||
uint32_t pl_minor; /* the pool minor number */
|
||||
uint32_t pl_padding; /* reminder - think about alignment */
|
||||
|
||||
/*
|
||||
* Even though we're zeroing out 8k at the front of the disk before
|
||||
* writing the label, putting this in
|
||||
*/
|
||||
char pl_reserve[184]; /* bump the structure size out to 512 bytes */
|
||||
};
|
||||
|
||||
#define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
|
||||
#define CPIN_16(x, y) {(x) = xlate16_be((y));}
|
||||
#define CPIN_32(x, y) {(x) = xlate32_be((y));}
|
||||
#define CPIN_64(x, y) {(x) = xlate64_be((y));}
|
||||
|
||||
static void pool_label_in(struct pool_disk *pl, void *buf)
|
||||
{
|
||||
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||
|
||||
CPIN_64(pl->pl_magic, bufpl->pl_magic);
|
||||
CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id);
|
||||
CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
|
||||
CPIN_32(pl->pl_version, bufpl->pl_version);
|
||||
CPIN_32(pl->pl_subpools, bufpl->pl_subpools);
|
||||
CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id);
|
||||
CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
|
||||
CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
|
||||
CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type);
|
||||
CPIN_64(pl->pl_blocks, bufpl->pl_blocks);
|
||||
CPIN_32(pl->pl_striping, bufpl->pl_striping);
|
||||
CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
|
||||
CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
|
||||
CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
|
||||
CPIN_32(pl->pl_minor, bufpl->pl_minor);
|
||||
CPIN_32(pl->pl_padding, bufpl->pl_padding);
|
||||
CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184);
|
||||
}
|
||||
|
||||
int dev_is_pool(struct device *dev, char *buf, int buflen)
|
||||
{
|
||||
struct pool_disk pd;
|
||||
int ret;
|
||||
|
||||
pool_label_in(&pd, buf);
|
||||
|
||||
/* can ignore 8 rightmost bits for ondisk format check */
|
||||
if ((pd.pl_magic == POOL_MAGIC) &&
|
||||
(pd.pl_version >> 8 == POOL_VERSION >> 8))
|
||||
ret = 1;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,12 @@ static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
|
||||
uint32_t md_magic;
|
||||
|
||||
/* Version 1 is little endian; version 0.90.0 is machine endian */
|
||||
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
|
||||
((md_magic == MD_SB_MAGIC) ||
|
||||
((MD_SB_MAGIC != xlate32(MD_SB_MAGIC)) && (md_magic == xlate32(MD_SB_MAGIC)))))
|
||||
|
||||
if (!dev_read_bytes(dev, sb_offset, sizeof(uint32_t), &md_magic))
|
||||
return_0;
|
||||
|
||||
if ((md_magic == MD_SB_MAGIC) ||
|
||||
((MD_SB_MAGIC != xlate32(MD_SB_MAGIC)) && (md_magic == xlate32(MD_SB_MAGIC))))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -109,11 +112,14 @@ static int _udev_dev_is_md(struct device *dev)
|
||||
/*
|
||||
* Returns -1 on error
|
||||
*/
|
||||
static int _native_dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
static int _native_dev_is_md(struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
int ret = 1;
|
||||
md_minor_version_t minor;
|
||||
uint64_t size, sb_offset;
|
||||
int ret;
|
||||
|
||||
if (!scan_bcache)
|
||||
return -EAGAIN;
|
||||
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
stack;
|
||||
@@ -123,38 +129,73 @@ static int _native_dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
if (size < MD_RESERVED_SECTORS * 2)
|
||||
return 0;
|
||||
|
||||
if (!dev_open_readonly(dev)) {
|
||||
stack;
|
||||
return -1;
|
||||
/*
|
||||
* 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
|
||||
* an extra read to every device in every command, just to check for
|
||||
* the old md format is a bad tradeoff.
|
||||
*
|
||||
* When "full" is set, we check a the start and end of the device for
|
||||
* md magic numbers. When "full" is not set, we only check at the
|
||||
* start of the device for the magic numbers. We decide for each
|
||||
* command if it should do a full check (cmd->use_full_md_check),
|
||||
* and set it for commands that could possibly write to an md dev
|
||||
* (pvcreate/vgcreate/vgextend).
|
||||
*
|
||||
* For old md versions with magic numbers at the end of devices,
|
||||
* the md dev components won't be filtered out here when full is 0,
|
||||
* so they will be scanned, and appear as duplicate PVs in lvmcache.
|
||||
* The md device itself will be chosen as the primary duplicate,
|
||||
* and the components are dropped from the list of duplicates in,
|
||||
* i.e. a kind of post-scan filtering.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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, sb_offset)) {
|
||||
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))
|
||||
if (_dev_has_md_magic(dev, sb_offset)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
} while (++minor <= MD_MINOR_VERSION_MAX);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
if (ret && offset_found)
|
||||
*offset_found = sb_offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
int dev_is_md(struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -163,7 +204,7 @@ int dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
* information is not in udev db.
|
||||
*/
|
||||
if ((dev->ext.src == DEV_EXT_NONE) || offset_found)
|
||||
return _native_dev_is_md(dev, offset_found);
|
||||
return _native_dev_is_md(dev, offset_found, full);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_md(dev);
|
||||
@@ -261,8 +302,7 @@ out:
|
||||
/*
|
||||
* Retrieve chunk size from md device using sysfs.
|
||||
*/
|
||||
static unsigned long dev_md_chunk_size(struct dev_types *dt,
|
||||
struct device *dev)
|
||||
static unsigned long _dev_md_chunk_size(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
const char *attribute = "chunk_size";
|
||||
unsigned long chunk_size_bytes = 0UL;
|
||||
@@ -280,7 +320,7 @@ static unsigned long dev_md_chunk_size(struct dev_types *dt,
|
||||
/*
|
||||
* Retrieve level from md device using sysfs.
|
||||
*/
|
||||
static int dev_md_level(struct dev_types *dt, struct device *dev)
|
||||
static int _dev_md_level(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
char level_string[MD_MAX_SYSFS_SIZE];
|
||||
const char *attribute = "level";
|
||||
@@ -303,7 +343,7 @@ static int dev_md_level(struct dev_types *dt, struct device *dev)
|
||||
/*
|
||||
* Retrieve raid_disks from md device using sysfs.
|
||||
*/
|
||||
static int dev_md_raid_disks(struct dev_types *dt, struct device *dev)
|
||||
static int _dev_md_raid_disks(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
const char *attribute = "raid_disks";
|
||||
int raid_disks = 0;
|
||||
@@ -327,15 +367,15 @@ unsigned long dev_md_stripe_width(struct dev_types *dt, struct device *dev)
|
||||
unsigned long stripe_width_sectors = 0UL;
|
||||
int level, raid_disks, data_disks;
|
||||
|
||||
chunk_size_sectors = dev_md_chunk_size(dt, dev);
|
||||
chunk_size_sectors = _dev_md_chunk_size(dt, dev);
|
||||
if (!chunk_size_sectors)
|
||||
return 0;
|
||||
|
||||
level = dev_md_level(dt, dev);
|
||||
level = _dev_md_level(dt, dev);
|
||||
if (level < 0)
|
||||
return 0;
|
||||
|
||||
raid_disks = dev_md_raid_disks(dt, dev);
|
||||
raid_disks = _dev_md_raid_disks(dt, dev);
|
||||
if (!raid_disks)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#define MAX_PAGESIZE (64 * 1024)
|
||||
#define SIGNATURE_SIZE 10
|
||||
|
||||
static int
|
||||
_swap_detect_signature(const char *buf)
|
||||
static int _swap_detect_signature(const char *buf)
|
||||
{
|
||||
if (memcmp(buf, "SWAP-SPACE", 10) == 0 ||
|
||||
memcmp(buf, "SWAPSPACE2", 10) == 0)
|
||||
@@ -36,19 +35,17 @@ _swap_detect_signature(const char *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dev_is_swap(struct device *dev, uint64_t *offset_found)
|
||||
int dev_is_swap(struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
char buf[10];
|
||||
uint64_t size;
|
||||
unsigned page;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
if (!scan_bcache)
|
||||
return -EAGAIN;
|
||||
|
||||
if (!dev_open_readonly(dev)) {
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
@@ -61,8 +58,7 @@ int dev_is_swap(struct device *dev, uint64_t *offset_found)
|
||||
continue;
|
||||
if (size < (page >> SECTOR_SHIFT))
|
||||
break;
|
||||
if (!dev_read(dev, page - SIGNATURE_SIZE,
|
||||
SIGNATURE_SIZE, buf)) {
|
||||
if (!dev_read_bytes(dev, page - SIGNATURE_SIZE, SIGNATURE_SIZE, buf)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
@@ -74,9 +70,6 @@ int dev_is_swap(struct device *dev, uint64_t *offset_found)
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "xlate.h"
|
||||
#include "config.h"
|
||||
#include "metadata.h"
|
||||
#include "bcache.h"
|
||||
#include "label.h"
|
||||
|
||||
#include <libgen.h>
|
||||
#include <ctype.h>
|
||||
@@ -213,6 +215,9 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
|
||||
if (MAJOR(dev->dev) == dt->device_mapper_major)
|
||||
return 1;
|
||||
|
||||
if (MAJOR(dev->dev) == dt->md_major)
|
||||
return 1;
|
||||
|
||||
if (MAJOR(dev->dev) == dt->drbd_major)
|
||||
return 1;
|
||||
|
||||
@@ -363,7 +368,7 @@ static int _has_partition_table(struct device *dev)
|
||||
uint16_t magic;
|
||||
} __attribute__((packed)) buf; /* sizeof() == SECTOR_SIZE */
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf))
|
||||
if (!dev_read_bytes(dev, UINT64_C(0), sizeof(buf), &buf))
|
||||
return_0;
|
||||
|
||||
/* FIXME Check for other types of partition table too */
|
||||
@@ -432,6 +437,9 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!scan_bcache)
|
||||
return -EAGAIN;
|
||||
|
||||
if (!_is_partitionable(dt, dev))
|
||||
return 0;
|
||||
|
||||
@@ -439,17 +447,8 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
|
||||
return 1;
|
||||
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: failed to open device, considering device "
|
||||
"is partitioned", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = _has_partition_table(dev);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -675,7 +674,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
} else
|
||||
log_verbose(_msg_wiping, type, name);
|
||||
|
||||
if (!dev_set(dev, offset_value, len, 0)) {
|
||||
if (!dev_write_zeros(dev, offset_value, len)) {
|
||||
log_error("Failed to wipe %s signature on %s.", type, name);
|
||||
return 0;
|
||||
}
|
||||
@@ -748,12 +747,12 @@ out:
|
||||
|
||||
static int _wipe_signature(struct device *dev, const char *type, const char *name,
|
||||
int wipe_len, int yes, force_t force, int *wiped,
|
||||
int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found))
|
||||
int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found, int full))
|
||||
{
|
||||
int wipe;
|
||||
uint64_t offset_found;
|
||||
|
||||
wipe = signature_detection_fn(dev, &offset_found);
|
||||
wipe = signature_detection_fn(dev, &offset_found, 1);
|
||||
if (wipe == -1) {
|
||||
log_error("Fatal error while trying to detect %s on %s.",
|
||||
type, name);
|
||||
@@ -772,7 +771,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
|
||||
}
|
||||
|
||||
log_print_unless_silent("Wiping %s on %s.", type, name);
|
||||
if (!dev_set(dev, offset_found, wipe_len, 0)) {
|
||||
if (!dev_write_zeros(dev, offset_found, wipe_len)) {
|
||||
log_error("Failed to wipe %s on %s.", type, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "device.h"
|
||||
#include "display.h"
|
||||
#include "label.h"
|
||||
|
||||
#define NUMBER_OF_MAJORS 4096
|
||||
|
||||
@@ -56,12 +57,15 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev);
|
||||
int major_is_scsi_device(struct dev_types *dt, int major);
|
||||
|
||||
/* Signature/superblock recognition with position returned where found. */
|
||||
int dev_is_md(struct device *dev, uint64_t *sb);
|
||||
int dev_is_swap(struct device *dev, uint64_t *signature);
|
||||
int dev_is_luks(struct device *dev, uint64_t *signature);
|
||||
int dev_is_md(struct device *dev, uint64_t *sb, int full);
|
||||
int dev_is_swap(struct device *dev, uint64_t *signature, int full);
|
||||
int dev_is_luks(struct device *dev, uint64_t *signature, int full);
|
||||
int dasd_is_cdl_formatted(struct device *dev);
|
||||
int udev_dev_is_mpath_component(struct device *dev);
|
||||
|
||||
int dev_is_lvm1(struct device *dev, char *buf, int buflen);
|
||||
int dev_is_pool(struct device *dev, char *buf, int buflen);
|
||||
|
||||
/* Signature wiping. */
|
||||
#define TYPE_LVM1_MEMBER 0x001
|
||||
#define TYPE_LVM2_MEMBER 0x002
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
|
||||
#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
|
||||
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
|
||||
#define DEV_IN_BCACHE 0x00000800 /* dev fd is open and used in bcache */
|
||||
#define DEV_BCACHE_EXCL 0x00001000 /* bcache_fd should be open EXCL */
|
||||
#define DEV_FILTER_AFTER_SCAN 0x00002000 /* apply filter after bcache has data */
|
||||
#define DEV_FILTER_OUT_SCAN 0x00004000 /* filtered out during label scan */
|
||||
#define DEV_BCACHE_WRITE 0x00008000 /* bcache_fd is open with RDWR */
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
@@ -65,12 +70,13 @@ struct device {
|
||||
int phys_block_size;
|
||||
int block_size;
|
||||
int read_ahead;
|
||||
int bcache_fd;
|
||||
uint32_t flags;
|
||||
unsigned size_seqno;
|
||||
uint64_t size;
|
||||
uint64_t end;
|
||||
struct dm_list open_list;
|
||||
struct dev_ext ext;
|
||||
const char *duplicate_prefer_reason;
|
||||
|
||||
const char *vgid; /* if device is an LV */
|
||||
const char *lvid; /* if device is an LV */
|
||||
@@ -79,6 +85,22 @@ struct device {
|
||||
char _padding[7];
|
||||
};
|
||||
|
||||
/*
|
||||
* All I/O is annotated with the reason it is performed.
|
||||
*/
|
||||
typedef enum dev_io_reason {
|
||||
DEV_IO_SIGNATURES = 0, /* Scanning device signatures */
|
||||
DEV_IO_LABEL, /* LVM PV disk label */
|
||||
DEV_IO_MDA_HEADER, /* Text format metadata area header */
|
||||
DEV_IO_MDA_CONTENT, /* Text format metadata area content */
|
||||
DEV_IO_MDA_EXTRA_HEADER, /* Header of any extra metadata areas on device */
|
||||
DEV_IO_MDA_EXTRA_CONTENT, /* Content of any extra metadata areas on device */
|
||||
DEV_IO_FMT1, /* Original LVM1 metadata format */
|
||||
DEV_IO_POOL, /* Pool metadata format */
|
||||
DEV_IO_LV, /* Content written to an LV */
|
||||
DEV_IO_LOG /* Logging messages */
|
||||
} dev_io_reason_t;
|
||||
|
||||
struct device_list {
|
||||
struct dm_list list;
|
||||
struct device *dev;
|
||||
@@ -123,18 +145,17 @@ int dev_open_readonly_buffered(struct device *dev);
|
||||
int dev_open_readonly_quiet(struct device *dev);
|
||||
int dev_close(struct device *dev);
|
||||
int dev_close_immediate(struct device *dev);
|
||||
void dev_close_all(void);
|
||||
int dev_test_excl(struct device *dev);
|
||||
|
||||
int dev_fd(struct device *dev);
|
||||
const char *dev_name(const struct device *dev);
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer);
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, char *buf);
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_append(struct device *dev, size_t len, char *buffer);
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value);
|
||||
uint64_t offset2, size_t len2, dev_io_reason_t reason, char *buf);
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer);
|
||||
int dev_append(struct device *dev, size_t len, dev_io_reason_t reason, char *buffer);
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, int value);
|
||||
void dev_flush(struct device *dev);
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
|
||||
@@ -705,13 +705,10 @@ void vgdisplay_full(const struct volume_group *vg)
|
||||
|
||||
log_print("--- Volume group ---");
|
||||
log_print("VG Name %s", vg->name);
|
||||
log_print("System ID %s", (vg->system_id && *vg->system_id) ? vg->system_id : vg->lvm1_system_id ? : "");
|
||||
log_print("System ID %s", (vg->system_id && *vg->system_id) ? vg->system_id : "");
|
||||
log_print("Format %s", vg->fid->fmt->name);
|
||||
if (vg->fid->fmt->features & FMT_MDAS) {
|
||||
log_print("Metadata Areas %d",
|
||||
vg_mda_count(vg));
|
||||
log_print("Metadata Sequence No %d", vg->seqno);
|
||||
}
|
||||
log_print("Metadata Areas %d", vg_mda_count(vg));
|
||||
log_print("Metadata Sequence No %d", vg->seqno);
|
||||
access_str = vg->status & (LVM_READ | LVM_WRITE);
|
||||
log_print("VG Access %s%s%s%s",
|
||||
access_str == (LVM_READ | LVM_WRITE) ? "read/write" : "",
|
||||
|
||||
@@ -15,14 +15,19 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter.h"
|
||||
#include "device.h"
|
||||
|
||||
static int _and_p(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_filter **filters;
|
||||
int ret;
|
||||
|
||||
for (filters = (struct dev_filter **) f->private; *filters; ++filters)
|
||||
if (!(*filters)->passes_filter(*filters, dev))
|
||||
for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
|
||||
ret = (*filters)->passes_filter(*filters, dev);
|
||||
|
||||
if (!ret)
|
||||
return 0; /* No 'stack': a filter, not an error. */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ struct dev_filter *internal_filter_create(void)
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
|
||||
log_debug_devs("internal filter initialised.");
|
||||
log_debug_devs("Internal filter initialised.");
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@@ -20,15 +20,88 @@
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping md component device"
|
||||
|
||||
static int _ignore_md(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
/*
|
||||
* The purpose of these functions is to ignore md component devices,
|
||||
* e.g. if /dev/md0 is a raid1 composed of /dev/loop0 and /dev/loop1,
|
||||
* lvm wants to deal with md0 and ignore loop0 and loop1. md0 should
|
||||
* pass the filter, and loop0,loop1 should not pass the filter so lvm
|
||||
* will ignore them.
|
||||
*
|
||||
* (This is assuming lvm.conf md_component_detection=1.)
|
||||
*
|
||||
* If lvm does *not* ignore the components, then lvm will read lvm
|
||||
* labels from the md dev and from the component devs, and will see
|
||||
* them all as duplicates of each other. LVM duplicate resolution
|
||||
* will then kick in and keep the md dev around to use and ignore
|
||||
* the components.
|
||||
*
|
||||
* It is better to exclude the components as early as possible during
|
||||
* lvm processing, ideally before lvm even looks for labels on the
|
||||
* components, so that duplicate resolution can be avoided. There are
|
||||
* a number of ways that md components can be excluded earlier than
|
||||
* the duplicate resolution phase:
|
||||
*
|
||||
* - When external_device_info_source="udev", lvm discovers a device is
|
||||
* an md component by asking udev during the initial filtering phase.
|
||||
* However, lvm's default is to not use udev for this. The
|
||||
* alternative is "native" detection in which lvm tries to detect
|
||||
* md components itself.
|
||||
*
|
||||
* - When using native detection, lvm's md filter looks for the md
|
||||
* superblock at the start of devices. It will see the md superblock
|
||||
* on the components, exclude them in the md filter, and avoid
|
||||
* handling them later in duplicate resolution.
|
||||
*
|
||||
* - When using native detection, lvm's md filter will not detect
|
||||
* components when the md device has an older superblock version that
|
||||
* places the superblock at the end of the device. This case will
|
||||
* fall back to duplicate resolution to exclude components.
|
||||
*
|
||||
* A variation of the description above occurs for lvm commands that
|
||||
* intend to create new PVs on devices (pvcreate, vgcreate, vgextend).
|
||||
* For these commands, the native md filter also reads the end of all
|
||||
* devices to check for the odd md superblocks.
|
||||
*
|
||||
* (The reason that external_device_info_source is not set to udev by
|
||||
* default is that there have be issues with udev not being promptly
|
||||
* or reliably updated about md state changes, causing the udev info
|
||||
* that lvm uses to be occasionally wrong.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Returns 0 if:
|
||||
* the device is an md component and it should be ignored.
|
||||
*
|
||||
* Returns 1 if:
|
||||
* the device is not md component and should not be ignored.
|
||||
*
|
||||
* The actual md device will pass this filter and should be used,
|
||||
* it is the md component devices that we are trying to exclude
|
||||
* that will not pass.
|
||||
*/
|
||||
|
||||
static int _passes_md_filter(struct device *dev, int full)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
/*
|
||||
* When md_component_dectection=0, don't even try to skip md
|
||||
* components.
|
||||
*/
|
||||
if (!md_filtering())
|
||||
return 1;
|
||||
|
||||
ret = dev_is_md(dev, NULL);
|
||||
|
||||
ret = dev_is_md(dev, NULL, full);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
/* let pass, call again after scan */
|
||||
dev->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
log_debug_devs("filter md deferred %s", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return 1;
|
||||
|
||||
if (ret == 1) {
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
@@ -48,6 +121,18 @@ static int _ignore_md(struct dev_filter *f __attribute__((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _passes_md_filter_lite(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
return _passes_md_filter(dev, 0);
|
||||
}
|
||||
|
||||
static int _passes_md_filter_full(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
return _passes_md_filter(dev, 1);
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
if (f->use_count)
|
||||
@@ -56,7 +141,7 @@ static void _destroy(struct dev_filter *f)
|
||||
dm_free(f);
|
||||
}
|
||||
|
||||
struct dev_filter *md_filter_create(struct dev_types *dt)
|
||||
struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
@@ -65,7 +150,18 @@ struct dev_filter *md_filter_create(struct dev_types *dt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = _ignore_md;
|
||||
/*
|
||||
* FIXME: for commands that want a full md check (pvcreate, vgcreate,
|
||||
* vgextend), we do an extra read at the end of every device that the
|
||||
* filter looks at. This isn't necessary; we only need to do the full
|
||||
* md check on the PVs that these commands are trying to use.
|
||||
*/
|
||||
|
||||
if (cmd->use_full_md_check)
|
||||
f->passes_filter = _passes_md_filter_full;
|
||||
else
|
||||
f->passes_filter = _passes_md_filter_lite;
|
||||
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
|
||||
@@ -21,8 +21,18 @@
|
||||
static int _passes_partitioned_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
int ret;
|
||||
|
||||
if (dev_is_partitioned(dt, dev)) {
|
||||
ret = dev_is_partitioned(dt, dev);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
/* let pass, call again after scan */
|
||||
log_debug_devs("filter partitioned deferred %s", dev_name(dev));
|
||||
dev->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
|
||||
@@ -26,12 +26,39 @@ struct pfilter {
|
||||
struct dev_types *dt;
|
||||
};
|
||||
|
||||
/*
|
||||
* The persistent filter is filter layer that sits above the other filters and
|
||||
* caches the final result of those other filters. When a device is first
|
||||
* checked against filters, it will not be in this cache, so this filter will
|
||||
* pass the device down to the other filters to check it. The other filters
|
||||
* will run and either include the device (good/pass) or exclude the device
|
||||
* (bad/fail). That good or bad result propagates up through this filter which
|
||||
* saves the result. The next time some code checks the filters against the
|
||||
* device, this persistent/cache filter is checked first. This filter finds
|
||||
* the previous result in its cache and returns it without reevaluating the
|
||||
* other real filters.
|
||||
*
|
||||
* FIXME: a cache like this should not be needed. The fact it's needed is a
|
||||
* symptom of code that should be fixed to not reevaluate filters multiple
|
||||
* times. A device should be checked against the filter once, and then not
|
||||
* need to be checked again. With scanning now controlled, we could probably
|
||||
* do this.
|
||||
*
|
||||
* FIXME: "persistent" isn't a great name for this caching filter. This filter
|
||||
* at one time saved its cache results to a file, which is how it got the name.
|
||||
* That .cache file does not work well, causes problems, and is no longer used
|
||||
* by default. The old code for it should be removed.
|
||||
*/
|
||||
|
||||
static char* _good_device = "good";
|
||||
static char* _bad_device = "bad";
|
||||
|
||||
/*
|
||||
* The hash table holds one of these two states
|
||||
* against each entry.
|
||||
*/
|
||||
#define PF_BAD_DEVICE ((void *) 1)
|
||||
#define PF_GOOD_DEVICE ((void *) 2)
|
||||
#define PF_BAD_DEVICE ((void *) &_good_device)
|
||||
#define PF_GOOD_DEVICE ((void *) &_bad_device)
|
||||
|
||||
static int _init_hash(struct pfilter *pf)
|
||||
{
|
||||
@@ -48,11 +75,7 @@ static void _persistent_filter_wipe(struct dev_filter *f)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
log_verbose("Wiping cache of LVM-capable devices");
|
||||
dm_hash_wipe(pf->devices);
|
||||
|
||||
/* Trigger complete device scan */
|
||||
dev_cache_scan(1);
|
||||
}
|
||||
|
||||
static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
|
||||
@@ -119,21 +142,13 @@ int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out
|
||||
if (!config_file_read(cft))
|
||||
goto_out;
|
||||
|
||||
log_debug_devs("Loading persistent filter cache from %s", pf->file);
|
||||
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
|
||||
PF_GOOD_DEVICE);
|
||||
/* We don't gain anything by holding invalid devices */
|
||||
/* _read_array(pf, cft, "persistent_filter_cache/invalid_devices",
|
||||
PF_BAD_DEVICE); */
|
||||
|
||||
/* Did we find anything? */
|
||||
if (dm_hash_get_num_entries(pf->devices)) {
|
||||
/* We populated dev_cache ourselves */
|
||||
dev_cache_scan(0);
|
||||
if (!dev_cache_index_devs())
|
||||
stack;
|
||||
r = 1;
|
||||
}
|
||||
|
||||
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
|
||||
|
||||
out:
|
||||
@@ -274,29 +289,61 @@ out:
|
||||
static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
void *l = dm_hash_lookup(pf->devices, dev_name(dev));
|
||||
void *l;
|
||||
struct dm_str_list *sl;
|
||||
int pass = 1;
|
||||
|
||||
/* Cached BAD? */
|
||||
if (l == PF_BAD_DEVICE) {
|
||||
log_debug_devs("%s: Skipping (cached)", dev_name(dev));
|
||||
if (dm_list_empty(&dev->aliases)) {
|
||||
log_debug_devs("%d:%d: filter cache skipping (no name)",
|
||||
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test dm devices every time, so cache them as GOOD. */
|
||||
if (MAJOR(dev->dev) == pf->dt->device_mapper_major) {
|
||||
if (!l)
|
||||
dm_list_iterate_items(sl, &dev->aliases)
|
||||
if (!dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE)) {
|
||||
log_error("Failed to hash device to filter.");
|
||||
return 0;
|
||||
}
|
||||
return pf->real->passes_filter(pf->real, dev);
|
||||
l = dm_hash_lookup(pf->devices, dev_name(dev));
|
||||
|
||||
/* Cached bad, skip dev */
|
||||
if (l == PF_BAD_DEVICE) {
|
||||
log_debug_devs("%s: filter cache skipping (cached bad)", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Uncached */
|
||||
/* Cached good, use dev */
|
||||
if (l == PF_GOOD_DEVICE) {
|
||||
log_debug_devs("%s: filter cache using (cached good)", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Uncached, check filters and cache the result */
|
||||
if (!l) {
|
||||
l = pf->real->passes_filter(pf->real, dev) ? PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
dev->flags &= ~DEV_FILTER_AFTER_SCAN;
|
||||
|
||||
pass = pf->real->passes_filter(pf->real, dev);
|
||||
|
||||
if (!pass) {
|
||||
/*
|
||||
* A device that does not pass one filter is excluded
|
||||
* even if the result of another filter is deferred,
|
||||
* because the deferred result won't change the exclude.
|
||||
*/
|
||||
l = PF_BAD_DEVICE;
|
||||
|
||||
} else if ((pass == -EAGAIN) || (dev->flags & DEV_FILTER_AFTER_SCAN)) {
|
||||
/*
|
||||
* When the filter result is deferred, we let the device
|
||||
* pass for now, but do not cache the result. We need to
|
||||
* rerun the filters later. At that point the final result
|
||||
* will be cached.
|
||||
*/
|
||||
log_debug_devs("filter cache deferred %s", dev_name(dev));
|
||||
dev->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
pass = 1;
|
||||
goto out;
|
||||
|
||||
} else if (pass) {
|
||||
l = PF_GOOD_DEVICE;
|
||||
}
|
||||
|
||||
log_debug_devs("filter caching %s %s", pass ? "good" : "bad", dev_name(dev));
|
||||
|
||||
dm_list_iterate_items(sl, &dev->aliases)
|
||||
if (!dm_hash_insert(pf->devices, sl->str, l)) {
|
||||
@@ -304,8 +351,8 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (l == PF_BAD_DEVICE) ? 0 : 1;
|
||||
out:
|
||||
return pass;
|
||||
}
|
||||
|
||||
static void _persistent_destroy(struct dev_filter *f)
|
||||
|
||||
96
lib/filters/filter-signature.c
Normal file
96
lib/filters/filter-signature.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Luca Berra
|
||||
* Copyright (C) 2004-2006 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.h"
|
||||
#include "filter.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
static int _ignore_signature(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
int ret = 0;
|
||||
|
||||
if (!scan_bcache) {
|
||||
/* let pass, call again after scan */
|
||||
log_debug_devs("filter signature deferred %s", dev_name(dev));
|
||||
dev->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(buf, 0, BUFSIZE);
|
||||
|
||||
if (!dev_read_bytes(dev, 0, BUFSIZE, buf)) {
|
||||
log_debug_devs("%s: Skipping: error in signature detection",
|
||||
dev_name(dev));
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_is_lvm1(dev, buf, BUFSIZE)) {
|
||||
log_debug_devs("%s: Skipping lvm1 device", dev_name(dev));
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_is_pool(dev, buf, BUFSIZE)) {
|
||||
log_debug_devs("%s: Skipping gfs-pool device", dev_name(dev));
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
if (f->use_count)
|
||||
log_error(INTERNAL_ERROR "Destroying signature filter while in use %u times.", f->use_count);
|
||||
|
||||
dm_free(f);
|
||||
}
|
||||
|
||||
struct dev_filter *signature_filter_create(struct dev_types *dt)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dm_zalloc(sizeof(*f)))) {
|
||||
log_error("md filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = _ignore_signature;
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
|
||||
log_debug_devs("signature filter initialised.");
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct dev_filter *signature_filter_create(struct dev_types *dt)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -27,12 +27,6 @@ static int _native_check_pv_min_size(struct device *dev)
|
||||
uint64_t size;
|
||||
int ret = 0;
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: Skipping: open failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's not too small */
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed", dev_name(dev));
|
||||
@@ -47,9 +41,6 @@ static int _native_check_pv_min_size(struct device *dev)
|
||||
|
||||
ret = 1;
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *md_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt);
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *mpath_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *partitioned_filter_create(struct dev_types *dt);
|
||||
@@ -31,6 +31,7 @@ struct dev_filter *persistent_filter_create(struct dev_types *dt,
|
||||
struct dev_filter *f,
|
||||
const char *file);
|
||||
struct dev_filter *sysfs_filter_create(void);
|
||||
struct dev_filter *signature_filter_create(struct dev_types *dt);
|
||||
|
||||
struct dev_filter *internal_filter_create(void);
|
||||
int internal_filter_allow(struct dm_pool *mem, struct device *dev);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user