mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-21 15:33:18 +03:00
Compare commits
792 Commits
v2_02_181
...
dev-mcsont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec4fa75cee | ||
|
|
a4dbbefaff | ||
|
|
208a09745d | ||
|
|
7eaa3adedf | ||
|
|
4bb7d3da0e | ||
|
|
0f350ba890 | ||
|
|
c9203a6106 | ||
|
|
e225bf59ff | ||
|
|
b7850faba7 | ||
|
|
49b8846567 | ||
|
|
550536474f | ||
|
|
5036244ce8 | ||
|
|
a07cc8dbef | ||
|
|
36cbc6db24 | ||
|
|
4c020b4d4a | ||
|
|
dbc5543cbb | ||
|
|
f1b4aeba66 | ||
|
|
d7c1168c6a | ||
|
|
878741502a | ||
|
|
4fa1638301 | ||
|
|
9156640b60 | ||
|
|
d3636ff832 | ||
|
|
a3a676e0e7 | ||
|
|
ba7ff96faf | ||
|
|
015b906069 | ||
|
|
5dd32680b0 | ||
|
|
47effdc025 | ||
|
|
de3d3b11f4 | ||
|
|
89914a541f | ||
|
|
ab61a6d85d | ||
|
|
45b164f62c | ||
|
|
027e0e92e6 | ||
|
|
86d831b916 | ||
|
|
889b5d3183 | ||
|
|
b2447e3538 | ||
|
|
0b18c25d93 | ||
|
|
650524b955 | ||
|
|
aeafdc1f45 | ||
|
|
db98a6e362 | ||
|
|
a2c309a5c5 | ||
|
|
07d41de74c | ||
|
|
24bd35b4ce | ||
|
|
4d11bf8d50 | ||
|
|
cb6277aa8a | ||
|
|
2bcd43c683 | ||
|
|
c315112a3b | ||
|
|
2b241eb1f6 | ||
|
|
356ea897cc | ||
|
|
bada89a224 | ||
|
|
4d9f41b119 | ||
|
|
ddd68fbead | ||
|
|
e3c4ab0cc7 | ||
|
|
d18e491f68 | ||
|
|
669a834981 | ||
|
|
a9907bef99 | ||
|
|
eebb5e9fff | ||
|
|
e055b89d28 | ||
|
|
645dd27604 | ||
|
|
ef2d61fea8 | ||
|
|
52586b1039 | ||
|
|
1022b88a66 | ||
|
|
6169c0a51b | ||
|
|
2036608423 | ||
|
|
78afe75b08 | ||
|
|
cf3f463929 | ||
|
|
99ca06ca46 | ||
|
|
dc1e12dcd4 | ||
|
|
60bf9c9f33 | ||
|
|
6422b9ddc5 | ||
|
|
19ef399ea7 | ||
|
|
0c26aa13ca | ||
|
|
85dbcda150 | ||
|
|
1f7c9da554 | ||
|
|
4ff472b907 | ||
|
|
9f561f2206 | ||
|
|
3405ead1e0 | ||
|
|
6ff1583c1b | ||
|
|
1e9e21a171 | ||
|
|
6078585381 | ||
|
|
ac627fd1ce | ||
|
|
8c56e31134 | ||
|
|
d60d59a5f3 | ||
|
|
7a5ea681fb | ||
|
|
a520b3002c | ||
|
|
3c70ae1803 | ||
|
|
99de816a1b | ||
|
|
81735b46d9 | ||
|
|
0046c4e7a7 | ||
|
|
adfb9bf20c | ||
|
|
90b94ead12 | ||
|
|
d7054cd28a | ||
|
|
366c1ac15b | ||
|
|
6d0f09f478 | ||
|
|
c3e385c108 | ||
|
|
a519be8d4b | ||
|
|
8c87dda195 | ||
|
|
ccd1386070 | ||
|
|
8fbaa6d9a5 | ||
|
|
44cfa55843 | ||
|
|
116bd314cb | ||
|
|
aa75b31db5 | ||
|
|
41ba2b568b | ||
|
|
d0b869e46a | ||
|
|
0cc80ccfd5 | ||
|
|
25f231cf06 | ||
|
|
0cab341e1d | ||
|
|
344a9e9afd | ||
|
|
7836e7aa1c | ||
|
|
6f18186bfd | ||
|
|
48e9f116ae | ||
|
|
f58a70c168 | ||
|
|
0ba316f102 | ||
|
|
6b89c0d4b7 | ||
|
|
417724efe2 | ||
|
|
6f408f68d2 | ||
|
|
c33770c02d | ||
|
|
50800e33d5 | ||
|
|
5d6fe796bd | ||
|
|
fcec6691f0 | ||
|
|
e27d027155 | ||
|
|
7c3de2fd93 | ||
|
|
bca0a4df9a | ||
|
|
2f471f0184 | ||
|
|
27cfeb1d39 | ||
|
|
86b96ede2a | ||
|
|
85e68a8333 | ||
|
|
d369de8399 | ||
|
|
9b4926aaff | ||
|
|
7f757ab616 | ||
|
|
5139e5f1b3 | ||
|
|
1117f1d46f | ||
|
|
597113646d | ||
|
|
4411fe2ba8 | ||
|
|
677aa84be3 | ||
|
|
0db22c5f81 | ||
|
|
ac31bfd6fd | ||
|
|
030c39073e | ||
|
|
1cc690e911 | ||
|
|
74b5f22838 | ||
|
|
dc6dea4033 | ||
|
|
1eeb2fa3f6 | ||
|
|
da31541bd8 | ||
|
|
d84134c75b | ||
|
|
9b2b0fef9c | ||
|
|
98b7a3a42d | ||
|
|
4e20ebd6a1 | ||
|
|
a0c848d4e4 | ||
|
|
07483cc165 | ||
|
|
7edbf8a441 | ||
|
|
3584e0c0d5 | ||
|
|
dd8d083795 | ||
|
|
3ed9256985 | ||
|
|
fb83719d7f | ||
|
|
ce79b62bc2 | ||
|
|
a9eaab6beb | ||
|
|
c8fc18e8bf | ||
|
|
90149c303e | ||
|
|
74460f70ef | ||
|
|
9aea6ae956 | ||
|
|
ccfbd505fe | ||
|
|
eff33684f7 | ||
|
|
74a388cca1 | ||
|
|
f0089472e7 | ||
|
|
71a302effe | ||
|
|
fedeab28c3 | ||
|
|
7be6791e70 | ||
|
|
0aa51a2f61 | ||
|
|
3ebce8dbd2 | ||
|
|
d19e372795 | ||
|
|
5cf8888976 | ||
|
|
d04520c321 | ||
|
|
cb90606c83 | ||
|
|
59b87cf7d6 | ||
|
|
87864f09f6 | ||
|
|
b64021ee5f | ||
|
|
ab1fd0cb37 | ||
|
|
78dd9d820d | ||
|
|
58ad831c72 | ||
|
|
cbf62b9262 | ||
|
|
30ad845f3d | ||
|
|
2a45ef0300 | ||
|
|
2264399b0d | ||
|
|
105a8edea1 | ||
|
|
e689bfb5d5 | ||
|
|
fc02343eff | ||
|
|
f3c52a515b | ||
|
|
3d367f3348 | ||
|
|
cbadf3d370 | ||
|
|
246b0c444b | ||
|
|
2cac4bfc15 | ||
|
|
01cbdc4e67 | ||
|
|
a16d914d34 | ||
|
|
08cabe9b83 | ||
|
|
bd6709cec6 | ||
|
|
f1ad4b0679 | ||
|
|
ca72d19691 | ||
|
|
ab031d673d | ||
|
|
022ebb0cfe | ||
|
|
74ae1c5bc1 | ||
|
|
30a3dda9d6 | ||
|
|
9a0535e354 | ||
|
|
21742c3f3d | ||
|
|
e8ea3c9a61 | ||
|
|
28f3125aaa | ||
|
|
f87dd7b127 | ||
|
|
0d142f6514 | ||
|
|
f43b7bb461 | ||
|
|
b4c3382990 | ||
|
|
1ed4b3f23b | ||
|
|
4c1fd82774 | ||
|
|
b6d26245fb | ||
|
|
5f102b3421 | ||
|
|
facd520931 | ||
|
|
ebaaff3590 | ||
|
|
e158835a05 | ||
|
|
7b5abc3fb1 | ||
|
|
3cf7668e34 | ||
|
|
6620dc9475 | ||
|
|
81b3b71dae | ||
|
|
c0c202e606 | ||
|
|
54a569be40 | ||
|
|
61e378c4e7 | ||
|
|
fdd612b824 | ||
|
|
6298eaeca5 | ||
|
|
bc40391b7d | ||
|
|
938b6b8253 | ||
|
|
89c61f2018 | ||
|
|
ee9d623d38 | ||
|
|
6d8356d208 | ||
|
|
1dee4b4ffc | ||
|
|
88faf5a53b | ||
|
|
44aeb6d6b8 | ||
|
|
fc479b2b07 | ||
|
|
83c6f7e7e6 | ||
|
|
1fc5d8c428 | ||
|
|
26ead4bf45 | ||
|
|
9dfb1a11b7 | ||
|
|
a355aeb17a | ||
|
|
8db2527c6e | ||
|
|
e2c017fdac | ||
|
|
2724a09e58 | ||
|
|
095c9791ca | ||
|
|
82f66834ef | ||
|
|
a13fa75d8e | ||
|
|
65cb8efd16 | ||
|
|
fb85d5d024 | ||
|
|
9830aa207c | ||
|
|
3750b0cff5 | ||
|
|
0161ebe484 | ||
|
|
a4577c427a | ||
|
|
a3fe619552 | ||
|
|
71af650760 | ||
|
|
7832d35668 | ||
|
|
98924e4703 | ||
|
|
18aa541ca2 | ||
|
|
a7034fa420 | ||
|
|
5bdcafff47 | ||
|
|
ab1f1a306b | ||
|
|
3320ab8334 | ||
|
|
9785e40b8d | ||
|
|
f05104af76 | ||
|
|
b068f21f6a | ||
|
|
93c7bca08f | ||
|
|
88153c7c0a | ||
|
|
e0c2d374ae | ||
|
|
07fc4866f0 | ||
|
|
e82303fd6a | ||
|
|
1f1d36f6a2 | ||
|
|
2076dda0b8 | ||
|
|
5db56b36f1 | ||
|
|
94237354dd | ||
|
|
0dc7abe013 | ||
|
|
b5366b1d8d | ||
|
|
143c8dcd7f | ||
|
|
a665206453 | ||
|
|
f619cac598 | ||
|
|
a63015442e | ||
|
|
d76b4afb8e | ||
|
|
a8cdd9e16a | ||
|
|
701ecff0ff | ||
|
|
8bf445b2de | ||
|
|
035a7b9a4b | ||
|
|
c666e8d25e | ||
|
|
f514e37978 | ||
|
|
2e01af0f78 | ||
|
|
a6cba2d0a0 | ||
|
|
51f08efaa7 | ||
|
|
f1684bf8e8 | ||
|
|
859feb81e5 | ||
|
|
db6d9e04af | ||
|
|
cc5cfb88d7 | ||
|
|
73bef5e3dd | ||
|
|
4801919b01 | ||
|
|
454024f957 | ||
|
|
0f5bdd4d31 | ||
|
|
63b0f0dab8 | ||
|
|
0b19387dae | ||
|
|
3c37764333 | ||
|
|
46a8d2e898 | ||
|
|
627f0e2bd8 | ||
|
|
dd5716ddf2 | ||
|
|
b2d1facd96 | ||
|
|
edb72cb70c | ||
|
|
a4b8377488 | ||
|
|
21784e94d6 | ||
|
|
92b0d014aa | ||
|
|
73687b7b75 | ||
|
|
752b1e95f4 | ||
|
|
3d2fd95af7 | ||
|
|
89c11a2b49 | ||
|
|
c1b2de936c | ||
|
|
a063d2d123 | ||
|
|
5a5e3bcf15 | ||
|
|
d8ad73e937 | ||
|
|
0d61a17152 | ||
|
|
1aac59f82a | ||
|
|
250e05a965 | ||
|
|
a1e5b8832b | ||
|
|
38c7ba315d | ||
|
|
65eb29503b | ||
|
|
93dfb5dd3e | ||
|
|
c61c4271a4 | ||
|
|
6a4a6a7cd7 | ||
|
|
c0c318e4f2 | ||
|
|
8b87ffaa8a | ||
|
|
7fb280ceac | ||
|
|
46f946145c | ||
|
|
41afe8c5cc | ||
|
|
e940293c33 | ||
|
|
7da75f41ed | ||
|
|
217d647a46 | ||
|
|
5f87ba68d4 | ||
|
|
74731a5277 | ||
|
|
e3a22cdc31 | ||
|
|
fc482406ec | ||
|
|
4ddd756d6f | ||
|
|
98c21e98b2 | ||
|
|
f54ead831f | ||
|
|
ceb2f0ad3b | ||
|
|
483ed8f767 | ||
|
|
8bb5dd5430 | ||
|
|
cb04b84c79 | ||
|
|
cd0fb0846d | ||
|
|
ea9b2c2122 | ||
|
|
d8284beb23 | ||
|
|
904e1e3d26 | ||
|
|
2d1152103f | ||
|
|
4b5d6de86b | ||
|
|
229e63b638 | ||
|
|
9deb134014 | ||
|
|
7e721ca048 | ||
|
|
ca66d52032 | ||
|
|
b1e9fe9505 | ||
|
|
cb15373ad7 | ||
|
|
b968c73d21 | ||
|
|
b2261b5d81 | ||
|
|
54de0d829b | ||
|
|
a53024cafc | ||
|
|
6d2609a232 | ||
|
|
0747a6d0de | ||
|
|
f7adcb5f6d | ||
|
|
14f24c2175 | ||
|
|
4021e88a31 | ||
|
|
188bedf8de | ||
|
|
ea001426af | ||
|
|
2d89192935 | ||
|
|
a23ed35f6c | ||
|
|
97a95f9648 | ||
|
|
fd8001a9fc | ||
|
|
83d9ea7348 | ||
|
|
55a8d6c86b | ||
|
|
43f8da7699 | ||
|
|
1ae5bf2b83 | ||
|
|
10e191fd12 | ||
|
|
d44bfe90f1 | ||
|
|
df2fa88e63 | ||
|
|
16fed9ef0c | ||
|
|
e6be10ffd2 | ||
|
|
3ca8ed66a7 | ||
|
|
814cff0c20 | ||
|
|
819b469880 | ||
|
|
cbee4d3d88 | ||
|
|
1c0b02e367 | ||
|
|
8aec65c054 | ||
|
|
c203ce7f86 | ||
|
|
970f49dcab | ||
|
|
517332e78d | ||
|
|
836dc9876b | ||
|
|
38770db19b | ||
|
|
2f02e8d33a | ||
|
|
73132bc254 | ||
|
|
025332edc2 | ||
|
|
8794fb71db | ||
|
|
e1e33e75e7 | ||
|
|
8c5fbd5fac | ||
|
|
d4de3cfa4d | ||
|
|
f86f01a3a1 | ||
|
|
3a557dcfbf | ||
|
|
6cee8f1b06 | ||
|
|
c1703845c3 | ||
|
|
1dc5603f73 | ||
|
|
3ae5569570 | ||
|
|
cac4a9743a | ||
|
|
8c9d9a7446 | ||
|
|
e548e7c29d | ||
|
|
a686391eca | ||
|
|
23948e99b3 | ||
|
|
3e547fa952 | ||
|
|
5ee1727f80 | ||
|
|
7541e002b2 | ||
|
|
85b4b2f924 | ||
|
|
e26dacf30a | ||
|
|
f3f3d6066b | ||
|
|
8d7075528f | ||
|
|
a427a93549 | ||
|
|
ad0268e239 | ||
|
|
a1b1b3dbb6 | ||
|
|
9a6f0e64f9 | ||
|
|
9d9979963f | ||
|
|
aa8b2d6a0f | ||
|
|
d3ebb18f40 | ||
|
|
70e3d0a613 | ||
|
|
a91ac41b93 | ||
|
|
9238b972c5 | ||
|
|
0d934e730e | ||
|
|
813347cf84 | ||
|
|
c7789daec0 | ||
|
|
bc1976011a | ||
|
|
79879bd201 | ||
|
|
6235861e64 | ||
|
|
1951e0db0f | ||
|
|
5d747f724e | ||
|
|
e7a56d5cd3 | ||
|
|
f6a54a50a0 | ||
|
|
7a170873aa | ||
|
|
0b01e3f5d7 | ||
|
|
925aaf0b87 | ||
|
|
19f2105b87 | ||
|
|
420af27f08 | ||
|
|
913c28917e | ||
|
|
1e40e734e6 | ||
|
|
aecf542126 | ||
|
|
8df2dd66ce | ||
|
|
16ae968d24 | ||
|
|
fc35a9169e | ||
|
|
7498f83833 | ||
|
|
9e1ee07d69 | ||
|
|
015231b11f | ||
|
|
32f1afbe36 | ||
|
|
69bebfd958 | ||
|
|
f1ac72c848 | ||
|
|
4db228b907 | ||
|
|
c15ac326cc | ||
|
|
05b5774827 | ||
|
|
6179cab877 | ||
|
|
2217d6396a | ||
|
|
06a4a356db | ||
|
|
fdd76da33d | ||
|
|
c4f39decc8 | ||
|
|
43e4bfe428 | ||
|
|
84f00f5058 | ||
|
|
b57e73a0f1 | ||
|
|
70950bbd97 | ||
|
|
f1ac130dc1 | ||
|
|
668c9d0762 | ||
|
|
b1ff52ca14 | ||
|
|
2513661467 | ||
|
|
cbbdace006 | ||
|
|
253989ecd9 | ||
|
|
13c49033ed | ||
|
|
a7298810d1 | ||
|
|
eb566e034f | ||
|
|
9b71212262 | ||
|
|
30b1b57506 | ||
|
|
eed8715e1d | ||
|
|
20971f7034 | ||
|
|
77aa055e8a | ||
|
|
2ab784440a | ||
|
|
9b85ecb85b | ||
|
|
3222924c3d | ||
|
|
fbfbbf6d6a | ||
|
|
1bb30a8c27 | ||
|
|
5811fa33bb | ||
|
|
954b885a08 | ||
|
|
48768cc5be | ||
|
|
6462e8dffc | ||
|
|
9ed869cce1 | ||
|
|
f8462cff92 | ||
|
|
37366ec3b0 | ||
|
|
6e12a33292 | ||
|
|
5c36ad06a1 | ||
|
|
194eccf925 | ||
|
|
11d4e63888 | ||
|
|
a49f494c4d | ||
|
|
6be1efd13d | ||
|
|
91c7e66f2b | ||
|
|
09131e3922 | ||
|
|
30c94b0324 | ||
|
|
8424655af9 | ||
|
|
bda4f3a7ae | ||
|
|
ba6d8a3195 | ||
|
|
bb17302084 | ||
|
|
ebd2d7773f | ||
|
|
0ac7913c6a | ||
|
|
abe2210c26 | ||
|
|
945d13541e | ||
|
|
41ef146dc3 | ||
|
|
fdb6ef8a85 | ||
|
|
0c00af776a | ||
|
|
ccb08dfa1d | ||
|
|
19a59cc53c | ||
|
|
e9b6cdd6e6 | ||
|
|
81ca0cb161 | ||
|
|
297f6d5122 | ||
|
|
1365f0d4c8 | ||
|
|
0aeca60aaa | ||
|
|
17bd91e33e | ||
|
|
5fb15b1934 | ||
|
|
3832329a6b | ||
|
|
df67b1da4d | ||
|
|
d0ff078e77 | ||
|
|
3255e384db | ||
|
|
4d964133e2 | ||
|
|
07d2794a16 | ||
|
|
b070c14a8b | ||
|
|
3bcc6c7e60 | ||
|
|
989626926c | ||
|
|
e2e30a64ab | ||
|
|
22a1304368 | ||
|
|
61600f8fa7 | ||
|
|
fa0a04236c | ||
|
|
bfcecbbce1 | ||
|
|
a0f6f18841 | ||
|
|
03ed2aae3a | ||
|
|
3d5c4847b6 | ||
|
|
cb17ef221b | ||
|
|
fade9ca3b6 | ||
|
|
3c966e637f | ||
|
|
e83c4f07ca | ||
|
|
10ede2cc0f | ||
|
|
4578411633 | ||
|
|
8b05f1f230 | ||
|
|
54668feaab | ||
|
|
d131024255 | ||
|
|
acab591378 | ||
|
|
c34291e3bf | ||
|
|
9adae653e9 | ||
|
|
763219611c | ||
|
|
aa464aa2f6 | ||
|
|
9cd05d1f1e | ||
|
|
7f49d463d6 | ||
|
|
a004bb07f1 | ||
|
|
8b0729af0f | ||
|
|
2f43f0393e | ||
|
|
706606627f | ||
|
|
5ff18f51b9 | ||
|
|
279f3bfdc0 | ||
|
|
97506a7e2a | ||
|
|
7709b70f97 | ||
|
|
86c3940537 | ||
|
|
bf4be80669 | ||
|
|
2214dc12c3 | ||
|
|
778ce8d808 | ||
|
|
8a66c81b9b | ||
|
|
63ec42f428 | ||
|
|
117160b27e | ||
|
|
edf3f86184 | ||
|
|
06439a2562 | ||
|
|
db741e75a2 | ||
|
|
c47655f231 | ||
|
|
faa126882a | ||
|
|
12213445b5 | ||
|
|
7b8aa4af57 | ||
|
|
6206bd0e79 | ||
|
|
c58733ca15 | ||
|
|
6945bbdbc6 | ||
|
|
96e9929f2f | ||
|
|
a821b88a43 | ||
|
|
44c99a8822 | ||
|
|
5807993bbf | ||
|
|
4f708e8709 | ||
|
|
493ffe7a0f | ||
|
|
00990ed53e | ||
|
|
0dafd159a8 | ||
|
|
aa63dfbe39 | ||
|
|
aff69ecf39 | ||
|
|
4b7a57c9ed | ||
|
|
a8f84f7801 | ||
|
|
c66a960149 | ||
|
|
d8a41f22e9 | ||
|
|
0d9a4c6989 | ||
|
|
4a90b0c4c9 | ||
|
|
2e05f6018b | ||
|
|
80e6097ea6 | ||
|
|
b98846998b | ||
|
|
5f3eff8eae | ||
|
|
9b6b4f14d8 | ||
|
|
4a64bb9573 | ||
|
|
5cf0923e18 | ||
|
|
e9d1f676b3 | ||
|
|
333eb8667e | ||
|
|
6d1c983122 | ||
|
|
a55d4b6051 | ||
|
|
c8b4f9414c | ||
|
|
b697aa9646 | ||
|
|
c96400b6c7 | ||
|
|
c1a6b10d09 | ||
|
|
d56e400d44 | ||
|
|
f2b856c994 | ||
|
|
2bb9627d01 | ||
|
|
ed3428b7ed | ||
|
|
0bae9a1bff | ||
|
|
b55d30956d | ||
|
|
52b07672f8 | ||
|
|
29b9ccd261 | ||
|
|
f96fd9961d | ||
|
|
163a30d784 | ||
|
|
a14f21bf1d | ||
|
|
4194fc9bbd | ||
|
|
739a213d2e | ||
|
|
a1c81c009a | ||
|
|
19b92ae3f3 | ||
|
|
cea88a9e4e | ||
|
|
357e9f9572 | ||
|
|
9c0d92d957 | ||
|
|
8949903fbb | ||
|
|
6b3a4aac09 | ||
|
|
106ee05ba0 | ||
|
|
6c84a36b53 | ||
|
|
8215e3503d | ||
|
|
fa58fc3257 | ||
|
|
c728d88e11 | ||
|
|
086f1ef4a0 | ||
|
|
254e5c5d11 | ||
|
|
18528180d9 | ||
|
|
72e2e92f4c | ||
|
|
dd7ebec120 | ||
|
|
15826214f9 | ||
|
|
e166d2b14c | ||
|
|
40c1f7889f | ||
|
|
c8cfbfa605 | ||
|
|
20b9746c5d | ||
|
|
42f7caf1c2 | ||
|
|
f85a010a6b | ||
|
|
565df4e732 | ||
|
|
428514a07f | ||
|
|
ccab4a1994 | ||
|
|
328303d4d4 | ||
|
|
54f61e7dcc | ||
|
|
3fd75d1bcd | ||
|
|
8eab37593e | ||
|
|
27c647d6ce | ||
|
|
2a7f2a3a24 | ||
|
|
7d8bd97187 | ||
|
|
9d2b9e5bc6 | ||
|
|
52e7270e23 | ||
|
|
faf3cc8f71 | ||
|
|
b2cb8f846a | ||
|
|
b1729dbcdd | ||
|
|
f4abbafde7 | ||
|
|
b58160a191 | ||
|
|
a35098b110 | ||
|
|
218c57410c | ||
|
|
752c39d91d | ||
|
|
33703995ae | ||
|
|
f38a54227d | ||
|
|
70b159d145 | ||
|
|
3eff3aa4f8 | ||
|
|
5b515db71b | ||
|
|
52ab3c1584 | ||
|
|
a457566e91 | ||
|
|
c6be409609 | ||
|
|
327f62a255 | ||
|
|
b5f444d447 | ||
|
|
e84e9cd115 | ||
|
|
fededfbbbc | ||
|
|
0524829af6 | ||
|
|
e53cfc6a88 | ||
|
|
9b79f0244a | ||
|
|
fa00fce97c | ||
|
|
a163d5341a | ||
|
|
d067263f51 | ||
|
|
5fca75877d | ||
|
|
22c5467add | ||
|
|
17f5572bc9 | ||
|
|
9df6f601e0 | ||
|
|
885e57cb27 | ||
|
|
7824bb710d | ||
|
|
be3af7f93e | ||
|
|
981a3ba98e | ||
|
|
9a8c36b891 | ||
|
|
c4153a8dfc | ||
|
|
3b6b7f8f9b | ||
|
|
1c79cf9830 | ||
|
|
77d5caae90 | ||
|
|
75fed05d3e | ||
|
|
e82b70e739 | ||
|
|
9c7ee1e1c4 | ||
|
|
5c2f7f083c | ||
|
|
2a307ce33c | ||
|
|
b48e10d9e6 | ||
|
|
ebd147ff24 | ||
|
|
4ce9579099 | ||
|
|
1c59140f5f | ||
|
|
a8759dc7a6 | ||
|
|
5e672df6ae | ||
|
|
8266b7e951 | ||
|
|
ae961a192a | ||
|
|
669b1295ae | ||
|
|
dbc3e62cc0 | ||
|
|
73b7e6fde7 | ||
|
|
7c4b19c335 | ||
|
|
0ac89fb860 | ||
|
|
61e67e51e1 | ||
|
|
962a3eb3fa | ||
|
|
d5da55ed85 | ||
|
|
0e2a358da9 | ||
|
|
59dc9b445d | ||
|
|
f20e828ec2 | ||
|
|
bb7c064b23 | ||
|
|
c93e0932e8 | ||
|
|
8b111f28b0 | ||
|
|
bc8c8d2f87 | ||
|
|
5cb4b2a424 | ||
|
|
1f5f8382ae | ||
|
|
fb171edd45 | ||
|
|
0c62ae3f89 | ||
|
|
c78239d860 | ||
|
|
286c1ba336 | ||
|
|
88ae928ca3 | ||
|
|
9573ff3a3b | ||
|
|
b67ef90438 | ||
|
|
cc87f55e25 | ||
|
|
0d22b58172 | ||
|
|
e6bb780d24 | ||
|
|
c7c7017f0c | ||
|
|
60db97ae1d | ||
|
|
00befc04d0 | ||
|
|
6e6ef95ba6 | ||
|
|
e966752b86 | ||
|
|
229582c97c | ||
|
|
da30b4a786 | ||
|
|
616eeba6f2 | ||
|
|
e7aa51c70f | ||
|
|
18259d5559 | ||
|
|
e4d9099e19 | ||
|
|
d154dd6638 | ||
|
|
1539e51721 | ||
|
|
bd8c6cf862 | ||
|
|
f2ff06d675 | ||
|
|
55521be2cb | ||
|
|
802382e21f | ||
|
|
b7da704566 | ||
|
|
58a9254252 | ||
|
|
d2d8dd7f7f | ||
|
|
c157c43f7c | ||
|
|
eb60029245 | ||
|
|
3c657adc0a | ||
|
|
c67bd8b47b | ||
|
|
74460cd009 | ||
|
|
3e781ea446 | ||
|
|
11384637fb | ||
|
|
3810fd8d0d | ||
|
|
bd7cdd0b09 | ||
|
|
de66704253 | ||
|
|
2eda683a20 | ||
|
|
232918fb86 | ||
|
|
29abba3785 | ||
|
|
66b10275c5 | ||
|
|
f6eeb218b2 | ||
|
|
891f8dc19d | ||
|
|
1140d70893 | ||
|
|
eebf070d32 | ||
|
|
21a5be2364 | ||
|
|
6a1f458bb7 | ||
|
|
4d19321fd3 | ||
|
|
02c4901d89 | ||
|
|
7b5b1a9b6f | ||
|
|
0625c7f372 | ||
|
|
09177b53dd | ||
|
|
b6f0f20da2 | ||
|
|
c4497ee9e8 | ||
|
|
15a8142f6d | ||
|
|
dbba1e9b93 | ||
|
|
cb379c86c4 | ||
|
|
d4d39d0f90 | ||
|
|
7635df8cce | ||
|
|
272ec3fa73 | ||
|
|
89fdc0b588 | ||
|
|
ccc35e2647 | ||
|
|
7f97c7ea9a | ||
|
|
02b99be57e |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -25,17 +25,25 @@ make.tmpl
|
||||
|
||||
/autom4te.cache/
|
||||
/autoscan.log
|
||||
/build/
|
||||
/config.cache
|
||||
/config.log
|
||||
/config.status
|
||||
/configure.scan
|
||||
/cscope.out
|
||||
/html/
|
||||
/reports/
|
||||
/tags
|
||||
/tmp/
|
||||
|
||||
coverity/coverity_model.xml
|
||||
|
||||
tools/man-generator
|
||||
tools/man-generator.c
|
||||
|
||||
test/.lib-dir-stamp
|
||||
test/.tests-stamp
|
||||
test/lib/dmsecuretest
|
||||
test/lib/lvchange
|
||||
test/lib/lvconvert
|
||||
test/lib/lvcreate
|
||||
@@ -60,6 +68,7 @@ test/lib/pvremove
|
||||
test/lib/pvresize
|
||||
test/lib/pvs
|
||||
test/lib/pvscan
|
||||
test/lib/securetest
|
||||
test/lib/vgcfgbackup
|
||||
test/lib/vgcfgrestore
|
||||
test/lib/vgchange
|
||||
|
||||
25
COPYING.BSD
Normal file
25
COPYING.BSD
Normal file
@@ -0,0 +1,25 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2014, Red Hat, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
78
Makefile.in
78
Makefile.in
@@ -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 device_mapper tools
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||
|
||||
ifeq ("@UDEV_RULES@", "yes")
|
||||
SUBDIRS += udev
|
||||
@@ -28,14 +28,6 @@ ifeq ("@INTL@", "yes")
|
||||
SUBDIRS += po
|
||||
endif
|
||||
|
||||
ifeq ("@APPLIB@", "yes")
|
||||
SUBDIRS += liblvm
|
||||
endif
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
SUBDIRS += python
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),clean)
|
||||
SUBDIRS += test
|
||||
endif
|
||||
@@ -43,7 +35,7 @@ endif
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = conf include man test scripts \
|
||||
libdaemon lib tools daemons libdm \
|
||||
udev po liblvm python device_mapper
|
||||
udev po
|
||||
tools.distclean: test.distclean
|
||||
endif
|
||||
DISTCLEAN_DIRS += lcov_reports*
|
||||
@@ -51,23 +43,25 @@ DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
|
||||
|
||||
include make.tmpl
|
||||
|
||||
include $(top_srcdir)/base/Makefile
|
||||
include $(top_srcdir)/device_mapper/Makefile
|
||||
include $(top_srcdir)/test/unit/Makefile
|
||||
|
||||
libdm: include
|
||||
libdaemon: include
|
||||
lib: libdm libdaemon
|
||||
liblvm: lib
|
||||
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
||||
daemons: lib libdaemon tools
|
||||
tools: lib libdaemon device-mapper
|
||||
scripts: lib
|
||||
tools: lib libdaemon
|
||||
po: tools daemons
|
||||
man: tools
|
||||
all_man: tools
|
||||
scripts: liblvm libdm
|
||||
scripts: libdm
|
||||
test: tools daemons
|
||||
unit-test: lib
|
||||
run-unit-test: unit-test
|
||||
unit-test run-unit-test: test
|
||||
|
||||
lib.device-mapper: include.device-mapper
|
||||
libdm.device-mapper: include.device-mapper
|
||||
liblvm.device-mapper: include.device-mapper
|
||||
daemons.device-mapper: libdm.device-mapper
|
||||
tools.device-mapper: libdm.device-mapper
|
||||
scripts.device-mapper: include.device-mapper
|
||||
@@ -81,10 +75,6 @@ po.pofile: tools.pofile daemons.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
python: liblvm
|
||||
endif
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
tools.cflow: libdm.cflow lib.cflow
|
||||
daemons.cflow: tools.cflow
|
||||
@@ -99,7 +89,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-test run-unit-test: test
|
||||
check check_system check_cluster check_local check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock: test
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate man.generate: tools
|
||||
@@ -161,27 +151,11 @@ install_systemd_units:
|
||||
install_all_man:
|
||||
$(MAKE) -C man install_all_man
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
install_python_bindings:
|
||||
$(MAKE) -C liblvm/python install_python_bindings
|
||||
endif
|
||||
|
||||
install_tmpfiles_configuration:
|
||||
$(MAKE) -C scripts 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 \
|
||||
daemons/lvmlockd.info \
|
||||
daemons/lvmpolld.info
|
||||
|
||||
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||
|
||||
ifneq ("$(LCOV)", "")
|
||||
.PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES)
|
||||
.PHONY: lcov-reset lcov lcov-dated
|
||||
|
||||
ifeq ($(MAKECMDGOALS),lcov-dated)
|
||||
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
|
||||
@@ -191,30 +165,22 @@ LCOV_REPORTS_DIR := lcov_reports
|
||||
endif
|
||||
|
||||
lcov-reset:
|
||||
$(LCOV) --zerocounters $(addprefix -d , $(basename $(LCOV_TRACES)))
|
||||
|
||||
# maybe use subdirs processing to create tracefiles...
|
||||
$(LCOV_TRACES):
|
||||
$(LCOV) -b $(basename $@) -d $(basename $@) \
|
||||
--ignore-errors source -c -o - | $(SED) \
|
||||
-e "s/\(dmeventd_lvm.[ch]\)/plugins\/lvm2\/\1/" \
|
||||
-e "s/dmeventd_\(mirror\|snapshot\|thin\|raid\)\.c/plugins\/\1\/dmeventd_\1\.c/" \
|
||||
>$@
|
||||
$(LCOV) --zerocounters --directory $(top_builddir)
|
||||
|
||||
ifneq ("$(GENHTML)", "")
|
||||
lcov: $(LCOV_TRACES)
|
||||
$(RM) -r $(LCOV_REPORTS_DIR)
|
||||
lcov:
|
||||
$(RM) -rf $(LCOV_REPORTS_DIR)
|
||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||
for i in $(LCOV_TRACES); do \
|
||||
test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
|
||||
done; \
|
||||
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
||||
-o $(LCOV_REPORTS_DIR) $$lc
|
||||
$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
|
||||
--output-file $(LCOV_REPORTS_DIR)/out.info
|
||||
-test ! -s $(LCOV_REPORTS_DIR)/out.info || \
|
||||
$(GENHTML) -o $(LCOV_REPORTS_DIR) --ignore-errors source \
|
||||
$(LCOV_REPORTS_DIR)/out.info
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
ifneq ($(shell which ctags 2>/dev/null),)
|
||||
.PHONY: tags
|
||||
tags:
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||
|
||||
3
README
3
README
@@ -1,5 +1,8 @@
|
||||
This tree contains the LVM2 and device-mapper tools and libraries.
|
||||
|
||||
This is development branch, for stable 2.02 release see 2018-06-01-stable
|
||||
branch.
|
||||
|
||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
|
||||
Installation instructions are in INSTALL.
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.147-git (2018-05-24)
|
||||
1.02.163-git (2019-06-10)
|
||||
|
||||
91
WHATS_NEW
91
WHATS_NEW
@@ -1,5 +1,94 @@
|
||||
Version 2.02.178 -
|
||||
Version 2.03.05 -
|
||||
================================
|
||||
Fix command definition for pvchange -a.
|
||||
Add vgck --updatemetadata command that will repair metadata problems.
|
||||
Improve VG reading to work if one good copy of metadata is found.
|
||||
Report/display/scan commands that read VGs will no longer write/repair.
|
||||
Move metadata repairs from VG reading to VG writing.
|
||||
Add config setting md_component_checks to control MD component checks.
|
||||
Add end of device MD component checks when dev has no udev info.
|
||||
|
||||
Version 2.03.04 - 10th June 2019
|
||||
================================
|
||||
Remove unused_duplicate_devs from cmd causing segfault in dmeventd.
|
||||
|
||||
Version 2.03.03 - 07th June 2019
|
||||
================================
|
||||
Report no_discard_passdown for cache LVs with lvs -o+kernel_discards.
|
||||
Add pvck --dump option to extract metadata.
|
||||
Fix signal delivery checking race in libdaemon (lvmetad).
|
||||
Add missing Before=shutdown.target to LVM2 services to fix shutdown ordering.
|
||||
Skip autoactivation for a PV when PV size does not match device size.
|
||||
Remove first-pvscan-initialization which should no longer be needed.
|
||||
Add remote refresh through lvmlockd/dlm for shared LVs after lvextend.
|
||||
Ignore foreign and shared PVs for pvscan online files.
|
||||
Add config setting to control fields in debug file and verbose output.
|
||||
Add command[pid] and timestamp to debug file and verbose output.
|
||||
Fix missing growth of _pmsmare volume when extending _tmeta volume.
|
||||
Automatically grow thin metadata, when thin data gets too big.
|
||||
Add synchronization with udev before removing cached devices.
|
||||
Add support for caching VDO LVs and VDOPOOL LVs.
|
||||
Add support for vgsplit with cached devices.
|
||||
Query mpath device only once per command for its state.
|
||||
Use device INFO instead of STATUS when checking for mpath device uuid.
|
||||
Change default io_memory_size from 4 to 8 MiB.
|
||||
Add config setting io_memory_size to set bcache size.
|
||||
Fix pvscan autoactivation for concurrent pvscans.
|
||||
Change scan_lvs default to 0 so LVs are not scanned for PVs.
|
||||
Thin-pool selects power-of-2 chunk size by default.
|
||||
Cache selects power-of-2 chunk size by default.
|
||||
Support reszing for VDOPoolLV and VDOLV.
|
||||
Improve -lXXX%VG modifier which improves cache segment estimation.
|
||||
Ensure migration_threshold for cache is at least 8 chunks.
|
||||
Restore missing man info lvcreate --zero for thin-pools.
|
||||
Drop misleadning comment for metadata minimum_io_size for VDO segment.
|
||||
Add device hints to reduce scanning.
|
||||
Introduce LVM_SUPPRESS_SYSLOG to suppress syslog usage by generator.
|
||||
Fix generator quering lvmconfig unpresent config option.
|
||||
Fix memleak on bcache error path code.
|
||||
Fix missing unlock on lvm2 dmeventd plugin error path initialization.
|
||||
Improve Makefile dependency tracking.
|
||||
Move VDO support towards V2 target (6.2) support.
|
||||
|
||||
Version 2.03.02 - 18th December 2018
|
||||
====================================
|
||||
Fix missing proper initialization of pv_list struct when adding pv.
|
||||
Fix (de)activation of RaidLVs with visible SubLVs.
|
||||
Prohibit mirrored 'mirror' log via lvcreate and lvconvert.
|
||||
Use sync io if async io_setup fails, or use_aio=0 is set in config.
|
||||
Fix more issues reported by coverity scan.
|
||||
|
||||
Version 2.03.01 - 31st October 2018
|
||||
===================================
|
||||
|
||||
Version 2.03.00 - 10th October 2018
|
||||
===================================
|
||||
Add hot fix to avoiding locking collision when monitoring thin-pools.
|
||||
Allow raid4 -> linear conversion request.
|
||||
Fix lvconvert striped/raid0/raid0_meta -> raid6 regression.
|
||||
Add 'lvm2-activation-generator:' prefix for kmsg messages logged by generator.
|
||||
Add After=rbdmap.service to {lvm2-activation-net,blk-availability}.service.
|
||||
Reduce max concurrent aios to avoid EMFILE with many devices.
|
||||
Fix lvconvert conversion attempts to linear.
|
||||
Fix lvconvert raid0/raid0_meta -> striped regression.
|
||||
Fix lvconvert --splitmirror for mirror type (2.02.178).
|
||||
Do not pair cache policy and cache metadata format.
|
||||
lvconvert: reject conversions on raid1 LVs with split tracked SubLVs
|
||||
lvconvert: reject conversions on raid1 split tracked SubLVs
|
||||
Add basic creation support for VDO target.
|
||||
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.
|
||||
Configure supports --disable-silent-rules for verbose builds.
|
||||
Fix unmonitoring of merging snapshots.
|
||||
Cache can uses metadata format 2 with cleaner policy.
|
||||
Fix check if resized PV can also fit metadata area.
|
||||
Avoid showing internal error in lvs output or pvmoved LVs.
|
||||
Remove clvmd
|
||||
Remove lvmlib (api)
|
||||
Remove lvmetad
|
||||
lvconvert: provide possible layouts between linear and striped/raid
|
||||
Use versionsort to fix archive file expiry beyond 100000 files.
|
||||
|
||||
Version 2.02.178-rc1 - 24th May 2018
|
||||
|
||||
38
WHATS_NEW_DM
38
WHATS_NEW_DM
@@ -1,6 +1,42 @@
|
||||
Version 1.02.147 -
|
||||
Version 1.02.163 -
|
||||
=================================
|
||||
|
||||
Version 1.02.161 - 10th June 2019
|
||||
=================================
|
||||
|
||||
Version 1.02.159 - 07th June 2019
|
||||
=================================
|
||||
Parsing of cache status understand no_discard_passdown.
|
||||
Ensure migration_threshold for cache is at least 8 chunks.
|
||||
|
||||
Version 1.02.155 - 18th December 2018
|
||||
=====================================
|
||||
Include correct internal header inside libdm list.c.
|
||||
Enhance ioctl flattening and add parameters only when needed.
|
||||
Add DM_DEVICE_ARM_POLL for API completness matching kernel.
|
||||
Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
|
||||
Fix dmstats report printing no output.
|
||||
|
||||
Version 1.02.153 - 31st October 2018
|
||||
====================================
|
||||
|
||||
Version 1.02.151 - 10th October 2018
|
||||
====================================
|
||||
Add hot fix to avoiding locking collision when monitoring thin-pools.
|
||||
|
||||
Version 1.02.150 - 01 August 2018
|
||||
=================================
|
||||
Add vdo plugin for monitoring VDO devices.
|
||||
|
||||
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.
|
||||
|
||||
91
aclocal.m4
vendored
91
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
||||
# generated automatically by aclocal 1.15 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_python_module.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
@@ -37,7 +37,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 8
|
||||
#serial 9
|
||||
|
||||
AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
|
||||
AC_DEFUN([AX_PYTHON_MODULE],[
|
||||
@@ -69,9 +69,9 @@ AC_DEFUN([AX_PYTHON_MODULE],[
|
||||
fi
|
||||
])
|
||||
|
||||
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
dnl serial 11 (pkg-config-0.29)
|
||||
dnl
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 11 (pkg-config-0.29.1)
|
||||
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
@@ -112,7 +112,7 @@ 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_define([PKG_MACROS_VERSION], [0.29.1])
|
||||
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
|
||||
@@ -345,7 +345,75 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])dnl PKG_CHECK_VAR
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES,
|
||||
dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],
|
||||
dnl [DESCRIPTION], [DEFAULT])
|
||||
dnl ------------------------------------------
|
||||
dnl
|
||||
dnl Prepare a "--with-" configure option using the lowercase
|
||||
dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and
|
||||
dnl PKG_CHECK_MODULES in a single macro.
|
||||
AC_DEFUN([PKG_WITH_MODULES],
|
||||
[
|
||||
m4_pushdef([with_arg], m4_tolower([$1]))
|
||||
|
||||
m4_pushdef([description],
|
||||
[m4_default([$5], [build with ]with_arg[ support])])
|
||||
|
||||
m4_pushdef([def_arg], [m4_default([$6], [auto])])
|
||||
m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes])
|
||||
m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no])
|
||||
|
||||
m4_case(def_arg,
|
||||
[yes],[m4_pushdef([with_without], [--without-]with_arg)],
|
||||
[m4_pushdef([with_without],[--with-]with_arg)])
|
||||
|
||||
AC_ARG_WITH(with_arg,
|
||||
AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),,
|
||||
[AS_TR_SH([with_]with_arg)=def_arg])
|
||||
|
||||
AS_CASE([$AS_TR_SH([with_]with_arg)],
|
||||
[yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
|
||||
[auto],[PKG_CHECK_MODULES([$1],[$2],
|
||||
[m4_n([def_action_if_found]) $3],
|
||||
[m4_n([def_action_if_not_found]) $4])])
|
||||
|
||||
m4_popdef([with_arg])
|
||||
m4_popdef([description])
|
||||
m4_popdef([def_arg])
|
||||
|
||||
])dnl PKG_WITH_MODULES
|
||||
|
||||
dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
|
||||
dnl [DESCRIPTION], [DEFAULT])
|
||||
dnl -----------------------------------------------
|
||||
dnl
|
||||
dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES
|
||||
dnl check._[VARIABLE-PREFIX] is exported as make variable.
|
||||
AC_DEFUN([PKG_HAVE_WITH_MODULES],
|
||||
[
|
||||
PKG_WITH_MODULES([$1],[$2],,,[$3],[$4])
|
||||
|
||||
AM_CONDITIONAL([HAVE_][$1],
|
||||
[test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"])
|
||||
])dnl PKG_HAVE_WITH_MODULES
|
||||
|
||||
dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
|
||||
dnl [DESCRIPTION], [DEFAULT])
|
||||
dnl ------------------------------------------------------
|
||||
dnl
|
||||
dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after
|
||||
dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make
|
||||
dnl and preprocessor variable.
|
||||
AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES],
|
||||
[
|
||||
PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4])
|
||||
|
||||
AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
|
||||
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
|
||||
])dnl PKG_HAVE_DEFINE_WITH_MODULES
|
||||
|
||||
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
@@ -378,8 +446,9 @@ AC_DEFUN([AM_PATH_PYTHON],
|
||||
[
|
||||
dnl Find a Python interpreter. Python versions prior to 2.0 are not
|
||||
dnl supported. (2.0 was released on October 16, 2000).
|
||||
dnl FIXME: Remove the need to hard-code Python versions here.
|
||||
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
|
||||
[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
|
||||
[python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
|
||||
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
|
||||
|
||||
AC_ARG_VAR([PYTHON], [the Python interpreter])
|
||||
@@ -580,7 +649,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
|
||||
sys.exit(sys.hexversion < minverhex)"
|
||||
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
||||
40
base/Makefile
Normal file
40
base/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
# 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
|
||||
|
||||
# Uncomment this to build the simple radix tree. You'll need to make clean too.
|
||||
# Comment to build the advanced radix tree.
|
||||
#base/data-struct/radix-tree.o: CFLAGS += -DSIMPLE_RADIX_TREE
|
||||
|
||||
# NOTE: this Makefile only works as 'include' for toplevel Makefile
|
||||
# which defined all top_* variables
|
||||
|
||||
BASE_SOURCE=\
|
||||
base/data-struct/hash.c \
|
||||
base/data-struct/list.c \
|
||||
base/data-struct/radix-tree.c
|
||||
|
||||
BASE_TARGET = base/libbase.a
|
||||
BASE_DEPENDS = $(BASE_SOURCE:%.c=%.d)
|
||||
BASE_OBJECTS = $(BASE_SOURCE:%.c=%.o)
|
||||
CLEAN_TARGETS += $(BASE_DEPENDS) $(BASE_OBJECTS) \
|
||||
$(BASE_SOURCE:%.c=%.gcda) \
|
||||
$(BASE_SOURCE:%.c=%.gcno) \
|
||||
$(BASE_TARGET)
|
||||
|
||||
$(BASE_TARGET): $(BASE_OBJECTS)
|
||||
@echo " [AR] $@"
|
||||
$(Q) $(RM) $@
|
||||
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
||||
|
||||
ifeq ("$(DEPENDS)","yes")
|
||||
-include $(BASE_DEPENDS)
|
||||
endif
|
||||
394
base/data-struct/hash.c
Normal file
394
base/data-struct/hash.c
Normal file
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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
|
||||
*/
|
||||
|
||||
#include "device_mapper/misc/dmlib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "hash.h"
|
||||
|
||||
struct dm_hash_node {
|
||||
struct dm_hash_node *next;
|
||||
void *data;
|
||||
unsigned data_len;
|
||||
unsigned keylen;
|
||||
char key[0];
|
||||
};
|
||||
|
||||
struct dm_hash_table {
|
||||
unsigned num_nodes;
|
||||
unsigned num_slots;
|
||||
struct dm_hash_node **slots;
|
||||
};
|
||||
|
||||
/* Permutation of the Integers 0 through 255 */
|
||||
static unsigned char _nums[] = {
|
||||
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
||||
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
||||
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
||||
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
|
||||
144,
|
||||
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
|
||||
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
|
||||
221,
|
||||
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
|
||||
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
|
||||
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
|
||||
194,
|
||||
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
||||
139,
|
||||
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
|
||||
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
|
||||
43,
|
||||
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
||||
71,
|
||||
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
||||
109,
|
||||
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
|
||||
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
|
||||
209
|
||||
};
|
||||
|
||||
static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||
{
|
||||
struct dm_hash_node *n = malloc(sizeof(*n) + len);
|
||||
|
||||
if (n) {
|
||||
memcpy(n->key, str, len);
|
||||
n->keylen = len;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long _hash(const char *str, unsigned len)
|
||||
{
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[(unsigned char) *str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
h ^= g >> 5u;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
||||
{
|
||||
size_t len;
|
||||
unsigned new_size = 16u;
|
||||
struct dm_hash_table *hc = zalloc(sizeof(*hc));
|
||||
|
||||
if (!hc)
|
||||
return_0;
|
||||
|
||||
/* round size hint up to a power of two */
|
||||
while (new_size < size_hint)
|
||||
new_size = new_size << 1;
|
||||
|
||||
hc->num_slots = new_size;
|
||||
len = sizeof(*(hc->slots)) * new_size;
|
||||
if (!(hc->slots = zalloc(len)))
|
||||
goto_bad;
|
||||
|
||||
return hc;
|
||||
|
||||
bad:
|
||||
free(hc->slots);
|
||||
free(hc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _free_nodes(struct dm_hash_table *t)
|
||||
{
|
||||
struct dm_hash_node *c, *n;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
n = c->next;
|
||||
free(c);
|
||||
}
|
||||
}
|
||||
|
||||
void dm_hash_destroy(struct dm_hash_table *t)
|
||||
{
|
||||
_free_nodes(t);
|
||||
free(t->slots);
|
||||
free(t);
|
||||
}
|
||||
|
||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||
struct dm_hash_node **c;
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
continue;
|
||||
|
||||
if (!memcmp(key, (*c)->key, len))
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
return *c ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len, void *data)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
if (*c)
|
||||
(*c)->data = data;
|
||||
else {
|
||||
struct dm_hash_node *n = _create_node(key, len);
|
||||
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
n->data = data;
|
||||
n->next = 0;
|
||||
*c = n;
|
||||
t->num_nodes++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_hash_remove_binary(struct dm_hash_table *t, const void *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
if (*c) {
|
||||
struct dm_hash_node *old = *c;
|
||||
*c = (*c)->next;
|
||||
free(old);
|
||||
t->num_nodes--;
|
||||
}
|
||||
}
|
||||
|
||||
void *dm_hash_lookup(struct dm_hash_table *t, const char *key)
|
||||
{
|
||||
return dm_hash_lookup_binary(t, key, strlen(key) + 1);
|
||||
}
|
||||
|
||||
int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data)
|
||||
{
|
||||
return dm_hash_insert_binary(t, key, strlen(key) + 1, data);
|
||||
}
|
||||
|
||||
void dm_hash_remove(struct dm_hash_table *t, const char *key)
|
||||
{
|
||||
dm_hash_remove_binary(t, key, strlen(key) + 1);
|
||||
}
|
||||
|
||||
static struct dm_hash_node **_find_str_with_val(struct dm_hash_table *t,
|
||||
const void *key, const void *val,
|
||||
uint32_t len, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
unsigned h;
|
||||
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
continue;
|
||||
|
||||
if (!memcmp(key, (*c)->key, len) && (*c)->data) {
|
||||
if (((*c)->data_len == val_len) &&
|
||||
!memcmp(val, (*c)->data, val_len))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
struct dm_hash_node *first;
|
||||
int len = strlen(key) + 1;
|
||||
unsigned h;
|
||||
|
||||
n = _create_node(key, len);
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
n->data = (void *)val;
|
||||
n->data_len = val_len;
|
||||
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
first = t->slots[h];
|
||||
|
||||
if (first)
|
||||
n->next = first;
|
||||
else
|
||||
n->next = 0;
|
||||
t->slots[h] = n;
|
||||
|
||||
t->num_nodes++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look through multiple entries with the same key for one that has a
|
||||
* matching val and return that. If none have maching val, return NULL.
|
||||
*/
|
||||
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
|
||||
c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len);
|
||||
|
||||
return (c && *c) ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look through multiple entries with the same key for one that has a
|
||||
* matching val and remove that.
|
||||
*/
|
||||
void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
|
||||
c = _find_str_with_val(t, key, val, strlen(key) + 1, val_len);
|
||||
|
||||
if (c && *c) {
|
||||
struct dm_hash_node *old = *c;
|
||||
*c = (*c)->next;
|
||||
free(old);
|
||||
t->num_nodes--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the value for a key and count how many
|
||||
* entries have the same key.
|
||||
*
|
||||
* If no entries have key, return NULL and set count to 0.
|
||||
*
|
||||
* If one entry has the key, the function returns the val,
|
||||
* and sets count to 1.
|
||||
*
|
||||
* If N entries have the key, the function returns the val
|
||||
* from the first entry, and sets count to N.
|
||||
*/
|
||||
void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count)
|
||||
{
|
||||
struct dm_hash_node **c;
|
||||
struct dm_hash_node **c1 = NULL;
|
||||
uint32_t len = strlen(key) + 1;
|
||||
unsigned h;
|
||||
|
||||
*count = 0;
|
||||
|
||||
h = _hash(key, len) & (t->num_slots - 1);
|
||||
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next)) {
|
||||
if ((*c)->keylen != len)
|
||||
continue;
|
||||
|
||||
if (!memcmp(key, (*c)->key, len)) {
|
||||
(*count)++;
|
||||
if (!c1)
|
||||
c1 = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c1)
|
||||
return NULL;
|
||||
else
|
||||
return *c1 ? (*c1)->data : 0;
|
||||
}
|
||||
|
||||
unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
|
||||
{
|
||||
return t->num_nodes;
|
||||
}
|
||||
|
||||
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
|
||||
{
|
||||
struct dm_hash_node *c, *n;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
n = c->next;
|
||||
f(c->data);
|
||||
}
|
||||
}
|
||||
|
||||
void dm_hash_wipe(struct dm_hash_table *t)
|
||||
{
|
||||
_free_nodes(t);
|
||||
memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
|
||||
t->num_nodes = 0u;
|
||||
}
|
||||
|
||||
char *dm_hash_get_key(struct dm_hash_table *t __attribute__((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->key;
|
||||
}
|
||||
|
||||
void *dm_hash_get_data(struct dm_hash_table *t __attribute__((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->data;
|
||||
}
|
||||
|
||||
static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
|
||||
{
|
||||
struct dm_hash_node *c = NULL;
|
||||
unsigned i;
|
||||
|
||||
for (i = s; i < t->num_slots && !c; i++)
|
||||
c = t->slots[i];
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
|
||||
{
|
||||
return _next_slot(t, 0);
|
||||
}
|
||||
|
||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
{
|
||||
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
||||
94
base/data-struct/hash.h
Normal file
94
base/data-struct/hash.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#ifndef BASE_DATA_STRUCT_HASH_H
|
||||
#define BASE_DATA_STRUCT_HASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
struct dm_hash_table;
|
||||
struct dm_hash_node;
|
||||
|
||||
typedef void (*dm_hash_iterate_fn) (void *data);
|
||||
|
||||
struct dm_hash_table *dm_hash_create(unsigned size_hint)
|
||||
__attribute__((__warn_unused_result__));
|
||||
void dm_hash_destroy(struct dm_hash_table *t);
|
||||
void dm_hash_wipe(struct dm_hash_table *t);
|
||||
|
||||
void *dm_hash_lookup(struct dm_hash_table *t, const char *key);
|
||||
int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data);
|
||||
void dm_hash_remove(struct dm_hash_table *t, const char *key);
|
||||
|
||||
void *dm_hash_lookup_binary(struct dm_hash_table *t, const void *key, uint32_t len);
|
||||
int dm_hash_insert_binary(struct dm_hash_table *t, const void *key, uint32_t len,
|
||||
void *data);
|
||||
void dm_hash_remove_binary(struct dm_hash_table *t, const void *key, uint32_t len);
|
||||
|
||||
unsigned dm_hash_get_num_entries(struct dm_hash_table *t);
|
||||
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f);
|
||||
|
||||
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n);
|
||||
void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n);
|
||||
struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t);
|
||||
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n);
|
||||
|
||||
/*
|
||||
* dm_hash_insert() replaces the value of an existing
|
||||
* entry with a matching key if one exists. Otherwise
|
||||
* it adds a new entry.
|
||||
*
|
||||
* dm_hash_insert_with_val() inserts a new entry if
|
||||
* another entry with the same key already exists.
|
||||
* val_len is the size of the data being inserted.
|
||||
*
|
||||
* If two entries with the same key exist,
|
||||
* (added using dm_hash_insert_allow_multiple), then:
|
||||
* . dm_hash_lookup() returns the first one it finds, and
|
||||
* dm_hash_lookup_with_val() returns the one with a matching
|
||||
* val_len/val.
|
||||
* . dm_hash_remove() removes the first one it finds, and
|
||||
* dm_hash_remove_with_val() removes the one with a matching
|
||||
* val_len/val.
|
||||
*
|
||||
* If a single entry with a given key exists, and it has
|
||||
* zero val_len, then:
|
||||
* . dm_hash_lookup() returns it
|
||||
* . dm_hash_lookup_with_val(val_len=0) returns it
|
||||
* . dm_hash_remove() removes it
|
||||
* . dm_hash_remove_with_val(val_len=0) removes it
|
||||
*
|
||||
* dm_hash_lookup_with_count() is a single call that will
|
||||
* both lookup a key's value and check if there is more
|
||||
* than one entry with the given key.
|
||||
*
|
||||
* (It is not meant to retrieve all the entries with the
|
||||
* given key. In the common case where a single entry exists
|
||||
* for the key, it is useful to have a single call that will
|
||||
* both look up the value and indicate if multiple values
|
||||
* exist for the key.)
|
||||
*
|
||||
* dm_hash_lookup_with_count:
|
||||
* . If no entries exist, the function returns NULL, and
|
||||
* the count is set to 0.
|
||||
* . If only one entry exists, the value of that entry is
|
||||
* returned and count is set to 1.
|
||||
* . If N entries exists, the value of the first entry is
|
||||
* returned and count is set to N.
|
||||
*/
|
||||
|
||||
void *dm_hash_lookup_with_val(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len);
|
||||
void dm_hash_remove_with_val(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len);
|
||||
int dm_hash_insert_allow_multiple(struct dm_hash_table *t, const char *key,
|
||||
const void *val, uint32_t val_len);
|
||||
void *dm_hash_lookup_with_count(struct dm_hash_table *t, const char *key, int *count);
|
||||
|
||||
|
||||
#define dm_hash_iterate(v, h) \
|
||||
for (v = dm_hash_get_first((h)); v; \
|
||||
v = dm_hash_get_next((h), v))
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
170
base/data-struct/list.c
Normal file
170
base/data-struct/list.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 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 "list.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* Initialise a list before use.
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
void dm_list_init(struct dm_list *head)
|
||||
{
|
||||
head->n = head->p = head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
void dm_list_add(struct dm_list *head, struct dm_list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head;
|
||||
elem->p = head->p;
|
||||
|
||||
head->p->n = elem;
|
||||
head->p = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
void dm_list_add_h(struct dm_list *head, struct dm_list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head->n;
|
||||
elem->p = head;
|
||||
|
||||
head->n->p = elem;
|
||||
head->n = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
void dm_list_del(struct dm_list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an element from existing list and insert before 'head'.
|
||||
*/
|
||||
void dm_list_move(struct dm_list *head, struct dm_list *elem)
|
||||
{
|
||||
dm_list_del(elem);
|
||||
dm_list_add(head, elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
int dm_list_empty(const struct dm_list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
int dm_list_start(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return elem->p == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
int dm_list_end(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
struct dm_list *dm_list_first(const struct dm_list *head)
|
||||
{
|
||||
return (dm_list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
struct dm_list *dm_list_last(const struct dm_list *head)
|
||||
{
|
||||
return (dm_list_empty(head) ? NULL : head->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return (dm_list_start(head, elem) ? NULL : elem->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem)
|
||||
{
|
||||
return (dm_list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
unsigned int dm_list_size(const struct dm_list *head)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
const struct dm_list *v;
|
||||
|
||||
dm_list_iterate(v, head)
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Join two lists together.
|
||||
* This moves all the elements of the list 'head1' to the end of the list
|
||||
* 'head', leaving 'head1' empty.
|
||||
*/
|
||||
void dm_list_splice(struct dm_list *head, struct dm_list *head1)
|
||||
{
|
||||
assert(head->n);
|
||||
assert(head1->n);
|
||||
|
||||
if (dm_list_empty(head1))
|
||||
return;
|
||||
|
||||
head1->p->n = head;
|
||||
head1->n->p = head->p;
|
||||
|
||||
head->p->n = head1->n;
|
||||
head->p = head1->p;
|
||||
|
||||
dm_list_init(head1);
|
||||
}
|
||||
209
base/data-struct/list.h
Normal file
209
base/data-struct/list.h
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef BASE_DATA_STRUCT_LIST_H
|
||||
#define BASE_DATA_STRUCT_LIST_H
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* A list consists of a list head plus elements.
|
||||
* Each element has 'next' and 'previous' pointers.
|
||||
* The list head's pointers point to the first and the last element.
|
||||
*/
|
||||
|
||||
struct dm_list {
|
||||
struct dm_list *n, *p;
|
||||
};
|
||||
|
||||
/*
|
||||
* String list.
|
||||
*/
|
||||
struct dm_str_list {
|
||||
struct dm_list list;
|
||||
const char *str;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialise a list before use.
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
#define DM_LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
#define DM_LIST_INIT(name) struct dm_list name = DM_LIST_HEAD_INIT(name)
|
||||
void dm_list_init(struct dm_list *head);
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
void dm_list_add(struct dm_list *head, struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
void dm_list_add_h(struct dm_list *head, struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
void dm_list_del(struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Remove an element from existing list and insert before 'head'.
|
||||
*/
|
||||
void dm_list_move(struct dm_list *head, struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Join 'head1' to the end of 'head'.
|
||||
*/
|
||||
void dm_list_splice(struct dm_list *head, struct dm_list *head1);
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
int dm_list_empty(const struct dm_list *head);
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
int dm_list_start(const struct dm_list *head, const struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
int dm_list_end(const struct dm_list *head, const struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
struct dm_list *dm_list_first(const struct dm_list *head);
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
struct dm_list *dm_list_last(const struct dm_list *head);
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
struct dm_list *dm_list_prev(const struct dm_list *head, const struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *elem);
|
||||
|
||||
/*
|
||||
* Given the address v of an instance of 'struct dm_list' called 'head'
|
||||
* contained in a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define dm_list_struct_base(v, t, head) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
|
||||
/*
|
||||
* Given the address v of an instance of 'struct dm_list list' contained in
|
||||
* a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define dm_list_item(v, t) dm_list_struct_base((v), t, list)
|
||||
|
||||
/*
|
||||
* Given the address v of one known element e in a known structure of type t,
|
||||
* return another element f.
|
||||
*/
|
||||
#define dm_struct_field(v, t, e, f) \
|
||||
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
|
||||
|
||||
/*
|
||||
* Given the address v of a known element e in a known structure of type t,
|
||||
* return the list head 'list'
|
||||
*/
|
||||
#define dm_list_head(v, t, e) dm_struct_field(v, t, e, list)
|
||||
|
||||
/*
|
||||
* Set v to each element of a list in turn.
|
||||
*/
|
||||
#define dm_list_iterate(v, head) \
|
||||
for (v = (head)->n; v != head; v = v->n)
|
||||
|
||||
/*
|
||||
* Set v to each element in a list in turn, starting from the element
|
||||
* in front of 'start'.
|
||||
* You can use this to 'unwind' a list_iterate and back out actions on
|
||||
* already-processed elements.
|
||||
* If 'start' is 'head' it walks the list backwards.
|
||||
*/
|
||||
#define dm_list_uniterate(v, head, start) \
|
||||
for (v = (start)->p; v != head; v = v->p)
|
||||
|
||||
/*
|
||||
* A safe way to walk a list and delete and free some elements along
|
||||
* the way.
|
||||
* t must be defined as a temporary variable of the same type as v.
|
||||
*/
|
||||
#define dm_list_iterate_safe(v, t, head) \
|
||||
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
||||
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct dm_list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define dm_list_iterate_items_gen(v, head, field) \
|
||||
for (v = dm_list_struct_base((head)->n, __typeof__(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = dm_list_struct_base(v->field.n, __typeof__(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct dm_list list' within the containing structure.
|
||||
*/
|
||||
#define dm_list_iterate_items(v, head) dm_list_iterate_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct dm_list' variable within the containing structure is 'field'.
|
||||
* t must be defined as a temporary variable of the same type as v.
|
||||
*/
|
||||
#define dm_list_iterate_items_gen_safe(v, t, head, field) \
|
||||
for (v = dm_list_struct_base((head)->n, __typeof__(*v), field), \
|
||||
t = dm_list_struct_base(v->field.n, __typeof__(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = t, t = dm_list_struct_base(v->field.n, __typeof__(*v), field))
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct dm_list list' within the containing structure.
|
||||
* t must be defined as a temporary variable of the same type as v.
|
||||
*/
|
||||
#define dm_list_iterate_items_safe(v, t, head) \
|
||||
dm_list_iterate_items_gen_safe(v, t, (head), list)
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct dm_list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define dm_list_iterate_back_items_gen(v, head, field) \
|
||||
for (v = dm_list_struct_base((head)->p, __typeof__(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = dm_list_struct_base(v->field.p, __typeof__(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct dm_list list' within the containing structure.
|
||||
*/
|
||||
#define dm_list_iterate_back_items(v, head) dm_list_iterate_back_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
unsigned int dm_list_size(const struct dm_list *head);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
1297
base/data-struct/radix-tree-adaptive.c
Normal file
1297
base/data-struct/radix-tree-adaptive.c
Normal file
File diff suppressed because it is too large
Load Diff
256
base/data-struct/radix-tree-simple.c
Normal file
256
base/data-struct/radix-tree-simple.c
Normal file
@@ -0,0 +1,256 @@
|
||||
// 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>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// This implementation is based around nested binary trees. Very
|
||||
// simple (and hopefully correct).
|
||||
|
||||
struct node {
|
||||
struct node *left;
|
||||
struct node *right;
|
||||
|
||||
uint8_t key;
|
||||
struct node *center;
|
||||
|
||||
bool has_value;
|
||||
union radix_value value;
|
||||
};
|
||||
|
||||
struct radix_tree {
|
||||
radix_value_dtr dtr;
|
||||
void *dtr_context;
|
||||
|
||||
struct node *root;
|
||||
};
|
||||
|
||||
struct radix_tree *
|
||||
radix_tree_create(radix_value_dtr dtr, void *dtr_context)
|
||||
{
|
||||
struct radix_tree *rt = zalloc(sizeof(*rt));
|
||||
|
||||
if (rt) {
|
||||
rt->dtr = dtr;
|
||||
rt->dtr_context = dtr_context;
|
||||
}
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
// Returns the number of entries in the tree
|
||||
static unsigned _destroy_tree(struct node *n, radix_value_dtr dtr, void *context)
|
||||
{
|
||||
unsigned r;
|
||||
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
r = _destroy_tree(n->left, dtr, context);
|
||||
r += _destroy_tree(n->right, dtr, context);
|
||||
r += _destroy_tree(n->center, dtr, context);
|
||||
|
||||
if (n->has_value) {
|
||||
if (dtr)
|
||||
dtr(context, n->value);
|
||||
r++;
|
||||
}
|
||||
|
||||
free(n);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void radix_tree_destroy(struct radix_tree *rt)
|
||||
{
|
||||
_destroy_tree(rt->root, rt->dtr, rt->dtr_context);
|
||||
free(rt);
|
||||
}
|
||||
|
||||
static unsigned _count(struct node *n)
|
||||
{
|
||||
unsigned r;
|
||||
|
||||
if (!n)
|
||||
return 0;
|
||||
|
||||
r = _count(n->left);
|
||||
r += _count(n->right);
|
||||
r += _count(n->center);
|
||||
|
||||
if (n->has_value)
|
||||
r++;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned radix_tree_size(struct radix_tree *rt)
|
||||
{
|
||||
return _count(rt->root);
|
||||
}
|
||||
|
||||
static struct node **_lookup(struct node **pn, uint8_t *kb, uint8_t *ke)
|
||||
{
|
||||
struct node *n = *pn;
|
||||
|
||||
if (!n || (kb == ke))
|
||||
return pn;
|
||||
|
||||
if (*kb < n->key)
|
||||
return _lookup(&n->left, kb, ke);
|
||||
|
||||
else if (*kb > n->key)
|
||||
return _lookup(&n->right, kb, ke);
|
||||
|
||||
else
|
||||
return _lookup(&n->center, kb + 1, ke);
|
||||
}
|
||||
|
||||
static bool _insert(struct node **pn, uint8_t *kb, uint8_t *ke, union radix_value v)
|
||||
{
|
||||
struct node *n = *pn;
|
||||
|
||||
if (!n) {
|
||||
n = zalloc(sizeof(*n));
|
||||
if (!n)
|
||||
return false;
|
||||
|
||||
n->key = *kb;
|
||||
*pn = n;
|
||||
}
|
||||
|
||||
if (kb == ke) {
|
||||
n->has_value = true;
|
||||
n->value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*kb < n->key)
|
||||
return _insert(&n->left, kb, ke, v);
|
||||
|
||||
else if (*kb > n->key)
|
||||
return _insert(&n->right, kb, ke, v);
|
||||
|
||||
else
|
||||
return _insert(&n->center, kb + 1, ke, v);
|
||||
}
|
||||
|
||||
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v)
|
||||
{
|
||||
return _insert(&rt->root, kb, ke, v);
|
||||
}
|
||||
|
||||
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
|
||||
{
|
||||
struct node **pn = _lookup(&rt->root, kb, ke);
|
||||
struct node *n = *pn;
|
||||
|
||||
if (!n || !n->has_value)
|
||||
return false;
|
||||
|
||||
else {
|
||||
if (rt->dtr)
|
||||
rt->dtr(rt->dtr_context, n->value);
|
||||
|
||||
if (n->left || n->center || n->right) {
|
||||
n->has_value = false;
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// FIXME: delete parent if this was the last entry
|
||||
free(n);
|
||||
*pn = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
|
||||
{
|
||||
struct node **pn;
|
||||
unsigned count;
|
||||
|
||||
pn = _lookup(&rt->root, kb, ke);
|
||||
|
||||
if (*pn) {
|
||||
count = _destroy_tree(*pn, rt->dtr, rt->dtr_context);
|
||||
*pn = NULL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool
|
||||
radix_tree_lookup(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value *result)
|
||||
{
|
||||
struct node **pn = _lookup(&rt->root, kb, ke);
|
||||
struct node *n = *pn;
|
||||
|
||||
if (n && n->has_value) {
|
||||
*result = n->value;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _iterate(struct node *n, struct radix_tree_iterator *it)
|
||||
{
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
_iterate(n->left, it);
|
||||
|
||||
if (n->has_value)
|
||||
// FIXME: fill out the key
|
||||
it->visit(it, NULL, NULL, n->value);
|
||||
|
||||
_iterate(n->center, it);
|
||||
_iterate(n->right, it);
|
||||
}
|
||||
|
||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||
struct radix_tree_iterator *it)
|
||||
{
|
||||
if (kb == ke)
|
||||
_iterate(rt->root, it);
|
||||
|
||||
else {
|
||||
struct node **pn = _lookup(&rt->root, kb, ke);
|
||||
struct node *n = *pn;
|
||||
|
||||
if (n) {
|
||||
if (n->has_value)
|
||||
it->visit(it, NULL, NULL, n->value);
|
||||
_iterate(n->center, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool radix_tree_is_well_formed(struct radix_tree *rt)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void radix_tree_dump(struct radix_tree *rt, FILE *out)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -10,853 +10,12 @@
|
||||
// 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);
|
||||
}
|
||||
#ifdef SIMPLE_RADIX_TREE
|
||||
#include "base/data-struct/radix-tree-simple.c"
|
||||
#else
|
||||
#include "base/data-struct/radix-tree-adaptive.c"
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -53,6 +54,11 @@ struct radix_tree_iterator {
|
||||
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
|
||||
struct radix_tree_iterator *it);
|
||||
|
||||
// Checks that some constraints on the shape of the tree are
|
||||
// being held. For debug only.
|
||||
bool radix_tree_is_well_formed(struct radix_tree *rt);
|
||||
void radix_tree_dump(struct radix_tree *rt, FILE *out);
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,16 +14,12 @@
|
||||
#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;
|
||||
return calloc(1, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
@@ -25,6 +25,7 @@ PROFILES=$(PROFILE_TEMPLATES) \
|
||||
$(srcdir)/cache-smq.profile \
|
||||
$(srcdir)/thin-generic.profile \
|
||||
$(srcdir)/thin-performance.profile \
|
||||
$(srcdir)/vdo-small.profile \
|
||||
$(srcdir)/lvmdbusd.profile
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
@@ -32,8 +33,8 @@ include $(top_builddir)/make.tmpl
|
||||
.PHONY: install_conf install_localconf install_profiles
|
||||
|
||||
generate:
|
||||
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
|
||||
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
|
||||
$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
|
||||
$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.conf.in
|
||||
|
||||
install_conf: $(CONFSRC)
|
||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||
@@ -48,8 +49,9 @@ install_localconf: $(CONFLOCAL)
|
||||
fi
|
||||
|
||||
install_profiles: $(PROFILES)
|
||||
$(INSTALL_DIR) $(profiledir)
|
||||
$(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DIR) $(profiledir)
|
||||
$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
||||
|
||||
install_lvm2: install_conf install_localconf install_profiles
|
||||
|
||||
|
||||
@@ -88,6 +88,22 @@ devices {
|
||||
#
|
||||
external_device_info_source = "none"
|
||||
|
||||
# Configuration option devices/hints.
|
||||
# Use a local file to remember which devices have PVs on them.
|
||||
# Some commands will use this as an optimization to reduce device
|
||||
# scanning, and will only scan the listed PVs. Removing the hint file
|
||||
# will cause lvm to generate a new one. Disable hints if PVs will
|
||||
# be copied onto devices using non-lvm commands, like dd.
|
||||
#
|
||||
# Accepted values:
|
||||
# all
|
||||
# Use all hints.
|
||||
# none
|
||||
# Use no hints.
|
||||
#
|
||||
# This configuration option has an automatic default value.
|
||||
# hints = "all"
|
||||
|
||||
# Configuration option devices/preferred_names.
|
||||
# Select which path name to display for a block device.
|
||||
# If multiple path names exist for a block device, and LVM needs to
|
||||
@@ -123,7 +139,6 @@ devices {
|
||||
# then the device is accepted. Be careful mixing 'a' and 'r' patterns,
|
||||
# as the combination might produce unexpected results (test changes.)
|
||||
# Run vgscan after changing the filter to regenerate the cache.
|
||||
# See the use_lvmetad comment for a special case regarding filters.
|
||||
#
|
||||
# Example
|
||||
# Accept every block device:
|
||||
@@ -143,31 +158,13 @@ devices {
|
||||
# Configuration option devices/global_filter.
|
||||
# Limit the block devices that are used by LVM system components.
|
||||
# Because devices/filter may be overridden from the command line, it is
|
||||
# not suitable for system-wide device filtering, e.g. udev and lvmetad.
|
||||
# not suitable for system-wide device filtering, e.g. udev.
|
||||
# Use global_filter to hide devices from these LVM system components.
|
||||
# The syntax is the same as devices/filter. Devices rejected by
|
||||
# global_filter are not opened by LVM.
|
||||
# This configuration option has an automatic default value.
|
||||
# global_filter = [ "a|.*/|" ]
|
||||
|
||||
# Configuration option devices/cache_dir.
|
||||
# Directory in which to store the device cache file.
|
||||
# The results of filtering are cached on disk to avoid rescanning dud
|
||||
# devices (which can take a very long time). By default this cache is
|
||||
# stored in a file named .cache. It is safe to delete this file; the
|
||||
# tools regenerate it. If obtain_device_list_from_udev is enabled, the
|
||||
# list of devices is obtained from udev and any existing .cache file
|
||||
# is removed.
|
||||
cache_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@"
|
||||
|
||||
# Configuration option devices/cache_file_prefix.
|
||||
# A prefix used before the .cache file name. See devices/cache_dir.
|
||||
cache_file_prefix = ""
|
||||
|
||||
# Configuration option devices/write_cache_state.
|
||||
# Enable/disable writing the cache file. See devices/cache_dir.
|
||||
write_cache_state = 1
|
||||
|
||||
# Configuration option devices/types.
|
||||
# List of additional acceptable block device types.
|
||||
# These are of device type names from /proc/devices, followed by the
|
||||
@@ -185,14 +182,53 @@ devices {
|
||||
# present on the system. sysfs must be part of the kernel and mounted.)
|
||||
sysfs_scan = 1
|
||||
|
||||
# Configuration option devices/scan_lvs.
|
||||
# Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.
|
||||
# When 1, LVM will detect PVs layered on LVs, and caution must be
|
||||
# taken to avoid a host accessing a layered VG that may not belong
|
||||
# to it, e.g. from a guest image. This generally requires excluding
|
||||
# the LVs with device filters. Also, when this setting is enabled,
|
||||
# every LVM command will scan every active LV on the system (unless
|
||||
# filtered), which can cause performance problems on systems with
|
||||
# many active LVs. When this setting is 0, LVM will not detect or
|
||||
# use PVs that exist on LVs, and will not allow a PV to be created on
|
||||
# an LV. The LVs are ignored using a built in device filter that
|
||||
# identifies and excludes LVs.
|
||||
scan_lvs = 0
|
||||
|
||||
# Configuration option devices/multipath_component_detection.
|
||||
# Ignore devices that are components of DM multipath devices.
|
||||
multipath_component_detection = 1
|
||||
|
||||
# Configuration option devices/md_component_detection.
|
||||
# Ignore devices that are components of software RAID (md) devices.
|
||||
# Enable detection and exclusion of MD component devices.
|
||||
# An MD component device is a block device that MD uses as part
|
||||
# of a software RAID virtual device. When an LVM PV is created
|
||||
# on an MD device, LVM must only use the top level MD device as
|
||||
# the PV, and should ignore the underlying component devices.
|
||||
# In cases where the MD superblock is located at the end of the
|
||||
# component devices, it is more difficult for LVM to consistently
|
||||
# identify an MD component, see the md_component_checks setting.
|
||||
md_component_detection = 1
|
||||
|
||||
# Configuration option devices/md_component_checks.
|
||||
# The checks LVM should use to detect MD component devices.
|
||||
# MD component devices are block devices used by MD software RAID.
|
||||
#
|
||||
# Accepted values:
|
||||
# auto
|
||||
# LVM will skip scanning the end of devices when it has other
|
||||
# indications that the device is not an MD component.
|
||||
# start
|
||||
# LVM will only scan the start of devices for MD superblocks.
|
||||
# This does not incur extra I/O by LVM.
|
||||
# full
|
||||
# LVM will scan the start and end of devices for MD superblocks.
|
||||
# This requires an extra read at the end of devices.
|
||||
#
|
||||
# This configuration option has an automatic default value.
|
||||
# md_component_checks = "auto"
|
||||
|
||||
# Configuration option devices/fw_raid_component_detection.
|
||||
# Ignore devices that are components of firmware RAID devices.
|
||||
# LVM must use an external_device_info_source other than none for this
|
||||
@@ -200,19 +236,24 @@ devices {
|
||||
fw_raid_component_detection = 0
|
||||
|
||||
# Configuration option devices/md_chunk_alignment.
|
||||
# Align PV data blocks with md device's stripe-width.
|
||||
# Align the start of a PV data area with md device's stripe-width.
|
||||
# This applies if a PV is placed directly on an md device.
|
||||
# default_data_alignment will be overriden if it is not aligned
|
||||
# with the value detected for this setting.
|
||||
# This setting is overriden by data_alignment_detection,
|
||||
# data_alignment, and the --dataalignment option.
|
||||
md_chunk_alignment = 1
|
||||
|
||||
# Configuration option devices/default_data_alignment.
|
||||
# Default alignment of the start of a PV data area in MB.
|
||||
# If set to 0, a value of 64KiB will be used.
|
||||
# Set to 1 for 1MiB, 2 for 2MiB, etc.
|
||||
# Align the start of a PV data area with this number of MiB.
|
||||
# Set to 1 for 1MiB, 2 for 2MiB, etc. Set to 0 to disable.
|
||||
# This setting is overriden by data_alignment and the --dataalignment
|
||||
# option.
|
||||
# This configuration option has an automatic default value.
|
||||
# default_data_alignment = 1
|
||||
|
||||
# Configuration option devices/data_alignment_detection.
|
||||
# Detect PV data alignment based on sysfs device information.
|
||||
# Align the start of a PV data area with sysfs io properties.
|
||||
# The start of a PV data area will be a multiple of minimum_io_size or
|
||||
# optimal_io_size exposed in sysfs. minimum_io_size is the smallest
|
||||
# request the device can perform without incurring a read-modify-write
|
||||
@@ -220,27 +261,29 @@ devices {
|
||||
# preferred unit of receiving I/O, e.g. MD stripe width.
|
||||
# minimum_io_size is used if optimal_io_size is undefined (0).
|
||||
# If md_chunk_alignment is enabled, that detects the optimal_io_size.
|
||||
# This setting takes precedence over md_chunk_alignment.
|
||||
# default_data_alignment and md_chunk_alignment will be overriden
|
||||
# if they are not aligned with the value detected for this setting.
|
||||
# This setting is overriden by data_alignment and the --dataalignment
|
||||
# option.
|
||||
data_alignment_detection = 1
|
||||
|
||||
# Configuration option devices/data_alignment.
|
||||
# Alignment of the start of a PV data area in KiB.
|
||||
# If a PV is placed directly on an md device and md_chunk_alignment or
|
||||
# data_alignment_detection are enabled, then this setting is ignored.
|
||||
# Otherwise, md_chunk_alignment and data_alignment_detection are
|
||||
# disabled if this is set. Set to 0 to use the default alignment or the
|
||||
# page size, if larger.
|
||||
# Align the start of a PV data area with this number of KiB.
|
||||
# When non-zero, this setting overrides default_data_alignment.
|
||||
# Set to 0 to disable, in which case default_data_alignment
|
||||
# is used to align the first PE in units of MiB.
|
||||
# This setting is overriden by the --dataalignment option.
|
||||
data_alignment = 0
|
||||
|
||||
# Configuration option devices/data_alignment_offset_detection.
|
||||
# Detect PV data alignment offset based on sysfs device information.
|
||||
# The start of a PV aligned data area will be shifted by the
|
||||
# Shift the start of an aligned PV data area based on sysfs information.
|
||||
# After a PV data area is aligned, it will be shifted by the
|
||||
# alignment_offset exposed in sysfs. This offset is often 0, but may
|
||||
# be non-zero. Certain 4KiB sector drives that compensate for windows
|
||||
# partitioning will have an alignment_offset of 3584 bytes (sector 7
|
||||
# is the lowest aligned logical block, the 4KiB sectors start at
|
||||
# LBA -1, and consequently sector 63 is aligned on a 4KiB boundary).
|
||||
# pvcreate --dataalignmentoffset will skip this detection.
|
||||
# This setting is overriden by the --dataalignmentoffset option.
|
||||
data_alignment_offset_detection = 1
|
||||
|
||||
# Configuration option devices/ignore_suspended_devices.
|
||||
@@ -268,14 +311,6 @@ devices {
|
||||
# different way, making them a better choice for VG stacking.
|
||||
ignore_lvm_mirrors = 1
|
||||
|
||||
# Configuration option devices/disable_after_error_count.
|
||||
# Number of I/O errors after which a device is skipped.
|
||||
# During each LVM operation, errors received from each device are
|
||||
# counted. If the counter of a device exceeds the limit set here,
|
||||
# no further I/O is sent to that device for the remainder of the
|
||||
# operation. Setting this to 0 disables the counters altogether.
|
||||
disable_after_error_count = 0
|
||||
|
||||
# Configuration option devices/require_restorefile_with_uuid.
|
||||
# Allow use of pvcreate --uuid without requiring --restorefile.
|
||||
require_restorefile_with_uuid = 1
|
||||
@@ -346,7 +381,7 @@ allocation {
|
||||
maximise_cling = 1
|
||||
|
||||
# Configuration option allocation/use_blkid_wiping.
|
||||
# Use blkid to detect existing signatures on new PVs and LVs.
|
||||
# Use blkid to detect and erase existing signatures on new PVs and LVs.
|
||||
# The blkid library can detect more signatures than the native LVM
|
||||
# detection code, but may take longer. LVM needs to be compiled with
|
||||
# blkid wiping support for this setting to apply. LVM native detection
|
||||
@@ -498,6 +533,154 @@ allocation {
|
||||
# Default physical extent size in KiB to use for new VGs.
|
||||
# This configuration option has an automatic default value.
|
||||
# physical_extent_size = 4096
|
||||
|
||||
# Configuration option allocation/vdo_use_compression.
|
||||
# Enables or disables compression when creating a VDO volume.
|
||||
# Compression may be disabled if necessary to maximize performance
|
||||
# or to speed processing of data that is unlikely to compress.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_compression = 1
|
||||
|
||||
# Configuration option allocation/vdo_use_deduplication.
|
||||
# Enables or disables deduplication when creating a VDO volume.
|
||||
# Deduplication may be disabled in instances where data is not expected
|
||||
# to have good deduplication rates but compression is still desired.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_deduplication = 1
|
||||
|
||||
# Configuration option allocation/vdo_use_metadata_hints.
|
||||
# Enables or disables whether VDO volume should tag its latency-critical
|
||||
# writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5
|
||||
# process writes with this flag at a higher priority.
|
||||
# Default is enabled.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_metadata_hints = 1
|
||||
|
||||
# Configuration option allocation/vdo_minimum_io_size.
|
||||
# The minimum IO size for VDO volume to accept, in bytes.
|
||||
# Valid values are 512 or 4096. The recommended and default value is 4096.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_minimum_io_size = 4096
|
||||
|
||||
# Configuration option allocation/vdo_block_map_cache_size_mb.
|
||||
# Specifies the amount of memory in MiB allocated for caching block map
|
||||
# pages for VDO volume. The value must be a multiple of 4096 and must be
|
||||
# at least 128MiB and less than 16TiB. The cache must be at least 16MiB
|
||||
# per logical thread. Note that there is a memory overhead of 15%.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_block_map_cache_size_mb = 128
|
||||
|
||||
# Configuration option allocation/vdo_block_map_period.
|
||||
# The speed with which the block map cache writes out modified block map pages.
|
||||
# A smaller era length is likely to reduce the amount time spent rebuilding,
|
||||
# at the cost of increased block map writes during normal operation.
|
||||
# The maximum and recommended value is 16380; the minimum value is 1.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_block_map_period = 16380
|
||||
|
||||
# Configuration option allocation/vdo_check_point_frequency.
|
||||
# The default check point frequency for VDO volume.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_check_point_frequency = 0
|
||||
|
||||
# Configuration option allocation/vdo_use_sparse_index.
|
||||
# Enables sparse indexing for VDO volume.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_use_sparse_index = 0
|
||||
|
||||
# Configuration option allocation/vdo_index_memory_size_mb.
|
||||
# Specifies the amount of index memory in MiB for VDO volume.
|
||||
# The value must be at least 256MiB and at most 1TiB.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_index_memory_size_mb = 256
|
||||
|
||||
# Configuration option allocation/vdo_slab_size_mb.
|
||||
# Specifies the size in MiB of the increment by which a VDO is grown.
|
||||
# Using a smaller size constrains the total maximum physical size
|
||||
# that can be accommodated. Must be a power of two between 128MiB and 32GiB.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_slab_size_mb = 2048
|
||||
|
||||
# Configuration option allocation/vdo_ack_threads.
|
||||
# Specifies the number of threads to use for acknowledging
|
||||
# completion of requested VDO I/O operations.
|
||||
# The value must be at in range [0..100].
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_ack_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_bio_threads.
|
||||
# Specifies the number of threads to use for submitting I/O
|
||||
# operations to the storage device of VDO volume.
|
||||
# The value must be in range [1..100]
|
||||
# Each additional thread after the first will use an additional 18MiB of RAM,
|
||||
# plus 1.12 MiB of RAM per megabyte of configured read cache size.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_bio_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_bio_rotation.
|
||||
# Specifies the number of I/O operations to enqueue for each bio-submission
|
||||
# thread before directing work to the next. The value must be in range [1..1024].
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_bio_rotation = 64
|
||||
|
||||
# Configuration option allocation/vdo_cpu_threads.
|
||||
# Specifies the number of threads to use for CPU-intensive work such as
|
||||
# hashing or compression for VDO volume. The value must be in range [1..100]
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_cpu_threads = 2
|
||||
|
||||
# Configuration option allocation/vdo_hash_zone_threads.
|
||||
# Specifies the number of threads across which to subdivide parts of the VDO
|
||||
# processing based on the hash value computed from the block data.
|
||||
# The value must be at in range [0..100].
|
||||
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
|
||||
# either all zero or all non-zero.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_hash_zone_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_logical_threads.
|
||||
# Specifies the number of threads across which to subdivide parts of the VDO
|
||||
# processing based on the hash value computed from the block data.
|
||||
# A logical thread count of 9 or more will require explicitly specifying
|
||||
# a sufficiently large block map cache size, as well.
|
||||
# The value must be in range [0..100].
|
||||
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
|
||||
# either all zero or all non-zero.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_logical_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_physical_threads.
|
||||
# Specifies the number of threads across which to subdivide parts of the VDO
|
||||
# processing based on physical block addresses.
|
||||
# Each additional thread after the first will use an additional 10MiB of RAM.
|
||||
# The value must be in range [0..16].
|
||||
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
|
||||
# either all zero or all non-zero.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_physical_threads = 1
|
||||
|
||||
# Configuration option allocation/vdo_write_policy.
|
||||
# Specifies the write policy:
|
||||
# auto - VDO will check the storage device and determine whether it supports flushes.
|
||||
# If it does, VDO will run in async mode, otherwise it will run in sync mode.
|
||||
# sync - Writes are acknowledged only after data is stably written.
|
||||
# This policy is not supported if the underlying storage is not also synchronous.
|
||||
# async - Writes are acknowledged after data has been cached for writing to stable storage.
|
||||
# Data which has not been flushed is not guaranteed to persist in this mode.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_write_policy = "auto"
|
||||
|
||||
# Configuration option allocation/vdo_max_discard.
|
||||
# Specified te maximum size of discard bio accepted, in 4096 byte blocks.
|
||||
# I/O requests to a VDO volume are normally split into 4096-byte blocks,
|
||||
# and processed up to 2048 at a time. However, discard requests to a VDO volume
|
||||
# can be automatically split to a larger size, up to <max discard> 4096-byte blocks
|
||||
# in a single bio, and are limited to 1500 at a time.
|
||||
# Increasing this value may provide better overall performance, at the cost of
|
||||
# increased latency for the individual discard requests.
|
||||
# The default and minimum is 1. The maximum is UINT_MAX / 4096.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_max_discard = 1
|
||||
}
|
||||
|
||||
# Configuration section log.
|
||||
@@ -588,7 +771,8 @@ log {
|
||||
|
||||
# Configuration option log/indent.
|
||||
# Indent messages according to their severity.
|
||||
indent = 1
|
||||
# This configuration option has an automatic default value.
|
||||
# indent = 0
|
||||
|
||||
# Configuration option log/command_names.
|
||||
# Display the command name on each line of output.
|
||||
@@ -611,9 +795,23 @@ 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, io, activation, allocation, lvmetad,
|
||||
# available: memory, devices, io, activation, allocation,
|
||||
# metadata, cache, locking, lvmpolld. Use "all" to see everything.
|
||||
debug_classes = [ "memory", "devices", "io", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
|
||||
debug_classes = [ "memory", "devices", "io", "activation", "allocation", "metadata", "cache", "locking", "lvmpolld", "dbus" ]
|
||||
|
||||
# Configuration option log/debug_file_fields.
|
||||
# The fields included in debug output written to log file.
|
||||
# Use "all" to include everything (the default).
|
||||
# This configuration option is advanced.
|
||||
# This configuration option has an automatic default value.
|
||||
# debug_file_fields = [ "time", "command", "fileline", "message" ]
|
||||
|
||||
# Configuration option log/debug_output_fields.
|
||||
# The fields included in debug output written to stderr.
|
||||
# Use "all" to include everything (the default).
|
||||
# This configuration option is advanced.
|
||||
# This configuration option has an automatic default value.
|
||||
# debug_output_fields = [ "time", "command", "fileline", "message" ]
|
||||
}
|
||||
|
||||
# Configuration section backup.
|
||||
@@ -701,20 +899,6 @@ global {
|
||||
# the error messages.
|
||||
activation = 1
|
||||
|
||||
# Configuration option global/fallback_to_lvm1.
|
||||
# This setting is no longer used.
|
||||
# This configuration option has an automatic default value.
|
||||
# fallback_to_lvm1 = 0
|
||||
|
||||
# Configuration option global/format.
|
||||
# This setting is no longer used.
|
||||
# This configuration option has an automatic default value.
|
||||
# format = "lvm2"
|
||||
|
||||
# Configuration option global/format_libraries.
|
||||
# This setting is no longer used.
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option global/segment_libraries.
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
@@ -727,57 +911,10 @@ global {
|
||||
# Location of /etc system configuration directory.
|
||||
etc = "@CONFDIR@"
|
||||
|
||||
# Configuration option global/locking_type.
|
||||
# Type of locking to use.
|
||||
#
|
||||
# Accepted values:
|
||||
# 0
|
||||
# Turns off locking. Warning: this risks metadata corruption if
|
||||
# commands run concurrently.
|
||||
# 1
|
||||
# LVM uses local file-based locking, the standard mode.
|
||||
# 2
|
||||
# LVM uses the external shared library locking_library.
|
||||
# 3
|
||||
# LVM uses built-in clustered locking with clvmd.
|
||||
# This is incompatible with lvmetad. If use_lvmetad is enabled,
|
||||
# LVM prints a warning and disables lvmetad use.
|
||||
# 4
|
||||
# LVM uses read-only locking which forbids any operations that
|
||||
# might change metadata.
|
||||
# 5
|
||||
# Offers dummy locking for tools that do not need any locks.
|
||||
# You should not need to set this directly; the tools will select
|
||||
# when to use it instead of the configured locking_type.
|
||||
# Do not use lvmetad or the kernel device-mapper driver with this
|
||||
# locking type. It is used by the --readonly option that offers
|
||||
# read-only access to Volume Group metadata that cannot be locked
|
||||
# safely because it belongs to an inaccessible domain and might be
|
||||
# in use, for example a virtual machine image or a disk that is
|
||||
# shared by a clustered machine.
|
||||
#
|
||||
locking_type = 1
|
||||
|
||||
# Configuration option global/wait_for_locks.
|
||||
# When disabled, fail if a lock request would block.
|
||||
wait_for_locks = 1
|
||||
|
||||
# Configuration option global/fallback_to_clustered_locking.
|
||||
# Attempt to use built-in cluster locking if locking_type 2 fails.
|
||||
# If using external locking (type 2) and initialisation fails, with
|
||||
# this enabled, an attempt will be made to use the built-in clustered
|
||||
# locking. Disable this if using a customised locking_library.
|
||||
fallback_to_clustered_locking = 1
|
||||
|
||||
# Configuration option global/fallback_to_local_locking.
|
||||
# Use locking_type 1 (local) if locking_type 2 or 3 fail.
|
||||
# If an attempt to initialise type 2 or type 3 locking failed, perhaps
|
||||
# because cluster components such as clvmd are not running, with this
|
||||
# enabled, an attempt will be made to use local file-based locking
|
||||
# (type 1). If this succeeds, only commands against local VGs will
|
||||
# proceed. VGs marked as clustered will be ignored.
|
||||
fallback_to_local_locking = 1
|
||||
|
||||
# Configuration option global/locking_dir.
|
||||
# Directory to use for LVM command file locks.
|
||||
# Local non-LV directory that holds file-based locks while commands are
|
||||
@@ -798,11 +935,6 @@ global {
|
||||
# Search this directory first for shared libraries.
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option global/locking_library.
|
||||
# The external locking library to use for locking_type 2.
|
||||
# This configuration option has an automatic default value.
|
||||
# locking_library = "liblvm2clusterlock.so"
|
||||
|
||||
# Configuration option global/abort_on_internal_errors.
|
||||
# Abort a command that encounters an internal error.
|
||||
# Treat any internal errors as fatal errors, aborting the process that
|
||||
@@ -843,6 +975,16 @@ global {
|
||||
#
|
||||
mirror_segtype_default = "@DEFAULT_MIRROR_SEGTYPE@"
|
||||
|
||||
# Configuration option global/support_mirrored_mirror_log.
|
||||
# Enable mirrored 'mirror' log type for testing.
|
||||
#
|
||||
# This type is deprecated to create or convert to but can
|
||||
# be enabled to test that activation of existing mirrored
|
||||
# logs and conversion to disk/core works.
|
||||
#
|
||||
# Not supported for regular operation!
|
||||
support_mirrored_mirror_log = 0
|
||||
|
||||
# Configuration option global/raid10_segtype_default.
|
||||
# The segment type used by the -i -m combination.
|
||||
# The --type raid10|mirror option overrides this setting.
|
||||
@@ -891,41 +1033,20 @@ global {
|
||||
# This configuration option has an automatic default value.
|
||||
# lvdisplay_shows_full_device_path = 0
|
||||
|
||||
# Configuration option global/use_lvmetad.
|
||||
# Use lvmetad to cache metadata and reduce disk scanning.
|
||||
# When enabled (and running), lvmetad provides LVM commands with VG
|
||||
# metadata and PV state. LVM commands then avoid reading this
|
||||
# information from disks which can be slow. When disabled (or not
|
||||
# running), LVM commands fall back to scanning disks to obtain VG
|
||||
# metadata. lvmetad is kept updated via udev rules which must be set
|
||||
# up for LVM to work correctly. (The udev rules should be installed
|
||||
# by default.) Without a proper udev setup, changes in the system's
|
||||
# block device configuration will be unknown to LVM, and ignored
|
||||
# until a manual 'pvscan --cache' is run. If lvmetad was running
|
||||
# while use_lvmetad was disabled, it must be stopped, use_lvmetad
|
||||
# enabled, and then started. When using lvmetad, LV activation is
|
||||
# switched to an automatic, event-based mode. In this mode, LVs are
|
||||
# activated based on incoming udev events that inform lvmetad when
|
||||
# PVs appear on the system. When a VG is complete (all PVs present),
|
||||
# it is auto-activated. The auto_activation_volume_list setting
|
||||
# controls which LVs are auto-activated (all by default.)
|
||||
# When lvmetad is updated (automatically by udev events, or directly
|
||||
# by pvscan --cache), devices/filter is ignored and all devices are
|
||||
# scanned by default. lvmetad always keeps unfiltered information
|
||||
# which is provided to LVM commands. Each LVM command then filters
|
||||
# based on devices/filter. This does not apply to other, non-regexp,
|
||||
# filtering settings: component filters such as multipath and MD
|
||||
# are checked during pvscan --cache. To filter a device and prevent
|
||||
# scanning from the LVM system entirely, including lvmetad, use
|
||||
# devices/global_filter.
|
||||
use_lvmetad = @DEFAULT_USE_LVMETAD@
|
||||
# Configuration option global/event_activation.
|
||||
# Activate LVs based on system-generated device events.
|
||||
# When a device appears on the system, a system-generated event runs
|
||||
# the pvscan command to activate LVs if the new PV completes the VG.
|
||||
# Use auto_activation_volume_list to select which LVs should be
|
||||
# activated from these events (the default is all.)
|
||||
# When event_activation is disabled, the system will generally run
|
||||
# a direct activation command to activate LVs in complete VGs.
|
||||
event_activation = 1
|
||||
|
||||
# Configuration option global/lvmetad_update_wait_time.
|
||||
# Number of seconds a command will wait for lvmetad update to finish.
|
||||
# After waiting for this period, a command will not use lvmetad, and
|
||||
# will revert to disk scanning.
|
||||
# Configuration option global/use_aio.
|
||||
# Use async I/O when reading and writing devices.
|
||||
# This configuration option has an automatic default value.
|
||||
# lvmetad_update_wait_time = 10
|
||||
# use_aio = 1
|
||||
|
||||
# Configuration option global/use_lvmlockd.
|
||||
# Use lvmlockd for locking among hosts using LVM on shared storage.
|
||||
@@ -1051,6 +1172,17 @@ global {
|
||||
# This configuration option has an automatic default value.
|
||||
# cache_repair_options = [ "" ]
|
||||
|
||||
# Configuration option global/vdo_format_executable.
|
||||
# The full path to the vdoformat command.
|
||||
# LVM uses this command to initial data volume for VDO type logical volume
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_format_executable = "@VDO_FORMAT_CMD@"
|
||||
|
||||
# Configuration option global/vdo_format_options.
|
||||
# List of options passed added to standard vdoformat command.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_format_options = [ "" ]
|
||||
|
||||
# Configuration option global/fsadm_executable.
|
||||
# The full path to the fsadm command.
|
||||
# LVM uses this command to help with lvresize -r operations.
|
||||
@@ -1108,6 +1240,16 @@ global {
|
||||
# When enabled, an LVM command that changes PVs, changes VG metadata,
|
||||
# or changes the activation state of an LV will send a notification.
|
||||
notify_dbus = 1
|
||||
|
||||
# Configuration option global/io_memory_size.
|
||||
# The amount of memory in KiB that LVM allocates to perform disk io.
|
||||
# LVM performance may benefit from more io memory when there are many
|
||||
# disks or VG metadata is large. Increasing this size may be necessary
|
||||
# when a single copy of VG metadata is larger than the current setting.
|
||||
# This value should usually not be decreased from the default; setting
|
||||
# it too low can result in lvm failing to read VGs.
|
||||
# This configuration option has an automatic default value.
|
||||
# io_memory_size = 8192
|
||||
}
|
||||
|
||||
# Configuration section activation.
|
||||
@@ -1424,6 +1566,33 @@ activation {
|
||||
#
|
||||
thin_pool_autoextend_percent = 20
|
||||
|
||||
# Configuration option activation/vdo_pool_autoextend_threshold.
|
||||
# Auto-extend a VDO pool when its usage exceeds this percent.
|
||||
# Setting this to 100 disables automatic extension.
|
||||
# The minimum value is 50 (a smaller value is treated as 50.)
|
||||
# Also see vdo_pool_autoextend_percent.
|
||||
# Automatic extension requires dmeventd to be monitoring the LV.
|
||||
#
|
||||
# Example
|
||||
# Using 70% autoextend threshold and 20% autoextend size, when a 10G
|
||||
# VDO pool exceeds 7G, it is extended to 12G, and when it exceeds
|
||||
# 8.4G, it is extended to 14.4G:
|
||||
# vdo_pool_autoextend_threshold = 70
|
||||
#
|
||||
vdo_pool_autoextend_threshold = 100
|
||||
|
||||
# Configuration option activation/vdo_pool_autoextend_percent.
|
||||
# Auto-extending a VDO pool adds this percent extra space.
|
||||
# The amount of additional space added to a VDO pool is this
|
||||
# percent of its current size.
|
||||
#
|
||||
# Example
|
||||
# Using 70% autoextend threshold and 20% autoextend size, when a 10G
|
||||
# VDO pool exceeds 7G, it is extended to 12G, and when it exceeds
|
||||
# 8.4G, it is extended to 14.4G:
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_pool_autoextend_percent = 20
|
||||
|
||||
# Configuration option activation/mlock_filter.
|
||||
# Do not mlock these memory areas.
|
||||
# While activating devices, I/O to devices being (re)configured is
|
||||
@@ -1569,13 +1738,20 @@ activation {
|
||||
# vgmetadatacopies = 0
|
||||
|
||||
# Configuration option metadata/pvmetadatasize.
|
||||
# Approximate number of sectors to use for each metadata copy.
|
||||
# VGs with large numbers of PVs or LVs, or VGs containing complex LV
|
||||
# structures, may need additional space for VG metadata. The metadata
|
||||
# areas are treated as circular buffers, so unused space becomes filled
|
||||
# with an archive of the most recent previous versions of the metadata.
|
||||
# The default size of the metadata area in units of 512 byte sectors.
|
||||
# The metadata area begins at an offset of the page size from the start
|
||||
# of the device. The first PE is by default at 1 MiB from the start of
|
||||
# the device. The space between these is the default metadata area size.
|
||||
# The actual size of the metadata area may be larger than what is set
|
||||
# here due to default_data_alignment making the first PE a MiB multiple.
|
||||
# The metadata area begins with a 512 byte header and is followed by a
|
||||
# circular buffer used for VG metadata text. The maximum size of the VG
|
||||
# metadata is about half the size of the metadata buffer. VGs with large
|
||||
# numbers of PVs or LVs, or VGs containing complex LV structures, may need
|
||||
# additional space for VG metadata. The --metadatasize option overrides
|
||||
# this setting.
|
||||
# This configuration option does not have a default value defined.
|
||||
# This configuration option has an automatic default value.
|
||||
# pvmetadatasize = 255
|
||||
|
||||
# Configuration option metadata/pvmetadataignore.
|
||||
# Ignore metadata areas on a new PV.
|
||||
@@ -1590,24 +1766,6 @@ activation {
|
||||
# This configuration option is advanced.
|
||||
# This configuration option has an automatic default value.
|
||||
# stripesize = 64
|
||||
|
||||
# Configuration option metadata/dirs.
|
||||
# Directories holding live copies of text format metadata.
|
||||
# These directories must not be on logical volumes!
|
||||
# It's possible to use LVM with a couple of directories here,
|
||||
# preferably on different (non-LV) filesystems, and with no other
|
||||
# on-disk metadata (pvmetadatacopies = 0). Or this can be in addition
|
||||
# to on-disk metadata areas. The feature was originally added to
|
||||
# simplify testing and is not supported under low memory situations -
|
||||
# the machine could lock up. Never edit any files in these directories
|
||||
# by hand unless you are absolutely sure you know what you are doing!
|
||||
# Use the supplied toolset to make changes (e.g. vgcfgrestore).
|
||||
#
|
||||
# Example
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
#
|
||||
# This configuration option is advanced.
|
||||
# This configuration option does not have a default value defined.
|
||||
# }
|
||||
|
||||
# Configuration section report.
|
||||
@@ -2058,6 +2216,23 @@ dmeventd {
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_command = "lvm lvextend --use-policies"
|
||||
|
||||
# Configuration option dmeventd/vdo_library.
|
||||
# The library dmeventd uses when monitoring a VDO pool device.
|
||||
# libdevmapper-event-lvm2vdo.so monitors the filling of a pool
|
||||
# and emits a warning through syslog when the usage exceeds 80%. The
|
||||
# warning is repeated when 85%, 90% and 95% of the pool is filled.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_library = "libdevmapper-event-lvm2vdo.so"
|
||||
|
||||
# Configuration option dmeventd/vdo_command.
|
||||
# The plugin runs command with each 5% increment when VDO pool volume
|
||||
# gets above 50%.
|
||||
# Command which starts with 'lvm ' prefix is internal lvm command.
|
||||
# You can write your own handler to customise behaviour in more details.
|
||||
# User handler is specified with the full path starting with '/'.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_command = "lvm lvextend --use-policies"
|
||||
|
||||
# Configuration option dmeventd/executable.
|
||||
# The full path to the dmeventd binary.
|
||||
# This configuration option has an automatic default value.
|
||||
|
||||
24
conf/vdo-small.profile
Normal file
24
conf/vdo-small.profile
Normal file
@@ -0,0 +1,24 @@
|
||||
# Demo configuration for 'VDO' using less memory.
|
||||
# ~lvmconfig --type full | grep vdo
|
||||
|
||||
allocation {
|
||||
vdo_use_compression=1
|
||||
vdo_use_deduplication=1
|
||||
vdo_use_metadata_hints=1
|
||||
vdo_minimum_io_size=4096
|
||||
vdo_block_map_cache_size_mb=128
|
||||
vdo_block_map_period=16380
|
||||
vdo_check_point_frequency=0
|
||||
vdo_use_sparse_index=0
|
||||
vdo_index_memory_size_mb=256
|
||||
vdo_slab_size_mb=2048
|
||||
vdo_ack_threads=1
|
||||
vdo_bio_threads=1
|
||||
vdo_bio_rotation=64
|
||||
vdo_cpu_threads=2
|
||||
vdo_hash_zone_threads=1
|
||||
vdo_logical_threads=1
|
||||
vdo_physical_threads=1
|
||||
vdo_write_policy="auto"
|
||||
vdo_max_discard=1
|
||||
}
|
||||
547
configure.ac
547
configure.ac
@@ -30,7 +30,7 @@ AC_CANONICAL_TARGET([])
|
||||
AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
|
||||
CLDFLAGS="${CLDFLAGS:"$LDFLAGS"} -Wl,--version-script,.export.sym"
|
||||
# equivalent to -rdynamic
|
||||
ELDFLAGS="-Wl,--export-dynamic"
|
||||
# FIXME Generate list and use --dynamic-list=.dlopen.sym
|
||||
@@ -39,20 +39,19 @@ case "$host_os" in
|
||||
LDDEPS="$LDDEPS .export.sym"
|
||||
LIB_SUFFIX=so
|
||||
DEVMAPPER=yes
|
||||
BUILD_LVMETAD=no
|
||||
BUILD_LVMPOLLD=no
|
||||
LOCKDSANLOCK=no
|
||||
LOCKDDLM=no
|
||||
LOCKDDLM_CONTROL=no
|
||||
ODIRECT=yes
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
CLUSTER=internal
|
||||
FSADM=yes
|
||||
BLKDEACTIVATE=yes
|
||||
;;
|
||||
darwin*)
|
||||
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
|
||||
CLDFLAGS="$CLDFLAGS"
|
||||
CLDFLAGS="${CLDFLAGS:"$LDFLAGS"}"
|
||||
ELDFLAGS=
|
||||
CLDWHOLEARCHIVE="-all_load"
|
||||
CLDNOWHOLEARCHIVE=
|
||||
@@ -61,10 +60,12 @@ case "$host_os" in
|
||||
ODIRECT=no
|
||||
DM_IOCTLS=no
|
||||
SELINUX=no
|
||||
CLUSTER=none
|
||||
FSADM=no
|
||||
BLKDEACTIVATE=no
|
||||
;;
|
||||
*)
|
||||
CLDFLAGS="${CLDFLAGS:"$LDFLAGS"}"
|
||||
;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
@@ -142,11 +143,17 @@ AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AX_GCC_BUILTIN([__builtin_clz])
|
||||
AX_GCC_BUILTIN([__builtin_clzll])
|
||||
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], 1, [Define to get access to GNU/Linux extension])
|
||||
AC_DEFINE([_REENTRANT], 1, [Define to use re-entrant thread safe versions])
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for functions
|
||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
|
||||
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
|
||||
memchr memset mkdir mkfifo munmap nl_langinfo pselect realpath rmdir setenv \
|
||||
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
|
||||
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_FUNC_ALLOCA
|
||||
@@ -172,6 +179,15 @@ AC_ARG_ENABLE(dependency-tracking,
|
||||
USE_TRACKING=$enableval, USE_TRACKING=yes)
|
||||
AC_MSG_RESULT($USE_TRACKING)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable silence rules
|
||||
AC_MSG_CHECKING(whether to build silently)
|
||||
AC_ARG_ENABLE(silent-rules,
|
||||
AC_HELP_STRING([--disable-silent-rules], [disable silent building]),
|
||||
SILENT_RULES=$enableval, SILENT_RULES=yes)
|
||||
AC_MSG_RESULT($SILENT_RULES)
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Enables statically-linked tools
|
||||
AC_MSG_CHECKING(whether to use static linking)
|
||||
@@ -282,22 +298,6 @@ esac
|
||||
AC_MSG_RESULT($MANGLING)
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour])
|
||||
|
||||
################################################################################
|
||||
dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
AC_ARG_WITH(cluster,
|
||||
AC_HELP_STRING([--with-cluster=TYPE],
|
||||
[cluster LVM locking support: internal/shared/none [internal]]),
|
||||
CLUSTER=$withval)
|
||||
AC_MSG_RESULT($CLUSTER)
|
||||
|
||||
case "$CLUSTER" in
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for clustered LVM locking.]) ;;
|
||||
*) AC_MSG_ERROR([--with-cluster parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- snapshots inclusion type
|
||||
AC_MSG_CHECKING(whether to include snapshots)
|
||||
@@ -600,6 +600,71 @@ AC_DEFINE_UNQUOTED([CACHE_REPAIR_CMD], ["$CACHE_REPAIR_CMD"],
|
||||
AC_DEFINE_UNQUOTED([CACHE_RESTORE_CMD], ["$CACHE_RESTORE_CMD"],
|
||||
[The path to 'cache_restore', if available.])
|
||||
|
||||
################################################################################
|
||||
dnl -- cache inclusion type
|
||||
AC_MSG_CHECKING(whether to include vdo)
|
||||
AC_ARG_WITH(vdo,
|
||||
AC_HELP_STRING([--with-vdo=TYPE],
|
||||
[vdo support: internal/none [internal]]),
|
||||
VDO=$withval, VDO="none")
|
||||
|
||||
AC_MSG_RESULT($VDO)
|
||||
|
||||
AC_ARG_WITH(vdo-format,
|
||||
AC_HELP_STRING([--with-vdo-format=PATH],
|
||||
[vdoformat tool: [autodetect]]),
|
||||
VDO_FORMAT_CMD=$withval, VDO_FORMAT_CMD="autodetect")
|
||||
case "$VDO" in
|
||||
none) ;;
|
||||
internal)
|
||||
AC_DEFINE([VDO_INTERNAL], 1, [Define to 1 to include built-in support for vdo.])
|
||||
if test "$VDO_FORMAT_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(VDO_FORMAT_CMD, vdoformat, [], [$PATH])
|
||||
if test -z "$VDO_FORMAT_CMD"; then
|
||||
AC_MSG_WARN([vdoformat not found in path $PATH])
|
||||
VDO_FORMAT_CMD=/usr/bin/vdoformat
|
||||
VDO_CONFIGURE_WARN=y
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*) AC_MSG_ERROR([--with-vdo parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
AC_DEFINE_UNQUOTED([VDO_FORMAT_CMD], ["$VDO_FORMAT_CMD"],
|
||||
[The path to 'vdoformat', if available.])
|
||||
#
|
||||
# Do we need to use the API??
|
||||
# Do we want to link lvm2 with a big library for vdoformating ?
|
||||
#
|
||||
#AC_ARG_WITH(vdo-include,
|
||||
# AC_HELP_STRING([--with-vdo-include=PATH],
|
||||
# [vdo support: Path to utils headers: [/usr/include/vdo/utils]]),
|
||||
# VDO_INCLUDE=$withval, VDO_INCLUDE="/usr/include/vdo/utils")
|
||||
#AC_MSG_RESULT($VDO_INCLUDE)
|
||||
#
|
||||
#AC_ARG_WITH(vdo-lib,
|
||||
# AC_HELP_STRING([--with-vdo-lib=PATH],
|
||||
# [vdo support: Path to utils lib: [/usr/lib]]),
|
||||
# VDO_LIB=$withval, VDO_LIB="/usr/lib")
|
||||
#AC_MSG_RESULT($VDO_LIB)
|
||||
|
||||
################################################################################
|
||||
dnl -- writecache inclusion type
|
||||
AC_MSG_CHECKING(whether to include writecache)
|
||||
AC_ARG_WITH(writecache,
|
||||
AC_HELP_STRING([--with-writecache=TYPE],
|
||||
[writecache support: internal/none [internal]]),
|
||||
WRITECACHE=$withval, WRITECACHE="none")
|
||||
|
||||
AC_MSG_RESULT($WRITECACHE)
|
||||
|
||||
case "$WRITECACHE" in
|
||||
none) ;;
|
||||
internal)
|
||||
AC_DEFINE([WRITECACHE_INTERNAL], 1, [Define to 1 to include built-in support for writecache.])
|
||||
;;
|
||||
*) AC_MSG_ERROR([--with-writecache parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable readline
|
||||
@@ -671,241 +736,6 @@ AC_ARG_WITH(default-run-dir,
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||
[Default LVM run directory.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
AC_ARG_WITH(clvmd,
|
||||
[ --with-clvmd=TYPE build cluster LVM Daemon
|
||||
The following cluster manager combinations are valid:
|
||||
* cman (RHEL5 or equivalent)
|
||||
* cman,corosync,openais (or selection of them)
|
||||
* singlenode (localhost only)
|
||||
* all (autodetect)
|
||||
* none (disable build)
|
||||
[[none]]],
|
||||
CLVMD=$withval, CLVMD=none)
|
||||
test "$CLVMD" = yes && CLVMD=all
|
||||
AC_MSG_RESULT($CLVMD)
|
||||
|
||||
dnl -- If clvmd enabled without cluster locking, automagically include it
|
||||
test "$CLVMD" != none -a "$CLUSTER" = none && CLUSTER=internal
|
||||
|
||||
dnl -- init pkgconfig if required
|
||||
test "$CLVMD" != none && pkg_config_init
|
||||
|
||||
dnl -- Express clvmd init script Required-Start / Required-Stop
|
||||
CLVMD_CMANAGERS=""
|
||||
dnl -- On RHEL4/RHEL5, qdiskd is started from a separate init script.
|
||||
dnl -- Enable if we are build for cman.
|
||||
CLVMD_NEEDS_QDISKD=no
|
||||
|
||||
dnl -- define build types
|
||||
if [[ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]]; then
|
||||
AC_MSG_ERROR([Since version 2.02.87 GULM locking is no longer supported.]);
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*cman.*'` != 0 ]]; then
|
||||
BUILDCMAN=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
|
||||
CLVMD_NEEDS_QDISKD=yes
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
|
||||
BUILDCOROSYNC=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*openais.*'` != 0 ]]; then
|
||||
BUILDOPENAIS=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
|
||||
fi
|
||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
|
||||
|
||||
dnl -- define a soft bailout if we are autodetecting
|
||||
soft_bailout() {
|
||||
NOTFOUND=1
|
||||
}
|
||||
|
||||
hard_bailout() {
|
||||
AC_MSG_ERROR([bailing out])
|
||||
}
|
||||
|
||||
dnl -- if clvmd=all then set soft_bailout (we do not want to error)
|
||||
dnl -- and set all builds to yes. We need to do this here
|
||||
dnl -- to skip the openais|corosync sanity check above.
|
||||
if test "$CLVMD" = all; then
|
||||
bailout=soft_bailout
|
||||
BUILDCMAN=yes
|
||||
BUILDCOROSYNC=yes
|
||||
BUILDOPENAIS=yes
|
||||
else
|
||||
bailout=hard_bailout
|
||||
fi
|
||||
|
||||
dnl -- helper macro to check libs without adding them to LIBS
|
||||
check_lib_no_libs() {
|
||||
lib_no_libs_arg1=$1
|
||||
shift
|
||||
lib_no_libs_arg2=$1
|
||||
shift
|
||||
lib_no_libs_args=$@
|
||||
AC_CHECK_LIB([$lib_no_libs_arg1],
|
||||
[$lib_no_libs_arg2],,
|
||||
[$bailout],
|
||||
[$lib_no_libs_args])
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
}
|
||||
|
||||
dnl -- Look for cman libraries if required.
|
||||
if test "$BUILDCMAN" = yes; then
|
||||
PKG_CHECK_MODULES(CMAN, libcman, [HAVE_CMAN=yes],
|
||||
[NOTFOUND=0
|
||||
AC_CHECK_HEADERS(libcman.h,,$bailout)
|
||||
check_lib_no_libs cman cman_init
|
||||
if test $NOTFOUND = 0; then
|
||||
AC_MSG_RESULT([no pkg for libcman, using -lcman])
|
||||
CMAN_LIBS="-lcman"
|
||||
HAVE_CMAN=yes
|
||||
fi])
|
||||
CHECKCONFDB=yes
|
||||
CHECKDLM=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for corosync that is required also for openais build
|
||||
dnl -- only enough recent version of corosync ship pkg-config files.
|
||||
dnl -- We can safely rely on that to detect the correct bits.
|
||||
if test "$BUILDCOROSYNC" = yes -o "$BUILDOPENAIS" = yes; then
|
||||
PKG_CHECK_MODULES(COROSYNC, corosync, [HAVE_COROSYNC=yes], $bailout)
|
||||
CHECKCONFDB=yes
|
||||
CHECKCMAP=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for corosync libraries if required.
|
||||
if test "$BUILDCOROSYNC" = yes; then
|
||||
PKG_CHECK_MODULES(QUORUM, libquorum, [HAVE_QUORUM=yes], $bailout)
|
||||
CHECKCPG=yes
|
||||
CHECKDLM=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for openais libraries if required.
|
||||
if test "$BUILDOPENAIS" = yes; then
|
||||
PKG_CHECK_MODULES(SALCK, libSaLck, [HAVE_SALCK=yes], $bailout)
|
||||
CHECKCPG=yes
|
||||
fi
|
||||
|
||||
dnl -- Below are checks for libraries common to more than one build.
|
||||
|
||||
dnl -- Check confdb library.
|
||||
dnl -- mandatory for corosync < 2.0 build.
|
||||
dnl -- optional for openais/cman build.
|
||||
|
||||
if test "$CHECKCONFDB" = yes; then
|
||||
PKG_CHECK_MODULES(CONFDB, libconfdb,
|
||||
[HAVE_CONFDB=yes], [HAVE_CONFDB=no])
|
||||
|
||||
AC_CHECK_HEADERS([corosync/confdb.h],
|
||||
[HAVE_CONFDB_H=yes], [HAVE_CONFDB_H=no])
|
||||
|
||||
if test "$HAVE_CONFDB" != yes -a "$HAVE_CONFDB_H" = yes; then
|
||||
check_lib_no_libs confdb confdb_initialize
|
||||
AC_MSG_RESULT([no pkg for confdb, using -lconfdb])
|
||||
CONFDB_LIBS="-lconfdb"
|
||||
HAVE_CONFDB=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl -- Check cmap library
|
||||
dnl -- mandatory for corosync >= 2.0 build.
|
||||
|
||||
if test "$CHECKCMAP" = yes; then
|
||||
PKG_CHECK_MODULES(CMAP, libcmap,
|
||||
[HAVE_CMAP=yes], [HAVE_CMAP=no])
|
||||
|
||||
AC_CHECK_HEADERS([corosync/cmap.h],
|
||||
[HAVE_CMAP_H=yes], [HAVE_CMAP_H=no])
|
||||
|
||||
if test "$HAVE_CMAP" != yes -a "$HAVE_CMAP_H" = yes; then
|
||||
check_lib_no_libs cmap cmap_initialize
|
||||
AC_MSG_RESULT([no pkg for cmap, using -lcmap])
|
||||
CMAP_LIBS="-lcmap"
|
||||
HAVE_CMAP=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$BUILDCOROSYNC" = yes -a \
|
||||
"$HAVE_CMAP" != yes -a "$HAVE_CONFDB" != yes -a "$CLVMD" != all; then
|
||||
AC_MSG_ERROR([bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required])
|
||||
fi
|
||||
|
||||
dnl -- Check cpg library.
|
||||
if test "$CHECKCPG" = yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg, [HAVE_CPG=yes], [$bailout])
|
||||
fi
|
||||
|
||||
dnl -- Check dlm library.
|
||||
if test "$CHECKDLM" = yes; then
|
||||
PKG_CHECK_MODULES(DLM, libdlm, [HAVE_DLM=yes],
|
||||
[NOTFOUND=0
|
||||
AC_CHECK_HEADERS(libdlm.h,,[$bailout])
|
||||
check_lib_no_libs dlm dlm_lock -lpthread
|
||||
if test $NOTFOUND = 0; then
|
||||
AC_MSG_RESULT([no pkg for libdlm, using -ldlm])
|
||||
DLM_LIBS="-ldlm -lpthread"
|
||||
HAVE_DLM=yes
|
||||
fi])
|
||||
fi
|
||||
|
||||
dnl -- If we are autodetecting, we need to re-create
|
||||
dnl -- the depedencies checks and set a proper CLVMD,
|
||||
dnl -- together with init script Required-Start/Stop entries.
|
||||
if test "$CLVMD" = all; then
|
||||
CLVMD=none
|
||||
CLVMD_CMANAGERS=""
|
||||
CLVMD_NEEDS_QDISKD=no
|
||||
if test "$HAVE_CMAN" = yes -a \
|
||||
"$HAVE_DLM" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd cman cluster manager])
|
||||
CLVMD="$CLVMD,cman"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
|
||||
CLVMD_NEEDS_QDISKD=yes
|
||||
fi
|
||||
if test "$HAVE_COROSYNC" = yes -a \
|
||||
"$HAVE_QUORUM" = yes -a \
|
||||
"$HAVE_CPG" = yes -a \
|
||||
"$HAVE_DLM" = yes; then
|
||||
if test "$HAVE_CONFDB" = yes -o "$HAVE_CMAP" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd corosync cluster manager])
|
||||
CLVMD="$CLVMD,corosync"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
|
||||
fi
|
||||
fi
|
||||
if test "$HAVE_COROSYNC" = yes -a \
|
||||
"$HAVE_CPG" = yes -a \
|
||||
"$HAVE_SALCK" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd openais cluster manager])
|
||||
CLVMD="$CLVMD,openais"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
|
||||
fi
|
||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
|
||||
test "$CLVMD" = none && AC_MSG_RESULT([Disabling clvmd build. No cluster manager detected.])
|
||||
fi
|
||||
|
||||
dnl -- Fixup CLVMD_CMANAGERS with new corosync
|
||||
dnl -- clvmd built with corosync >= 2.0 needs dlm (either init or systemd service)
|
||||
dnl -- to be started.
|
||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
|
||||
test "$HAVE_CMAP" = yes && CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- clvmd pidfile
|
||||
if test "$CLVMD" != none; then
|
||||
AC_ARG_WITH(clvmd-pidfile,
|
||||
AC_HELP_STRING([--with-clvmd-pidfile=PATH],
|
||||
[clvmd pidfile [PID_DIR/clvmd.pid]]),
|
||||
CLVMD_PIDFILE=$withval,
|
||||
CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid")
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"],
|
||||
[Path to clvmd pidfile.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster mirror log daemon
|
||||
AC_MSG_CHECKING(whether to build cluster mirror log daemon)
|
||||
@@ -934,11 +764,6 @@ dnl -- Look for corosync libraries if required.
|
||||
if [[ "$BUILD_CMIRRORD" = yes ]]; then
|
||||
pkg_config_init
|
||||
|
||||
AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 1, [Define to 1 to include libSaCkpt.])
|
||||
PKG_CHECK_MODULES(SACKPT, libSaCkpt, [HAVE_SACKPT=yes],
|
||||
[AC_MSG_RESULT([no libSaCkpt, compiling without it])
|
||||
AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 0, [Define to 0 to exclude libSaCkpt.])])
|
||||
|
||||
if test "$HAVE_CPG" != yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg)
|
||||
fi
|
||||
@@ -1044,16 +869,6 @@ if test "$DEVMAPPER" = yes; then
|
||||
AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmetad
|
||||
AC_MSG_CHECKING(whether to build LVMetaD)
|
||||
AC_ARG_ENABLE(lvmetad,
|
||||
AC_HELP_STRING([--enable-lvmetad],
|
||||
[enable the LVM Metadata Daemon]),
|
||||
LVMETAD=$enableval)
|
||||
test -n "$LVMETAD" && BUILD_LVMETAD=$LVMETAD
|
||||
AC_MSG_RESULT($BUILD_LVMETAD)
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmpolld
|
||||
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||
@@ -1102,6 +917,24 @@ if test "$BUILD_LOCKDDLM" = yes; then
|
||||
BUILD_LVMLOCKD=yes
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmlockddlmcontrol
|
||||
AC_MSG_CHECKING(whether to build lvmlockddlmcontrol)
|
||||
AC_ARG_ENABLE(lvmlockd-dlmcontrol,
|
||||
AC_HELP_STRING([--enable-lvmlockd-dlmcontrol],
|
||||
[enable lvmlockd remote refresh using libdlmcontrol]),
|
||||
LOCKDDLM_CONTROL=$enableval)
|
||||
AC_MSG_RESULT($LOCKDDLM_CONTROL)
|
||||
|
||||
BUILD_LOCKDDLM_CONTROL=$LOCKDDLM_CONTROL
|
||||
|
||||
dnl -- Look for libdlmcontrol libraries
|
||||
if test "$BUILD_LOCKDDLM_CONTROL" = yes; then
|
||||
PKG_CHECK_MODULES(LOCKD_DLM_CONTROL, libdlmcontrol >= 3.2, [HAVE_LOCKD_DLM_CONTROL=yes], $bailout)
|
||||
AC_DEFINE([LOCKDDLM_CONTROL_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm control option.])
|
||||
BUILD_LVMLOCKD=yes
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmlockd
|
||||
AC_MSG_CHECKING(whether to build lvmlockd)
|
||||
@@ -1109,9 +942,7 @@ AC_MSG_RESULT($BUILD_LVMLOCKD)
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AS_IF([test "$LVMPOLLD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmpolld.])])
|
||||
AS_IF([test "$LVMETAD" = no], [AC_MSG_ERROR([cannot build lvmlockd with --disable-lvmetad.])])
|
||||
AS_IF([test "$BUILD_LVMPOLLD" = no], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
|
||||
AS_IF([test "$BUILD_LVMETAD" = no], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
|
||||
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||
AC_ARG_ENABLE(use_lvmlockd,
|
||||
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||
@@ -1136,33 +967,6 @@ fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
|
||||
[Use lvmlockd by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check lvmetad
|
||||
if test "$BUILD_LVMETAD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmetad])
|
||||
AC_ARG_ENABLE(use_lvmetad,
|
||||
AC_HELP_STRING([--disable-use-lvmetad],
|
||||
[disable usage of LVM Metadata Daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMETAD=1 ;;
|
||||
*) DEFAULT_USE_LVMETAD=0 ;;
|
||||
esac], DEFAULT_USE_LVMETAD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMETAD)
|
||||
AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
|
||||
|
||||
AC_ARG_WITH(lvmetad-pidfile,
|
||||
AC_HELP_STRING([--with-lvmetad-pidfile=PATH],
|
||||
[lvmetad pidfile [PID_DIR/lvmetad.pid]]),
|
||||
LVMETAD_PIDFILE=$withval,
|
||||
LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
|
||||
[Path to lvmetad pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMETAD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
|
||||
[Use lvmetad by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check lvmpolld
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
@@ -1366,20 +1170,6 @@ if test "$ODIRECT" = yes; then
|
||||
AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable liblvm2app.so
|
||||
AC_MSG_CHECKING(whether to build liblvm2app.so application library)
|
||||
AC_ARG_ENABLE(applib,
|
||||
AC_HELP_STRING([--enable-applib], [build application library]),
|
||||
APPLIB=$enableval, APPLIB=no)
|
||||
AC_MSG_RESULT($APPLIB)
|
||||
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
|
||||
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
|
||||
@@ -1403,45 +1193,9 @@ 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
|
||||
AC_MSG_CHECKING(whether to build Python wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python_bindings,
|
||||
AC_HELP_STRING([--enable-python_bindings], [build default Python applib bindings]),
|
||||
PYTHON_BINDINGS=$enableval, PYTHON_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON_BINDINGS)
|
||||
dnl -- Enable Python dbus library
|
||||
|
||||
AC_MSG_CHECKING(whether to build Python2 wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python2_bindings,
|
||||
AC_HELP_STRING([--enable-python2_bindings], [build Python2 applib bindings]),
|
||||
PYTHON2_BINDINGS=$enableval, PYTHON2_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON2_BINDINGS)
|
||||
|
||||
|
||||
AC_MSG_CHECKING(whether to build Python3 wrapper for liblvm2app.so)
|
||||
AC_ARG_ENABLE(python3_bindings,
|
||||
AC_HELP_STRING([--enable-python3_bindings], [build Python3 applib bindings]),
|
||||
PYTHON3_BINDINGS=$enableval, PYTHON3_BINDINGS=no)
|
||||
AC_MSG_RESULT($PYTHON3_BINDINGS)
|
||||
|
||||
if test "$PYTHON_BINDINGS" = yes; then
|
||||
AC_MSG_ERROR([--enable-python-bindings is replaced by --enable-python2-bindings and --enable-python3-bindings])
|
||||
fi
|
||||
|
||||
if test "$PYTHON2_BINDINGS" = yes; then
|
||||
AM_PATH_PYTHON([2])
|
||||
AC_PATH_TOOL(PYTHON2, python2)
|
||||
test -z "$PYTHON2" && AC_MSG_ERROR([python2 is required for --enable-python2_bindings but cannot be found])
|
||||
AC_PATH_TOOL(PYTHON2_CONFIG, python2-config)
|
||||
test -z "$PYTHON2_CONFIG" && AC_PATH_TOOL(PYTHON2_CONFIG, python-config)
|
||||
test -z "$PYTHON2_CONFIG" && AC_MSG_ERROR([python headers are required for --enable-python2_bindings but cannot be found])
|
||||
PYTHON2_INCDIRS=`"$PYTHON2_CONFIG" --includes`
|
||||
PYTHON2_LIBDIRS=`"$PYTHON2_CONFIG" --libs`
|
||||
PYTHON2DIR=$pythondir
|
||||
PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
||||
unset PYTHON PYTHON_CONFIG
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
unset am_cv_pathless_PYTHON ac_cv_path_PYTHON am_cv_python_platform
|
||||
unset am_cv_python_pythondir am_cv_python_version am_cv_python_pyexecdir
|
||||
unset ac_cv_path_PYTHON_CONFIG ac_cv_path_ac_pt_PYTHON_CONFIG
|
||||
@@ -1454,19 +1208,12 @@ if test "$PYTHON3_BINDINGS" = yes -o "$BUILD_LVMDBUSD" = yes; then
|
||||
PYTHON3_LIBDIRS=`"$PYTHON3_CONFIG" --libs`
|
||||
PYTHON3DIR=$pythondir
|
||||
test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMDBUSD" = yes; then
|
||||
# To get this macro, install autoconf-archive package then run autoreconf
|
||||
AC_PYTHON_MODULE([pyudev], [Required], python3)
|
||||
AC_PYTHON_MODULE([dbus], [Required], python3)
|
||||
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
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable pkg-config
|
||||
AC_ARG_ENABLE(pkgconfig,
|
||||
@@ -1538,7 +1285,7 @@ AC_CHECK_LIB(dl, dlopen,
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for shared/static conflicts
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared \
|
||||
\) -a "$STATIC_LINK" = yes ]]; then
|
||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||
fi
|
||||
@@ -1758,18 +1505,6 @@ if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_FUNC_STRERROR_R
|
||||
fi
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
||||
AC_FUNC_GETMNTENT
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
fi
|
||||
|
||||
if test "$CLUSTER" != none; then
|
||||
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,hard_bailout)
|
||||
AC_CHECK_FUNCS(socket,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
AC_CHECK_HEADERS(arpa/inet.h,,hard_bailout)
|
||||
fi
|
||||
@@ -1803,9 +1538,10 @@ SBINDIR="$(eval echo $(eval echo $sbindir))"
|
||||
LVM_PATH="$SBINDIR/lvm"
|
||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
LVMCONFIG_PATH="$SBINDIR/lvmconfig"
|
||||
AC_DEFINE_UNQUOTED(LVMCONFIG_PATH, ["$LVMCONFIG_PATH"], [Path to lvmconfig binary.])
|
||||
|
||||
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
|
||||
CLVMD_PATH="$USRSBINDIR/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
|
||||
FSADM_PATH="$SBINDIR/fsadm"
|
||||
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
|
||||
@@ -1885,15 +1621,6 @@ AC_ARG_WITH(default-locking-dir,
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
|
||||
[Name of default locking directory.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup default data alignment
|
||||
AC_ARG_WITH(default-data-alignment,
|
||||
AC_HELP_STRING([--with-default-data-alignment=NUM],
|
||||
[set the default data alignment in MiB [1]]),
|
||||
DEFAULT_DATA_ALIGNMENT=$withval, DEFAULT_DATA_ALIGNMENT=1)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_DATA_ALIGNMENT, [$DEFAULT_DATA_ALIGNMENT],
|
||||
[Default data alignment.])
|
||||
|
||||
################################################################################
|
||||
dnl -- which kernel interface to use (ioctl only)
|
||||
AC_MSG_CHECKING(for kernel interface choice)
|
||||
@@ -1925,17 +1652,16 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
|
||||
AC_DEFINE_UNQUOTED(LVM_CONFIGURE_LINE, "$CONFIGURE_LINE", [configure command line used])
|
||||
|
||||
################################################################################
|
||||
AC_SUBST(APPLIB)
|
||||
AC_SUBST(AWK)
|
||||
AC_SUBST(BLKID_PC)
|
||||
AC_SUBST(BUILD_CMIRRORD)
|
||||
AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMDBUSD)
|
||||
AC_SUBST(BUILD_LVMETAD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
AC_SUBST(BUILD_LVMLOCKD)
|
||||
AC_SUBST(BUILD_LOCKDSANLOCK)
|
||||
AC_SUBST(BUILD_LOCKDDLM)
|
||||
AC_SUBST(BUILD_LOCKDDLM_CONTROL)
|
||||
AC_SUBST(BUILD_DMFILEMAPD)
|
||||
AC_SUBST(CACHE)
|
||||
AC_SUBST(CFLAGS)
|
||||
@@ -1944,14 +1670,6 @@ AC_SUBST(CHMOD)
|
||||
AC_SUBST(CLDFLAGS)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLVMD_CMANAGERS)
|
||||
AC_SUBST(CLVMD_PATH)
|
||||
AC_SUBST(CMAN_CFLAGS)
|
||||
AC_SUBST(CMAN_LIBS)
|
||||
AC_SUBST(CMAP_CFLAGS)
|
||||
AC_SUBST(CMAP_LIBS)
|
||||
AC_SUBST(CMDLIB)
|
||||
AC_SUBST(CONFDB_CFLAGS)
|
||||
AC_SUBST(CONFDB_LIBS)
|
||||
@@ -1964,7 +1682,6 @@ AC_SUBST(DEBUG)
|
||||
AC_SUBST(DEFAULT_ARCHIVE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_BACKUP_SUBDIR)
|
||||
AC_SUBST(DEFAULT_CACHE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
|
||||
@@ -1976,7 +1693,6 @@ 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)
|
||||
AC_SUBST(DEFAULT_USE_LVMLOCKD)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
@@ -2060,14 +1776,17 @@ AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(USE_TRACKING)
|
||||
AC_SUBST(SILENT_RULES)
|
||||
AC_SUBST(USRSBINDIR)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(VDO)
|
||||
AC_SUBST(VDO_FORMAT_CMD)
|
||||
AC_SUBST(VDO_INCLUDE)
|
||||
AC_SUBST(VDO_LIB)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMETAD_PIDFILE)
|
||||
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||
AC_SUBST(LVMLOCKD_PIDFILE)
|
||||
AC_SUBST(CLVMD_PIDFILE)
|
||||
AC_SUBST(CMIRRORD_PIDFILE)
|
||||
AC_SUBST(interface)
|
||||
AC_SUBST(kerneldir)
|
||||
@@ -2088,8 +1807,8 @@ dnl -- keep utility scripts running properly
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
make.tmpl
|
||||
libdm/make.tmpl
|
||||
daemons/Makefile
|
||||
daemons/clvmd/Makefile
|
||||
daemons/cmirrord/Makefile
|
||||
daemons/dmeventd/Makefile
|
||||
daemons/dmeventd/libdevmapper-event.pc
|
||||
@@ -2099,68 +1818,51 @@ daemons/dmeventd/plugins/raid/Makefile
|
||||
daemons/dmeventd/plugins/mirror/Makefile
|
||||
daemons/dmeventd/plugins/snapshot/Makefile
|
||||
daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/dmfilemapd/Makefile
|
||||
daemons/dmeventd/plugins/vdo/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/dm-tools/Makefile
|
||||
libdm/libdevmapper.pc
|
||||
liblvm/Makefile
|
||||
liblvm/liblvm2app.pc
|
||||
man/Makefile
|
||||
po/Makefile
|
||||
python/Makefile
|
||||
python/setup.py
|
||||
scripts/lvm2-pvscan.service
|
||||
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/lvmlockd.service
|
||||
scripts/lvmlocks.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
|
||||
])
|
||||
@@ -2178,6 +1880,9 @@ AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
|
||||
AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
|
||||
[AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
|
||||
|
||||
AS_IF([test -n "$VDO_CONFIGURE_WARN"],
|
||||
[AC_MSG_WARN([unrecognized 'vdoformat' tool is REQUIRED for VDO logical volume creation!])])
|
||||
|
||||
|
||||
AS_IF([test "$ODIRECT" != yes],
|
||||
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
|
||||
|
||||
@@ -15,11 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
|
||||
|
||||
ifneq ("@CLVMD@", "none")
|
||||
SUBDIRS += clvmd
|
||||
endif
|
||||
.PHONY: dmeventd cmirrord lvmpolld lvmlockd
|
||||
|
||||
ifeq ("@BUILD_CMIRRORD@", "yes")
|
||||
SUBDIRS += cmirrord
|
||||
@@ -32,10 +28,6 @@ daemons.cflow: dmeventd.cflow
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMETAD@", "yes")
|
||||
SUBDIRS += lvmetad
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
SUBDIRS += lvmpolld
|
||||
endif
|
||||
@@ -48,12 +40,8 @@ ifeq ("@BUILD_LVMDBUSD@", "yes")
|
||||
SUBDIRS += lvmdbusd
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_DMFILEMAPD@", "yes")
|
||||
SUBDIRS += dmfilemapd
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
|
||||
SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd
|
||||
endif
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
1
daemons/clvmd/.gitignore
vendored
1
daemons/clvmd/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
clvmd
|
||||
@@ -1,94 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2004 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 General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
CMAN_LIBS = @CMAN_LIBS@
|
||||
CMAN_CFLAGS = @CMAN_CFLAGS@
|
||||
CMAP_LIBS = @CMAP_LIBS@
|
||||
CMAP_CFLAGS = @CMAP_CFLAGS@
|
||||
CONFDB_LIBS = @CONFDB_LIBS@
|
||||
CONFDB_CFLAGS = @CONFDB_CFLAGS@
|
||||
CPG_LIBS = @CPG_LIBS@
|
||||
CPG_CFLAGS = @CPG_CFLAGS@
|
||||
DLM_LIBS = @DLM_LIBS@
|
||||
DLM_CFLAGS = @DLM_CFLAGS@
|
||||
QUORUM_LIBS = @QUORUM_LIBS@
|
||||
QUORUM_CFLAGS = @QUORUM_CFLAGS@
|
||||
SALCK_LIBS = @SALCK_LIBS@
|
||||
SALCK_CFLAGS = @SALCK_CFLAGS@
|
||||
|
||||
SOURCES = \
|
||||
clvmd-command.c\
|
||||
clvmd.c\
|
||||
lvm-functions.c\
|
||||
refresh_clvmd.c
|
||||
|
||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-cman.c
|
||||
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
|
||||
CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS)
|
||||
DEFS += -DUSE_CMAN
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring openais,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-openais.c
|
||||
LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS)
|
||||
CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS)
|
||||
DEFS += -DUSE_OPENAIS
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring corosync,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-corosync.c
|
||||
LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
|
||||
CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
|
||||
DEFS += -DUSE_COROSYNC
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring singlenode,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-singlenode.c
|
||||
DEFS += -DUSE_SINGLENODE
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SOURCES += clvmd-cman.c
|
||||
SOURCES += clvmd-openais.c
|
||||
SOURCES += clvmd-corosync.c
|
||||
SOURCES += clvmd-singlenode.c
|
||||
endif
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
|
||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o clvmd $(OBJECTS) $(LMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
install_clvmd: $(TARGETS)
|
||||
$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
install_cluster: $(INSTALL_TARGETS)
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Definitions for CLVMD server and clients */
|
||||
|
||||
/*
|
||||
* The protocol spoken over the cluster and across the local socket.
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_H
|
||||
#define _CLVM_H
|
||||
|
||||
#include "configure.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
struct clvm_header {
|
||||
uint8_t cmd; /* See below */
|
||||
uint8_t flags; /* See below */
|
||||
uint16_t xid; /* Transaction ID */
|
||||
uint32_t clientid; /* Only used in Daemon->Daemon comms */
|
||||
int32_t status; /* For replies, whether request succeeded */
|
||||
uint32_t arglen; /* Length of argument below.
|
||||
If >1500 then it will be passed
|
||||
around the cluster in the system LV */
|
||||
char node[1]; /* Actually a NUL-terminated string, node name.
|
||||
If this is empty then the command is
|
||||
forwarded to all cluster nodes unless
|
||||
FLAG_LOCAL or FLAG_REMOTE is also set. */
|
||||
char args[1]; /* Arguments for the command follow the
|
||||
node name, This member is only
|
||||
valid if the node name is empty */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Flags */
|
||||
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
|
||||
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
|
||||
#define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */
|
||||
#define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */
|
||||
|
||||
/* Name of the local socket to communicate between lvm and clvmd */
|
||||
#define CLVMD_SOCKNAME DEFAULT_RUN_DIR "/clvmd.sock"
|
||||
|
||||
/* Internal commands & replies */
|
||||
#define CLVMD_CMD_REPLY 1
|
||||
#define CLVMD_CMD_VERSION 2 /* Send version around cluster when we start */
|
||||
#define CLVMD_CMD_GOAWAY 3 /* Die if received this - we are running
|
||||
an incompatible version */
|
||||
#define CLVMD_CMD_TEST 4 /* Just for mucking about */
|
||||
|
||||
#define CLVMD_CMD_LOCK 30
|
||||
#define CLVMD_CMD_UNLOCK 31
|
||||
|
||||
/* Lock/Unlock commands */
|
||||
#define CLVMD_CMD_LOCK_LV 50
|
||||
#define CLVMD_CMD_LOCK_VG 51
|
||||
#define CLVMD_CMD_LOCK_QUERY 52
|
||||
|
||||
/* Misc functions */
|
||||
#define CLVMD_CMD_REFRESH 40
|
||||
#define CLVMD_CMD_GET_CLUSTERNAME 41
|
||||
#define CLVMD_CMD_SET_DEBUG 42
|
||||
#define CLVMD_CMD_VG_BACKUP 43
|
||||
#define CLVMD_CMD_RESTART 44
|
||||
#define CLVMD_CMD_SYNC_NAMES 45
|
||||
|
||||
/* Used internally by some callers, but not part of the protocol.*/
|
||||
#ifndef NODE_ALL
|
||||
# define NODE_ALL "*"
|
||||
# define NODE_LOCAL "."
|
||||
# define NODE_REMOTE "^"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,505 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CMAN communication layer for clvmd.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include <libdlm.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
struct clvmd_node
|
||||
{
|
||||
struct cman_node *node;
|
||||
int clvmd_up;
|
||||
};
|
||||
|
||||
static int num_nodes;
|
||||
static struct cman_node *nodes = NULL;
|
||||
static struct cman_node this_node;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static struct dm_hash_table *node_updown_hash;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
static cman_handle_t c_handle;
|
||||
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(const char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
struct dlm_lksb lksb;
|
||||
};
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
node_updown_hash = dm_hash_create(100);
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
c_handle = cman_init(NULL);
|
||||
if (!c_handle) {
|
||||
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Connected to CMAN\n");
|
||||
|
||||
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
|
||||
syslog(LOG_ERR, "Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cman_start_notification(c_handle, event_callback)) {
|
||||
syslog(LOG_ERR, "Can't start cluster event listening");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
|
||||
DEBUGLOG("CMAN initialisation complete\n");
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
|
||||
if (!lockspace) {
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Created DLM lockspace for CLVMD.\n");
|
||||
} else
|
||||
DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
|
||||
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_init_completed(void)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return cman_get_fd(c_handle);
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
int i;
|
||||
int nnodes = 0;
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
int nodeid = 0;
|
||||
|
||||
if (csid)
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
|
||||
{
|
||||
log_error("%s", errtext);
|
||||
}
|
||||
return msglen;
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
if (this_node.cn_nodeid == 0) {
|
||||
cman_get_node(c_handle, 0, &this_node);
|
||||
}
|
||||
memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
|
||||
static int _cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid) {
|
||||
int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int));
|
||||
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, up);
|
||||
if (!up)
|
||||
somedown = -1;
|
||||
}
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB messages from the cluster socket */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
switch (reason) {
|
||||
case CMAN_REASON_PORTCLOSED:
|
||||
name_from_nodeid(arg, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
|
||||
|
||||
dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
|
||||
break;
|
||||
|
||||
case CMAN_REASON_STATECHANGE:
|
||||
DEBUGLOG("Got state change message, re-reading members list\n");
|
||||
get_members();
|
||||
break;
|
||||
|
||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
|
||||
case CMAN_REASON_PORTOPENED:
|
||||
/* Ignore this, wait for startup message from clvmd itself */
|
||||
break;
|
||||
|
||||
case CMAN_REASON_TRY_SHUTDOWN:
|
||||
DEBUGLOG("Got try shutdown, sending OK\n");
|
||||
cman_replyto_shutdown(c_handle, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown event callback message: %d\n", reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct local_client *cman_client;
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
|
||||
/* Save this for data_callback */
|
||||
cman_client = fd;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
return cman_dispatch(c_handle, 0);
|
||||
}
|
||||
|
||||
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid)
|
||||
{
|
||||
/* Ignore looped back messages */
|
||||
if (nodeid == this_node.cn_nodeid)
|
||||
return;
|
||||
process_message(cman_client, buf, len, (char *)&nodeid);
|
||||
}
|
||||
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
/* It's up ! */
|
||||
int nodeid = nodeid_from_csid(csid);
|
||||
|
||||
dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1);
|
||||
DEBUGLOG("Added new node %d to updown list\n", nodeid);
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
cman_finish(c_handle);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
int status;
|
||||
|
||||
do {
|
||||
status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
|
||||
if (status < 0 && errno == EBUSY) { /* Don't busywait */
|
||||
sleep(1);
|
||||
errno = EBUSY; /* In case sleep trashes it */
|
||||
}
|
||||
}
|
||||
while (status < 0 && errno == EBUSY);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Populate the list of CLVMDs running.
|
||||
called only at startup time */
|
||||
static void count_clvmds_running(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
int nodeid = nodes[i].cn_nodeid;
|
||||
|
||||
if (is_listening(nodeid) == 1)
|
||||
dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
|
||||
else
|
||||
dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members(void)
|
||||
{
|
||||
int retnodes;
|
||||
int status;
|
||||
int i;
|
||||
int high_nodeid = 0;
|
||||
|
||||
num_nodes = cman_get_node_count(c_handle);
|
||||
if (num_nodes == -1) {
|
||||
log_error("Unable to get node count");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
nodes = NULL;
|
||||
}
|
||||
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cman_node));
|
||||
if (!nodes) {
|
||||
log_error("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
|
||||
if (status < 0) {
|
||||
log_error("Unable to get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Get the highest nodeid */
|
||||
for (i=0; i<retnodes; i++) {
|
||||
if (nodes[i].cn_nodeid > high_nodeid)
|
||||
high_nodeid = nodes[i].cn_nodeid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].cn_name) == 0) {
|
||||
memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node name */
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a node ID to a node name */
|
||||
static int name_from_nodeid(int nodeid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].cn_nodeid) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node ID */
|
||||
static int nodeid_from_csid(const char *csid)
|
||||
{
|
||||
int nodeid;
|
||||
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
return cman_is_quorate(c_handle);
|
||||
}
|
||||
|
||||
static void sync_ast_routine(void *arg)
|
||||
{
|
||||
struct lock_wait *lwait = arg;
|
||||
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
if (!lockid) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
|
||||
/* Conversions need the lockid in the LKSB */
|
||||
if (flags & LKF_CONVERT)
|
||||
lwait.lksb.sb_lkid = *lockid;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_lock(lockspace,
|
||||
mode,
|
||||
&lwait.lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0, sync_ast_routine, &lwait, NULL, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
*lockid = lwait.lksb.sb_lkid;
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
|
||||
if (lwait.lksb.sb_status)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
if (lwait.lksb.sb_status != EUNLOCK)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cman_cluster_t cluster_info;
|
||||
int status;
|
||||
|
||||
status = cman_get_cluster(c_handle, &cluster_info);
|
||||
if (!status) {
|
||||
strncpy(buf, cluster_info.ci_name, buflen);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.name = "cman",
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_cman_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_cman_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
CLVMD Cluster LVM daemon command processor.
|
||||
|
||||
To add commands to the daemon simply add a processor in do_command and return
|
||||
and messages back in buf and the length in *retlen. The initial value of
|
||||
buflen is the maximum size of the buffer. if buf is not large enough then it
|
||||
may be reallocated by the functions in here to a suitable size bearing in
|
||||
mind that anything larger than the passed-in size will have to be returned
|
||||
using the system LV and so performance will suffer.
|
||||
|
||||
The status return will be negated and passed back to the originating node.
|
||||
|
||||
pre- and post- command routines are called only on the local node. The
|
||||
purpose is primarily to get and release locks, though the pre- routine should
|
||||
also do any other local setups required by the command (if any) and can
|
||||
return a failure code that prevents the command from being distributed around
|
||||
the cluster
|
||||
|
||||
The pre- and post- routines are run in their own thread so can block as long
|
||||
they like, do_command is run in the main clvmd thread so should not block for
|
||||
too long. If the pre-command returns an error code (!=0) then the command
|
||||
will not be propogated around the cluster but the post-command WILL be called
|
||||
|
||||
Also note that the pre and post routine are *always* called on the local
|
||||
node, even if the command to be executed was only requested to run on a
|
||||
remote node. It may peek inside the client structure to check the status of
|
||||
the command.
|
||||
|
||||
The clients of the daemon must, naturally, understand the return messages and
|
||||
codes.
|
||||
|
||||
Routines in here may only READ the values in the client structure passed in
|
||||
apart from client->private which they are free to do what they like with.
|
||||
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-globals.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
static int restart_clvmd(void);
|
||||
|
||||
/* This is where all the real work happens:
|
||||
NOTE: client will be NULL when this is executed on a remote node */
|
||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
char **buf, int buflen, int *retlen)
|
||||
{
|
||||
char *args = msg->node + strlen(msg->node) + 1;
|
||||
int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
const char *locktype;
|
||||
struct utsname nodeinfo;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
|
||||
/* Do the command */
|
||||
switch (msg->cmd) {
|
||||
/* Just a test message */
|
||||
case CLVMD_CMD_TEST:
|
||||
if (arglen > buflen) {
|
||||
char *new_buf;
|
||||
buflen = arglen + 200;
|
||||
new_buf = realloc(*buf, buflen);
|
||||
if (new_buf == NULL) {
|
||||
status = errno;
|
||||
free (*buf);
|
||||
}
|
||||
*buf = new_buf;
|
||||
}
|
||||
if (*buf) {
|
||||
if (uname(&nodeinfo))
|
||||
memset(&nodeinfo, 0, sizeof(nodeinfo));
|
||||
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen,
|
||||
"TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
/* Check to see if the VG is in use by LVM1 */
|
||||
do_lock_vg(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
/* This is the biggie */
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = do_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
/* Replace EIO with something less scary */
|
||||
if (status == EIO) {
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen, "%s",
|
||||
get_last_lvm_error());
|
||||
return EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_QUERY:
|
||||
lockname = &args[2];
|
||||
if (buflen < 3)
|
||||
return EIO;
|
||||
if ((locktype = do_lock_query(lockname)))
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
do_refresh_cache();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_SYNC_NAMES:
|
||||
lvm_do_fs_unlock();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_SET_DEBUG:
|
||||
clvmd_set_debug((debug_t) args[0]);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_RESTART:
|
||||
status = restart_clvmd();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
status = clops->get_cluster_name(*buf, buflen);
|
||||
if (!status)
|
||||
*retlen = strlen(*buf)+1;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_VG_BACKUP:
|
||||
/*
|
||||
* Do not run backup on local node, caller should do that.
|
||||
*/
|
||||
if (!client)
|
||||
lvm_do_backup(&args[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Won't get here because command is validated in pre_command */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the status of the command and return the error text */
|
||||
if (status) {
|
||||
if (*buf)
|
||||
*retlen = dm_snprintf(*buf, buflen, "%s", strerror(status)) + 1;
|
||||
else
|
||||
*retlen = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int lock_vg(struct local_client *client)
|
||||
{
|
||||
struct dm_hash_table *lock_hash;
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
int lock_mode;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lkid;
|
||||
int status;
|
||||
char *lockname;
|
||||
|
||||
/*
|
||||
* Keep a track of VG locks in our own hash table. In current
|
||||
* practice there should only ever be more than two VGs locked
|
||||
* if a user tries to merge lots of them at once
|
||||
*/
|
||||
if (!client->bits.localsock.private) {
|
||||
if (!(lock_hash = dm_hash_create(3)))
|
||||
return ENOMEM;
|
||||
client->bits.localsock.private = (void *) lock_hash;
|
||||
} else
|
||||
lock_hash = (struct dm_hash_table *) client->bits.localsock.private;
|
||||
|
||||
lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
|
||||
lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
|
||||
/* lock_flags = args[1]; */
|
||||
lockname = &args[2];
|
||||
DEBUGLOG("(%p) doing PRE command LOCK_VG '%s' at %x\n", client, lockname, lock_cmd);
|
||||
|
||||
if (lock_mode == LCK_UNLOCK) {
|
||||
if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
|
||||
return EINVAL;
|
||||
|
||||
if ((status = sync_unlock(lockname, lkid)))
|
||||
status = errno;
|
||||
else
|
||||
dm_hash_remove(lock_hash, lockname);
|
||||
} else {
|
||||
/* Read locks need to be PR; other modes get passed through */
|
||||
if (lock_mode == LCK_READ)
|
||||
lock_mode = LCK_PREAD;
|
||||
|
||||
if ((status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid)))
|
||||
status = errno;
|
||||
else if (!dm_hash_insert(lock_hash, lockname, (void *) (long) lkid))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Pre-command is a good place to get locks that are needed only for the duration
|
||||
of the commands around the cluster (don't forget to free them in post-command),
|
||||
and to sanity check the command arguments */
|
||||
int do_pre_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lockid = 0;
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid);
|
||||
client->bits.localsock.private = (void *)(long)lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lockname = &args[2];
|
||||
/* We take out a real lock unless LCK_CACHE was set */
|
||||
if (!strncmp(lockname, "V_", 2) ||
|
||||
!strncmp(lockname, "P_#", 3))
|
||||
status = lock_vg(client);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
case CLVMD_CMD_SET_DEBUG:
|
||||
case CLVMD_CMD_VG_BACKUP:
|
||||
case CLVMD_CMD_SYNC_NAMES:
|
||||
case CLVMD_CMD_LOCK_QUERY:
|
||||
case CLVMD_CMD_RESTART:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown command %d received\n", header->cmd);
|
||||
status = EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Note that the post-command routine is called even if the pre-command or the real command
|
||||
failed */
|
||||
int do_post_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
int status = 0;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
|
||||
client->bits.localsock.private = NULL;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = post_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Nothing to do here */
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Called when the client is about to be deleted */
|
||||
void cmd_client_cleanup(struct local_client *client)
|
||||
{
|
||||
struct dm_hash_node *v;
|
||||
struct dm_hash_table *lock_hash;
|
||||
int lkid;
|
||||
char *lockname;
|
||||
|
||||
DEBUGLOG("(%p) Client thread cleanup\n", client);
|
||||
if (!client->bits.localsock.private)
|
||||
return;
|
||||
|
||||
lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
|
||||
|
||||
dm_hash_iterate(v, lock_hash) {
|
||||
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
|
||||
lockname = dm_hash_get_key(lock_hash, v);
|
||||
DEBUGLOG("(%p) Cleanup: Unlocking lock %s %x\n", client, lockname, lkid);
|
||||
(void) sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
dm_hash_destroy(lock_hash);
|
||||
client->bits.localsock.private = NULL;
|
||||
}
|
||||
|
||||
static int restart_clvmd(void)
|
||||
{
|
||||
const char **argv;
|
||||
char *lv_name;
|
||||
int argc = 0, max_locks = 0;
|
||||
struct dm_hash_node *hn = NULL;
|
||||
char debug_arg[16];
|
||||
const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH;
|
||||
|
||||
DEBUGLOG("clvmd restart requested\n");
|
||||
|
||||
/* Count exclusively-open LVs */
|
||||
do {
|
||||
hn = get_next_excl_lock(hn, &lv_name);
|
||||
if (lv_name) {
|
||||
max_locks++;
|
||||
if (!*lv_name)
|
||||
break; /* FIXME: Is this error ? */
|
||||
}
|
||||
} while (hn);
|
||||
|
||||
/* clvmd + locks (-E uuid) + debug (-d X) + NULL */
|
||||
if (!(argv = malloc((max_locks * 2 + 6) * sizeof(*argv))))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Build the command-line
|
||||
*/
|
||||
argv[argc++] = "clvmd";
|
||||
|
||||
/* Propagate debug options */
|
||||
if (clvmd_get_debug()) {
|
||||
if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0)
|
||||
goto_out;
|
||||
argv[argc++] = debug_arg;
|
||||
}
|
||||
|
||||
/* Propagate foreground options */
|
||||
if (clvmd_get_foreground())
|
||||
argv[argc++] = "-f";
|
||||
|
||||
argv[argc++] = "-I";
|
||||
argv[argc++] = clops->name;
|
||||
|
||||
/* Now add the exclusively-open LVs */
|
||||
hn = NULL;
|
||||
do {
|
||||
hn = get_next_excl_lock(hn, &lv_name);
|
||||
if (lv_name) {
|
||||
if (!*lv_name)
|
||||
break; /* FIXME: Is this error ? */
|
||||
argv[argc++] = "-E";
|
||||
argv[argc++] = lv_name;
|
||||
DEBUGLOG("excl lock: %s\n", lv_name);
|
||||
}
|
||||
} while (hn);
|
||||
argv[argc] = NULL;
|
||||
|
||||
/* Exec new clvmd */
|
||||
DEBUGLOG("--- Restarting %s ---\n", clvmd);
|
||||
for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]);
|
||||
|
||||
/* NOTE: This will fail when downgrading! */
|
||||
execvp(clvmd, (char **)argv);
|
||||
out:
|
||||
/* We failed */
|
||||
DEBUGLOG("Restart of clvmd failed.\n");
|
||||
|
||||
free(argv);
|
||||
|
||||
return EIO;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstraction layer for clvmd cluster communications
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_COMMS_H
|
||||
#define _CLVMD_COMMS_H
|
||||
|
||||
struct local_client;
|
||||
|
||||
struct cluster_ops {
|
||||
const char *name;
|
||||
void (*cluster_init_completed) (void);
|
||||
|
||||
int (*cluster_send_message) (const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext);
|
||||
int (*name_from_csid) (const char *csid, char *name);
|
||||
int (*csid_from_name) (char *csid, const char *name);
|
||||
int (*get_num_nodes) (void);
|
||||
int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client);
|
||||
int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */
|
||||
int (*cluster_do_node_callback) (struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *csid,
|
||||
int node_up));
|
||||
int (*is_quorate) (void);
|
||||
|
||||
void (*get_our_csid) (char *csid);
|
||||
void (*add_up_node) (const char *csid);
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*get_cluster_name)(char *buf, int buflen);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode,
|
||||
int flags, int *lockid);
|
||||
int (*sync_unlock) (const char *resource, int lockid);
|
||||
|
||||
};
|
||||
|
||||
#ifdef USE_CMAN
|
||||
# include <netinet/in.h>
|
||||
# include "libcman.h"
|
||||
# define CMAN_MAX_CSID_LEN 4
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
|
||||
# endif
|
||||
# undef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_NODENAME_LEN
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 1500
|
||||
# define CLUSTER_PORT_CLVMD 11
|
||||
struct cluster_ops *init_cman_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENAIS
|
||||
# include <openais/saAis.h>
|
||||
# include <corosync/totem/totem.h>
|
||||
# define OPENAIS_CSID_LEN (sizeof(int))
|
||||
# define OPENAIS_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_openais_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COROSYNC
|
||||
# include <corosync/corotypes.h>
|
||||
# define COROSYNC_CSID_LEN (sizeof(int))
|
||||
# define COROSYNC_MAX_CLUSTER_MESSAGE 65535
|
||||
# define COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 65535
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_corosync_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SINGLENODE
|
||||
# define SINGLENODE_CSID_LEN (sizeof(int))
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN 64
|
||||
# endif
|
||||
# define SINGLENODE_MAX_CLUSTER_MESSAGE 65535
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_singlenode_cluster(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,662 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides the interface between clvmd and corosync/DLM as the cluster
|
||||
* and lock manager.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include "locking.h"
|
||||
|
||||
#include <corosync/cpg.h>
|
||||
#include <corosync/quorum.h>
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
# include <corosync/confdb.h>
|
||||
#elif defined HAVE_COROSYNC_CMAP_H
|
||||
# include <corosync/cmap.h>
|
||||
#else
|
||||
# error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined."
|
||||
#endif
|
||||
|
||||
#include <libdlm.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
/* Timeout value for several corosync calls */
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len);
|
||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries);
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* Corosync handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static quorum_handle_t quorum_handle;
|
||||
|
||||
/* DLM Handle */
|
||||
static dlm_lshandle_t *lockspace;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Corosync callback structs */
|
||||
cpg_callbacks_t corosync_cpg_callbacks = {
|
||||
.cpg_deliver_fn = corosync_cpg_deliver_callback,
|
||||
.cpg_confchg_fn = corosync_cpg_confchg_callback,
|
||||
};
|
||||
|
||||
quorum_callbacks_t quorum_callbacks = {
|
||||
.quorum_notify_fn = NULL,
|
||||
};
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_DOWN, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int cs_to_errno(cs_error_t err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case CS_OK:
|
||||
return 0;
|
||||
case CS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case CS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case CS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case CS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case CS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case CS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case CS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case CS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case CS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case CS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case CS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case CS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case CS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case CS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case CS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case CS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case CS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case CS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_corosync_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, COROSYNC_CSID_LEN);
|
||||
|
||||
DEBUGLOG("%u got message from nodeid %d for %d. len %zd\n",
|
||||
our_nodeid, nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (nodeid != our_nodeid)
|
||||
if (target_nodeid == our_nodeid || target_nodeid == 0)
|
||||
process_message(cluster_client, (char *)msg+COROSYNC_CSID_LEN,
|
||||
msg_len-COROSYNC_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %zd joined, %zd left, %zd members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
COROSYNC_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
COROSYNC_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
COROSYNC_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
num_nodes = member_list_entries;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
cs_error_t err;
|
||||
|
||||
#ifdef QUORUM_SET /* corosync/quorum.h */
|
||||
uint32_t quorum_type;
|
||||
#endif
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&corosync_cpg_callbacks);
|
||||
if (err != CS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise Corosync CPG service: %d", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
#ifdef QUORUM_SET
|
||||
err = quorum_initialize(&quorum_handle,
|
||||
&quorum_callbacks,
|
||||
&quorum_type);
|
||||
|
||||
if (quorum_type != QUORUM_SET) {
|
||||
syslog(LOG_ERR, "Corosync quorum service is not configured");
|
||||
DEBUGLOG("Corosync quorum service is not configured");
|
||||
return EINVAL;
|
||||
}
|
||||
#else
|
||||
err = quorum_initialize(&quorum_handle,
|
||||
&quorum_callbacks);
|
||||
#endif
|
||||
|
||||
if (err != CS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise Corosync quorum service: %d", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
|
||||
if (!lockspace) {
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Created DLM lockspace for CLVMD.\n");
|
||||
} else
|
||||
DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
|
||||
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != CS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group: %d\n", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
err = cpg_local_get(cpg_handle,
|
||||
&our_nodeid);
|
||||
if (err != CS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
DEBUGLOG("Connected to Corosync\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* Corosync doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_corosync_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("corosync_add_up_node no node_hash entry for csid %s\n",
|
||||
print_corosync_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("corosync_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[COROSYNC_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), COROSYNC_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
callback(master_client, csid, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct dlm_lksb lksb;
|
||||
int err;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
if (flags & LKF_CONVERT)
|
||||
lksb.sb_lkid = *lockid;
|
||||
|
||||
err = dlm_ls_lock_wait(lockspace,
|
||||
mode,
|
||||
&lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_lock returned %d\n", errno);
|
||||
return err;
|
||||
}
|
||||
if (lksb.sb_status != 0)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_lock returns lksb.sb_status %d\n", lksb.sb_status);
|
||||
errno = lksb.sb_status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%x\n", err, lksb.sb_lkid);
|
||||
|
||||
*lockid = lksb.sb_lkid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(const char *resource, int lockid)
|
||||
{
|
||||
struct dlm_lksb lksb;
|
||||
int err;
|
||||
|
||||
DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
|
||||
lksb.sb_lkid = lockid;
|
||||
|
||||
err = dlm_ls_unlock_wait(lockspace,
|
||||
lockid,
|
||||
0,
|
||||
&lksb);
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return err;
|
||||
}
|
||||
if (lksb.sb_status != EUNLOCK)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_unlock_wait returns lksb.sb_status: %d\n", lksb.sb_status);
|
||||
errno = lksb.sb_status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
int quorate;
|
||||
if (quorum_getquorate(quorum_handle, &quorate) == CS_OK)
|
||||
return quorate;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, CS_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct iovec iov[2];
|
||||
cs_error_t err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, COROSYNC_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
/*
|
||||
* We are not necessarily connected to a Red Hat Cluster system,
|
||||
* but if we are, this returns the cluster name from cluster.conf.
|
||||
* I've used confdb rather than ccs to reduce the inter-package
|
||||
* dependancies as well as to allow people to set a cluster name
|
||||
* for themselves even if they are not running on RH cluster.
|
||||
*/
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
confdb_handle_t handle;
|
||||
int result;
|
||||
size_t namelen = buflen;
|
||||
hdb_handle_t cluster_handle;
|
||||
confdb_callbacks_t callbacks = {
|
||||
.confdb_key_change_notify_fn = NULL,
|
||||
.confdb_object_create_change_notify_fn = NULL,
|
||||
.confdb_object_delete_change_notify_fn = NULL
|
||||
};
|
||||
|
||||
/* This is a default in case everything else fails */
|
||||
strncpy(buf, "Corosync", buflen);
|
||||
|
||||
/* Look for a cluster name in confdb */
|
||||
result = confdb_initialize (&handle, &callbacks);
|
||||
if (result != CS_OK)
|
||||
return 0;
|
||||
|
||||
result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
buf[namelen] = '\0';
|
||||
|
||||
out:
|
||||
confdb_finalize(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined HAVE_COROSYNC_CMAP_H
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cmap_handle_t cmap_handle = 0;
|
||||
int result;
|
||||
char *name = NULL;
|
||||
|
||||
/* This is a default in case everything else fails */
|
||||
strncpy(buf, "Corosync", buflen);
|
||||
|
||||
/* Look for a cluster name in cmap */
|
||||
result = cmap_initialize(&cmap_handle);
|
||||
if (result != CS_OK)
|
||||
return 0;
|
||||
|
||||
result = cmap_get_string(cmap_handle, "totem.cluster_name", &name);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
strncpy(buf, name, buflen - 1);
|
||||
|
||||
out:
|
||||
if (name)
|
||||
free(name);
|
||||
cmap_finalize(cmap_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct cluster_ops _cluster_corosync_ops = {
|
||||
.name = "corosync",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _lock_resource,
|
||||
.sync_unlock = _unlock_resource,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_corosync_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_corosync_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,687 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides the interface between clvmd and OpenAIS as the cluster
|
||||
* and lock manager.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <openais/saAis.h>
|
||||
#include <openais/saLck.h>
|
||||
|
||||
#include <corosync/corotypes.h>
|
||||
#include <corosync/cpg.h>
|
||||
|
||||
#include "locking.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
/* Timeout value for several openais calls */
|
||||
#define TIMEOUT 10
|
||||
|
||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len);
|
||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries);
|
||||
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* For associating lock IDs & resource handles */
|
||||
static struct dm_hash_table *lock_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* OpenAIS handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static SaLckHandleT lck_handle;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Openais callback structs */
|
||||
cpg_callbacks_t openais_cpg_callbacks = {
|
||||
.cpg_deliver_fn = openais_cpg_deliver_callback,
|
||||
.cpg_confchg_fn = openais_cpg_confchg_callback,
|
||||
};
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
struct lock_info
|
||||
{
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaLckLockIdT lock_id;
|
||||
SaNameT lock_name;
|
||||
};
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int ais_to_errno(SaAisErrorT err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case SA_AIS_OK:
|
||||
return 0;
|
||||
case SA_AIS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case SA_AIS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case SA_AIS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case SA_AIS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case SA_AIS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case SA_AIS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_openais_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int add_internal_client(int fd, fd_callback_t callback)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
|
||||
|
||||
if (!(client = dm_zalloc(sizeof(*client)))) {
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_INTERNAL;
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n",
|
||||
our_nodeid, nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (nodeid != our_nodeid)
|
||||
if (target_nodeid == our_nodeid || target_nodeid == 0)
|
||||
process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
|
||||
msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
||||
FMTsize_t " left, %" PRIsize_t " members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
for (i=0; i<member_list_entries; i++) {
|
||||
if (member_list[i].nodeid == 0) continue;
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&member_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = member_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
num_nodes = member_list_entries;
|
||||
}
|
||||
|
||||
static int lck_dispatch(struct local_client *client, char *buf, int len,
|
||||
const char *csid, struct local_client **new_client)
|
||||
{
|
||||
*new_client = NULL;
|
||||
saLckDispatch(lck_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
SaVersionT ver = { 'B', 1, 1 };
|
||||
int select_fd;
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
lock_hash = dm_hash_create(10);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&openais_cpg_callbacks);
|
||||
if (err != SA_AIS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckInitialize(&lck_handle,
|
||||
NULL,
|
||||
&ver);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_initialize(&cpg_handle, &openais_cpg_callbacks);
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group: %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = cpg_local_get(cpg_handle,
|
||||
&our_nodeid);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
|
||||
add_internal_client(select_fd, lck_dispatch);
|
||||
|
||||
DEBUGLOG("Connected to OpenAIS\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
saLckFinalize(lck_handle);
|
||||
cpg_finalize(cpg_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* OpenAIS doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_openais_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes()
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
|
||||
print_openais_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
int somedown = 0;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[OPENAIS_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
if (ninfo->state != NODE_CLVMD)
|
||||
somedown = -1;
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct lock_info *linfo;
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaAisErrorT err;
|
||||
SaLckLockIdT lock_id;
|
||||
SaLckLockStatusT lockStatus;
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
|
||||
if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
|
||||
|
||||
linfo = malloc(sizeof(struct lock_info));
|
||||
if (!linfo)
|
||||
return -1;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
linfo->lock_name.length = strlen(resource)+1;
|
||||
strcpy((char *)linfo->lock_name.value, resource);
|
||||
|
||||
err = saLckResourceOpen(lck_handle, &linfo->lock_name,
|
||||
SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("ResourceOpen returned %d\n", err);
|
||||
free(linfo);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckResourceLock(
|
||||
res_handle,
|
||||
&lock_id,
|
||||
mode,
|
||||
flags,
|
||||
0,
|
||||
SA_TIME_END,
|
||||
&lockStatus);
|
||||
if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED)
|
||||
{
|
||||
free(linfo);
|
||||
saLckResourceClose(res_handle);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n",
|
||||
err, lock_id);
|
||||
|
||||
linfo->lock_id = lock_id;
|
||||
linfo->res_handle = res_handle;
|
||||
|
||||
dm_hash_insert(lock_hash, resource, linfo);
|
||||
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(char *resource, int lockid)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
struct lock_info *linfo;
|
||||
|
||||
DEBUGLOG("unlock_resource %s\n", resource);
|
||||
linfo = dm_hash_lookup(lock_hash, resource);
|
||||
if (!linfo)
|
||||
return 0;
|
||||
|
||||
DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id);
|
||||
err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Release the resource */
|
||||
dm_hash_remove(lock_hash, resource);
|
||||
saLckResourceClose(linfo->res_handle);
|
||||
free(linfo);
|
||||
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock too then bail out */
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
|
||||
lockid);
|
||||
if (status == SA_LCK_LOCK_NOT_QUEUED)
|
||||
{
|
||||
_unlock_resource(lock1, *lockid);
|
||||
status = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_PREAD:
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock2, *lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock1, *lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*lockid = mode;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource, int lockid)
|
||||
{
|
||||
int status = 0;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
_unlock_resource(lock1, lockid);
|
||||
_unlock_resource(lock2, lockid);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* We are always quorate ! */
|
||||
static int _is_quorate()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
SaAisErrorT err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, OPENAIS_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* We don't have a cluster name to report here */
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
strncpy(buf, "OpenAIS", buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_openais_ops = {
|
||||
.name = "openais",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_openais_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_openais_ops;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2013 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 "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "locking.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
|
||||
static int listen_fd = -1;
|
||||
|
||||
static struct dm_hash_table *_locks;
|
||||
static int _lockid;
|
||||
|
||||
static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Using one common condition for all locks for simplicity */
|
||||
static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
struct lock {
|
||||
struct dm_list list;
|
||||
int lockid;
|
||||
int mode;
|
||||
};
|
||||
|
||||
static void close_comms(void)
|
||||
{
|
||||
if (listen_fd != -1 && close(listen_fd))
|
||||
stack;
|
||||
(void)unlink(SINGLENODE_CLVMD_SOCKNAME);
|
||||
listen_fd = -1;
|
||||
}
|
||||
|
||||
static int init_comms(void)
|
||||
{
|
||||
mode_t old_mask;
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
|
||||
sizeof(addr.sun_path))) {
|
||||
DEBUGLOG("%s: singlenode socket name too long.",
|
||||
SINGLENODE_CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close_comms();
|
||||
|
||||
(void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
|
||||
old_mask = umask(0077);
|
||||
|
||||
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
if (fcntl(listen_fd, F_SETFD, 1)) {
|
||||
DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
if (listen(listen_fd, 10) < 0) {
|
||||
DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
umask(old_mask);
|
||||
(void) dm_prepare_selinux_context(NULL, 0);
|
||||
return 0;
|
||||
error:
|
||||
umask(old_mask);
|
||||
(void) dm_prepare_selinux_context(NULL, 0);
|
||||
close_comms();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!(_locks = dm_hash_create(128))) {
|
||||
DEBUGLOG("Failed to allocate single-node hash table.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = init_comms();
|
||||
if (r) {
|
||||
dm_hash_destroy(_locks);
|
||||
_locks = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
DEBUGLOG("Single-node cluster initialised.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
close_comms();
|
||||
|
||||
/* If there is any awaited resource, kill it softly */
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
dm_hash_destroy(_locks);
|
||||
_locks = NULL;
|
||||
_lockid = 0;
|
||||
pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
int nodeid = 1;
|
||||
memcpy(csid, &nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
strcpy(name, "SINGLENODE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _lock_file(const char *file, uint32_t flags);
|
||||
|
||||
static const char *_get_mode(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case LCK_NULL: return "NULL";
|
||||
case LCK_READ: return "READ";
|
||||
case LCK_PREAD: return "PREAD";
|
||||
case LCK_WRITE: return "WRITE";
|
||||
case LCK_EXCL: return "EXCLUSIVE";
|
||||
case LCK_UNLOCK: return "UNLOCK";
|
||||
default: return "????";
|
||||
}
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
/* DLM table of allowed transition states */
|
||||
static const int _dlm_table[6][6] = {
|
||||
/* Mode NL CR CW PR PW EX */
|
||||
/* NL */ { 1, 1, 1, 1, 1, 1},
|
||||
/* CR */ { 1, 1, 1, 1, 1, 0},
|
||||
/* CW */ { 1, 1, 1, 0, 0, 0},
|
||||
/* PR */ { 1, 1, 0, 1, 0, 0},
|
||||
/* PW */ { 1, 1, 0, 0, 0, 0},
|
||||
/* EX */ { 1, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
struct lock *lck = NULL, *lckt;
|
||||
struct dm_list *head;
|
||||
|
||||
DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n",
|
||||
resource, flags,
|
||||
(flags & LCKF_NOQUEUE) ? "NOQUEUE" : "",
|
||||
((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) ==
|
||||
(LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "",
|
||||
(flags & LCKF_CONVERT) ? "CONVERT" : "",
|
||||
_get_mode(mode), mode);
|
||||
|
||||
mode &= LCK_TYPE_MASK;
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
|
||||
retry:
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
if (flags & LCKF_CONVERT) {
|
||||
/* In real DLM, lock is identified only by lockid, resource is not used */
|
||||
DEBUGLOG("Unlocked resource %s cannot be converted\n", resource);
|
||||
goto_bad;
|
||||
}
|
||||
/* Add new locked resource */
|
||||
if (!(head = dm_malloc(sizeof(struct dm_list))) ||
|
||||
!dm_hash_insert(_locks, resource, head)) {
|
||||
dm_free(head);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
dm_list_init(head);
|
||||
} else /* Update/convert locked resource */
|
||||
dm_list_iterate_items(lck, head) {
|
||||
/* Check is all locks are compatible with requested lock */
|
||||
if (flags & LCKF_CONVERT) {
|
||||
if (lck->lockid != *lockid)
|
||||
continue;
|
||||
|
||||
DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode));
|
||||
dm_list_iterate_items(lckt, head) {
|
||||
if ((lckt->lockid != *lockid) &&
|
||||
!_dlm_table[mode][lckt->mode]) {
|
||||
if (!(flags & LCKF_NOQUEUE) &&
|
||||
/* TODO: Real dlm uses here conversion queues */
|
||||
!pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
|
||||
_locks) /* End of the game? */
|
||||
goto retry;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
lck->mode = mode; /* Lock is now converted */
|
||||
goto out;
|
||||
} else if (!_dlm_table[mode][lck->mode]) {
|
||||
DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
if (!(flags & LCKF_NOQUEUE) &&
|
||||
!pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
|
||||
_locks) { /* End of the game? */
|
||||
DEBUGLOG("Resource %s retrying lock in mode:%s...\n",
|
||||
resource, _get_mode(mode));
|
||||
goto retry;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & LCKF_CONVERT)) {
|
||||
if (!(lck = dm_malloc(sizeof(struct lock))))
|
||||
goto_bad;
|
||||
|
||||
*lockid = lck->lockid = ++_lockid;
|
||||
lck->mode = mode;
|
||||
dm_list_add(head, &lck->list);
|
||||
}
|
||||
out:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Failed to lock resource %s\n", resource);
|
||||
|
||||
return 1; /* fail */
|
||||
}
|
||||
|
||||
static int _unlock_resource(const char *resource, int lockid)
|
||||
{
|
||||
struct lock *lck;
|
||||
struct dm_list *head;
|
||||
int r = 1;
|
||||
|
||||
if (lockid < 0) {
|
||||
DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n",
|
||||
resource, lockid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid);
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
|
||||
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Resource %s is not locked.\n", resource);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(lck, head)
|
||||
if (lck->lockid == lockid) {
|
||||
dm_list_del(&lck->list);
|
||||
dm_free(lck);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGLOG("Resource %s has wrong lockid %d.\n", resource, lockid);
|
||||
out:
|
||||
if (dm_list_empty(head)) {
|
||||
//DEBUGLOG("Resource %s is no longer hashed (lockid=%d).\n", resource, lockid);
|
||||
dm_hash_remove(_locks, resource);
|
||||
dm_free(head);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
return dm_strncpy(buf, "localcluster", buflen) ? 0 : 1;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_singlenode_ops = {
|
||||
.name = "singlenode",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _lock_resource,
|
||||
.sync_unlock = _unlock_resource,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_singlenode_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_singlenode_ops;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_H
|
||||
#define _CLVMD_H
|
||||
|
||||
#define CLVMD_MAJOR_VERSION 0
|
||||
#define CLVMD_MINOR_VERSION 2
|
||||
#define CLVMD_PATCH_VERSION 1
|
||||
|
||||
/* Default time (in seconds) we will wait for all remote commands to execute
|
||||
before declaring them dead */
|
||||
#define DEFAULT_CMD_TIMEOUT 60
|
||||
|
||||
/* One of these for each reply we get from command execution on a node */
|
||||
struct node_reply {
|
||||
char node[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
char *replymsg;
|
||||
int status;
|
||||
struct node_reply *next;
|
||||
};
|
||||
|
||||
typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t;
|
||||
|
||||
/*
|
||||
* These exist for the use of local sockets only when we are
|
||||
* collecting responses from all cluster nodes
|
||||
*/
|
||||
struct localsock_bits {
|
||||
struct node_reply *replies;
|
||||
int num_replies;
|
||||
int expected_replies;
|
||||
time_t sent_time; /* So we can check for timeouts */
|
||||
int in_progress; /* Only execute one cmd at a time per client */
|
||||
int sent_out; /* Flag to indicate that a command was sent
|
||||
to remote nodes */
|
||||
void *private; /* Private area for command processor use */
|
||||
void *cmd; /* Whole command as passed down local socket */
|
||||
int cmd_len; /* Length of above */
|
||||
int pipe; /* Pipe to send PRE completion status down */
|
||||
int finished; /* Flag to tell subthread to exit */
|
||||
int all_success; /* Set to 0 if any node (or the pre_command)
|
||||
failed */
|
||||
int cleanup_needed; /* helper for cleanup_zombie */
|
||||
struct local_client *pipe_client;
|
||||
pthread_t threadid;
|
||||
enum { PRE_COMMAND, POST_COMMAND } state;
|
||||
pthread_mutex_t mutex; /* Main thread and worker synchronisation */
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
/* Entries for PIPE clients */
|
||||
struct pipe_bits {
|
||||
struct local_client *client; /* Actual (localsock) client */
|
||||
pthread_t threadid; /* Our own copy of the thread id */
|
||||
};
|
||||
|
||||
/* Entries for Network socket clients */
|
||||
struct netsock_bits {
|
||||
void *private;
|
||||
int flags;
|
||||
};
|
||||
|
||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client ** new_client);
|
||||
|
||||
/* One of these for each fd we are listening on */
|
||||
struct local_client {
|
||||
int fd;
|
||||
enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS,
|
||||
LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type;
|
||||
struct local_client *next;
|
||||
unsigned short xid;
|
||||
fd_callback_t callback;
|
||||
uint8_t removeme;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
struct pipe_bits pipe;
|
||||
struct netsock_bits net;
|
||||
} bits;
|
||||
};
|
||||
|
||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args)
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
/* The real command processor is in clvmd-command.c */
|
||||
extern int do_command(struct local_client *client, struct clvm_header *msg,
|
||||
int msglen, char **buf, int buflen, int *retlen);
|
||||
|
||||
/* Pre and post command routines are called only on the local node */
|
||||
extern int do_pre_command(struct local_client *client);
|
||||
extern int do_post_command(struct local_client *client);
|
||||
extern void cmd_client_cleanup(struct local_client *client);
|
||||
extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
extern void process_message(struct local_client *client, char *buf,
|
||||
int len, const char *csid);
|
||||
extern void debuglog(const char *fmt, ... )
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
void clvmd_set_debug(debug_t new_de);
|
||||
debug_t clvmd_get_debug(void);
|
||||
int clvmd_get_foreground(void);
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
#endif
|
||||
@@ -1,927 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
/* LVM2 headers */
|
||||
#include "toolcontext.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lvm-globals.h"
|
||||
#include "activate.h"
|
||||
#include "archiver.h"
|
||||
#include "memlock.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static pthread_mutex_t lvm_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
static const char *decode_full_locking_cmd(uint32_t cmdl)
|
||||
{
|
||||
static char buf[128];
|
||||
const char *type;
|
||||
const char *scope;
|
||||
const char *command;
|
||||
|
||||
switch (cmdl & LCK_TYPE_MASK) {
|
||||
case LCK_NULL:
|
||||
type = "NULL";
|
||||
break;
|
||||
case LCK_READ:
|
||||
type = "READ";
|
||||
break;
|
||||
case LCK_PREAD:
|
||||
type = "PREAD";
|
||||
break;
|
||||
case LCK_WRITE:
|
||||
type = "WRITE";
|
||||
break;
|
||||
case LCK_EXCL:
|
||||
type = "EXCL";
|
||||
break;
|
||||
case LCK_UNLOCK:
|
||||
type = "UNLOCK";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cmdl & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
scope = "VG";
|
||||
command = "LCK_VG";
|
||||
break;
|
||||
case LCK_LV:
|
||||
scope = "LV";
|
||||
switch (cmdl & LCK_MASK) {
|
||||
case LCK_LV_EXCLUSIVE & LCK_MASK:
|
||||
command = "LCK_LV_EXCLUSIVE";
|
||||
break;
|
||||
case LCK_LV_SUSPEND & LCK_MASK:
|
||||
command = "LCK_LV_SUSPEND";
|
||||
break;
|
||||
case LCK_LV_RESUME & LCK_MASK:
|
||||
command = "LCK_LV_RESUME";
|
||||
break;
|
||||
case LCK_LV_ACTIVATE & LCK_MASK:
|
||||
command = "LCK_LV_ACTIVATE";
|
||||
break;
|
||||
case LCK_LV_DEACTIVATE & LCK_MASK:
|
||||
command = "LCK_LV_DEACTIVATE";
|
||||
break;
|
||||
default:
|
||||
command = "unknown";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scope = "unknown";
|
||||
command = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope,
|
||||
cmdl & LCK_NONBLOCK ? "|NONBLOCK" : "",
|
||||
cmdl & LCK_HOLD ? "|HOLD" : "",
|
||||
cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "",
|
||||
cmdl & LCK_CACHE ? "|CACHE" : "");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only processes 8 bits: excludes LCK_CACHE.
|
||||
*/
|
||||
static const char *decode_locking_cmd(unsigned char cmdl)
|
||||
{
|
||||
return decode_full_locking_cmd((uint32_t) cmdl);
|
||||
}
|
||||
|
||||
static const char *decode_flags(unsigned char flags)
|
||||
{
|
||||
static char buf[128];
|
||||
int len;
|
||||
|
||||
len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s%s)", flags,
|
||||
flags & LCK_PARTIAL_MODE ? "PARTIAL_MODE|" : "",
|
||||
flags & LCK_MIRROR_NOSYNC_MODE ? "MIRROR_NOSYNC|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
||||
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
||||
flags & LCK_TEST_MODE ? "TEST|" : "",
|
||||
flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
||||
flags & LCK_REVERT_MODE ? "REVERT|" : "");
|
||||
|
||||
if (len > 1)
|
||||
buf[len - 2] = ' ';
|
||||
else
|
||||
buf[0] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *get_last_lvm_error(void)
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash lock info helpers
|
||||
*/
|
||||
static struct lv_info *lookup_info(const char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
lvi = dm_hash_lookup(lv_hash, resource);
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
|
||||
return lvi;
|
||||
}
|
||||
|
||||
static int insert_info(const char *resource, struct lv_info *lvi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
ret = dm_hash_insert(lv_hash, resource, lvi);
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void remove_info(const char *resource)
|
||||
{
|
||||
int num_open;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
dm_hash_remove(lv_hash, resource);
|
||||
|
||||
/* When last lock is remove, validate there are not left opened devices */
|
||||
if (!dm_hash_get_first(lv_hash)) {
|
||||
if (critical_section())
|
||||
log_error(INTERNAL_ERROR "No volumes are locked however clvmd is in activation mode critical section.");
|
||||
if ((num_open = dev_cache_check_for_open_devices()))
|
||||
log_error(INTERNAL_ERROR "No volumes are locked however %d devices are still open.", num_open);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the mode a lock is currently held at (or -1 if not held)
|
||||
*/
|
||||
static int get_current_lock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
if ((lvi = lookup_info(resource)))
|
||||
return lvi->lock_mode;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void init_lvhash(void)
|
||||
{
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = dm_hash_create(1024);
|
||||
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||
pthread_mutex_init(&lvm_lock, NULL);
|
||||
}
|
||||
|
||||
/* Called at shutdown to tidy the lockspace */
|
||||
void destroy_lvhash(void)
|
||||
{
|
||||
struct dm_hash_node *v;
|
||||
struct lv_info *lvi;
|
||||
char *resource;
|
||||
int status;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
|
||||
dm_hash_iterate(v, lv_hash) {
|
||||
lvi = dm_hash_get_data(lv_hash, v);
|
||||
resource = dm_hash_get_key(lv_hash, v);
|
||||
|
||||
if ((status = sync_unlock(resource, lvi->lock_id)))
|
||||
DEBUGLOG("unlock_all. unlock failed(%d): %s\n",
|
||||
status, strerror(errno));
|
||||
dm_free(lvi);
|
||||
}
|
||||
|
||||
dm_hash_destroy(lv_hash);
|
||||
lv_hash = NULL;
|
||||
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
}
|
||||
|
||||
/* Gets a real lock and keeps the info in the hash table */
|
||||
static int hold_lock(char *resource, int mode, int flags)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
struct lv_info *lvi;
|
||||
|
||||
/* Mask off invalid options */
|
||||
flags &= LCKF_NOQUEUE | LCKF_CONVERT;
|
||||
|
||||
lvi = lookup_info(resource);
|
||||
|
||||
if (lvi) {
|
||||
if (lvi->lock_mode == mode) {
|
||||
DEBUGLOG("hold_lock, lock mode %d already held\n",
|
||||
mode);
|
||||
return 0;
|
||||
}
|
||||
if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
|
||||
DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
|
||||
"ignoring LCK_WRITE request\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only allow explicit conversions */
|
||||
if (lvi && !(flags & LCKF_CONVERT)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
if (lvi) {
|
||||
/* Already exists - convert it */
|
||||
status = sync_lock(resource, mode, flags, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status)
|
||||
lvi->lock_mode = mode;
|
||||
else
|
||||
DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
if (!(lvi = dm_malloc(sizeof(struct lv_info)))) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
lvi->lock_mode = mode;
|
||||
lvi->lock_id = 0;
|
||||
status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (status) {
|
||||
dm_free(lvi);
|
||||
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
} else
|
||||
if (!insert_info(resource, lvi)) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Unlock and remove it from the hash table */
|
||||
static int hold_unlock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
int status;
|
||||
int saved_errno;
|
||||
|
||||
if (!(lvi = lookup_info(resource))) {
|
||||
DEBUGLOG("hold_unlock, lock not already held\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = sync_unlock(resource, lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status) {
|
||||
remove_info(resource);
|
||||
dm_free(lvi);
|
||||
} else {
|
||||
DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Watch the return codes here.
|
||||
liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno.
|
||||
libdlm API functions return 0 for success, -1 for failure and do set errno.
|
||||
These functions here return 0 for success or >0 for failure (where the retcode is errno)
|
||||
*/
|
||||
|
||||
/* Activate LV exclusive or non-exclusive */
|
||||
static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
int activate_lv;
|
||||
int exclusive = 0;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it already open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == mode && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode);
|
||||
return 0; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* Does the config file want us to activate this LV ? */
|
||||
if (!lv_activation_filter(cmd, resource, &activate_lv, NULL))
|
||||
return EIO;
|
||||
|
||||
if (!activate_lv)
|
||||
return 0; /* Success, we did nothing! */
|
||||
|
||||
/* Do we need to activate exclusively? */
|
||||
if ((activate_lv == 2) || (mode == LCK_EXCL)) {
|
||||
exclusive = 1;
|
||||
mode = LCK_EXCL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get the lock if it's a clustered volume group.
|
||||
* Use lock conversion only if requested, to prevent implicit conversion
|
||||
* of exclusive lock to shared one during activation.
|
||||
*/
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
|
||||
if (status) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
* rather than the strerror text for EAGAIN.
|
||||
*/
|
||||
if (errno == EAGAIN) {
|
||||
sprintf(last_error, "Volume is busy on another node");
|
||||
errno = EIO;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0))
|
||||
goto error;
|
||||
|
||||
if (lvi.suspended) {
|
||||
critical_section_inc(cmd, "resuming");
|
||||
if (!lv_resume(cmd, resource, 0, NULL)) {
|
||||
critical_section_dec(cmd, "resumed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now activate it */
|
||||
if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL))
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!test_mode() && (oldmode == -1 || oldmode != mode))
|
||||
(void)hold_unlock(resource);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* Resume the LV if it was active */
|
||||
static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode, origin_only, exclusive, revert;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_resume_lv, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
|
||||
revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0;
|
||||
|
||||
if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert, NULL))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Suspend the device if active */
|
||||
static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode;
|
||||
unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
unsigned exclusive;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_suspend_lv, lock not already held\n");
|
||||
return 0; /* Not active, so it's OK */
|
||||
}
|
||||
|
||||
exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
|
||||
|
||||
/* Always call lv_suspend to read commited and precommited data */
|
||||
if (!lv_suspend_if_active(cmd, resource, origin_only, exclusive, NULL, NULL))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_deactivate(cmd, resource, NULL))
|
||||
return EIO;
|
||||
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_unlock(resource);
|
||||
if (status)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *do_lock_query(char *resource)
|
||||
{
|
||||
int mode;
|
||||
const char *type;
|
||||
|
||||
mode = get_current_lock(resource);
|
||||
switch (mode) {
|
||||
case LCK_NULL: type = "NL"; break;
|
||||
case LCK_READ: type = "CR"; break;
|
||||
case LCK_PREAD:type = "PR"; break;
|
||||
case LCK_WRITE:type = "PW"; break;
|
||||
case LCK_EXCL: type = "EX"; break;
|
||||
default: type = NULL;
|
||||
}
|
||||
|
||||
DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "--");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* This is the LOCK_LV part that happens on all nodes in the cluster -
|
||||
it is responsible for the interaction with device-mapper and LVM */
|
||||
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
|
||||
|
||||
if (!cmd->initialized.config || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (do_refresh_cache()) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE)
|
||||
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
|
||||
else {
|
||||
if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
|
||||
init_dmeventd_monitor(1);
|
||||
else
|
||||
init_dmeventd_monitor(0);
|
||||
}
|
||||
|
||||
cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0;
|
||||
|
||||
/* clvmd should never try to read suspended device */
|
||||
init_ignore_suspended_devices(1);
|
||||
|
||||
switch (command & LCK_MASK) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, command, lock_flags, LCK_EXCL);
|
||||
break;
|
||||
|
||||
case LCK_LV_SUSPEND:
|
||||
status = do_suspend_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
case LCK_UNLOCK:
|
||||
case LCK_LV_RESUME: /* if active */
|
||||
status = do_resume_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
case LCK_LV_ACTIVATE:
|
||||
status = do_activate_lv(resource, command, lock_flags, LCK_READ);
|
||||
break;
|
||||
|
||||
case LCK_LV_DEACTIVATE:
|
||||
status = do_deactivate_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGLOG("Invalid LV command 0x%x\n", command);
|
||||
status = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
cmd->partial_activation = 0;
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
init_test(0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section());
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
|
||||
int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
|
||||
lock out on this node (because we are the node modifying the metadata)
|
||||
before suspending cluster-wide.
|
||||
LCKF_CONVERT is used always, local node is going to modify metadata
|
||||
*/
|
||||
if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND &&
|
||||
(command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags));
|
||||
|
||||
if (!(lock_flags & LCK_TEST_MODE) &&
|
||||
hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT))
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
int status;
|
||||
unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME &&
|
||||
(command & LCK_CLUSTER_VG)) {
|
||||
int oldmode;
|
||||
|
||||
DEBUGLOG("post_lock_lv: resource '%s', cmd = %s, flags = %s\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags));
|
||||
|
||||
/* If the lock state is PW then restore it to what it was */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == LCK_WRITE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
if (!status)
|
||||
return EIO;
|
||||
|
||||
if (!(lock_flags & LCK_TEST_MODE)) {
|
||||
if (lvi.exists) {
|
||||
if (hold_lock(resource, LCK_READ, LCKF_CONVERT))
|
||||
return errno;
|
||||
} else if (hold_unlock(resource))
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_refresh_cache(void)
|
||||
{
|
||||
DEBUGLOG("Refreshing context\n");
|
||||
log_notice("Refreshing context");
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_ignore_suspended_devices(1);
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle VG lock - drop metadata or update lvmcache state
|
||||
*/
|
||||
void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
uint32_t lock_cmd = command;
|
||||
char *vgname = resource + 2;
|
||||
|
||||
lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD);
|
||||
|
||||
/*
|
||||
* Check if LCK_CACHE should be set. All P_ locks except # are cache related.
|
||||
*/
|
||||
if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2))
|
||||
lock_cmd |= LCK_CACHE;
|
||||
|
||||
DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section());
|
||||
|
||||
/* P_#global causes a full cache refresh */
|
||||
if (!strcmp(resource, "P_" VG_GLOBAL)) {
|
||||
do_refresh_cache();
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
|
||||
|
||||
switch (lock_cmd) {
|
||||
case LCK_VG_COMMIT:
|
||||
DEBUGLOG("vg_commit notification for VG %s\n", vgname);
|
||||
lvmcache_commit_metadata(vgname);
|
||||
break;
|
||||
case LCK_VG_REVERT:
|
||||
DEBUGLOG("vg_revert notification for VG %s\n", vgname);
|
||||
lvmcache_drop_metadata(vgname, 1);
|
||||
break;
|
||||
case LCK_VG_DROP_CACHE:
|
||||
default:
|
||||
DEBUGLOG("Invalidating cached metadata for VG %s\n", vgname);
|
||||
lvmcache_drop_metadata(vgname, 0);
|
||||
}
|
||||
|
||||
init_test(0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, clvmd should be started before any LVs are active
|
||||
* but this may not be the case...
|
||||
* I suppose this also comes in handy if clvmd crashes, not that it would!
|
||||
*/
|
||||
static int get_initial_state(struct dm_hash_table *excl_uuid)
|
||||
{
|
||||
int lock_mode;
|
||||
char lv[65], vg[65], flags[26], vg_flags[26]; /* with space for '\0' */
|
||||
char uuid[65];
|
||||
char line[255];
|
||||
char *lvs_cmd;
|
||||
const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH;
|
||||
FILE *lvs;
|
||||
|
||||
if (dm_asprintf(&lvs_cmd, "%s lvs --config 'log{command_names=0 prefix=\"\"}' "
|
||||
"--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
|
||||
lvm_binary) < 0)
|
||||
return_0;
|
||||
|
||||
/* FIXME: Maybe link and use liblvm2cmd directly instead of fork */
|
||||
if (!(lvs = popen(lvs_cmd, "r"))) {
|
||||
dm_free(lvs_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), lvs)) {
|
||||
if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) {
|
||||
|
||||
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
|
||||
if (strlen(vg) == 38 && /* is is a valid UUID ? */
|
||||
(flags[4] == 'a' || flags[4] == 's') && /* is it active or suspended? */
|
||||
vg_flags[5] == 'c') { /* is it clustered ? */
|
||||
/* Convert hyphen-separated UUIDs into one */
|
||||
memcpy(&uuid[0], &vg[0], 6);
|
||||
memcpy(&uuid[6], &vg[7], 4);
|
||||
memcpy(&uuid[10], &vg[12], 4);
|
||||
memcpy(&uuid[14], &vg[17], 4);
|
||||
memcpy(&uuid[18], &vg[22], 4);
|
||||
memcpy(&uuid[22], &vg[27], 4);
|
||||
memcpy(&uuid[26], &vg[32], 6);
|
||||
memcpy(&uuid[32], &lv[0], 6);
|
||||
memcpy(&uuid[38], &lv[7], 4);
|
||||
memcpy(&uuid[42], &lv[12], 4);
|
||||
memcpy(&uuid[46], &lv[17], 4);
|
||||
memcpy(&uuid[50], &lv[22], 4);
|
||||
memcpy(&uuid[54], &lv[27], 4);
|
||||
memcpy(&uuid[58], &lv[32], 6);
|
||||
uuid[64] = '\0';
|
||||
|
||||
/* Look for this lock in the list of EX locks
|
||||
we were passed on the command-line */
|
||||
lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ?
|
||||
LCK_EXCL : LCK_READ;
|
||||
|
||||
DEBUGLOG("getting initial lock for %s\n", uuid);
|
||||
if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE))
|
||||
DEBUGLOG("Failed to hold lock %s\n", uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pclose(lvs))
|
||||
DEBUGLOG("lvs pclose failed: %s\n", strerror(errno));
|
||||
|
||||
dm_free(lvs_cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
|
||||
const char *message)
|
||||
{
|
||||
|
||||
/* Send messages to the normal LVM2 logging system too,
|
||||
so we get debug output when it's asked for.
|
||||
We need to NULL the function ptr otherwise it will just call
|
||||
back into here! */
|
||||
init_log_fn(NULL);
|
||||
print_log(level, file, line, dm_errno, "%s", message);
|
||||
init_log_fn(lvm2_log_fn);
|
||||
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
return;
|
||||
|
||||
(void) dm_strncpy(last_error, message, sizeof(last_error));
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config(void)
|
||||
{
|
||||
int locking_type;
|
||||
|
||||
locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL);
|
||||
|
||||
if (locking_type == 3) /* compiled-in cluster support */
|
||||
return;
|
||||
|
||||
if (locking_type == 2) { /* External library, check name */
|
||||
const char *libname;
|
||||
|
||||
libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL);
|
||||
if (libname && strstr(libname, "liblvm2clusterlock.so"))
|
||||
return;
|
||||
|
||||
log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
|
||||
return;
|
||||
}
|
||||
log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
|
||||
}
|
||||
|
||||
/* Backups up the LVM metadata if it's changed */
|
||||
void lvm_do_backup(const char *vgname)
|
||||
{
|
||||
struct volume_group * vg;
|
||||
int consistent = 0;
|
||||
|
||||
DEBUGLOG("Triggering backup of VG metadata for %s.\n", vgname);
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, WARN_PV_READ, &consistent);
|
||||
|
||||
if (vg && consistent)
|
||||
check_current_backup(vg);
|
||||
else
|
||||
log_error("Error backing up metadata, can't find VG for group %s", vgname);
|
||||
|
||||
release_vg(vg);
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
*name = NULL;
|
||||
if (!v)
|
||||
v = dm_hash_get_first(lv_hash);
|
||||
|
||||
do {
|
||||
if (v) {
|
||||
lvi = dm_hash_get_data(lv_hash, v);
|
||||
DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode);
|
||||
|
||||
if (lvi->lock_mode == LCK_EXCL) {
|
||||
*name = dm_hash_get_key(lv_hash, v);
|
||||
}
|
||||
v = dm_hash_get_next(lv_hash, v);
|
||||
}
|
||||
} while (v && !*name);
|
||||
|
||||
if (*name)
|
||||
DEBUGLOG("returning EXclusive UUID %s\n", *name);
|
||||
return v;
|
||||
}
|
||||
|
||||
void lvm_do_fs_unlock(void)
|
||||
{
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
DEBUGLOG("Syncing device names\n");
|
||||
fs_unlock();
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_clvm(struct dm_hash_table *excl_uuid)
|
||||
{
|
||||
/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
|
||||
init_syslog(LOG_DAEMON);
|
||||
openlog("clvmd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
/* Initialise already held locks */
|
||||
if (!get_initial_state(excl_uuid))
|
||||
log_error("Cannot load initial lock states.");
|
||||
|
||||
if (!udev_init_library_context())
|
||||
stack;
|
||||
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
udev_fin_library_context();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stored_errno()) {
|
||||
destroy_toolcontext(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->cmd_line = "clvmd";
|
||||
|
||||
/* Check lvm.conf is setup for cluster-LVM */
|
||||
check_config();
|
||||
init_ignore_suspended_devices(1);
|
||||
|
||||
/* Trap log messages so we can pass them back to the user */
|
||||
init_log_fn(lvm2_log_fn);
|
||||
memlock_inc_daemon(cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_lvm(void)
|
||||
{
|
||||
if (cmd) {
|
||||
memlock_dec_daemon(cmd);
|
||||
destroy_toolcontext(cmd);
|
||||
udev_fin_library_context();
|
||||
cmd = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Functions in lvm-functions.c */
|
||||
|
||||
#ifndef _LVM_FUNCTIONS_H
|
||||
#define _LVM_FUNCTIONS_H
|
||||
|
||||
extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
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_refresh_cache(void);
|
||||
extern int init_clvm(struct dm_hash_table *excl_uuid);
|
||||
extern void destroy_lvm(void);
|
||||
extern void init_lvhash(void);
|
||||
extern void destroy_lvhash(void);
|
||||
extern void lvm_do_backup(const char *vgname);
|
||||
extern char *get_last_lvm_error(void);
|
||||
extern void do_lock_vg(unsigned char command, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name);
|
||||
void lvm_do_fs_unlock(void);
|
||||
|
||||
#endif
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* FIXME Remove duplicated functions from this file. */
|
||||
|
||||
/*
|
||||
* Send a command to a running clvmd from the command-line
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include "clvm.h"
|
||||
#include "refresh_clvmd.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
} lvm_response_t;
|
||||
|
||||
/*
|
||||
* This gets stuck at the start of memory we allocate so we
|
||||
* can sanity-check it at deallocation time
|
||||
*/
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
static int _clvmd_sock = -1;
|
||||
|
||||
/* Open connection to the clvm daemon */
|
||||
static int _open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
|
||||
fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open local socket */
|
||||
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
fprintf(stderr, "connect() failed on local socket: %s\n",
|
||||
strerror(errno));
|
||||
if (close(local_socket))
|
||||
return -1;
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
unsigned off;
|
||||
int buflen;
|
||||
int err;
|
||||
|
||||
/* Send it to CLVMD */
|
||||
rewrite:
|
||||
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
|
||||
if (err == -1 && errno == EINTR)
|
||||
goto rewrite;
|
||||
fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (no_response)
|
||||
return 1;
|
||||
|
||||
/* Get the response */
|
||||
reread:
|
||||
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
if (errno == EINTR)
|
||||
goto reread;
|
||||
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
buflen = len + outheader->arglen;
|
||||
*retbuf = dm_malloc(buflen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
while (off <= outheader->arglen && len > 0) {
|
||||
len = read(_clvmd_sock, outheader->args + off,
|
||||
buflen - off - offsetof(struct clvm_header, args));
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
unsigned int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->xid = 0;
|
||||
head->clientid = 0;
|
||||
if (len)
|
||||
/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
|
||||
head->arglen = len - 1;
|
||||
else {
|
||||
head->arglen = 0;
|
||||
*head->args = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate special node names.
|
||||
*/
|
||||
if (!node || !strcmp(node, NODE_ALL))
|
||||
head->node[0] = '\0';
|
||||
else if (!strcmp(node, NODE_LOCAL)) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to a(or all) node(s) in the cluster and wait for replies
|
||||
*/
|
||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num, int no_response)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
_clvmd_sock = _open_local_sock();
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
_build_header(head, cmd, node, len);
|
||||
if (len)
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status = _send_request(outbuf, sizeof(struct clvm_header) +
|
||||
strlen(head->node) + len, &retbuf, no_response);
|
||||
if (!status || no_response)
|
||||
goto out;
|
||||
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate response array.
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
*response = NULL;
|
||||
if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2))) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
dm_free(rarray);
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
|
||||
out:
|
||||
dm_free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refresh_clvmd(int all_nodes)
|
||||
{
|
||||
int num_responses;
|
||||
char args[1]; // No args really.
|
||||
lvm_response_t *response = NULL;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error resetting node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int restart_clvmd(int all_nodes)
|
||||
{
|
||||
int dummy, status;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1);
|
||||
|
||||
/*
|
||||
* FIXME: we cannot receive response, clvmd re-exec before it.
|
||||
* but also should not close socket too early (the whole rq is dropped then).
|
||||
* FIXME: This should be handled this way:
|
||||
* - client waits for RESTART ack (and socket close)
|
||||
* - server restarts
|
||||
* - client checks that server is ready again (VERSION command?)
|
||||
*/
|
||||
usleep(500000);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int debug_clvmd(int level, int clusterwide)
|
||||
{
|
||||
int num_responses;
|
||||
char args[1];
|
||||
const char *nodes;
|
||||
lvm_response_t *response = NULL;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
args[0] = level;
|
||||
if (clusterwide)
|
||||
nodes = NODE_ALL;
|
||||
else
|
||||
nodes = NODE_LOCAL;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error setting debug on node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
int refresh_clvmd(int all_nodes);
|
||||
int restart_clvmd(int all_nodes);
|
||||
int debug_clvmd(int level, int clusterwide);
|
||||
|
||||
@@ -17,8 +17,6 @@ top_builddir = @top_builddir@
|
||||
|
||||
CPG_LIBS = @CPG_LIBS@
|
||||
CPG_CFLAGS = @CPG_CFLAGS@
|
||||
SACKPT_LIBS = @SACKPT_LIBS@
|
||||
SACKPT_CFLAGS = @SACKPT_CFLAGS@
|
||||
|
||||
SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
|
||||
|
||||
@@ -26,14 +24,15 @@ TARGETS = cmirrord
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper
|
||||
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LMLIBS += $(CPG_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
|
||||
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||
$(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||
cmirrord: $(OBJECTS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
|
||||
|
||||
install: $(TARGETS)
|
||||
$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
#include "functions.h"
|
||||
#include "link_mon.h"
|
||||
#include "local.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
|
||||
/* FIXME: remove this and the code */
|
||||
#define CMIRROR_HAS_CHECKPOINT 0
|
||||
|
||||
#include <corosync/cpg.h>
|
||||
#include <errno.h>
|
||||
@@ -399,13 +403,12 @@ static struct checkpoint_data *prepare_checkpoint(struct clog_cpg *entry,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = malloc(sizeof(*new));
|
||||
new = zalloc(sizeof(*new));
|
||||
if (!new) {
|
||||
LOG_ERROR("Unable to create checkpoint data for %u",
|
||||
cp_requester);
|
||||
return NULL;
|
||||
}
|
||||
memset(new, 0, sizeof(*new));
|
||||
new->requester = cp_requester;
|
||||
strncpy(new->uuid, entry->name.value, entry->name.length);
|
||||
|
||||
@@ -640,13 +643,12 @@ static int export_checkpoint(struct checkpoint_data *cp)
|
||||
rq_size += RECOVERING_REGION_SECTION_SIZE;
|
||||
rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
|
||||
|
||||
rq = malloc(rq_size);
|
||||
rq = zalloc(rq_size);
|
||||
if (!rq) {
|
||||
LOG_ERROR("export_checkpoint: "
|
||||
"Unable to allocate transfer structs");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(rq, 0, rq_size);
|
||||
|
||||
dm_list_init(&rq->u.list);
|
||||
rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
|
||||
@@ -1618,12 +1620,11 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
new = malloc(sizeof(*new));
|
||||
new = zalloc(sizeof(*new));
|
||||
if (!new) {
|
||||
LOG_ERROR("Unable to allocate memory for clog_cpg");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(new, 0, sizeof(*new));
|
||||
dm_list_init(&new->list);
|
||||
new->lowest_id = 0xDEAD;
|
||||
dm_list_init(&new->startup_list);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#ifndef _LVM_CLOG_CLUSTER_H
|
||||
#define _LVM_CLOG_CLUSTER_H
|
||||
|
||||
#include "dm-log-userspace.h"
|
||||
#include "libdevmapper.h"
|
||||
#include "libdm/misc/dm-log-userspace.h"
|
||||
#include "libdm/libdevmapper.h"
|
||||
|
||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
||||
#define DM_ULOG_CHECKPOINT_READY 21
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "logging.h"
|
||||
#include "cluster.h"
|
||||
#include "compat.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
#include "logging.h"
|
||||
#include "functions.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <dirent.h>
|
||||
@@ -435,7 +436,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
||||
block_on_error = 1;
|
||||
}
|
||||
|
||||
lc = dm_zalloc(sizeof(*lc));
|
||||
lc = zalloc(sizeof(*lc));
|
||||
if (!lc) {
|
||||
LOG_ERROR("Unable to allocate cluster log context");
|
||||
r = -ENOMEM;
|
||||
@@ -532,9 +533,9 @@ fail:
|
||||
LOG_ERROR("Close device error, %s: %s",
|
||||
disk_path, strerror(errno));
|
||||
free(lc->disk_buffer);
|
||||
dm_free(lc->sync_bits);
|
||||
dm_free(lc->clean_bits);
|
||||
dm_free(lc);
|
||||
free(lc->sync_bits);
|
||||
free(lc->clean_bits);
|
||||
free(lc);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -659,9 +660,9 @@ static int clog_dtr(struct dm_ulog_request *rq)
|
||||
strerror(errno));
|
||||
if (lc->disk_buffer)
|
||||
free(lc->disk_buffer);
|
||||
dm_free(lc->clean_bits);
|
||||
dm_free(lc->sync_bits);
|
||||
dm_free(lc);
|
||||
free(lc->clean_bits);
|
||||
free(lc->sync_bits);
|
||||
free(lc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef _LVM_CLOG_FUNCTIONS_H
|
||||
#define _LVM_CLOG_FUNCTIONS_H
|
||||
|
||||
#include "dm-log-userspace.h"
|
||||
#include "device_mapper/misc/dm-log-userspace.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#define LOG_RESUMED 1
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
#ifndef _LVM_CLOG_LOGGING_H
|
||||
#define _LVM_CLOG_LOGGING_H
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "configure.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <syslog.h>
|
||||
|
||||
@@ -57,14 +57,16 @@ all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
|
||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += -ldevmapper $(PTHREAD_LIBS)
|
||||
LIBS += $(PTHREAD_LIBS) -L$(top_builddir)/libdm -ldevmapper
|
||||
|
||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) -lm
|
||||
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
ifeq ("@PKGCONFIG@", "yes")
|
||||
@@ -73,7 +75,6 @@ endif
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
|
||||
@@ -81,23 +82,28 @@ CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
endif
|
||||
|
||||
install_include: $(srcdir)/libdevmapper-event.h
|
||||
$(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
||||
|
||||
install_pkgconfig: libdevmapper-event.pc
|
||||
$(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
|
||||
|
||||
install_lib_dynamic: install_lib_shared
|
||||
|
||||
install_lib_static: $(LIB_STATIC)
|
||||
$(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
|
||||
|
||||
install_lib: $(INSTALL_LIB_TARGETS)
|
||||
|
||||
install_dmeventd_dynamic: dmeventd
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_dmeventd_static: dmeventd.static
|
||||
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||
|
||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
* dmeventd - dm event daemon to monitor active mapped devices
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include "tool.h"
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <signal.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
#include <fcntl.h> /* for musl libc */
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
@@ -60,8 +62,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
@@ -264,19 +264,19 @@ static pthread_cond_t _timeout_cond = PTHREAD_COND_INITIALIZER;
|
||||
/* DSO data allocate/free. */
|
||||
static void _free_dso_data(struct dso_data *data)
|
||||
{
|
||||
dm_free(data->dso_name);
|
||||
dm_free(data);
|
||||
free(data->dso_name);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static struct dso_data *_alloc_dso_data(struct message_data *data)
|
||||
{
|
||||
struct dso_data *ret = (typeof(ret)) dm_zalloc(sizeof(*ret));
|
||||
struct dso_data *ret = (typeof(ret)) zalloc(sizeof(*ret));
|
||||
|
||||
if (!ret)
|
||||
return_NULL;
|
||||
|
||||
if (!(ret->dso_name = dm_strdup(data->dso_name))) {
|
||||
dm_free(ret);
|
||||
if (!(ret->dso_name = strdup(data->dso_name))) {
|
||||
free(ret);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
@@ -397,9 +397,9 @@ static void _free_thread_status(struct thread_status *thread)
|
||||
_lib_put(thread->dso_data);
|
||||
if (thread->wait_task)
|
||||
dm_task_destroy(thread->wait_task);
|
||||
dm_free(thread->device.uuid);
|
||||
dm_free(thread->device.name);
|
||||
dm_free(thread);
|
||||
free(thread->device.uuid);
|
||||
free(thread->device.name);
|
||||
free(thread);
|
||||
}
|
||||
|
||||
/* Note: events_field must not be 0, ensured by caller */
|
||||
@@ -408,7 +408,7 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
|
||||
{
|
||||
struct thread_status *thread;
|
||||
|
||||
if (!(thread = dm_zalloc(sizeof(*thread)))) {
|
||||
if (!(thread = zalloc(sizeof(*thread)))) {
|
||||
log_error("Cannot create new thread, out of memory.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -422,11 +422,11 @@ static struct thread_status *_alloc_thread_status(const struct message_data *dat
|
||||
if (!dm_task_set_uuid(thread->wait_task, data->device_uuid))
|
||||
goto_out;
|
||||
|
||||
if (!(thread->device.uuid = dm_strdup(data->device_uuid)))
|
||||
if (!(thread->device.uuid = strdup(data->device_uuid)))
|
||||
goto_out;
|
||||
|
||||
/* Until real name resolved, use UUID */
|
||||
if (!(thread->device.name = dm_strdup(data->device_uuid)))
|
||||
if (!(thread->device.name = strdup(data->device_uuid)))
|
||||
goto_out;
|
||||
|
||||
/* runs ioctl and may register lvm2 pluging */
|
||||
@@ -515,7 +515,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
|
||||
if ((p = strchr(*src, delimiter))) {
|
||||
if (*src < p) {
|
||||
*p = 0; /* Temporary exit with \0 */
|
||||
if (!(*ptr = dm_strdup(*src))) {
|
||||
if (!(*ptr = strdup(*src))) {
|
||||
log_error("Failed to fetch item %s.", *src);
|
||||
ret = 0; /* Allocation fail */
|
||||
}
|
||||
@@ -525,7 +525,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
|
||||
(*src)++; /* Skip delmiter, next field */
|
||||
} else if ((len = strlen(*src))) {
|
||||
/* No delimiter, item ends with '\0' */
|
||||
if (!(*ptr = dm_strdup(*src))) {
|
||||
if (!(*ptr = strdup(*src))) {
|
||||
log_error("Failed to fetch last item %s.", *src);
|
||||
ret = 0; /* Fail */
|
||||
}
|
||||
@@ -538,11 +538,11 @@ out:
|
||||
/* Free message memory. */
|
||||
static void _free_message(struct message_data *message_data)
|
||||
{
|
||||
dm_free(message_data->id);
|
||||
dm_free(message_data->dso_name);
|
||||
dm_free(message_data->device_uuid);
|
||||
dm_free(message_data->events_str);
|
||||
dm_free(message_data->timeout_str);
|
||||
free(message_data->id);
|
||||
free(message_data->dso_name);
|
||||
free(message_data->device_uuid);
|
||||
free(message_data->events_str);
|
||||
free(message_data->timeout_str);
|
||||
}
|
||||
|
||||
/* Parse a register message from the client. */
|
||||
@@ -574,7 +574,7 @@ static int _parse_message(struct message_data *message_data)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
|
||||
return ret;
|
||||
@@ -608,8 +608,8 @@ static int _fill_device_data(struct thread_status *ts)
|
||||
if (!dm_task_run(dmt))
|
||||
goto fail;
|
||||
|
||||
dm_free(ts->device.name);
|
||||
if (!(ts->device.name = dm_strdup(dm_task_get_name(dmt))))
|
||||
free(ts->device.name);
|
||||
if (!(ts->device.name = strdup(dm_task_get_name(dmt))))
|
||||
goto fail;
|
||||
|
||||
if (!dm_task_get_info(dmt, &dmi))
|
||||
@@ -696,8 +696,8 @@ static int _get_status(struct message_data *message_data)
|
||||
|
||||
len = strlen(message_data->id);
|
||||
msg->size = size + len + 1;
|
||||
dm_free(msg->data);
|
||||
if (!(msg->data = dm_malloc(msg->size)))
|
||||
free(msg->data);
|
||||
if (!(msg->data = malloc(msg->size)))
|
||||
goto out;
|
||||
|
||||
memcpy(msg->data, message_data->id, len);
|
||||
@@ -712,7 +712,7 @@ static int _get_status(struct message_data *message_data)
|
||||
ret = 0;
|
||||
out:
|
||||
for (j = 0; j < i; ++j)
|
||||
dm_free(buffers[j]);
|
||||
free(buffers[j]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -721,7 +721,7 @@ static int _get_parameters(struct message_data *message_data) {
|
||||
struct dm_event_daemon_message *msg = message_data->msg;
|
||||
int size;
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
|
||||
message_data->id, getpid(),
|
||||
_foreground ? "no" : "yes",
|
||||
@@ -1225,7 +1225,7 @@ static int _registered_device(struct message_data *message_data,
|
||||
int r;
|
||||
struct dm_event_daemon_message *msg = message_data->msg;
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
|
||||
if ((r = dm_asprintf(&(msg->data), "%s %s %s %u",
|
||||
message_data->id,
|
||||
@@ -1365,7 +1365,7 @@ static int _get_timeout(struct message_data *message_data)
|
||||
if (!thread)
|
||||
return -ENODEV;
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
|
||||
message_data->id, thread->timeout);
|
||||
|
||||
@@ -1502,7 +1502,7 @@ static int _client_read(struct dm_event_fifos *fifos,
|
||||
bytes = 0;
|
||||
if (!size)
|
||||
break; /* No data -> error */
|
||||
buf = msg->data = dm_malloc(msg->size);
|
||||
buf = msg->data = malloc(msg->size);
|
||||
if (!buf)
|
||||
break; /* No mem -> error */
|
||||
header = 0;
|
||||
@@ -1510,7 +1510,7 @@ static int _client_read(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
if (bytes != size) {
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -1530,7 +1530,7 @@ static int _client_write(struct dm_event_fifos *fifos,
|
||||
fd_set fds;
|
||||
|
||||
size_t size = 2 * sizeof(uint32_t) + ((msg->data) ? msg->size : 0);
|
||||
uint32_t *header = dm_malloc(size);
|
||||
uint32_t *header = malloc(size);
|
||||
char *buf = (char *)header;
|
||||
|
||||
if (!header) {
|
||||
@@ -1560,7 +1560,7 @@ static int _client_write(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
if (header != temp)
|
||||
dm_free(header);
|
||||
free(header);
|
||||
|
||||
return (bytes == size);
|
||||
}
|
||||
@@ -1622,7 +1622,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
|
||||
msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
|
||||
(msg->cmd == DM_EVENT_CMD_DIE) ? "DYING" : "HELLO",
|
||||
DM_EVENT_PROTOCOL_VERSION);
|
||||
dm_free(answer);
|
||||
free(answer);
|
||||
}
|
||||
} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
|
||||
stack;
|
||||
@@ -1664,7 +1664,7 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
|
||||
DEBUGLOG("<<< CMD:%s (0x%x) completed (result %d).", decode_cmd(cmd), cmd, msg.cmd);
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
if (cmd == DM_EVENT_CMD_DIE) {
|
||||
if (unlink(DMEVENTD_PIDFILE))
|
||||
@@ -1975,7 +1975,7 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
||||
int i, ret;
|
||||
|
||||
ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
msg.data = NULL;
|
||||
|
||||
if (ret) {
|
||||
@@ -2061,13 +2061,13 @@ static void _restart_dmeventd(void)
|
||||
++count;
|
||||
}
|
||||
|
||||
if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) {
|
||||
if (!(_initial_registrations = malloc(sizeof(char*) * (count + 1)))) {
|
||||
fprintf(stderr, "Memory allocation registration failed.\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (!(_initial_registrations[i] = dm_strdup(message))) {
|
||||
if (!(_initial_registrations[i] = strdup(message))) {
|
||||
fprintf(stderr, "Memory allocation for message failed.\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
#include "dmlib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
#include "libdm/misc/dm-logging.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
|
||||
#include "lib/misc/intl.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
@@ -25,6 +27,7 @@
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int _debug_level = 0;
|
||||
static int _use_syslog = 0;
|
||||
@@ -47,8 +50,8 @@ struct dm_event_handler {
|
||||
|
||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
|
||||
{
|
||||
dm_free(dmevh->dev_name);
|
||||
dm_free(dmevh->uuid);
|
||||
free(dmevh->dev_name);
|
||||
free(dmevh->uuid);
|
||||
dmevh->dev_name = dmevh->uuid = NULL;
|
||||
dmevh->major = dmevh->minor = 0;
|
||||
}
|
||||
@@ -57,7 +60,7 @@ struct dm_event_handler *dm_event_handler_create(void)
|
||||
{
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
|
||||
if (!(dmevh = zalloc(sizeof(*dmevh)))) {
|
||||
log_error("Failed to allocate event handler.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -68,9 +71,9 @@ struct dm_event_handler *dm_event_handler_create(void)
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
|
||||
{
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dm_free(dmevh->dso);
|
||||
dm_free(dmevh->dmeventd_path);
|
||||
dm_free(dmevh);
|
||||
free(dmevh->dso);
|
||||
free(dmevh->dmeventd_path);
|
||||
free(dmevh);
|
||||
}
|
||||
|
||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
|
||||
@@ -78,9 +81,9 @@ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const cha
|
||||
if (!dmeventd_path) /* noop */
|
||||
return 0;
|
||||
|
||||
dm_free(dmevh->dmeventd_path);
|
||||
free(dmevh->dmeventd_path);
|
||||
|
||||
if (!(dmevh->dmeventd_path = dm_strdup(dmeventd_path)))
|
||||
if (!(dmevh->dmeventd_path = strdup(dmeventd_path)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -91,9 +94,9 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
|
||||
if (!path) /* noop */
|
||||
return 0;
|
||||
|
||||
dm_free(dmevh->dso);
|
||||
free(dmevh->dso);
|
||||
|
||||
if (!(dmevh->dso = dm_strdup(path)))
|
||||
if (!(dmevh->dso = strdup(path)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -106,7 +109,7 @@ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *de
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
if (!(dmevh->dev_name = dm_strdup(dev_name)))
|
||||
if (!(dmevh->dev_name = strdup(dev_name)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -119,7 +122,7 @@ int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
if (!(dmevh->uuid = dm_strdup(uuid)))
|
||||
if (!(dmevh->uuid = strdup(uuid)))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -259,7 +262,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||
msg->cmd = ntohl(header[0]);
|
||||
msg->size = ntohl(header[1]);
|
||||
buf = msg->data = dm_malloc(msg->size);
|
||||
buf = msg->data = malloc(msg->size);
|
||||
size = msg->size;
|
||||
bytes = 0;
|
||||
header = 0;
|
||||
@@ -267,7 +270,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
if (bytes != size) {
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
}
|
||||
return bytes == size;
|
||||
@@ -370,13 +373,13 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
||||
*/
|
||||
if (!_daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
do {
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = NULL;
|
||||
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
@@ -619,7 +622,7 @@ static int _do_event(int cmd, char *dmeventd_path, struct dm_event_daemon_messag
|
||||
|
||||
ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||
|
||||
dm_free(msg->data);
|
||||
free(msg->data);
|
||||
msg->data = 0;
|
||||
|
||||
if (!ret)
|
||||
@@ -645,6 +648,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if (!strstr(dmevh->dso, "libdevmapper-event-lvm2thin.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2vdo.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
||||
@@ -659,7 +663,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
@@ -686,7 +690,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
@@ -702,7 +706,7 @@ static char *_fetch_string(char **src, const int delimiter)
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((ret = dm_strdup(*src)))
|
||||
if ((ret = strdup(*src)))
|
||||
*src += strlen(ret) + 1;
|
||||
|
||||
if (p)
|
||||
@@ -722,11 +726,11 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
(*dso_name = _fetch_string(&p, ' ')) &&
|
||||
(*uuid = _fetch_string(&p, ' '))) {
|
||||
*evmask = atoi(p);
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -768,7 +772,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
dm_task_destroy(dmt);
|
||||
dmt = NULL;
|
||||
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
msg.data = NULL;
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
@@ -777,7 +781,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(dmevh->uuid = dm_strdup(reply_uuid))) {
|
||||
if (!(dmevh->uuid = strdup(reply_uuid))) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -790,13 +794,13 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
dm_event_handler_set_dso(dmevh, reply_dso);
|
||||
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||
|
||||
dm_free(reply_dso);
|
||||
free(reply_dso);
|
||||
reply_dso = NULL;
|
||||
|
||||
dm_free(reply_uuid);
|
||||
free(reply_uuid);
|
||||
reply_uuid = NULL;
|
||||
|
||||
if (!(dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)))) {
|
||||
if (!(dmevh->dev_name = strdup(dm_task_get_name(dmt)))) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -814,9 +818,9 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
dm_free(msg.data);
|
||||
dm_free(reply_dso);
|
||||
dm_free(reply_uuid);
|
||||
free(msg.data);
|
||||
free(reply_dso);
|
||||
free(reply_uuid);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
@@ -981,12 +985,12 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
if (!p) {
|
||||
log_error("Malformed reply from dmeventd '%s'.",
|
||||
msg.data);
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
return -EIO;
|
||||
}
|
||||
*timeout = atoi(p);
|
||||
}
|
||||
dm_free(msg.data);
|
||||
free(msg.data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef LIB_DMEVENT_H
|
||||
#define LIB_DMEVENT_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,4 +8,3 @@ Description: device-mapper event library
|
||||
Version: @DM_LIB_PATCHLEVEL@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -ldevmapper-event
|
||||
Requires.private: devmapper
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2005, 2011 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -16,11 +16,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SUBDIRS += lvm2 snapshot raid thin mirror
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = lvm2 mirror snapshot raid thin
|
||||
endif
|
||||
SUBDIRS += lvm2 snapshot raid thin mirror vdo
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
@@ -28,3 +24,4 @@ snapshot: lvm2
|
||||
mirror: lvm2
|
||||
raid: lvm2
|
||||
thin: lvm2
|
||||
vdo: lvm2
|
||||
|
||||
@@ -16,6 +16,7 @@ top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
CLDFLAGS += -L$(top_builddir)/tools
|
||||
LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@
|
||||
|
||||
SOURCES = dmeventd_lvm.c
|
||||
|
||||
@@ -24,8 +25,6 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
|
||||
|
||||
install_lvm2: install_lib_shared
|
||||
|
||||
install: install_lvm2
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "tools/lvm2cmd.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -31,6 +31,13 @@ static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int _register_count = 0;
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
static DM_LIST_INIT(_env_registry);
|
||||
|
||||
struct env_data {
|
||||
struct dm_list list;
|
||||
const char *cmd;
|
||||
const char *data;
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("#lvm")
|
||||
|
||||
@@ -100,6 +107,7 @@ void dmeventd_lvm2_exit(void)
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
dm_list_init(&_env_registry);
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
log_debug("lvm plugin exited.");
|
||||
@@ -124,6 +132,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
static char _internal_prefix[] = "_dmeventd_";
|
||||
char *vg = NULL, *lv = NULL, *layer;
|
||||
int r;
|
||||
struct env_data *env_data;
|
||||
const char *env = NULL;
|
||||
|
||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||
log_error("Unable to determine VG name from %s.",
|
||||
@@ -137,18 +147,36 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
*layer = '\0';
|
||||
|
||||
if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
|
||||
dmeventd_lvm2_lock();
|
||||
/* output of internal command passed via env var */
|
||||
if (!dmeventd_lvm2_run(cmd))
|
||||
cmd = NULL;
|
||||
else if ((cmd = getenv(cmd)))
|
||||
cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
|
||||
dmeventd_lvm2_unlock();
|
||||
/* check if ENVVAR wasn't already resolved */
|
||||
dm_list_iterate_items(env_data, &_env_registry)
|
||||
if (!strcmp(cmd, env_data->cmd)) {
|
||||
env = env_data->data;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cmd) {
|
||||
log_error("Unable to find configured command.");
|
||||
return 0;
|
||||
if (!env) {
|
||||
/* run lvm2 command to find out setting value */
|
||||
dmeventd_lvm2_lock();
|
||||
if (!dmeventd_lvm2_run(cmd) ||
|
||||
!(env = getenv(cmd))) {
|
||||
dmeventd_lvm2_unlock();
|
||||
log_error("Unable to find configured command.");
|
||||
return 0;
|
||||
}
|
||||
/* output of internal command passed via env var */
|
||||
env = dm_pool_strdup(_mem_pool, env); /* copy with lock */
|
||||
dmeventd_lvm2_unlock();
|
||||
if (!env ||
|
||||
!(env_data = dm_pool_zalloc(_mem_pool, sizeof(*env_data))) ||
|
||||
!(env_data->cmd = dm_pool_strdup(_mem_pool, cmd))) {
|
||||
log_error("Unable to allocate env memory.");
|
||||
return 0;
|
||||
}
|
||||
env_data->data = env;
|
||||
/* add to ENVVAR registry */
|
||||
dm_list_add(&_env_registry, &env_data->list);
|
||||
}
|
||||
cmd = env;
|
||||
}
|
||||
|
||||
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
|
||||
|
||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
SOURCES = dmeventd_mirror.c
|
||||
|
||||
@@ -30,8 +30,6 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
install: install_lvm2
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "activate.h" /* For TARGET_NAME* */
|
||||
#include "lib/misc/lib.h"
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "lib/activate/activate.h"
|
||||
|
||||
/* FIXME Reformat to 80 char lines. */
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
SOURCES = dmeventd_raid.c
|
||||
|
||||
@@ -29,8 +29,6 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
install: install_lvm2
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "defaults.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
#include "lib/config/defaults.h"
|
||||
|
||||
/* Hold enough elements for the mximum number of RAID images */
|
||||
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
|
||||
|
||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
SOURCES = dmeventd_snapshot.c
|
||||
|
||||
@@ -26,8 +26,6 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
install: install_lvm2
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -175,6 +175,7 @@ void process_event(struct dm_task *dmt,
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dm_info info;
|
||||
int ret;
|
||||
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->percent_check)
|
||||
@@ -205,7 +206,8 @@ void process_event(struct dm_task *dmt,
|
||||
/* Maybe configurable ? */
|
||||
_remove(dm_task_get_uuid(dmt));
|
||||
#endif
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
|
||||
log_sys_error("pthread_kill", "self");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -213,7 +215,8 @@ void process_event(struct dm_task *dmt,
|
||||
/* TODO eventually recognize earlier when room is enough */
|
||||
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
||||
device);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
|
||||
log_sys_error("pthread_kill", "self");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
SOURCES = dmeventd_thin.c
|
||||
|
||||
@@ -29,8 +29,6 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
install: install_lvm2
|
||||
|
||||
@@ -12,16 +12,16 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib.h" /* using here lvm log */
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
# include "libdm/misc/kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
@@ -286,7 +286,7 @@ void process_event(struct dm_task *dmt,
|
||||
if (state->fails++ <= state->max_fails) {
|
||||
log_debug("Postponing frequently failing policy (%u <= %u).",
|
||||
state->fails - 1, state->max_fails);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
if (state->max_fails < MAX_FAILS)
|
||||
state->max_fails <<= 1;
|
||||
|
||||
3
daemons/dmeventd/plugins/vdo/.exported_symbols
Normal file
3
daemons/dmeventd/plugins/vdo/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
@@ -1,3 +1,4 @@
|
||||
#
|
||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
@@ -14,10 +15,20 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES=\
|
||||
vdo/status.c
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||
LIBS += -ldevmapper-event-lvm2
|
||||
|
||||
SOURCES = dmeventd_vdo.c
|
||||
|
||||
LIB_NAME = libdevmapper-event-lvm2vdo
|
||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIB_NAME = libdevicemapper
|
||||
LIB_STATIC = $(LIB_NAME).a
|
||||
install_lvm2: install_dm_plugin
|
||||
|
||||
install: install_lvm2
|
||||
407
daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
Normal file
407
daemons/dmeventd/plugins/vdo/dmeventd_vdo.c
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* 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/misc/lib.h"
|
||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
||||
|
||||
/* Use parser from new device_mapper library */
|
||||
#include "device_mapper/vdo/status.c"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* First warning when VDO pool is 80% full. */
|
||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking VDO pool is less than 50% full. */
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */
|
||||
|
||||
#define VDO_DEBUG 0
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
int percent_check;
|
||||
int percent;
|
||||
uint64_t known_data_size;
|
||||
unsigned fails;
|
||||
unsigned max_fails;
|
||||
int restore_sigset;
|
||||
sigset_t old_sigset;
|
||||
pid_t pid;
|
||||
char *argv[3];
|
||||
const char *cmd_str;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("vdo")
|
||||
|
||||
static int _run_command(struct dso_state *state)
|
||||
{
|
||||
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) setenv("LVM_RUN_BY_DMEVENTD", "1", 1);
|
||||
|
||||
if (state->percent) {
|
||||
/* Prepare some known data to env vars for easy use */
|
||||
if (dm_snprintf(val, sizeof(val), "%d",
|
||||
state->percent / DM_PERCENT_1) != -1)
|
||||
(void) setenv("DMEVENTD_VDO_POOL", val, 1);
|
||||
} else {
|
||||
/* For an error event it's for a user to check status and decide */
|
||||
log_debug("Error event processing.");
|
||||
}
|
||||
|
||||
log_verbose("Executing command: %s", state->cmd_str);
|
||||
|
||||
/* TODO:
|
||||
* Support parallel run of 'task' and it's waitpid maintainence
|
||||
* ATM we can't handle signaling of SIGALRM
|
||||
* as signalling is not allowed while 'process_event()' is running
|
||||
*/
|
||||
if (!(state->pid = fork())) {
|
||||
/* child */
|
||||
(void) close(0);
|
||||
for (i = 3; i < 255; ++i) (void) close(i);
|
||||
execvp(state->argv[0], state->argv);
|
||||
_exit(errno);
|
||||
} else if (state->pid == -1) {
|
||||
log_error("Can't fork command %s.", state->cmd_str);
|
||||
state->fails = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
|
||||
{
|
||||
#if VDO_DEBUG
|
||||
log_debug("dmeventd executes: %s.", state->cmd_str);
|
||||
#endif
|
||||
if (state->argv[0])
|
||||
return _run_command(state);
|
||||
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
||||
log_error("Failed command for %s.", dm_task_get_name(dmt));
|
||||
state->fails = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
state->fails = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if executed command has finished
|
||||
* Only 1 command may run */
|
||||
static int _wait_for_pid(struct dso_state *state)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (state->pid == -1)
|
||||
return 1;
|
||||
|
||||
if (!waitpid(state->pid, &status, WNOHANG))
|
||||
return 0;
|
||||
|
||||
/* Wait for finish */
|
||||
if (WIFEXITED(status)) {
|
||||
log_verbose("Child %d exited with status %d.",
|
||||
state->pid, WEXITSTATUS(status));
|
||||
state->fails = WEXITSTATUS(status) ? 1 : 0;
|
||||
} else {
|
||||
if (WIFSIGNALED(status))
|
||||
log_verbose("Child %d was terminated with status %d.",
|
||||
state->pid, WTERMSIG(status));
|
||||
state->fails = 1;
|
||||
}
|
||||
|
||||
state->pid = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **user)
|
||||
{
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
int needs_policy = 0;
|
||||
struct dm_task *new_dmt = NULL;
|
||||
struct dm_vdo_status_parse_result vdop = { .status = NULL };
|
||||
|
||||
#if VDO_DEBUG
|
||||
log_debug("Watch for VDO %s:%.2f%%.", state->name,
|
||||
dm_percent_to_round_float(state->percent_check, 2));
|
||||
#endif
|
||||
if (!_wait_for_pid(state)) {
|
||||
log_warn("WARNING: Skipping event, child %d is still running (%s).",
|
||||
state->pid, state->cmd_str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||
#if VDO_DEBUG
|
||||
log_debug("VDO event error.");
|
||||
#endif
|
||||
/* Error -> no need to check and do instant resize */
|
||||
state->percent = 0;
|
||||
if (_use_policy(dmt, state))
|
||||
goto out;
|
||||
|
||||
stack;
|
||||
|
||||
if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
|
||||
goto_out;
|
||||
|
||||
/* Non-blocking status read */
|
||||
if (!dm_task_no_flush(new_dmt))
|
||||
log_warn("WARNING: Can't set no_flush for dm status.");
|
||||
|
||||
if (!dm_task_run(new_dmt))
|
||||
goto_out;
|
||||
|
||||
dmt = new_dmt;
|
||||
}
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
|
||||
if (!target_type || (strcmp(target_type, "vdo") != 0)) {
|
||||
log_error("Invalid target type.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_vdo_status_parse(state->mem, params, &vdop)) {
|
||||
log_error("Failed to parse status.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
state->percent = dm_make_percent(vdop.status->used_blocks,
|
||||
vdop.status->total_blocks);
|
||||
|
||||
#if VDO_DEBUG
|
||||
log_debug("VDO %s status %.2f%% " FMTu64 "/" FMTu64 ".",
|
||||
state->name, dm_percent_to_round_float(state->percent, 2),
|
||||
vdop.status->used_blocks, vdop.status->total_blocks);
|
||||
#endif
|
||||
|
||||
/* VDO pool size had changed. Clear the threshold. */
|
||||
if (state->known_data_size != vdop.status->total_blocks) {
|
||||
state->percent_check = CHECK_MINIMUM;
|
||||
state->known_data_size = vdop.status->total_blocks;
|
||||
state->fails = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger action when threshold boundary is exceeded.
|
||||
* Report 80% threshold warning when it's used above 80%.
|
||||
* Only 100% is exception as it cannot be surpased so policy
|
||||
* action is called for: >50%, >55% ... >95%, 100%
|
||||
*/
|
||||
if ((state->percent > WARNING_THRESH) &&
|
||||
(state->percent > state->percent_check))
|
||||
log_warn("WARNING: VDO %s %s is now %.2f%% full.",
|
||||
state->name, device,
|
||||
dm_percent_to_round_float(state->percent, 2));
|
||||
if (state->percent > CHECK_MINIMUM) {
|
||||
/* Run action when usage raised more than CHECK_STEP since the last time */
|
||||
if (state->percent > state->percent_check)
|
||||
needs_policy = 1;
|
||||
state->percent_check = (state->percent / CHECK_STEP + 1) * CHECK_STEP;
|
||||
if (state->percent_check == DM_PERCENT_100)
|
||||
state->percent_check--; /* Can't get bigger then 100% */
|
||||
} else
|
||||
state->percent_check = CHECK_MINIMUM;
|
||||
|
||||
/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
|
||||
* Avoids too high number of error retries, yet shows some status messages in log regularly.
|
||||
* i.e. PV could have been pvmoved and VG/LV was locked for a while...
|
||||
*/
|
||||
if (state->fails) {
|
||||
if (state->fails++ <= state->max_fails) {
|
||||
log_debug("Postponing frequently failing policy (%u <= %u).",
|
||||
state->fails - 1, state->max_fails);
|
||||
goto out;
|
||||
}
|
||||
if (state->max_fails < MAX_FAILS)
|
||||
state->max_fails <<= 1;
|
||||
state->fails = needs_policy = 1; /* Retry failing command */
|
||||
} else
|
||||
state->max_fails = 1; /* Reset on success */
|
||||
|
||||
if (needs_policy)
|
||||
_use_policy(dmt, state);
|
||||
out:
|
||||
if (vdop.status)
|
||||
dm_pool_free(state->mem, vdop.status);
|
||||
|
||||
if (new_dmt)
|
||||
dm_task_destroy(new_dmt);
|
||||
}
|
||||
|
||||
/* Handle SIGCHLD for a thread */
|
||||
static void _sig_child(int signum __attribute__((unused)))
|
||||
{
|
||||
/* empty SIG_IGN */;
|
||||
}
|
||||
|
||||
/* Setup handler for SIGCHLD when executing external command
|
||||
* to get quick 'waitpid()' reaction
|
||||
* It will interrupt syscall just like SIGALRM and
|
||||
* invoke process_event().
|
||||
*/
|
||||
static void _init_thread_signals(struct dso_state *state)
|
||||
{
|
||||
struct sigaction act = { .sa_handler = _sig_child };
|
||||
sigset_t my_sigset;
|
||||
|
||||
sigemptyset(&my_sigset);
|
||||
|
||||
if (sigaction(SIGCHLD, &act, NULL))
|
||||
log_warn("WARNING: Failed to set SIGCHLD action.");
|
||||
else if (sigaddset(&my_sigset, SIGCHLD))
|
||||
log_warn("WARNING: Failed to add SIGCHLD to set.");
|
||||
else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
|
||||
log_warn("WARNING: Failed to unblock SIGCHLD.");
|
||||
else
|
||||
state->restore_sigset = 1;
|
||||
}
|
||||
|
||||
static void _restore_thread_signals(struct dso_state *state)
|
||||
{
|
||||
if (state->restore_sigset &&
|
||||
pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
|
||||
log_warn("WARNING: Failed to block SIGCHLD.");
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid,
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state;
|
||||
const char *cmd;
|
||||
char *str;
|
||||
char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
|
||||
const char *name = "pool";
|
||||
|
||||
if (!dmeventd_lvm2_init_with_pool("vdo_pool_state", state))
|
||||
goto_bad;
|
||||
|
||||
state->cmd_str = "";
|
||||
|
||||
/* Search for command for LVM- prefixed devices only */
|
||||
cmd = (strncmp(uuid, "LVM-", 4) == 0) ? "_dmeventd_vdo_command" : "";
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str), cmd, device))
|
||||
goto_bad;
|
||||
|
||||
if (strncmp(cmd_str, "lvm ", 4) == 0) {
|
||||
if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
|
||||
log_error("Failed to copy lvm VDO command.");
|
||||
goto bad;
|
||||
}
|
||||
} else if (cmd_str[0] == '/') {
|
||||
if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
|
||||
log_error("Failed to copy VDO command.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Find last space before 'vg/lv' */
|
||||
if (!(str = strrchr(state->cmd_str, ' ')))
|
||||
goto inval;
|
||||
|
||||
if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
|
||||
str - state->cmd_str))) {
|
||||
log_error("Failed to copy command.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
state->argv[1] = str + 1; /* 1 argument - vg/lv */
|
||||
_init_thread_signals(state);
|
||||
} else if (cmd[0] == 0) {
|
||||
state->name = "volume"; /* What to use with 'others?' */
|
||||
} else/* Unuspported command format */
|
||||
goto inval;
|
||||
|
||||
state->pid = -1;
|
||||
state->name = name;
|
||||
*user = state;
|
||||
|
||||
log_info("Monitoring VDO %s %s.", name, device);
|
||||
|
||||
return 1;
|
||||
inval:
|
||||
log_error("Invalid command for monitoring: %s.", cmd_str);
|
||||
bad:
|
||||
log_error("Failed to monitor VDO %s %s.", name, device);
|
||||
|
||||
if (state)
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
const char *name = state->name;
|
||||
int i;
|
||||
|
||||
for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
|
||||
if (i == 0)
|
||||
/* Give it 2 seconds, then try to terminate & kill it */
|
||||
log_verbose("Child %d still not finished (%s) waiting.",
|
||||
state->pid, state->cmd_str);
|
||||
else if (i == 3) {
|
||||
log_warn("WARNING: Terminating child %d.", state->pid);
|
||||
kill(state->pid, SIGINT);
|
||||
kill(state->pid, SIGTERM);
|
||||
} else if (i == 5) {
|
||||
log_warn("WARNING: Killing child %d.", state->pid);
|
||||
kill(state->pid, SIGKILL);
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (state->pid != -1)
|
||||
log_warn("WARNING: Cannot kill child %d!", state->pid);
|
||||
|
||||
_restore_thread_signals(state);
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring VDO %s %s.", name, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2016 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
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = dmfilemapd.c
|
||||
|
||||
TARGETS = dmfilemapd
|
||||
|
||||
.PHONY: install_dmfilemapd install_dmfilemapd_static
|
||||
|
||||
INSTALL_DMFILEMAPD_TARGETS = install_dmfilemapd_dynamic
|
||||
|
||||
CLEAN_TARGETS = dmfilemapd.static
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = dmfilemapd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
all: device-mapper
|
||||
device-mapper: $(TARGETS)
|
||||
|
||||
CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
|
||||
LIBS += -ldevmapper
|
||||
|
||||
dmfilemapd: $(LIB_SHARED) dmfilemapd.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS)
|
||||
|
||||
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o $(interfacebuilddir)/libdevmapper.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L$(interfacebuilddir) \
|
||||
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
-include $(top_builddir)/daemons/dmfilemapd/$(LIB_NAME).cflow
|
||||
endif
|
||||
|
||||
install_dmfilemapd_dynamic: dmfilemapd
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_dmfilemapd_static: dmfilemapd.static
|
||||
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||
|
||||
install_dmfilemapd: $(INSTALL_DMFILEMAPD_TARGETS)
|
||||
|
||||
install: install_dmfilemapd
|
||||
|
||||
install_device-mapper: install_dmfilemapd
|
||||
@@ -23,11 +23,10 @@ LVMDBUS_SRCDIR_FILES = \
|
||||
cfg.py \
|
||||
cmdhandler.py \
|
||||
fetch.py \
|
||||
__init__.py \
|
||||
job.py \
|
||||
loader.py \
|
||||
main.py \
|
||||
lv.py \
|
||||
main.py \
|
||||
manager.py \
|
||||
objectmanager.py \
|
||||
pv.py \
|
||||
@@ -35,7 +34,8 @@ LVMDBUS_SRCDIR_FILES = \
|
||||
state.py \
|
||||
udevwatch.py \
|
||||
utils.py \
|
||||
vg.py
|
||||
vg.py \
|
||||
__init__.py
|
||||
|
||||
LVMDBUS_BUILDDIR_FILES = \
|
||||
lvmdb.py \
|
||||
@@ -51,17 +51,18 @@ include $(top_builddir)/make.tmpl
|
||||
.PHONY: install_lvmdbusd
|
||||
|
||||
all:
|
||||
test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||
|
||||
install_lvmdbusd:
|
||||
$(INSTALL_DIR) $(sbindir)
|
||||
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||
$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
||||
(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
||||
$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
|
||||
PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||
$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
|
||||
$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_DIR) $(sbindir)
|
||||
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||
$(Q) $(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
||||
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
||||
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
|
||||
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||
$(Q) $(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
|
||||
$(Q) $(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
|
||||
|
||||
install_lvm2: install_lvmdbusd
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class AutomatedProperties(dbus.service.Object):
|
||||
# through all dbus objects as some don't have a search method, like
|
||||
# 'Manager' object.
|
||||
if not self._ap_search_method:
|
||||
return
|
||||
return 0
|
||||
|
||||
search = self.lvm_id
|
||||
if search_key:
|
||||
|
||||
@@ -87,3 +87,13 @@ blackbox = None
|
||||
|
||||
# RequestEntry ctor
|
||||
create_request_entry = None
|
||||
|
||||
|
||||
def exit_daemon():
|
||||
"""
|
||||
Exit the daemon cleanly
|
||||
:return:
|
||||
"""
|
||||
if run and loop:
|
||||
run.value = 0
|
||||
loop.quit()
|
||||
|
||||
@@ -67,7 +67,7 @@ class LvmFlightRecorder(object):
|
||||
with cmd_lock:
|
||||
if len(self.queue):
|
||||
log_error("LVM dbus flight recorder START")
|
||||
for c in self.queue:
|
||||
for c in reversed(self.queue):
|
||||
log_error(str(c))
|
||||
log_error("LVM dbus flight recorder END")
|
||||
|
||||
@@ -263,10 +263,10 @@ def lv_tag(lv_name, add, rm, tag_options):
|
||||
return _tag('lvchange', lv_name, add, rm, tag_options)
|
||||
|
||||
|
||||
def vg_rename(vg, new_name, rename_options):
|
||||
def vg_rename(vg_uuid, new_name, rename_options):
|
||||
cmd = ['vgrename']
|
||||
cmd.extend(options_to_cli_args(rename_options))
|
||||
cmd.extend([vg, new_name])
|
||||
cmd.extend([vg_uuid, new_name])
|
||||
return call(cmd)
|
||||
|
||||
|
||||
@@ -497,7 +497,8 @@ def lvm_full_report_json():
|
||||
])
|
||||
|
||||
rc, out, err = call(cmd)
|
||||
if rc == 0:
|
||||
# When we have an exported vg the exit code of lvs or fullreport will be 5
|
||||
if rc == 0 or rc == 5:
|
||||
# With the current implementation, if we are using the shell then we
|
||||
# are using JSON and JSON is returned back to us as it was parsed to
|
||||
# figure out if we completed OK or not
|
||||
|
||||
@@ -14,6 +14,7 @@ from . import cfg
|
||||
from .utils import MThreadRunner, log_debug, log_error
|
||||
import threading
|
||||
import queue
|
||||
import time
|
||||
import traceback
|
||||
|
||||
|
||||
@@ -82,6 +83,8 @@ class StateUpdate(object):
|
||||
|
||||
@staticmethod
|
||||
def update_thread(obj):
|
||||
exception_count = 0
|
||||
|
||||
queued_requests = []
|
||||
while cfg.run.value != 0:
|
||||
# noinspection PyBroadException
|
||||
@@ -136,12 +139,26 @@ class StateUpdate(object):
|
||||
# wake up if we get an exception
|
||||
queued_requests = []
|
||||
|
||||
# We retrieved OK, clear exception count
|
||||
exception_count = 0
|
||||
|
||||
except queue.Empty:
|
||||
pass
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
st = traceback.format_exc()
|
||||
log_error("update_thread exception: \n%s" % st)
|
||||
cfg.blackbox.dump()
|
||||
exception_count += 1
|
||||
if exception_count >= 5:
|
||||
for i in queued_requests:
|
||||
i.set_result(e)
|
||||
|
||||
log_error("Too many errors in update_thread, exiting daemon")
|
||||
cfg.exit_daemon()
|
||||
|
||||
else:
|
||||
# Slow things down when encountering errors
|
||||
time.sleep(1)
|
||||
|
||||
def __init__(self):
|
||||
self.lock = threading.RLock()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
from .automatedproperties import AutomatedProperties
|
||||
|
||||
from . import utils
|
||||
from .utils import vg_obj_path_generate
|
||||
from .utils import vg_obj_path_generate, log_error
|
||||
import dbus
|
||||
from . import cmdhandler
|
||||
from . import cfg
|
||||
@@ -24,6 +24,8 @@ from . import background
|
||||
from .utils import round_size, mt_remove_dbus_objects
|
||||
from .job import JobState
|
||||
|
||||
import traceback
|
||||
|
||||
|
||||
# Try and build a key for a LV, so that we sort the LVs with least dependencies
|
||||
# first. This may be error prone because of the flexibility LVM
|
||||
@@ -291,6 +293,22 @@ class LvCommon(AutomatedProperties):
|
||||
(lv_uuid, lv_name))
|
||||
return dbo
|
||||
|
||||
def attr_struct(self, index, type_map, default='undisclosed'):
|
||||
try:
|
||||
if self.state.Attr[index] not in type_map:
|
||||
log_error("LV %s %s with lv_attr %s, lv_attr[%d] = "
|
||||
"'%s' is not known" %
|
||||
(self.Uuid, self.Name, self.Attr, index,
|
||||
self.state.Attr[index]))
|
||||
|
||||
return dbus.Struct((self.state.Attr[index],
|
||||
type_map.get(self.state.Attr[index], default)),
|
||||
signature="(ss)")
|
||||
except BaseException:
|
||||
st = traceback.format_exc()
|
||||
log_error("attr_struct: \n%s" % st)
|
||||
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
|
||||
|
||||
@property
|
||||
def VolumeType(self):
|
||||
type_map = {'C': 'Cache', 'm': 'mirrored',
|
||||
@@ -304,16 +322,14 @@ class LvCommon(AutomatedProperties):
|
||||
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
||||
'e': 'raid or pool metadata or pool metadata spare',
|
||||
'-': 'Unspecified'}
|
||||
return dbus.Struct((self.state.Attr[0], type_map[self.state.Attr[0]]),
|
||||
signature="as")
|
||||
return self.attr_struct(0, type_map)
|
||||
|
||||
@property
|
||||
def Permissions(self):
|
||||
type_map = {'w': 'writable', 'r': 'read-only',
|
||||
'R': 'Read-only activation of non-read-only volume',
|
||||
'-': 'Unspecified'}
|
||||
return dbus.Struct((self.state.Attr[1], type_map[self.state.Attr[1]]),
|
||||
signature="(ss)")
|
||||
return self.attr_struct(1, type_map)
|
||||
|
||||
@property
|
||||
def AllocationPolicy(self):
|
||||
@@ -322,8 +338,7 @@ class LvCommon(AutomatedProperties):
|
||||
'i': 'inherited', 'I': 'inherited locked',
|
||||
'l': 'cling', 'L': 'cling locked',
|
||||
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
|
||||
return dbus.Struct((self.state.Attr[2], type_map[self.state.Attr[2]]),
|
||||
signature="(ss)")
|
||||
return self.attr_struct(2, type_map)
|
||||
|
||||
@property
|
||||
def FixedMinor(self):
|
||||
@@ -331,15 +346,20 @@ class LvCommon(AutomatedProperties):
|
||||
|
||||
@property
|
||||
def State(self):
|
||||
type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
|
||||
type_map = {'a': 'active',
|
||||
's': 'suspended',
|
||||
'I': 'Invalid snapshot',
|
||||
'S': 'invalid Suspended snapshot',
|
||||
'm': 'snapshot merge failed',
|
||||
'M': 'suspended snapshot (M)erge failed',
|
||||
'd': 'mapped device present without tables',
|
||||
'i': 'mapped device present with inactive table',
|
||||
'X': 'unknown', '-': 'Unspecified'}
|
||||
return dbus.Struct((self.state.Attr[4], type_map[self.state.Attr[4]]),
|
||||
signature="(ss)")
|
||||
'h': 'historical',
|
||||
'c': 'check needed suspended thin-pool',
|
||||
'C': 'check needed',
|
||||
'X': 'unknown',
|
||||
'-': 'Unspecified'}
|
||||
return self.attr_struct(4, type_map)
|
||||
|
||||
@property
|
||||
def TargetType(self):
|
||||
@@ -355,11 +375,18 @@ class LvCommon(AutomatedProperties):
|
||||
|
||||
@property
|
||||
def Health(self):
|
||||
type_map = {'p': 'partial', 'r': 'refresh',
|
||||
'm': 'mismatches', 'w': 'writemostly',
|
||||
'X': 'X unknown', '-': 'Unspecified'}
|
||||
return dbus.Struct((self.state.Attr[8], type_map[self.state.Attr[8]]),
|
||||
signature="(ss)")
|
||||
type_map = {'p': 'partial',
|
||||
'r': 'refresh needed',
|
||||
'm': 'mismatches',
|
||||
'w': 'writemostly',
|
||||
'X': 'unknown',
|
||||
'-': 'unspecified',
|
||||
's': 'reshaping',
|
||||
'F': 'failed',
|
||||
'D': 'Data space',
|
||||
'R': 'Remove',
|
||||
'M': 'Metadata'}
|
||||
return self.attr_struct(8, type_map)
|
||||
|
||||
@property
|
||||
def SkipActivation(self):
|
||||
|
||||
@@ -220,7 +220,10 @@ class LVMShellProxy(object):
|
||||
|
||||
# Parse the report to see what happened
|
||||
if 'log' in report_json:
|
||||
if report_json['log'][-1:][0]['log_ret_code'] == '1':
|
||||
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
|
||||
# If we have an exported vg we get a log_ret_code == 5 when
|
||||
# we do a 'fullreport'
|
||||
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
|
||||
rc = 0
|
||||
else:
|
||||
error_msg = self.get_error_msg()
|
||||
|
||||
@@ -141,13 +141,22 @@ class DataStore(object):
|
||||
|
||||
@staticmethod
|
||||
def _parse_vgs(_vgs):
|
||||
vgs = sorted(_vgs, key=lambda vk: vk['vg_name'])
|
||||
vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
|
||||
|
||||
c_vgs = OrderedDict()
|
||||
c_lookup = {}
|
||||
|
||||
for i in vgs:
|
||||
c_lookup[i['vg_name']] = i['vg_uuid']
|
||||
vg_name = i['vg_name']
|
||||
|
||||
# Lvm allows duplicate vg names. When this occurs, each subsequent
|
||||
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
|
||||
# invalid character for lvm VG names
|
||||
if vg_name in c_lookup:
|
||||
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
|
||||
i['vg_name'] = vg_name
|
||||
|
||||
c_lookup[vg_name] = i['vg_uuid']
|
||||
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
|
||||
|
||||
return c_vgs, c_lookup
|
||||
@@ -162,13 +171,22 @@ class DataStore(object):
|
||||
tmp_vg.extend(r['vg'])
|
||||
|
||||
# Sort for consistent output, however this is optional
|
||||
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_name'])
|
||||
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_uuid'])
|
||||
|
||||
c_vgs = OrderedDict()
|
||||
c_lookup = {}
|
||||
|
||||
for i in vgs:
|
||||
c_lookup[i['vg_name']] = i['vg_uuid']
|
||||
vg_name = i['vg_name']
|
||||
|
||||
# Lvm allows duplicate vg names. When this occurs, each subsequent
|
||||
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
|
||||
# invalid character for lvm VG names
|
||||
if vg_name in c_lookup:
|
||||
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
|
||||
i['vg_name'] = vg_name
|
||||
|
||||
c_lookup[vg_name] = i['vg_uuid']
|
||||
c_vgs[i['vg_uuid']] = i
|
||||
|
||||
return c_vgs, c_lookup
|
||||
@@ -521,6 +539,10 @@ if __name__ == "__main__":
|
||||
for v in ds.vgs.values():
|
||||
pp.pprint(v)
|
||||
|
||||
print("VG name to UUID")
|
||||
for k, v in ds.vg_name_to_uuid.items():
|
||||
print("%s: %s" % (k, v))
|
||||
|
||||
print("LVS")
|
||||
for v in ds.lvs.values():
|
||||
pp.pprint(v)
|
||||
|
||||
@@ -164,6 +164,8 @@ class Manager(AutomatedProperties):
|
||||
return the object path in O(1) time.
|
||||
|
||||
:param key: The lookup value
|
||||
:param cb: dbus python call back parameter, not client visible
|
||||
:param cbe: dbus python error call back parameter, not client visible
|
||||
:return: Return the object path. If object not found you will get '/'
|
||||
"""
|
||||
r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
|
||||
|
||||
@@ -189,8 +189,8 @@ class ObjectManager(AutomatedProperties):
|
||||
path = dbus_object.dbus_object_path()
|
||||
interfaces = dbus_object.interface()
|
||||
|
||||
# print 'UN-Registering object path %s for %s' % \
|
||||
# (path, dbus_object.lvm_id)
|
||||
# print('UN-Registering object path %s for %s' %
|
||||
# (path, dbus_object.lvm_id))
|
||||
|
||||
self._lookup_remove(path)
|
||||
|
||||
@@ -240,39 +240,19 @@ class ObjectManager(AutomatedProperties):
|
||||
return lookup_rc
|
||||
return '/'
|
||||
|
||||
def _uuid_verify(self, path, uuid, lvm_id):
|
||||
def _id_verify(self, path, uuid, lvm_id):
|
||||
"""
|
||||
Ensure uuid is present for a successful lvm_id lookup
|
||||
Ensure our lookups are correct
|
||||
NOTE: Internal call, assumes under object manager lock
|
||||
:param path: Path to object we looked up
|
||||
:param uuid: lvm uuid to verify
|
||||
:param lvm_id: lvm_id used to find object
|
||||
:param uuid: uuid lookup
|
||||
:param lvm_id: lvm_id lookup
|
||||
:return: None
|
||||
"""
|
||||
# This gets called when we found an object based on lvm_id, ensure
|
||||
# uuid is correct too, as they can change. There is no durable
|
||||
# non-changeable name in lvm
|
||||
# There is no durable non-changeable name in lvm
|
||||
if lvm_id != uuid:
|
||||
if uuid and uuid not in self._id_to_object_path:
|
||||
obj = self.get_object_by_path(path)
|
||||
self._lookup_add(obj, path, lvm_id, uuid)
|
||||
|
||||
def _lvm_id_verify(self, path, uuid, lvm_id):
|
||||
"""
|
||||
Ensure lvm_id is present for a successful uuid lookup
|
||||
NOTE: Internal call, assumes under object manager lock
|
||||
:param path: Path to object we looked up
|
||||
:param uuid: uuid used to find object
|
||||
:param lvm_id: lvm_id to verify
|
||||
:return: None
|
||||
"""
|
||||
# This gets called when we found an object based on uuid, ensure
|
||||
# lvm_id is correct too, as they can change. There is no durable
|
||||
# non-changeable name in lvm
|
||||
if lvm_id != uuid:
|
||||
if lvm_id and lvm_id not in self._id_to_object_path:
|
||||
obj = self.get_object_by_path(path)
|
||||
self._lookup_add(obj, path, lvm_id, uuid)
|
||||
obj = self.get_object_by_path(path)
|
||||
self._lookup_add(obj, path, lvm_id, uuid)
|
||||
|
||||
def _id_lookup(self, the_id):
|
||||
path = None
|
||||
@@ -339,22 +319,22 @@ class ObjectManager(AutomatedProperties):
|
||||
# Lets check for the uuid first
|
||||
path = self._id_lookup(uuid)
|
||||
if path:
|
||||
# Verify the lvm_id is sane
|
||||
self._lvm_id_verify(path, uuid, lvm_id)
|
||||
# Ensure table lookups are correct
|
||||
self._id_verify(path, uuid, lvm_id)
|
||||
else:
|
||||
# Unable to find by UUID, lets lookup by lvm_id
|
||||
path = self._id_lookup(lvm_id)
|
||||
if path:
|
||||
# Verify the uuid is sane
|
||||
self._uuid_verify(path, uuid, lvm_id)
|
||||
# Ensure table lookups are correct
|
||||
self._id_verify(path, uuid, lvm_id)
|
||||
else:
|
||||
# We have exhausted all lookups, let's create if we can
|
||||
if path_create:
|
||||
path = path_create()
|
||||
self._lookup_add(None, path, lvm_id, uuid)
|
||||
|
||||
# print('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
|
||||
# (uuid, lvm_id, str(path_create), str(gen_new), path))
|
||||
# print('get_object_path_by_lvm_id(%s, %s, %s): return %s' %
|
||||
# (uuid, lvm_id, str(path_create), path))
|
||||
|
||||
return path
|
||||
|
||||
|
||||
@@ -52,18 +52,23 @@ def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
||||
|
||||
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
||||
class VgState(State):
|
||||
|
||||
@property
|
||||
def lvm_id(self):
|
||||
def internal_name(self):
|
||||
return self.Name
|
||||
|
||||
@property
|
||||
def lvm_id(self):
|
||||
return self.internal_name
|
||||
|
||||
def identifiers(self):
|
||||
return (self.Uuid, self.Name)
|
||||
return (self.Uuid, self.internal_name)
|
||||
|
||||
def _lv_paths_build(self):
|
||||
rc = []
|
||||
for lv in cfg.db.lvs_in_vg(self.Uuid):
|
||||
(lv_name, meta, lv_uuid) = lv
|
||||
full_name = "%s/%s" % (self.Name, lv_name)
|
||||
full_name = "%s/%s" % (self.internal_name, lv_name)
|
||||
|
||||
gen = utils.lv_object_path_method(lv_name, meta)
|
||||
|
||||
@@ -92,7 +97,7 @@ class VgState(State):
|
||||
def create_dbus_object(self, path):
|
||||
if not path:
|
||||
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
||||
self.Uuid, self.Name, vg_obj_path_generate)
|
||||
self.Uuid, self.internal_name, vg_obj_path_generate)
|
||||
return Vg(path, self)
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
@@ -102,7 +107,6 @@ class VgState(State):
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
|
||||
@utils.dbus_property(VG_INTERFACE, 'Name', 's')
|
||||
@utils.dbus_property(VG_INTERFACE, 'Fmt', 's')
|
||||
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
|
||||
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
|
||||
@@ -135,6 +139,7 @@ class Vg(AutomatedProperties):
|
||||
_AllocNormal_meta = ('b', VG_INTERFACE)
|
||||
_AllocAnywhere_meta = ('b', VG_INTERFACE)
|
||||
_Clustered_meta = ('b', VG_INTERFACE)
|
||||
_Name_meta = ('s', VG_INTERFACE)
|
||||
|
||||
# noinspection PyUnusedLocal,PyPep8Naming
|
||||
def __init__(self, object_path, object_state):
|
||||
@@ -172,7 +177,7 @@ class Vg(AutomatedProperties):
|
||||
# Make sure we have a dbus object representing it
|
||||
Vg.validate_dbus_object(uuid, vg_name)
|
||||
rc, out, err = cmdhandler.vg_rename(
|
||||
vg_name, new_name, rename_options)
|
||||
uuid, new_name, rename_options)
|
||||
Vg.handle_execute(rc, out, err)
|
||||
return '/'
|
||||
|
||||
@@ -216,7 +221,7 @@ class Vg(AutomatedProperties):
|
||||
# TODO: This should be broken into a number of different methods
|
||||
# instead of having one method that takes a hash for parameters. Some of
|
||||
# the changes that vgchange does works on entire system, not just a
|
||||
# specfic vg, thus that should be in the Manager interface.
|
||||
# specific vg, thus that should be in the Manager interface.
|
||||
@dbus.service.method(
|
||||
dbus_interface=VG_INTERFACE,
|
||||
in_signature='ia{sv}',
|
||||
@@ -729,6 +734,12 @@ class Vg(AutomatedProperties):
|
||||
cb, cbe, return_tuple=False)
|
||||
cfg.worker_q.put(r)
|
||||
|
||||
@property
|
||||
def Name(self):
|
||||
if ':' in self.state.Name:
|
||||
return self.state.Name.split(':')[0]
|
||||
return self.state.Name
|
||||
|
||||
@property
|
||||
def Tags(self):
|
||||
return utils.parse_tags(self.state.tags)
|
||||
|
||||
2
daemons/lvmetad/.gitignore
vendored
2
daemons/lvmetad/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
lvmetad
|
||||
lvmetactl
|
||||
@@ -1,62 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2011-2012 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU Lesser General Public License v.2.1.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = lvmetad-core.c
|
||||
SOURCES2 = lvmetactl.c
|
||||
|
||||
TARGETS = lvmetad lvmetactl
|
||||
|
||||
.PHONY: install_lvmetad
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = lvmetad
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS_lvmetactl.o += $(EXTRA_EXEC_CFLAGS)
|
||||
CFLAGS_lvmetad-core.o += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
|
||||
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) -ldaemonserver $(LIBS)
|
||||
|
||||
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LIBS)
|
||||
|
||||
CLEAN_TARGETS += lvmetactl.o
|
||||
|
||||
# TODO: No idea. No idea how to test either.
|
||||
#ifneq ("$(CFLOW_CMD)", "")
|
||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
#-include $(top_builddir)/libdm/libdevmapper.cflow
|
||||
#-include $(top_builddir)/lib/liblvm-internal.cflow
|
||||
#-include $(top_builddir)/lib/liblvm2cmd.cflow
|
||||
#-include $(top_builddir)/daemons/dmeventd/$(LIB_NAME).cflow
|
||||
#-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
|
||||
#endif
|
||||
|
||||
install_lvmetad: lvmetad
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_lvm2: install_lvmetad
|
||||
|
||||
install: install_lvm2
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
|
||||
daemon_handle h;
|
||||
|
||||
static void print_reply(daemon_reply reply)
|
||||
{
|
||||
const char *a = daemon_reply_str(reply, "response", NULL);
|
||||
const char *b = daemon_reply_str(reply, "status", NULL);
|
||||
const char *c = daemon_reply_str(reply, "reason", NULL);
|
||||
|
||||
printf("response \"%s\" status \"%s\" reason \"%s\"\n",
|
||||
a ? a : "", b ? b : "", c ? c : "");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
daemon_reply reply;
|
||||
char *cmd;
|
||||
char *uuid;
|
||||
char *name;
|
||||
int val;
|
||||
int ver;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("lvmetactl dump\n");
|
||||
printf("lvmetactl pv_list\n");
|
||||
printf("lvmetactl vg_list\n");
|
||||
printf("lvmetactl get_global_info\n");
|
||||
printf("lvmetactl vg_lookup_name <name>\n");
|
||||
printf("lvmetactl vg_lookup_uuid <uuid>\n");
|
||||
printf("lvmetactl pv_lookup_uuid <uuid>\n");
|
||||
printf("lvmetactl set_global_invalid 0|1\n");
|
||||
printf("lvmetactl set_global_disable 0|1\n");
|
||||
printf("lvmetactl set_vg_version <uuid> <name> <version>\n");
|
||||
printf("lvmetactl vg_lock_type <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd = argv[1];
|
||||
|
||||
h = lvmetad_open(NULL);
|
||||
|
||||
if (!strcmp(cmd, "dump")) {
|
||||
reply = daemon_send_simple(h, "dump",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_list")) {
|
||||
reply = daemon_send_simple(h, "pv_list",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_list")) {
|
||||
reply = daemon_send_simple(h, "vg_list",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "get_global_info")) {
|
||||
reply = daemon_send_simple(h, "get_global_info",
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "set_global_invalid")) {
|
||||
if (argc < 3) {
|
||||
printf("set_global_invalid 0|1\n");
|
||||
return -1;
|
||||
}
|
||||
val = atoi(argv[2]);
|
||||
|
||||
reply = daemon_send_simple(h, "set_global_info",
|
||||
"global_invalid = " FMTd64, (int64_t) val,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "set_global_disable")) {
|
||||
if (argc < 3) {
|
||||
printf("set_global_disable 0|1\n");
|
||||
return -1;
|
||||
}
|
||||
val = atoi(argv[2]);
|
||||
|
||||
reply = daemon_send_simple(h, "set_global_info",
|
||||
"global_disable = " FMTd64, (int64_t) val,
|
||||
"disable_reason = %s", LVMETAD_DISABLE_REASON_DIRECT,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "set_vg_version")) {
|
||||
if (argc < 5) {
|
||||
printf("set_vg_version <uuid> <name> <ver>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
name = argv[3];
|
||||
ver = atoi(argv[4]);
|
||||
|
||||
if ((strlen(uuid) == 1) && (uuid[0] == '-'))
|
||||
uuid = NULL;
|
||||
if ((strlen(name) == 1) && (name[0] == '-'))
|
||||
name = NULL;
|
||||
|
||||
if (uuid && name) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"uuid = %s", uuid,
|
||||
"name = %s", name,
|
||||
"version = " FMTd64, (int64_t) ver,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
} else if (uuid) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"uuid = %s", uuid,
|
||||
"version = " FMTd64, (int64_t) ver,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
} else if (name) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"name = %s", name,
|
||||
"version = " FMTd64, (int64_t) ver,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
} else {
|
||||
printf("name or uuid required\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lookup_name")) {
|
||||
if (argc < 3) {
|
||||
printf("vg_lookup_name <name>\n");
|
||||
return -1;
|
||||
}
|
||||
name = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"name = %s", name,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lookup_uuid")) {
|
||||
if (argc < 3) {
|
||||
printf("vg_lookup_uuid <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lock_type")) {
|
||||
struct dm_config_node *metadata;
|
||||
const char *lock_type;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("vg_lock_type <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
/* printf("%s\n", reply.buffer.mem); */
|
||||
|
||||
metadata = dm_config_find_node(reply.cft->root, "metadata");
|
||||
if (!metadata) {
|
||||
printf("no metadata\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
|
||||
if (!lock_type) {
|
||||
printf("no lock_type\n");
|
||||
goto out;
|
||||
}
|
||||
printf("lock_type %s\n", lock_type);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_lookup_uuid")) {
|
||||
if (argc < 3) {
|
||||
printf("pv_lookup_uuid <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "pv_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
"pid = " FMTd64, (int64_t)getpid(),
|
||||
"cmd = %s", "lvmetactl",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else {
|
||||
printf("unknown command\n");
|
||||
goto out_close;
|
||||
}
|
||||
out:
|
||||
daemon_reply_destroy(reply);
|
||||
out_close:
|
||||
daemon_close(h);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_LVMETAD_CLIENT_H
|
||||
#define _LVM_LVMETAD_CLIENT_H
|
||||
|
||||
#include "daemon-client.h"
|
||||
|
||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||
|
||||
#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
|
||||
|
||||
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
|
||||
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
|
||||
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
|
||||
#define LVMETAD_DISABLE_REASON_REPAIR "REPAIR"
|
||||
|
||||
struct volume_group;
|
||||
|
||||
/* Different types of replies we may get from lvmetad. */
|
||||
|
||||
typedef struct {
|
||||
daemon_reply r;
|
||||
const char **uuids; /* NULL terminated array */
|
||||
} lvmetad_uuidlist;
|
||||
|
||||
typedef struct {
|
||||
daemon_reply r;
|
||||
struct dm_config_tree *cft;
|
||||
} lvmetad_vg;
|
||||
|
||||
/* Get a list of VG UUIDs that match a given VG name. */
|
||||
lvmetad_uuidlist lvmetad_lookup_vgname(daemon_handle h, const char *name);
|
||||
|
||||
/* Get the metadata of a single VG, identified by UUID. */
|
||||
lvmetad_vg lvmetad_get_vg(daemon_handle h, const char *uuid);
|
||||
|
||||
/*
|
||||
* Add and remove PVs on demand. Udev-driven systems will use this interface
|
||||
* instead of scanning.
|
||||
*/
|
||||
daemon_reply lvmetad_add_pv(daemon_handle h, const char *pv_uuid, const char *mda_content);
|
||||
daemon_reply lvmetad_remove_pv(daemon_handle h, const char *pv_uuid);
|
||||
|
||||
/* Trigger a full disk scan, throwing away all caches. XXX do we eventually want
|
||||
* this? Probably not yet, anyway.
|
||||
* daemon_reply lvmetad_rescan(daemon_handle h);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Update the version of metadata of a volume group. The VG has to be locked for
|
||||
* writing for this, and the VG metadata here has to match whatever has been
|
||||
* written to the disk (under this lock). This initially avoids the requirement
|
||||
* for lvmetad to write to disk (in later revisions, lvmetad_supersede_vg may
|
||||
* also do the writing, or we probably add another function to do that).
|
||||
*/
|
||||
daemon_reply lvmetad_supersede_vg(daemon_handle h, struct volume_group *vg);
|
||||
|
||||
/* Wrappers to open/close connection */
|
||||
|
||||
static inline daemon_handle lvmetad_open(const char *socket)
|
||||
{
|
||||
daemon_info lvmetad_info = {
|
||||
.path = "lvmetad",
|
||||
.socket = socket ?: LVMETAD_SOCKET,
|
||||
.protocol = "lvmetad",
|
||||
.protocol_version = 1,
|
||||
.autostart = 0
|
||||
};
|
||||
|
||||
return daemon_open(lvmetad_info);
|
||||
}
|
||||
|
||||
static inline void lvmetad_close(daemon_handle h)
|
||||
{
|
||||
return daemon_close(h);
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export LD_LIBRARY_PATH="$1"
|
||||
|
||||
test -n "$2" && {
|
||||
rm -f /var/run/lvmetad.{socket,pid}
|
||||
chmod +rx lvmetad
|
||||
valgrind ./lvmetad -f &
|
||||
PID=$!
|
||||
sleep 1
|
||||
./testclient
|
||||
kill $PID
|
||||
exit 0
|
||||
}
|
||||
|
||||
sudo ./test.sh "$1" .
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
#include "label.h"
|
||||
#include "lvmcache.h"
|
||||
#include "metadata.h"
|
||||
|
||||
const char *uuid1 = "abcd-efgh";
|
||||
const char *uuid2 = "bbcd-efgh";
|
||||
const char *vgid = "yada-yada";
|
||||
const char *uuid3 = "cbcd-efgh";
|
||||
|
||||
const char *metadata2 = "{\n"
|
||||
"id = \"yada-yada\"\n"
|
||||
"seqno = 15\n"
|
||||
"status = [\"READ\", \"WRITE\"]\n"
|
||||
"flags = []\n"
|
||||
"extent_size = 8192\n"
|
||||
"physical_volumes {\n"
|
||||
" pv0 {\n"
|
||||
" id = \"abcd-efgh\"\n"
|
||||
" }\n"
|
||||
" pv1 {\n"
|
||||
" id = \"bbcd-efgh\"\n"
|
||||
" }\n"
|
||||
" pv2 {\n"
|
||||
" id = \"cbcd-efgh\"\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"}\n";
|
||||
|
||||
void _handle_reply(daemon_reply reply) {
|
||||
const char *repl = daemon_reply_str(reply, "response", NULL);
|
||||
const char *status = daemon_reply_str(reply, "status", NULL);
|
||||
const char *vgid = daemon_reply_str(reply, "vgid", NULL);
|
||||
|
||||
fprintf(stderr, "[C] REPLY: %s\n", repl);
|
||||
if (!strcmp(repl, "failed"))
|
||||
fprintf(stderr, "[C] REASON: %s\n", daemon_reply_str(reply, "reason", "unknown"));
|
||||
if (vgid)
|
||||
fprintf(stderr, "[C] VGID: %s\n", vgid);
|
||||
if (status)
|
||||
fprintf(stderr, "[C] STATUS: %s\n", status);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
void _pv_add(daemon_handle h, const char *uuid, const char *metadata)
|
||||
{
|
||||
daemon_reply reply = daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
|
||||
"metadata = %b", metadata,
|
||||
NULL);
|
||||
_handle_reply(reply);
|
||||
}
|
||||
|
||||
int scan(daemon_handle h, char *fn) {
|
||||
struct device *dev = dev_cache_get(fn, NULL);
|
||||
|
||||
struct label *label;
|
||||
if (!label_read(dev, &label, 0)) {
|
||||
fprintf(stderr, "[C] no label found on %s\n", fn);
|
||||
return;
|
||||
}
|
||||
|
||||
char uuid[64];
|
||||
if (!id_write_format(dev->pvid, uuid, 64)) {
|
||||
fprintf(stderr, "[C] Failed to format PV UUID for %s", dev_name(dev));
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "[C] found PV: %s\n", uuid);
|
||||
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
|
||||
struct physical_volume pv = { 0, };
|
||||
|
||||
if (!(info->fmt->ops->pv_read(info->fmt, dev_name(dev), &pv, 0))) {
|
||||
fprintf(stderr, "[C] Failed to read PV %s", dev_name(dev));
|
||||
return;
|
||||
}
|
||||
|
||||
struct format_instance_ctx fic;
|
||||
struct format_instance *fid = info->fmt->ops->create_instance(info->fmt, &fic);
|
||||
struct metadata_area *mda;
|
||||
struct volume_group *vg = NULL;
|
||||
dm_list_iterate_items(mda, &info->mdas) {
|
||||
struct volume_group *this = mda->ops->vg_read(fid, "", mda);
|
||||
if (this && !vg || this->seqno > vg->seqno)
|
||||
vg = this;
|
||||
}
|
||||
if (vg) {
|
||||
char *buf = NULL;
|
||||
/* TODO. This is not entirely correct, since export_vg_to_buffer
|
||||
* adds trailing garbage to the buffer. We may need to use
|
||||
* export_vg_to_config_tree and format the buffer ourselves. It
|
||||
* does, however, work for now, since the garbage is well
|
||||
* formatted and has no conflicting keys with the rest of the
|
||||
* request. */
|
||||
export_vg_to_buffer(vg, &buf);
|
||||
daemon_reply reply =
|
||||
daemon_send_simple(h, "pv_add", "uuid = %s", uuid,
|
||||
"metadata = %b", strchr(buf, '{'),
|
||||
NULL);
|
||||
_handle_reply(reply);
|
||||
}
|
||||
}
|
||||
|
||||
void _dump_vg(daemon_handle h, const char *uuid)
|
||||
{
|
||||
daemon_reply reply = daemon_send_simple(h, "vg_by_uuid", "uuid = %s", uuid, NULL);
|
||||
fprintf(stderr, "[C] reply buffer: %s\n", reply.buffer);
|
||||
daemon_reply_destroy(reply);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
daemon_handle h = lvmetad_open();
|
||||
/* FIXME Missing error path */
|
||||
|
||||
if (argc > 1) {
|
||||
int i;
|
||||
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
|
||||
for (i = 1; i < argc; ++i) {
|
||||
const char *uuid = NULL;
|
||||
scan(h, argv[i]);
|
||||
}
|
||||
destroy_toolcontext(cmd);
|
||||
/* FIXME Missing lvmetad_close() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
_pv_add(h, uuid1, NULL);
|
||||
_pv_add(h, uuid2, metadata2);
|
||||
_dump_vg(h, vgid);
|
||||
_pv_add(h, uuid3, NULL);
|
||||
|
||||
daemon_close(h); /* FIXME lvmetad_close? */
|
||||
return 0;
|
||||
}
|
||||
@@ -15,6 +15,8 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
USE_SD_NOTIFY=yes
|
||||
|
||||
SOURCES = lvmlockd-core.c
|
||||
|
||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||
@@ -25,6 +27,7 @@ endif
|
||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||
SOURCES += lvmlockd-dlm.c
|
||||
LOCK_LIBS += -ldlm_lt
|
||||
LOCK_LIBS += -ldlmcontrol
|
||||
endif
|
||||
|
||||
SOURCES2 = lvmlockctl.c
|
||||
@@ -35,23 +38,26 @@ TARGETS = lvmlockd lvmlockctl
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS) $(SYSTEMD_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(PTHREAD_LIBS) $(SYSTEMD_LIBS)
|
||||
|
||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(LIBS)
|
||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
|
||||
|
||||
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LIBS)
|
||||
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
|
||||
install_lvmlockd: lvmlockd
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_lvmlockctl: lvmlockctl
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_lvm2: install_lvmlockd install_lvmlockctl
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "lvmlockd-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <getopt.h>
|
||||
@@ -24,7 +24,7 @@
|
||||
static int quit = 0;
|
||||
static int info = 0;
|
||||
static int dump = 0;
|
||||
static int wait_opt = 0;
|
||||
static int wait_opt = 1;
|
||||
static int force_opt = 0;
|
||||
static int kill_vg = 0;
|
||||
static int drop_vg = 0;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#ifndef _LVM_LVMLOCKD_CLIENT_H
|
||||
#define _LVM_LVMLOCKD_CLIENT_H
|
||||
|
||||
#include "daemon-client.h"
|
||||
#include "libdaemon/client/daemon-client.h"
|
||||
|
||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
||||
|
||||
|
||||
@@ -8,18 +8,13 @@
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
#define _REENTRANT
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include "daemon-io.h"
|
||||
#include "libdaemon/client/daemon-io.h"
|
||||
#include "daemon-server.h"
|
||||
#include "lvm-version.h"
|
||||
#include "lvmetad-client.h"
|
||||
#include "lvmlockd-client.h"
|
||||
#include "dm-ioctl.h" /* for DM_UUID_LEN */
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
#include "device_mapper/misc/dm-ioctl.h"
|
||||
|
||||
/* #include <assert.h> */
|
||||
#include <errno.h>
|
||||
@@ -36,6 +31,10 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#ifdef NOTIFYDBUS_SUPPORT
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#define EXTERN
|
||||
#include "lvmlockd-internal.h"
|
||||
|
||||
@@ -144,10 +143,6 @@ static const int lvmlockd_protocol_version = 1;
|
||||
static int daemon_quit;
|
||||
static int adopt_opt;
|
||||
|
||||
static daemon_handle lvmetad_handle;
|
||||
static pthread_mutex_t lvmetad_mutex;
|
||||
static int lvmetad_connected;
|
||||
|
||||
/*
|
||||
* We use a separate socket for dumping daemon info.
|
||||
* This will not interfere with normal operations, and allows
|
||||
@@ -410,12 +405,11 @@ struct lockspace *alloc_lockspace(void)
|
||||
{
|
||||
struct lockspace *ls;
|
||||
|
||||
if (!(ls = malloc(sizeof(struct lockspace)))) {
|
||||
if (!(ls = zalloc(sizeof(struct lockspace)))) {
|
||||
log_error("out of memory for lockspace");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ls, 0, sizeof(struct lockspace));
|
||||
INIT_LIST_HEAD(&ls->actions);
|
||||
INIT_LIST_HEAD(&ls->resources);
|
||||
pthread_mutex_init(&ls->mutex, NULL);
|
||||
@@ -508,6 +502,10 @@ static struct lock *alloc_lock(void)
|
||||
|
||||
static void free_action(struct action *act)
|
||||
{
|
||||
if (act->path) {
|
||||
free(act->path);
|
||||
act->path = NULL;
|
||||
}
|
||||
pthread_mutex_lock(&unused_struct_mutex);
|
||||
if (unused_action_count >= MAX_UNUSED_ACTION) {
|
||||
free(act);
|
||||
@@ -731,6 +729,8 @@ static const char *op_str(int x)
|
||||
return "rename_final";
|
||||
case LD_OP_RUNNING_LM:
|
||||
return "running_lm";
|
||||
case LD_OP_QUERY_LOCK:
|
||||
return "query_lock";
|
||||
case LD_OP_FIND_FREE_LOCK:
|
||||
return "find_free_lock";
|
||||
case LD_OP_KILL_VG:
|
||||
@@ -743,6 +743,8 @@ static const char *op_str(int x)
|
||||
return "dump_info";
|
||||
case LD_OP_BUSY:
|
||||
return "busy";
|
||||
case LD_OP_REFRESH_LV:
|
||||
return "refresh_lv";
|
||||
default:
|
||||
return "op_unknown";
|
||||
};
|
||||
@@ -930,12 +932,12 @@ static void lm_rem_resource(struct lockspace *ls, struct resource *r)
|
||||
lm_rem_resource_sanlock(ls, r);
|
||||
}
|
||||
|
||||
static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset)
|
||||
static int lm_find_free_lock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
|
||||
{
|
||||
if (ls->lm_type == LD_LM_DLM)
|
||||
return 0;
|
||||
else if (ls->lm_type == LD_LM_SANLOCK)
|
||||
return lm_find_free_lock_sanlock(ls, free_offset);
|
||||
return lm_find_free_lock_sanlock(ls, free_offset, sector_size, align_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1009,54 +1011,6 @@ 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;
|
||||
va_list ap;
|
||||
int retries = 0;
|
||||
int err;
|
||||
|
||||
va_start(ap, id);
|
||||
|
||||
/*
|
||||
* mutex is used because all threads share a single
|
||||
* lvmetad connection/handle.
|
||||
*/
|
||||
pthread_mutex_lock(&lvmetad_mutex);
|
||||
retry:
|
||||
if (!lvmetad_connected) {
|
||||
lvmetad_handle = lvmetad_open(NULL);
|
||||
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
|
||||
err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
log_debug("lvmetad_open reconnect error %d", err);
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
reply.error = ERR_LVMETAD_NOT_RUNNING;
|
||||
va_end(ap);
|
||||
return reply;
|
||||
} else {
|
||||
log_debug("lvmetad reconnected");
|
||||
lvmetad_connected = 1;
|
||||
}
|
||||
}
|
||||
|
||||
reply = daemon_send_simple_v(lvmetad_handle, id, ap);
|
||||
|
||||
/* lvmetad may have been restarted */
|
||||
if ((reply.error == ECONNRESET) && (retries < 2)) {
|
||||
daemon_close(lvmetad_handle);
|
||||
lvmetad_connected = 0;
|
||||
retries++;
|
||||
goto retry;
|
||||
}
|
||||
pthread_mutex_unlock(&lvmetad_mutex);
|
||||
|
||||
va_end(ap);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static int res_lock(struct lockspace *ls, struct resource *r, struct action *act, int *retry)
|
||||
{
|
||||
struct lock *lk;
|
||||
@@ -1252,6 +1206,18 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
rv = -EREMOVED;
|
||||
}
|
||||
|
||||
/*
|
||||
* lvmetad is no longer used, but the infrastructure for
|
||||
* distributed cache validation remains. The points
|
||||
* where vg or global cache state would be invalidated
|
||||
* remain below and log_debug messages point out where
|
||||
* they would occur.
|
||||
*
|
||||
* The comments related to "lvmetad" remain because they
|
||||
* describe how some other local cache like lvmetad would
|
||||
* be invalidated here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* r is vglk: tell lvmetad to set the vg invalid
|
||||
* flag, and provide the new r_version. If lvmetad finds
|
||||
@@ -1277,47 +1243,12 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
*/
|
||||
|
||||
if (inval_meta && (r->type == LD_RT_VG)) {
|
||||
daemon_reply reply;
|
||||
char *uuid;
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad vg version %u",
|
||||
log_debug("S %s R %s res_lock invalidate vg state version %u",
|
||||
ls->name, r->name, new_version);
|
||||
|
||||
if (!ls->vg_uuid[0] || !strcmp(ls->vg_uuid, "none"))
|
||||
uuid = (char *)"none";
|
||||
else
|
||||
uuid = ls->vg_uuid;
|
||||
|
||||
reply = send_lvmetad("set_vg_info",
|
||||
"token = %s", "skip",
|
||||
"uuid = %s", uuid,
|
||||
"name = %s", ls->vg_name,
|
||||
"version = " FMTd64, (int64_t)new_version,
|
||||
NULL);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (inval_meta && (r->type == LD_RT_GL)) {
|
||||
daemon_reply reply;
|
||||
|
||||
log_debug("S %s R %s res_lock set lvmetad global invalid",
|
||||
ls->name, r->name);
|
||||
|
||||
reply = send_lvmetad("set_global_info",
|
||||
"token = %s", "skip",
|
||||
"global_invalid = " FMTd64, INT64_C(1),
|
||||
NULL);
|
||||
|
||||
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);
|
||||
log_debug("S %s R %s res_lock invalidate global state", ls->name, r->name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1891,9 +1822,9 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
add_client_result(act);
|
||||
} else {
|
||||
/* persistent lock is sh, transient request is ex */
|
||||
/* FIXME: can we remove this case? do a convert here? */
|
||||
log_debug("res_process %s existing persistent lock new transient", r->name);
|
||||
r->last_client_id = act->client_id;
|
||||
act->flags |= LD_AF_SH_EXISTS;
|
||||
act->result = -EEXIST;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -2273,6 +2204,7 @@ static int process_op_during_kill(struct action *act)
|
||||
case LD_OP_UPDATE:
|
||||
case LD_OP_RENAME_BEFORE:
|
||||
case LD_OP_RENAME_FINAL:
|
||||
case LD_OP_QUERY_LOCK:
|
||||
case LD_OP_FIND_FREE_LOCK:
|
||||
return 0;
|
||||
};
|
||||
@@ -2298,7 +2230,7 @@ static void *lockspace_thread_main(void *arg_in)
|
||||
struct action *act_op_free = NULL;
|
||||
struct list_head tmp_act;
|
||||
struct list_head act_close;
|
||||
char tmp_name[MAX_NAME+1];
|
||||
char tmp_name[MAX_NAME+5];
|
||||
int free_vg = 0;
|
||||
int drop_vg = 0;
|
||||
int error = 0;
|
||||
@@ -2497,13 +2429,31 @@ static void *lockspace_thread_main(void *arg_in)
|
||||
break;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_QUERY_LOCK) {
|
||||
r = find_resource_act(ls, act, 0);
|
||||
if (!r)
|
||||
act->result = -ENOENT;
|
||||
else {
|
||||
act->result = 0;
|
||||
act->mode = r->mode;
|
||||
}
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_FIND_FREE_LOCK && act->rt == LD_RT_VG) {
|
||||
uint64_t free_offset = 0;
|
||||
int sector_size = 0;
|
||||
int align_size = 0;
|
||||
|
||||
log_debug("S %s find free lock", ls->name);
|
||||
rv = lm_find_free_lock(ls, &free_offset);
|
||||
log_debug("S %s find free lock %d offset %llu",
|
||||
ls->name, rv, (unsigned long long)free_offset);
|
||||
rv = lm_find_free_lock(ls, &free_offset, §or_size, &align_size);
|
||||
log_debug("S %s find free lock %d offset %llu sector_size %d align_size %d",
|
||||
ls->name, rv, (unsigned long long)free_offset, sector_size, align_size);
|
||||
ls->free_lock_offset = free_offset;
|
||||
ls->free_lock_sector_size = sector_size;
|
||||
ls->free_lock_align_size = align_size;
|
||||
list_del(&act->list);
|
||||
act->result = rv;
|
||||
add_client_result(act);
|
||||
@@ -2674,8 +2624,10 @@ out_act:
|
||||
* 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);
|
||||
memset(tmp_name, 0, sizeof(tmp_name));
|
||||
memcpy(tmp_name, "REM:", 4);
|
||||
strncpy(tmp_name+4, ls->name, sizeof(tmp_name)-4);
|
||||
memcpy(ls->name, tmp_name, sizeof(ls->name));
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
/* worker_thread will join this thread, and free the ls */
|
||||
@@ -2815,6 +2767,9 @@ static int add_lockspace_thread(const char *ls_name,
|
||||
if (ls2->thread_stop) {
|
||||
log_debug("add_lockspace_thread %s exists and stopping", ls->name);
|
||||
rv = -EAGAIN;
|
||||
} else if (!ls2->create_fail && !ls2->create_done) {
|
||||
log_debug("add_lockspace_thread %s exists and starting", ls->name);
|
||||
rv = -ESTARTING;
|
||||
} else {
|
||||
log_debug("add_lockspace_thread %s exists", ls->name);
|
||||
rv = -EEXIST;
|
||||
@@ -3056,7 +3011,7 @@ static int count_lockspace_starting(uint32_t client_id)
|
||||
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
list_for_each_entry(ls, &lockspaces, list) {
|
||||
if (ls->start_client_id != client_id)
|
||||
if (client_id && (ls->start_client_id != client_id))
|
||||
continue;
|
||||
|
||||
if (!ls->create_done && !ls->create_fail) {
|
||||
@@ -3309,6 +3264,8 @@ static int work_init_lv(struct action *act)
|
||||
char vg_args[MAX_ARGS+1];
|
||||
char lv_args[MAX_ARGS+1];
|
||||
uint64_t free_offset = 0;
|
||||
int sector_size = 0;
|
||||
int align_size = 0;
|
||||
int lm_type = 0;
|
||||
int rv = 0;
|
||||
|
||||
@@ -3324,6 +3281,8 @@ static int work_init_lv(struct action *act)
|
||||
lm_type = ls->lm_type;
|
||||
memcpy(vg_args, ls->vg_args, MAX_ARGS);
|
||||
free_offset = ls->free_lock_offset;
|
||||
sector_size = ls->free_lock_sector_size;
|
||||
align_size = ls->free_lock_align_size;
|
||||
}
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
@@ -3340,7 +3299,7 @@ static int work_init_lv(struct action *act)
|
||||
|
||||
if (lm_type == LD_LM_SANLOCK) {
|
||||
rv = lm_init_lv_sanlock(ls_name, act->vg_name, act->lv_uuid,
|
||||
vg_args, lv_args, free_offset);
|
||||
vg_args, lv_args, sector_size, align_size, free_offset);
|
||||
|
||||
memcpy(act->lv_args, lv_args, MAX_ARGS);
|
||||
return rv;
|
||||
@@ -3457,7 +3416,7 @@ static void *worker_thread_main(void *arg_in)
|
||||
add_client_result(act);
|
||||
|
||||
} else if (act->op == LD_OP_START_WAIT) {
|
||||
act->result = count_lockspace_starting(act->client_id);
|
||||
act->result = count_lockspace_starting(0);
|
||||
if (!act->result)
|
||||
add_client_result(act);
|
||||
else
|
||||
@@ -3470,6 +3429,15 @@ static void *worker_thread_main(void *arg_in)
|
||||
else
|
||||
list_add(&act->list, &delayed_list);
|
||||
|
||||
} else if (act->op == LD_OP_REFRESH_LV) {
|
||||
log_debug("work refresh_lv %s %s", act->lv_uuid, act->path);
|
||||
rv = lm_refresh_lv_start_dlm(act);
|
||||
if (rv < 0) {
|
||||
act->result = rv;
|
||||
add_client_result(act);
|
||||
} else
|
||||
list_add(&act->list, &delayed_list);
|
||||
|
||||
} else {
|
||||
log_error("work unknown op %d", act->op);
|
||||
act->result = -EINVAL;
|
||||
@@ -3491,7 +3459,7 @@ static void *worker_thread_main(void *arg_in)
|
||||
list_for_each_entry_safe(act, safe, &delayed_list, list) {
|
||||
if (act->op == LD_OP_START_WAIT) {
|
||||
log_debug("work delayed start_wait for client %u", act->client_id);
|
||||
act->result = count_lockspace_starting(act->client_id);
|
||||
act->result = count_lockspace_starting(0);
|
||||
if (!act->result) {
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -3505,6 +3473,19 @@ static void *worker_thread_main(void *arg_in)
|
||||
act->result = 0;
|
||||
add_client_result(act);
|
||||
}
|
||||
|
||||
} else if (act->op == LD_OP_REFRESH_LV) {
|
||||
log_debug("work delayed refresh_lv");
|
||||
rv = lm_refresh_lv_check_dlm(act);
|
||||
if (!rv) {
|
||||
list_del(&act->list);
|
||||
act->result = 0;
|
||||
add_client_result(act);
|
||||
} else if ((rv < 0) && (rv != -EAGAIN)) {
|
||||
list_del(&act->list);
|
||||
act->result = rv;
|
||||
add_client_result(act);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3710,6 +3691,9 @@ static int client_send_result(struct client *cl, struct action *act)
|
||||
if ((act->flags & LD_AF_WARN_GL_REMOVED) || gl_vg_removed)
|
||||
strcat(result_flags, "WARN_GL_REMOVED,");
|
||||
|
||||
if (act->flags & LD_AF_SH_EXISTS)
|
||||
strcat(result_flags, "SH_EXISTS,");
|
||||
|
||||
if (act->op == LD_OP_INIT) {
|
||||
/*
|
||||
* init is a special case where lock args need
|
||||
@@ -3738,6 +3722,20 @@ static int client_send_result(struct client *cl, struct action *act)
|
||||
"result_flags = %s", result_flags[0] ? result_flags : "none",
|
||||
NULL);
|
||||
|
||||
} else if (act->op == LD_OP_QUERY_LOCK) {
|
||||
|
||||
log_debug("send %s[%d] cl %u %s %s rv %d mode %d",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt),
|
||||
act->result, act->mode);
|
||||
|
||||
res = daemon_reply_simple("OK",
|
||||
"op = " FMTd64, (int64_t)act->op,
|
||||
"op_result = " FMTd64, (int64_t) act->result,
|
||||
"lock_type = %s", lm_str(act->lm_type),
|
||||
"mode = %s", mode_str(act->mode),
|
||||
NULL);
|
||||
|
||||
} else if (act->op == LD_OP_DUMP_LOG || act->op == LD_OP_DUMP_INFO) {
|
||||
/*
|
||||
* lvmlockctl creates the unix socket then asks us to write to it.
|
||||
@@ -4068,6 +4066,16 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
|
||||
*rt = 0;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "query_lock_vg")) {
|
||||
*op = LD_OP_QUERY_LOCK;
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "query_lock_lv")) {
|
||||
*op = LD_OP_QUERY_LOCK;
|
||||
*rt = LD_RT_LV;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "find_free_lock")) {
|
||||
*op = LD_OP_FIND_FREE_LOCK;
|
||||
*rt = LD_RT_VG;
|
||||
@@ -4083,6 +4091,11 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "refresh_lv")) {
|
||||
*op = LD_OP_REFRESH_LV;
|
||||
*rt = 0;
|
||||
return 0;
|
||||
}
|
||||
out:
|
||||
return -1;
|
||||
}
|
||||
@@ -4444,6 +4457,7 @@ static void client_recv_action(struct client *cl)
|
||||
const char *vg_name;
|
||||
const char *vg_uuid;
|
||||
const char *vg_sysid;
|
||||
const char *path;
|
||||
const char *str;
|
||||
int64_t val;
|
||||
uint32_t opts = 0;
|
||||
@@ -4530,6 +4544,7 @@ static void client_recv_action(struct client *cl)
|
||||
opts = str_to_opts(str);
|
||||
str = daemon_request_str(req, "vg_lock_type", NULL);
|
||||
lm = str_to_lm(str);
|
||||
path = daemon_request_str(req, "path", NULL);
|
||||
|
||||
if (cl_pid && cl_pid != cl->pid)
|
||||
log_error("client recv bad message pid %d client %d", cl_pid, cl->pid);
|
||||
@@ -4562,6 +4577,9 @@ static void client_recv_action(struct client *cl)
|
||||
act->flags = opts;
|
||||
act->lm_type = lm;
|
||||
|
||||
if (path)
|
||||
act->path = strdup(path);
|
||||
|
||||
if (vg_name && strcmp(vg_name, "none"))
|
||||
strncpy(act->vg_name, vg_name, MAX_NAME);
|
||||
|
||||
@@ -4638,6 +4656,7 @@ static void client_recv_action(struct client *cl)
|
||||
case LD_OP_STOP_ALL:
|
||||
case LD_OP_RENAME_FINAL:
|
||||
case LD_OP_RUNNING_LM:
|
||||
case LD_OP_REFRESH_LV:
|
||||
add_work_action(act);
|
||||
rv = 0;
|
||||
break;
|
||||
@@ -4647,6 +4666,7 @@ static void client_recv_action(struct client *cl)
|
||||
case LD_OP_DISABLE:
|
||||
case LD_OP_FREE:
|
||||
case LD_OP_RENAME_BEFORE:
|
||||
case LD_OP_QUERY_LOCK:
|
||||
case LD_OP_FIND_FREE_LOCK:
|
||||
case LD_OP_KILL_VG:
|
||||
case LD_OP_DROP_VG:
|
||||
@@ -4827,7 +4847,7 @@ static void close_client_thread(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a list of all VGs with a lockd type (sanlock|dlm) from lvmetad.
|
||||
* Get a list of all VGs with a lockd type (sanlock|dlm).
|
||||
* We'll match this list against a list of existing lockspaces that are
|
||||
* found in the lock manager.
|
||||
*
|
||||
@@ -4838,6 +4858,9 @@ static void close_client_thread(void)
|
||||
|
||||
static int get_lockd_vgs(struct list_head *vg_lockd)
|
||||
{
|
||||
/* FIXME: get VGs some other way */
|
||||
return -1;
|
||||
#if 0
|
||||
struct list_head update_vgs;
|
||||
daemon_reply reply;
|
||||
struct dm_config_node *cn;
|
||||
@@ -4994,6 +5017,7 @@ out:
|
||||
}
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char _dm_uuid[DM_UUID_LEN];
|
||||
@@ -5268,7 +5292,7 @@ static void adopt_locks(void)
|
||||
gl_use_sanlock = 1;
|
||||
|
||||
list_for_each_entry(ls, &vg_lockd, list) {
|
||||
log_debug("adopt lvmetad vg %s lock_type %s lock_args %s",
|
||||
log_debug("adopt vg %s lock_type %s lock_args %s",
|
||||
ls->vg_name, lm_str(ls->lm_type), ls->vg_args);
|
||||
|
||||
list_for_each_entry(r, &ls->resources, list)
|
||||
@@ -5333,7 +5357,7 @@ static void adopt_locks(void)
|
||||
/*
|
||||
* LS in ls_found, not in vg_lockd.
|
||||
* An lvm lockspace found in the lock manager has no
|
||||
* corresponding VG in lvmetad. This shouldn't usually
|
||||
* corresponding VG. This shouldn't usually
|
||||
* happen, but it's possible the VG could have been removed
|
||||
* while the orphaned lockspace from it was still around.
|
||||
* Report an error and leave the ls in the lm alone.
|
||||
@@ -5348,7 +5372,7 @@ static void adopt_locks(void)
|
||||
|
||||
/*
|
||||
* LS in vg_lockd, not in ls_found.
|
||||
* lockd vgs from lvmetad that do not have an existing lockspace.
|
||||
* lockd vgs that do not have an existing lockspace.
|
||||
* This wouldn't be unusual; we just skip the vg.
|
||||
* But, if the vg has active lvs, then it should have had locks
|
||||
* and a lockspace. Should we attempt to join the lockspace and
|
||||
@@ -5400,8 +5424,6 @@ static void adopt_locks(void)
|
||||
memcpy(act->vg_args, ls->vg_args, MAX_ARGS);
|
||||
act->host_id = ls->host_id;
|
||||
|
||||
/* set act->version from lvmetad data? */
|
||||
|
||||
log_debug("adopt add %s vg lockspace %s", lm_str(act->lm_type), act->vg_name);
|
||||
|
||||
rv = add_lockspace_thread(ls->name, act->vg_name, act->vg_uuid,
|
||||
@@ -5860,24 +5882,16 @@ static int main_loop(daemon_state *ds_arg)
|
||||
setup_worker_thread();
|
||||
setup_restart();
|
||||
|
||||
pthread_mutex_init(&lvmetad_mutex, NULL);
|
||||
lvmetad_handle = lvmetad_open(NULL);
|
||||
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0)
|
||||
log_debug("lvmetad_open error %d", lvmetad_handle.error);
|
||||
else
|
||||
lvmetad_connected = 1;
|
||||
#ifdef USE_SD_NOTIFY
|
||||
sd_notify(0, "READY=1");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attempt to rejoin lockspaces and adopt locks from a previous
|
||||
* instance of lvmlockd that left behind lockspaces/locks.
|
||||
*/
|
||||
if (adopt_opt) {
|
||||
/* FIXME: implement this without lvmetad */
|
||||
if (!lvmetad_connected)
|
||||
log_error("Cannot adopt locks without lvmetad running.");
|
||||
else
|
||||
adopt_locks();
|
||||
}
|
||||
if (adopt_opt)
|
||||
adopt_locks();
|
||||
|
||||
while (1) {
|
||||
rv = poll(pollfd, pollfd_maxi + 1, -1);
|
||||
@@ -5993,7 +6007,6 @@ static int main_loop(daemon_state *ds_arg)
|
||||
close_worker_thread();
|
||||
close_client_thread();
|
||||
closelog();
|
||||
daemon_close(lvmetad_handle);
|
||||
return 1; /* libdaemon uses 1 for success */
|
||||
}
|
||||
|
||||
|
||||
@@ -11,19 +11,20 @@
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "daemon-server.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include "lvmlockd-internal.h"
|
||||
#include "lvmlockd-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
/*
|
||||
* Using synchronous _wait dlm apis so do not define _REENTRANT and
|
||||
* link with non-threaded version of library, libdlm_lt.
|
||||
*/
|
||||
#include "libdlm.h"
|
||||
#include "libdlmcontrol.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <poll.h>
|
||||
@@ -127,16 +128,18 @@ static int read_cluster_name(char *clustername)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_VERSION 16
|
||||
|
||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
{
|
||||
char clustername[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_VERSION+1];
|
||||
int rv;
|
||||
|
||||
memset(clustername, 0, sizeof(clustername));
|
||||
memset(lock_args_version, 0, sizeof(lock_args_version));
|
||||
|
||||
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
||||
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||
|
||||
rv = read_cluster_name(clustername);
|
||||
@@ -148,7 +151,9 @@ int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
return -EARGS;
|
||||
}
|
||||
|
||||
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
|
||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
|
||||
if (rv >= MAX_ARGS)
|
||||
log_debug("init_vg_dlm vg_args may be too long %d %s", rv, vg_args);
|
||||
rv = 0;
|
||||
|
||||
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
|
||||
@@ -272,10 +277,9 @@ static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int wit
|
||||
int rv;
|
||||
|
||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||
buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||
buf = zalloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||
|
||||
rdd->vb = (struct val_blk *)buf;
|
||||
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
|
||||
@@ -777,3 +781,107 @@ int lm_is_running_dlm(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef LOCKDDLM_CONTROL_SUPPORT
|
||||
|
||||
int lm_refresh_lv_start_dlm(struct action *act)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char command[DLMC_RUN_COMMAND_LEN];
|
||||
char run_uuid[DLMC_RUN_UUID_LEN];
|
||||
char *p, *vgname, *lvname;
|
||||
int rv;
|
||||
|
||||
/* split /dev/vgname/lvname into vgname and lvname strings */
|
||||
strncpy(path, act->path, strlen(act->path));
|
||||
|
||||
/* skip past dev */
|
||||
p = strchr(path + 1, '/');
|
||||
|
||||
/* skip past slashes */
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
/* start of vgname */
|
||||
vgname = p;
|
||||
|
||||
/* skip past vgname */
|
||||
while (*p != '/')
|
||||
p++;
|
||||
|
||||
/* terminate vgname */
|
||||
*p = '\0';
|
||||
p++;
|
||||
|
||||
/* skip past slashes */
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
lvname = p;
|
||||
|
||||
memset(command, 0, sizeof(command));
|
||||
memset(run_uuid, 0, sizeof(run_uuid));
|
||||
|
||||
/* todo: add --readonly */
|
||||
|
||||
snprintf(command, DLMC_RUN_COMMAND_LEN,
|
||||
"lvm lvchange --refresh --partial --nolocking %s/%s",
|
||||
vgname, lvname);
|
||||
|
||||
rv = dlmc_run_start(command, strlen(command), 0,
|
||||
DLMC_FLAG_RUN_START_NODE_NONE,
|
||||
run_uuid);
|
||||
if (rv < 0) {
|
||||
log_debug("refresh_lv run_start error %d", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
log_debug("refresh_lv run_start %s", run_uuid);
|
||||
|
||||
/* Bit of a hack here, we don't need path once started,
|
||||
but we do need to save the run_uuid somewhere, so just
|
||||
replace the path with the uuid. */
|
||||
|
||||
free(act->path);
|
||||
act->path = strdup(run_uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_refresh_lv_check_dlm(struct action *act)
|
||||
{
|
||||
uint32_t check_status = 0;
|
||||
int rv;
|
||||
|
||||
/* NB act->path was replaced with run_uuid */
|
||||
|
||||
rv = dlmc_run_check(act->path, strlen(act->path), 0,
|
||||
DLMC_FLAG_RUN_CHECK_CLEAR,
|
||||
&check_status);
|
||||
if (rv < 0) {
|
||||
log_debug("refresh_lv check error %d", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
log_debug("refresh_lv check %s status %x", act->path, check_status);
|
||||
|
||||
if (!(check_status & DLMC_RUN_STATUS_DONE))
|
||||
return -EAGAIN;
|
||||
|
||||
if (check_status & DLMC_RUN_STATUS_FAILED)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* LOCKDDLM_CONTROL_SUPPORT */
|
||||
|
||||
int lm_refresh_lv_start_dlm(struct action *act)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_refresh_lv_check_dlm(struct action *act)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LOCKDDLM_CONTROL_SUPPORT */
|
||||
|
||||
@@ -53,6 +53,8 @@ enum {
|
||||
LD_OP_KILL_VG,
|
||||
LD_OP_DROP_VG,
|
||||
LD_OP_BUSY,
|
||||
LD_OP_QUERY_LOCK,
|
||||
LD_OP_REFRESH_LV,
|
||||
};
|
||||
|
||||
/* resource types */
|
||||
@@ -105,6 +107,7 @@ struct client {
|
||||
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||
#define LD_AF_LV_LOCK 0x00040000
|
||||
#define LD_AF_LV_UNLOCK 0x00080000
|
||||
#define LD_AF_SH_EXISTS 0x00100000
|
||||
|
||||
/*
|
||||
* Number of times to repeat a lock request after
|
||||
@@ -127,6 +130,7 @@ struct action {
|
||||
int max_retries;
|
||||
int result;
|
||||
int lm_rv; /* return value from lm_ function */
|
||||
char *path;
|
||||
char vg_uuid[64];
|
||||
char vg_name[MAX_NAME+1];
|
||||
char lv_name[MAX_NAME+1];
|
||||
@@ -174,7 +178,9 @@ struct lockspace {
|
||||
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
||||
void *lm_data;
|
||||
uint64_t host_id;
|
||||
uint64_t free_lock_offset; /* start search for free lock here */
|
||||
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
|
||||
int free_lock_sector_size; /* for sanlock */
|
||||
int free_lock_align_size; /* for sanlock */
|
||||
|
||||
uint32_t start_client_id; /* client_id that started the lockspace */
|
||||
pthread_t thread; /* makes synchronous lock requests */
|
||||
@@ -387,6 +393,8 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
||||
int lm_data_size_dlm(void);
|
||||
int lm_is_running_dlm(void);
|
||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
||||
int lm_refresh_lv_start_dlm(struct action *act);
|
||||
int lm_refresh_lv_check_dlm(struct action *act);
|
||||
|
||||
static inline int lm_support_dlm(void)
|
||||
{
|
||||
@@ -463,12 +471,22 @@ static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_refresh_lv_start_dlm(struct action *act)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_refresh_lv_check_dlm(struct action *act)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* dlm support */
|
||||
|
||||
#ifdef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
|
||||
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, int sector_size, int align_size, uint64_t free_offset);
|
||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
||||
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||
@@ -488,7 +506,7 @@ int lm_gl_is_enabled(struct lockspace *ls);
|
||||
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
||||
int lm_data_size_sanlock(void);
|
||||
int lm_is_running_sanlock(void);
|
||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
|
||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size);
|
||||
|
||||
static inline int lm_support_sanlock(void)
|
||||
{
|
||||
@@ -502,7 +520,7 @@ static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flag
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
|
||||
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, int sector_size, int align_size, uint64_t free_offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -590,7 +608,7 @@ static inline int lm_is_running_sanlock(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -11,23 +11,42 @@
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "daemon-server.h"
|
||||
#include "xlate.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
#include "lvmlockd-internal.h"
|
||||
#include "lvmlockd-client.h"
|
||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
||||
|
||||
#include "sanlock.h"
|
||||
#include "sanlock_rv.h"
|
||||
#include "sanlock_admin.h"
|
||||
#include "sanlock_resource.h"
|
||||
|
||||
/* FIXME: these are copied from sanlock.h only until
|
||||
an updated version of sanlock is available with them. */
|
||||
#define SANLK_RES_ALIGN1M 0x00000010
|
||||
#define SANLK_RES_ALIGN2M 0x00000020
|
||||
#define SANLK_RES_ALIGN4M 0x00000040
|
||||
#define SANLK_RES_ALIGN8M 0x00000080
|
||||
#define SANLK_RES_SECTOR512 0x00000100
|
||||
#define SANLK_RES_SECTOR4K 0x00000200
|
||||
#define SANLK_LSF_ALIGN1M 0x00000010
|
||||
#define SANLK_LSF_ALIGN2M 0x00000020
|
||||
#define SANLK_LSF_ALIGN4M 0x00000040
|
||||
#define SANLK_LSF_ALIGN8M 0x00000080
|
||||
#define SANLK_LSF_SECTOR512 0x00000100
|
||||
#define SANLK_LSF_SECTOR4K 0x00000200
|
||||
|
||||
#include <stddef.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <blkid/blkid.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#define ONE_MB 1048576
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -139,6 +158,7 @@ release all the leases for the VG.
|
||||
|
||||
struct lm_sanlock {
|
||||
struct sanlk_lockspace ss;
|
||||
int sector_size;
|
||||
int align_size;
|
||||
int sock; /* sanlock daemon connection */
|
||||
};
|
||||
@@ -201,7 +221,6 @@ int lm_data_size_sanlock(void)
|
||||
* ...
|
||||
*/
|
||||
|
||||
#define LS_BEGIN 0
|
||||
#define GL_LOCK_BEGIN UINT64_C(65)
|
||||
#define VG_LOCK_BEGIN UINT64_C(66)
|
||||
#define LV_LOCK_BEGIN UINT64_C(67)
|
||||
@@ -288,7 +307,8 @@ static int read_host_id_file(void)
|
||||
}
|
||||
}
|
||||
if (fclose(file))
|
||||
log_error("failed to close host id file %s", daemon_host_id_file);
|
||||
log_debug("Failed to fclose host id file %s (%s).",
|
||||
daemon_host_id_file, strerror(errno));
|
||||
out:
|
||||
log_debug("host_id %d from %s", host_id, daemon_host_id_file);
|
||||
return host_id;
|
||||
@@ -324,6 +344,154 @@ fail:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void _read_sysfs_size(dev_t devno, const char *name, unsigned int *val)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buf[32];
|
||||
FILE *fp;
|
||||
size_t len;
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/queue/%s",
|
||||
(int)major(devno), (int)minor(devno), name);
|
||||
|
||||
if (!(fp = fopen(path, "r")))
|
||||
return;
|
||||
|
||||
if (!fgets(buf, sizeof(buf), fp))
|
||||
goto out;
|
||||
|
||||
if ((len = strlen(buf)) && buf[len - 1] == '\n')
|
||||
buf[--len] = '\0';
|
||||
|
||||
if (strlen(buf))
|
||||
*val = atoi(buf);
|
||||
out:
|
||||
if (fclose(fp))
|
||||
log_debug("Failed to fclose host id file %s (%s).", path, strerror(errno));
|
||||
|
||||
}
|
||||
|
||||
/* Select sector/align size for a new VG based on what the device reports for
|
||||
sector size of the lvmlock LV. */
|
||||
|
||||
static int get_sizes_device(char *path, int *sector_size, int *align_size)
|
||||
{
|
||||
unsigned int physical_block_size = 0;
|
||||
unsigned int logical_block_size = 0;
|
||||
struct stat st;
|
||||
int rv;
|
||||
|
||||
rv = stat(path, &st);
|
||||
if (rv < 0) {
|
||||
log_error("Failed to stat device to get block size %s %d", path, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_read_sysfs_size(st.st_rdev, "physical_block_size", &physical_block_size);
|
||||
_read_sysfs_size(st.st_rdev, "logical_block_size", &logical_block_size);
|
||||
|
||||
if ((physical_block_size == 512) && (logical_block_size == 512)) {
|
||||
*sector_size = 512;
|
||||
*align_size = ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((physical_block_size == 4096) && (logical_block_size == 4096)) {
|
||||
*sector_size = 4096;
|
||||
*align_size = 8 * ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (physical_block_size && (physical_block_size != 512) && (physical_block_size != 4096)) {
|
||||
log_warn("WARNING: invalid block sizes physical %u logical %u for %s",
|
||||
physical_block_size, logical_block_size, path);
|
||||
physical_block_size = 0;
|
||||
}
|
||||
|
||||
if (logical_block_size && (logical_block_size != 512) && (logical_block_size != 4096)) {
|
||||
log_warn("WARNING: invalid block sizes physical %u logical %u for %s",
|
||||
physical_block_size, logical_block_size, path);
|
||||
logical_block_size = 0;
|
||||
}
|
||||
|
||||
if (!physical_block_size && !logical_block_size) {
|
||||
log_error("Failed to get a block size for %s", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!physical_block_size || !logical_block_size) {
|
||||
log_warn("WARNING: incomplete block size information physical %u logical %u for %s",
|
||||
physical_block_size, logical_block_size, path);
|
||||
if (!physical_block_size)
|
||||
physical_block_size = logical_block_size;
|
||||
if (!logical_block_size)
|
||||
logical_block_size = physical_block_size;
|
||||
}
|
||||
|
||||
if ((logical_block_size == 4096) && (physical_block_size == 512)) {
|
||||
log_warn("WARNING: mixed block sizes physical %u logical %u (using 4096) for %s",
|
||||
physical_block_size, logical_block_size, path);
|
||||
*sector_size = 4096;
|
||||
*align_size = 8 * ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((physical_block_size == 4096) && (logical_block_size == 512)) {
|
||||
log_warn("WARNING: mixed block sizes physical %u logical %u (using 4096) for %s",
|
||||
physical_block_size, logical_block_size, path);
|
||||
*sector_size = 4096;
|
||||
*align_size = 8 * ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (physical_block_size == 512) {
|
||||
*sector_size = 512;
|
||||
*align_size = ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (physical_block_size == 4096) {
|
||||
*sector_size = 4096;
|
||||
*align_size = 8 * ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_error("Failed to get a block size for %s", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Get the sector/align sizes that were used to create an existing VG.
|
||||
sanlock encoded this in the lockspace/resource structs on disk. */
|
||||
|
||||
static int get_sizes_lockspace(char *path, int *sector_size, int *align_size)
|
||||
{
|
||||
struct sanlk_lockspace ss;
|
||||
uint32_t io_timeout = 0;
|
||||
int rv;
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
memcpy(ss.host_id_disk.path, path, SANLK_PATH_LEN);
|
||||
ss.host_id_disk.offset = 0;
|
||||
|
||||
rv = sanlock_read_lockspace(&ss, 0, &io_timeout);
|
||||
if (rv < 0) {
|
||||
log_error("get_sizes_lockspace %s error %d", path, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN8M)) {
|
||||
*sector_size = 4096;
|
||||
*align_size = 8 * ONE_MB;
|
||||
} else if ((ss.flags & SANLK_LSF_SECTOR512) && (ss.flags & SANLK_LSF_ALIGN1M)) {
|
||||
*sector_size = 512;
|
||||
*align_size = ONE_MB;
|
||||
}
|
||||
|
||||
log_debug("get_sizes_lockspace found %d %d", *sector_size, *align_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vgcreate
|
||||
*
|
||||
@@ -332,18 +500,21 @@ fail:
|
||||
* version and lv name, and returns the real lock_args in vg_args.
|
||||
*/
|
||||
|
||||
#define MAX_VERSION 16
|
||||
|
||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
{
|
||||
struct sanlk_lockspace ss;
|
||||
struct sanlk_resourced rd;
|
||||
struct sanlk_disk disk;
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_VERSION+1];
|
||||
const char *gl_name = NULL;
|
||||
uint32_t daemon_version;
|
||||
uint32_t daemon_proto;
|
||||
uint64_t offset;
|
||||
int align_size;
|
||||
int sector_size = 0;
|
||||
int align_size = 0;
|
||||
int i, rv;
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
@@ -357,7 +528,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
return -EARGS;
|
||||
}
|
||||
|
||||
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
||||
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||
|
||||
/* see comment above about input vg_args being only lock_lv_name */
|
||||
@@ -374,7 +545,9 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
if (daemon_test) {
|
||||
if (!gl_lsname_sanlock[0])
|
||||
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
|
||||
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
||||
if (rv >= MAX_ARGS)
|
||||
log_debug("init_vg_san vg_args may be too long %d %s", rv, vg_args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -387,23 +560,25 @@ 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);
|
||||
|
||||
rv = sanlock_align(&disk);
|
||||
if (rv <= 0) {
|
||||
/* Nothing formatted on disk yet, use what the device reports. */
|
||||
rv = get_sizes_device(disk.path, §or_size, &align_size);
|
||||
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",
|
||||
log_error("S %s init_vg_san sanlock error %d trying to get sector/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);
|
||||
ss.host_id_disk.offset = LS_BEGIN * align_size;
|
||||
ss.host_id_disk.offset = 0;
|
||||
ss.flags = (sector_size == 4096) ? (SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M) :
|
||||
(SANLK_LSF_SECTOR512 | SANLK_LSF_ALIGN1M);
|
||||
|
||||
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
|
||||
if (rv < 0) {
|
||||
@@ -436,6 +611,8 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
|
||||
rd.rs.num_disks = 1;
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (rv < 0) {
|
||||
@@ -449,6 +626,8 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
|
||||
rd.rs.num_disks = 1;
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (rv < 0) {
|
||||
@@ -460,7 +639,9 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
if (!strcmp(gl_name, R_NAME_GL))
|
||||
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
|
||||
|
||||
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
||||
if (rv >= MAX_ARGS)
|
||||
log_debug("init_vg_san vg_args may be too long %d %s", rv, vg_args);
|
||||
|
||||
log_debug("S %s init_vg_san done vg_args %s", ls_name, vg_args);
|
||||
|
||||
@@ -472,6 +653,8 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
rd.rs.num_disks = 1;
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
strcpy(rd.rs.name, "#unused");
|
||||
@@ -510,13 +693,13 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
*/
|
||||
|
||||
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
char *vg_args, char *lv_args, uint64_t free_offset)
|
||||
char *vg_args, char *lv_args,
|
||||
int sector_size, int align_size, uint64_t free_offset)
|
||||
{
|
||||
struct sanlk_resourced rd;
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_VERSION+1];
|
||||
uint64_t offset;
|
||||
int align_size;
|
||||
int rv;
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
@@ -530,11 +713,11 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
return rv;
|
||||
}
|
||||
|
||||
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
||||
LV_LOCK_ARGS_MAJOR, LV_LOCK_ARGS_MINOR, LV_LOCK_ARGS_PATCH);
|
||||
|
||||
if (daemon_test) {
|
||||
align_size = 1048576;
|
||||
align_size = ONE_MB;
|
||||
snprintf(lv_args, MAX_ARGS, "%s:%llu",
|
||||
lock_args_version,
|
||||
(unsigned long long)((align_size * LV_LOCK_BEGIN) + (align_size * daemon_test_lv_count)));
|
||||
@@ -547,12 +730,35 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *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) {
|
||||
log_error("S %s init_lv_san align error %d", ls_name, align_size);
|
||||
return -EINVAL;
|
||||
/*
|
||||
* These should not usually be zero, maybe only the first time this function is called?
|
||||
* We need to use the same sector/align sizes that are already being used.
|
||||
*/
|
||||
if (!sector_size || !align_size) {
|
||||
rv = get_sizes_lockspace(rd.rs.disks[0].path, §or_size, &align_size);
|
||||
if (rv < 0) {
|
||||
log_error("S %s init_lv_san read_lockspace error %d %s",
|
||||
ls_name, rv, rd.rs.disks[0].path);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (sector_size)
|
||||
log_debug("S %s init_lv_san found ls sector_size %d align_size %d", ls_name, sector_size, align_size);
|
||||
else {
|
||||
/* use the old method */
|
||||
align_size = sanlock_align(&rd.rs.disks[0]);
|
||||
if (align_size <= 0) {
|
||||
log_error("S %s init_lv_san align error %d", ls_name, align_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
sector_size = (align_size == ONE_MB) ? 512 : 4096;
|
||||
log_debug("S %s init_lv_san found old sector_size %d align_size %d", ls_name, sector_size, align_size);
|
||||
}
|
||||
}
|
||||
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
if (free_offset)
|
||||
offset = free_offset;
|
||||
else
|
||||
@@ -595,6 +801,8 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
ls_name, lv_name, (unsigned long long)offset);
|
||||
|
||||
strncpy(rd.rs.name, lv_name, SANLK_NAME_LEN);
|
||||
rd.rs.flags = (sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (!rv) {
|
||||
@@ -626,7 +834,8 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
uint64_t offset;
|
||||
uint32_t io_timeout;
|
||||
int align_size;
|
||||
int sector_size = 0;
|
||||
int align_size = 0;
|
||||
int i, rv;
|
||||
|
||||
memset(&disk, 0, sizeof(disk));
|
||||
@@ -655,20 +864,13 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
/* FIXME: device is not always ready for us here */
|
||||
sleep(1);
|
||||
|
||||
align_size = sanlock_align(&disk);
|
||||
if (align_size <= 0) {
|
||||
log_error("S %s rename_vg_san bad align size %d %s",
|
||||
ls_name, align_size, disk.path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lockspace
|
||||
*/
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
||||
ss.host_id_disk.offset = LS_BEGIN * align_size;
|
||||
ss.host_id_disk.offset = 0;
|
||||
|
||||
rv = sanlock_read_lockspace(&ss, 0, &io_timeout);
|
||||
if (rv < 0) {
|
||||
@@ -677,6 +879,26 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
return rv;
|
||||
}
|
||||
|
||||
if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN8M)) {
|
||||
sector_size = 4096;
|
||||
align_size = 8 * ONE_MB;
|
||||
} else if ((ss.flags & SANLK_LSF_SECTOR512) && (ss.flags & SANLK_LSF_ALIGN1M)) {
|
||||
sector_size = 512;
|
||||
align_size = ONE_MB;
|
||||
} else {
|
||||
/* use the old method */
|
||||
align_size = sanlock_align(&ss.host_id_disk);
|
||||
if (align_size <= 0) {
|
||||
log_error("S %s rename_vg_san unknown sector/align size for %s",
|
||||
ls_name, ss.host_id_disk.path);
|
||||
return -1;
|
||||
}
|
||||
sector_size = (align_size == ONE_MB) ? 512 : 4096;
|
||||
}
|
||||
|
||||
if (!sector_size || !align_size)
|
||||
return -1;
|
||||
|
||||
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
|
||||
|
||||
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
|
||||
@@ -831,6 +1053,11 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
||||
strncpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
rd1.rs.disks[0].offset = lms->align_size * GL_LOCK_BEGIN;
|
||||
|
||||
rd1.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
rd2.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
rv = sanlock_acquire(lms->sock, -1, 0, 1, &rs1, NULL);
|
||||
if (rv < 0) {
|
||||
log_error("S %s ex_disable_gl_san acquire error %d",
|
||||
@@ -891,6 +1118,8 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
||||
rd.rs.num_disks = 1;
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
rd.rs.disks[0].offset = lms->align_size * GL_LOCK_BEGIN;
|
||||
rd.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
if (rv < 0) {
|
||||
@@ -936,7 +1165,8 @@ static int gl_is_enabled(struct lockspace *ls, struct lm_sanlock *lms)
|
||||
|
||||
rv = sanlock_read_resource(&rd.rs, 0);
|
||||
if (rv < 0) {
|
||||
log_error("gl_is_enabled read_resource error %d", rv);
|
||||
log_error("gl_is_enabled read_resource align_size %d offset %llu error %d",
|
||||
lms->align_size, (unsigned long long)offset, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -973,7 +1203,7 @@ int lm_gl_is_enabled(struct lockspace *ls)
|
||||
* been disabled.)
|
||||
*/
|
||||
|
||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
|
||||
{
|
||||
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||
struct sanlk_resourced rd;
|
||||
@@ -983,15 +1213,22 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||
int round = 0;
|
||||
|
||||
if (daemon_test) {
|
||||
*free_offset = (1048576 * LV_LOCK_BEGIN) + (1048576 * (daemon_test_lv_count + 1));
|
||||
*free_offset = (ONE_MB * LV_LOCK_BEGIN) + (ONE_MB * (daemon_test_lv_count + 1));
|
||||
*sector_size = 512;
|
||||
*align_size = ONE_MB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sector_size = lms->sector_size;
|
||||
*align_size = lms->align_size;
|
||||
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
|
||||
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
rd.rs.num_disks = 1;
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
rd.rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) :
|
||||
(SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
if (ls->free_lock_offset)
|
||||
offset = ls->free_lock_offset;
|
||||
@@ -1091,6 +1328,8 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
char disk_path[SANLK_PATH_LEN];
|
||||
char killpath[SANLK_PATH_LEN];
|
||||
char killargs[SANLK_PATH_LEN];
|
||||
int sector_size = 0;
|
||||
int align_size = 0;
|
||||
int gl_found;
|
||||
int ret, rv;
|
||||
|
||||
@@ -1160,7 +1399,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lms = malloc(sizeof(struct lm_sanlock));
|
||||
lms = zalloc(sizeof(struct lm_sanlock));
|
||||
if (!lms) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -1169,7 +1408,6 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
memset(lsname, 0, sizeof(lsname));
|
||||
strncpy(lsname, ls->name, SANLK_NAME_LEN);
|
||||
|
||||
memset(lms, 0, sizeof(struct lm_sanlock));
|
||||
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
|
||||
lms->ss.host_id_disk.offset = 0;
|
||||
lms->ss.host_id = ls->host_id;
|
||||
@@ -1207,13 +1445,34 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lms->align_size = sanlock_align(&lms->ss.host_id_disk);
|
||||
if (lms->align_size <= 0) {
|
||||
log_error("S %s prepare_lockspace_san align error %d", lsname, lms->align_size);
|
||||
rv = get_sizes_lockspace(disk_path, §or_size, &align_size);
|
||||
if (rv < 0) {
|
||||
log_error("S %s prepare_lockspace_san cannot get sector/align sizes %d", lsname, rv);
|
||||
ret = -EMANAGER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!sector_size) {
|
||||
log_debug("S %s prepare_lockspace_san using old size method", lsname);
|
||||
/* use the old method */
|
||||
align_size = sanlock_align(&lms->ss.host_id_disk);
|
||||
if (align_size <= 0) {
|
||||
log_error("S %s prepare_lockspace_san align error %d", lsname, align_size);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
sector_size = (align_size == ONE_MB) ? 512 : 4096;
|
||||
log_debug("S %s prepare_lockspace_san found old sector_size %d align_size %d", lsname, sector_size, align_size);
|
||||
}
|
||||
|
||||
log_debug("S %s prepare_lockspace_san sizes %d %d", lsname, sector_size, align_size);
|
||||
|
||||
lms->align_size = align_size;
|
||||
lms->sector_size = sector_size;
|
||||
|
||||
lms->ss.flags = (sector_size == 4096) ? (SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M) :
|
||||
(SANLK_LSF_SECTOR512 | SANLK_LSF_ALIGN1M);
|
||||
|
||||
gl_found = gl_is_enabled(ls, lms);
|
||||
if (gl_found < 0) {
|
||||
log_error("S %s prepare_lockspace_san gl_enabled error %d", lsname, gl_found);
|
||||
@@ -1351,6 +1610,7 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
strncpy(rds->rs.name, r->name, SANLK_NAME_LEN);
|
||||
rds->rs.num_disks = 1;
|
||||
memcpy(rds->rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
||||
rds->rs.flags = (lms->sector_size == 4096) ? (SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M) : (SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M);
|
||||
|
||||
if (r->type == LD_RT_GL)
|
||||
rds->rs.disks[0].offset = GL_LOCK_BEGIN * lms->align_size;
|
||||
@@ -1360,10 +1620,9 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
/* LD_RT_LV offset is set in each lm_lock call from lv_args. */
|
||||
|
||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||
rds->vb = malloc(sizeof(struct val_blk));
|
||||
rds->vb = zalloc(sizeof(struct val_blk));
|
||||
if (!rds->vb)
|
||||
return -ENOMEM;
|
||||
memset(rds->vb, 0, sizeof(struct val_blk));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1860,12 +2119,20 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
if (rv < 0)
|
||||
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
|
||||
|
||||
if (rv == -EIO)
|
||||
rv = -ELOCKIO;
|
||||
else if (rv < 0)
|
||||
rv = -ELMERR;
|
||||
/*
|
||||
* sanlock may return an error here if it fails to release the lease on
|
||||
* disk because of an io timeout. But, sanlock will continue trying to
|
||||
* release the lease after this call returns. We shouldn't return an
|
||||
* error here which would result in lvmlockd-core keeping the lock
|
||||
* around. By releasing the lock in lvmlockd-core at this point,
|
||||
* lvmlockd may send another acquire request to lvmlockd. If sanlock
|
||||
* has not been able to release the previous instance of the lock yet,
|
||||
* then it will return an error for the new request. But, acquiring a
|
||||
* new lock is able o fail gracefully, until sanlock is finally able to
|
||||
* release the old lock.
|
||||
*/
|
||||
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_hosts_sanlock(struct lockspace *ls, int notify)
|
||||
|
||||
@@ -29,15 +29,16 @@ include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
|
||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
||||
|
||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
|
||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
|
||||
install_lvmpolld: lvmpolld
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
@echo " [INSTALL] $<"
|
||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_lvm2: install_lvmpolld
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||
const char **newargv;
|
||||
|
||||
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
|
||||
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||
newargv = realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||
if (!newargv)
|
||||
return 0;
|
||||
*cmdargv = newargv;
|
||||
@@ -50,7 +50,7 @@ static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
|
||||
{
|
||||
unsigned i = 0;
|
||||
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
const char **cmd_argv = malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
|
||||
if (!cmd_argv)
|
||||
return NULL;
|
||||
@@ -98,7 +98,7 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
|
||||
|
||||
return cmd_argv;
|
||||
err:
|
||||
dm_free(cmd_argv);
|
||||
free(cmd_argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
|
||||
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
unsigned i = 0;
|
||||
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
const char **cmd_envp = malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
|
||||
if (!cmd_envp)
|
||||
return NULL;
|
||||
@@ -141,6 +141,6 @@ const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||
|
||||
return cmd_envp;
|
||||
err:
|
||||
dm_free(cmd_envp);
|
||||
free(cmd_envp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,10 @@
|
||||
#ifndef _LVM_LVMPOLLD_COMMON_H
|
||||
#define _LVM_LVMPOLLD_COMMON_H
|
||||
|
||||
#define _REENTRANT
|
||||
|
||||
#include "tool.h"
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "lvmpolld-cmd-utils.h"
|
||||
#include "lvmpolld-protocol.h"
|
||||
#include "daemons/lvmpolld/lvmpolld-protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -530,7 +530,7 @@ static response progress_info(client_handle h, struct lvmpolld_state *ls, reques
|
||||
|
||||
pdst_unlock(pdst);
|
||||
|
||||
dm_free(id);
|
||||
free(id);
|
||||
|
||||
if (pdlv) {
|
||||
if (st.error)
|
||||
@@ -673,7 +673,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
|
||||
id,
|
||||
polling_op(pdlv_get_type(pdlv)), polling_op(type));
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_EINVAL,
|
||||
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
|
||||
}
|
||||
@@ -683,14 +683,14 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||
if (!pdlv) {
|
||||
pdst_unlock(pdst);
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
if (!pdst_locked_insert(pdst, id, pdlv)) {
|
||||
pdlv_destroy(pdlv);
|
||||
pdst_unlock(pdst);
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
if (!spawn_detached_thread(pdlv)) {
|
||||
@@ -698,7 +698,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
pdst_locked_remove(pdst, id);
|
||||
pdlv_destroy(pdlv);
|
||||
pdst_unlock(pdst);
|
||||
dm_free(id);
|
||||
free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
|
||||
@@ -709,7 +709,7 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
||||
|
||||
pdst_unlock(pdst);
|
||||
|
||||
dm_free(id);
|
||||
free(id);
|
||||
|
||||
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
|
||||
}
|
||||
@@ -806,7 +806,7 @@ static int printout_raw_response(const char *prefix, const char *msg)
|
||||
char *buf;
|
||||
char *pos;
|
||||
|
||||
buf = dm_strdup(msg);
|
||||
buf = strdup(msg);
|
||||
pos = buf;
|
||||
|
||||
if (!buf)
|
||||
@@ -819,7 +819,7 @@ static int printout_raw_response(const char *prefix, const char *msg)
|
||||
_log_line(pos, &b);
|
||||
pos = next ? next + 1 : 0;
|
||||
}
|
||||
dm_free(buf);
|
||||
free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -915,7 +915,7 @@ int main(int argc, char *argv[])
|
||||
int option_index = 0;
|
||||
int client = 0, server = 0;
|
||||
unsigned action = ACTION_MAX;
|
||||
struct timeval timeout;
|
||||
struct timespec timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
struct lvmpolld_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "lvmpolld-common.h"
|
||||
|
||||
#include "config-util.h"
|
||||
#include "libdaemon/client/config-util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -27,12 +27,12 @@ static char *_construct_full_lvname(const char *vgname, const char *lvname)
|
||||
size_t l;
|
||||
|
||||
l = strlen(vgname) + strlen(lvname) + 2; /* vg/lv and \0 */
|
||||
name = (char *) dm_malloc(l * sizeof(char));
|
||||
name = (char *) malloc(l * sizeof(char));
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (dm_snprintf(name, l, "%s/%s", vgname, lvname) < 0) {
|
||||
dm_free(name);
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
|
||||
* just single char to store NULL byte
|
||||
*/
|
||||
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
|
||||
char *env = (char *) dm_malloc(l * sizeof(char));
|
||||
char *env = (char *) malloc(l * sizeof(char));
|
||||
|
||||
if (!env)
|
||||
return NULL;
|
||||
@@ -55,7 +55,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
|
||||
*env = '\0';
|
||||
|
||||
if (sysdir && dm_snprintf(env, l, "%s%s", LVM_SYSTEM_DIR, sysdir) < 0) {
|
||||
dm_free(env);
|
||||
free(env);
|
||||
env = NULL;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ char *construct_id(const char *sysdir, const char *uuid)
|
||||
size_t l;
|
||||
|
||||
l = strlen(uuid) + (sysdir ? strlen(sysdir) : 0) + 1;
|
||||
id = (char *) dm_malloc(l * sizeof(char));
|
||||
id = (char *) malloc(l * sizeof(char));
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
@@ -82,7 +82,7 @@ char *construct_id(const char *sysdir, const char *uuid)
|
||||
dm_snprintf(id, l, "%s", uuid);
|
||||
|
||||
if (r < 0) {
|
||||
dm_free(id);
|
||||
free(id);
|
||||
id = NULL;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
const char *sinterval, unsigned pdtimeout,
|
||||
struct lvmpolld_store *pdst)
|
||||
{
|
||||
char *lvmpolld_id = dm_strdup(id), /* copy */
|
||||
char *lvmpolld_id = strdup(id), /* copy */
|
||||
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
|
||||
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
|
||||
|
||||
@@ -106,12 +106,12 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
.lvid = _get_lvid(lvmpolld_id, sysdir),
|
||||
.lvname = full_lvname,
|
||||
.lvm_system_dir_env = lvm_system_dir_env,
|
||||
.sinterval = dm_strdup(sinterval), /* copy */
|
||||
.sinterval = strdup(sinterval), /* copy */
|
||||
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
||||
.cmd_state = { .retcode = -1, .signal = 0 },
|
||||
.pdst = pdst,
|
||||
.init_rq_count = 1
|
||||
}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
|
||||
}, *pdlv = (struct lvmpolld_lv *) malloc(sizeof(struct lvmpolld_lv));
|
||||
|
||||
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||
goto err;
|
||||
@@ -124,27 +124,27 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
return pdlv;
|
||||
|
||||
err:
|
||||
dm_free((void *)full_lvname);
|
||||
dm_free((void *)lvmpolld_id);
|
||||
dm_free((void *)lvm_system_dir_env);
|
||||
dm_free((void *)tmp.sinterval);
|
||||
dm_free((void *)pdlv);
|
||||
free((void *)full_lvname);
|
||||
free((void *)lvmpolld_id);
|
||||
free((void *)lvm_system_dir_env);
|
||||
free((void *)tmp.sinterval);
|
||||
free((void *)pdlv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
dm_free((void *)pdlv->lvmpolld_id);
|
||||
dm_free((void *)pdlv->lvname);
|
||||
dm_free((void *)pdlv->sinterval);
|
||||
dm_free((void *)pdlv->lvm_system_dir_env);
|
||||
dm_free((void *)pdlv->cmdargv);
|
||||
dm_free((void *)pdlv->cmdenvp);
|
||||
free((void *)pdlv->lvmpolld_id);
|
||||
free((void *)pdlv->lvname);
|
||||
free((void *)pdlv->sinterval);
|
||||
free((void *)pdlv->lvm_system_dir_env);
|
||||
free((void *)pdlv->cmdargv);
|
||||
free((void *)pdlv->cmdenvp);
|
||||
|
||||
pthread_mutex_destroy(&pdlv->lock);
|
||||
|
||||
dm_free((void *)pdlv);
|
||||
free((void *)pdlv);
|
||||
}
|
||||
|
||||
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
|
||||
@@ -194,7 +194,7 @@ void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
|
||||
|
||||
struct lvmpolld_store *pdst_init(const char *name)
|
||||
{
|
||||
struct lvmpolld_store *pdst = (struct lvmpolld_store *) dm_malloc(sizeof(struct lvmpolld_store));
|
||||
struct lvmpolld_store *pdst = (struct lvmpolld_store *) malloc(sizeof(struct lvmpolld_store));
|
||||
if (!pdst)
|
||||
return NULL;
|
||||
|
||||
@@ -212,7 +212,7 @@ struct lvmpolld_store *pdst_init(const char *name)
|
||||
err_mutex:
|
||||
dm_hash_destroy(pdst->store);
|
||||
err_hash:
|
||||
dm_free(pdst);
|
||||
free(pdst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ void pdst_destroy(struct lvmpolld_store *pdst)
|
||||
|
||||
dm_hash_destroy(pdst->store);
|
||||
pthread_mutex_destroy(&pdst->lock);
|
||||
dm_free(pdst);
|
||||
free(pdst);
|
||||
}
|
||||
|
||||
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
@@ -321,7 +321,7 @@ void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
|
||||
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) dm_malloc(sizeof(struct lvmpolld_thread_data));
|
||||
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) malloc(sizeof(struct lvmpolld_thread_data));
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
@@ -368,7 +368,7 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
pdst_unlock(data->pdlv->pdst);
|
||||
}
|
||||
|
||||
/* may get reallocated in getline(). dm_free must not be used */
|
||||
/* may get reallocated in getline(). free must not be used */
|
||||
free(data->line);
|
||||
|
||||
if (data->fout && !fclose(data->fout))
|
||||
@@ -389,5 +389,5 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
if (data->errpipe[1] >= 0)
|
||||
(void) close(data->errpipe[1]);
|
||||
|
||||
dm_free(data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#ifndef _LVM_LVMPOLLD_PROTOCOL_H
|
||||
#define _LVM_LVMPOLLD_PROTOCOL_H
|
||||
|
||||
#include "polling_ops.h"
|
||||
#include "daemons/lvmpolld/polling_ops.h"
|
||||
|
||||
#define LVMPOLLD_PROTOCOL "lvmpolld"
|
||||
#define LVMPOLLD_PROTOCOL_VERSION 1
|
||||
|
||||
52
device_mapper/Makefile
Normal file
52
device_mapper/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
# 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
|
||||
|
||||
# NOTE: this Makefile only works as 'include' for toplevel Makefile
|
||||
# which defined all top_* variables
|
||||
|
||||
DEVICE_MAPPER_SOURCE=\
|
||||
device_mapper/datastruct/bitset.c \
|
||||
device_mapper/ioctl/libdm-iface.c \
|
||||
device_mapper/libdm-common.c \
|
||||
device_mapper/libdm-config.c \
|
||||
device_mapper/libdm-deptree.c \
|
||||
device_mapper/libdm-file.c \
|
||||
device_mapper/libdm-report.c \
|
||||
device_mapper/libdm-string.c \
|
||||
device_mapper/libdm-targets.c \
|
||||
device_mapper/libdm-timestamp.c \
|
||||
device_mapper/mm/pool.c \
|
||||
device_mapper/regex/matcher.c \
|
||||
device_mapper/regex/parse_rx.c \
|
||||
device_mapper/regex/ttree.c \
|
||||
device_mapper/vdo/status.c \
|
||||
device_mapper/vdo/vdo_target.c
|
||||
|
||||
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
|
||||
DEVICE_MAPPER_DEPENDS = $(DEVICE_MAPPER_SOURCE:%.c=%.d)
|
||||
DEVICE_MAPPER_OBJECTS = $(DEVICE_MAPPER_SOURCE:%.c=%.o)
|
||||
CLEAN_TARGETS += $(DEVICE_MAPPER_DEPENDS) $(DEVICE_MAPPER_OBJECTS) \
|
||||
$(DEVICE_MAPPER_SOURCE:%.c=%.gcda) \
|
||||
$(DEVICE_MAPPER_SOURCE:%.c=%.gcno) \
|
||||
$(DEVICE_MAPPER_TARGET)
|
||||
|
||||
#$(DEVICE_MAPPER_DEPENDS): INCLUDES+=$(VDO_INCLUDES)
|
||||
#$(DEVICE_MAPPER_OBJECTS): INCLUDES+=$(VDO_INCLUDES)
|
||||
|
||||
$(DEVICE_MAPPER_TARGET): $(DEVICE_MAPPER_OBJECTS)
|
||||
@echo " [AR] $@"
|
||||
$(Q) $(RM) $@
|
||||
$(Q) $(AR) rsv $@ $(DEVICE_MAPPER_OBJECTS) > /dev/null
|
||||
|
||||
ifeq ("$(DEPENDS)","yes")
|
||||
-include $(DEVICE_MAPPER_DEPENDS)
|
||||
endif
|
||||
2181
device_mapper/all.h
Normal file
2181
device_mapper/all.h
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user