mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-09 04:23:47 +03:00
Compare commits
561 Commits
dev-dct-de
...
v2_02_188
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cde814abc0 | ||
|
|
844a075c01 | ||
|
|
85795593b8 | ||
|
|
f3babcb591 | ||
|
|
e2b693fbe6 | ||
|
|
1f220e8d43 | ||
|
|
0ab7fce2b3 | ||
|
|
c94657cc2e | ||
|
|
87e0b1a36f | ||
|
|
99d8b91422 | ||
|
|
37a97c8995 | ||
|
|
dee104668e | ||
|
|
02978e1f01 | ||
|
|
7bb472bc30 | ||
|
|
86cd2c6309 | ||
|
|
8bc7bb2dbf | ||
|
|
a157c9e1a1 | ||
|
|
0914ce76bd | ||
|
|
b6dda4ade2 | ||
|
|
5acbd709c1 | ||
|
|
1f6c287aac | ||
|
|
7243e32ce5 | ||
|
|
9344a04b37 | ||
|
|
7b51f39c84 | ||
|
|
6a1e8104f8 | ||
|
|
0f074a4d65 | ||
|
|
4eeb9e7663 | ||
|
|
d3a9bf4a56 | ||
|
|
619ad644cc | ||
|
|
6c99725261 | ||
|
|
cfb9bf13c7 | ||
|
|
18677e24c1 | ||
|
|
99bdbc53ba | ||
|
|
f6025cdc73 | ||
|
|
1728f41183 | ||
|
|
1282e9e298 | ||
|
|
862a86982c | ||
|
|
dd2501d64b | ||
|
|
72b12033a9 | ||
|
|
586bac0b10 | ||
|
|
5196392bcd | ||
|
|
5e97bc5e67 | ||
|
|
c56b3fa4e2 | ||
|
|
1d94748601 | ||
|
|
b9d31664dc | ||
|
|
194630be52 | ||
|
|
b98c334635 | ||
|
|
92a67e3d3f | ||
|
|
307acb072b | ||
|
|
da7ec2ec0f | ||
|
|
50ac89448f | ||
|
|
a12574303d | ||
|
|
4dcb35cb03 | ||
|
|
66ea26131b | ||
|
|
bb5f81624b | ||
|
|
f5a2607bb1 | ||
|
|
67dc22b95e | ||
|
|
9a2a59c0ed | ||
|
|
ab99382d7a | ||
|
|
ee2c80133c | ||
|
|
e478ef2f59 | ||
|
|
f33ccaee45 | ||
|
|
e8cd4e2057 | ||
|
|
df9eba8263 | ||
|
|
9690193ce0 | ||
|
|
511cd6adb7 | ||
|
|
f0913c6482 | ||
|
|
b9d2aa9488 | ||
|
|
50621533dd | ||
|
|
8af590b1bb | ||
|
|
aa4f1f117a | ||
|
|
2c048bd77d | ||
|
|
e5af7bef22 | ||
|
|
5ad30c57b3 | ||
|
|
b8454b59e1 | ||
|
|
ac5cf1544e | ||
|
|
e9241860a8 | ||
|
|
e94e0cd020 | ||
|
|
35104f7ba5 | ||
|
|
0559ce6be0 | ||
|
|
789fc2a081 | ||
|
|
f0a2b6737a | ||
|
|
cc5eb1d70f | ||
|
|
a46fdf5426 | ||
|
|
e5010662a1 | ||
|
|
9c746f153e | ||
|
|
8ee2479dd0 | ||
|
|
7a06bc2400 | ||
|
|
84f03e2b63 | ||
|
|
0c8f160fb2 | ||
|
|
1998825e12 | ||
|
|
ba7740df50 | ||
|
|
8792d417f3 | ||
|
|
afffab0921 | ||
|
|
d143ee13c7 | ||
|
|
ba69c433c1 | ||
|
|
9bddffd7ad | ||
|
|
ef5cddc208 | ||
|
|
7c262bfc85 | ||
|
|
7d3e7266c7 | ||
|
|
d1db024e16 | ||
|
|
6b3d0166ee | ||
|
|
4d8d8856f1 | ||
|
|
bd860802d4 | ||
|
|
1d7d3db571 | ||
|
|
2de99760f7 | ||
|
|
c380d4e9e2 | ||
|
|
e05c882ab5 | ||
|
|
d76b5f4308 | ||
|
|
de1b894337 | ||
|
|
c68380746a | ||
|
|
b97440290c | ||
|
|
03bddd7d41 | ||
|
|
e8df503885 | ||
|
|
479f0822ad | ||
|
|
5e64aa222b | ||
|
|
d32ee355c7 | ||
|
|
1ed9cfad09 | ||
|
|
305e80fe85 | ||
|
|
3b5d51e821 | ||
|
|
7d6dfe9019 | ||
|
|
0a82573416 | ||
|
|
45121aafe9 | ||
|
|
3094c423a0 | ||
|
|
6373a84977 | ||
|
|
d4d3ff352f | ||
|
|
8a0f9537f1 | ||
|
|
3a2ada80cb | ||
|
|
22b256a09a | ||
|
|
9e8016ffa9 | ||
|
|
5726b93709 | ||
|
|
05ba12350c | ||
|
|
688c72411e | ||
|
|
cd681efd9f | ||
|
|
3f06b5c39c | ||
|
|
276e22e263 | ||
|
|
f9327d040c | ||
|
|
238da8ddd9 | ||
|
|
b490cddfbc | ||
|
|
844037ecdf | ||
|
|
5b579fa796 | ||
|
|
9345b9cb26 | ||
|
|
57ddaaa47d | ||
|
|
db7aef215a | ||
|
|
667cfeeacf | ||
|
|
d1f7c531eb | ||
|
|
4ebc8875d3 | ||
|
|
0881ba9e9f | ||
|
|
de17c273de | ||
|
|
ff75d40298 | ||
|
|
92ee7e4c1f | ||
|
|
9c6089b2d0 | ||
|
|
a83e153670 | ||
|
|
d7131ab439 | ||
|
|
81538e6e50 | ||
|
|
c563af0476 | ||
|
|
57585ebacd | ||
|
|
8ad7c344cd | ||
|
|
5ac48c0655 | ||
|
|
8744d97c7b | ||
|
|
6b1f67da06 | ||
|
|
e5066339a5 | ||
|
|
5190e16c30 | ||
|
|
68f94a2dd3 | ||
|
|
6d2fc49e99 | ||
|
|
d063ea27b4 | ||
|
|
0bd9eb80c9 | ||
|
|
f0c281f9a9 | ||
|
|
736691ee6c | ||
|
|
8e778995de | ||
|
|
7c80bf4daa | ||
|
|
29436d6da9 | ||
|
|
d53456be24 | ||
|
|
87769c5713 | ||
|
|
1ac22fb00b | ||
|
|
6b97921ee8 | ||
|
|
6de0f5eab9 | ||
|
|
2dc1981a5a | ||
|
|
2839912d12 | ||
|
|
86056c56f4 | ||
|
|
f7b4b127e9 | ||
|
|
55a8b1bd37 | ||
|
|
d48266b7fb | ||
|
|
90a9a7785e | ||
|
|
94b5aa0aad | ||
|
|
9ffe17d2a8 | ||
|
|
950a9bbde9 | ||
|
|
c4202bf458 | ||
|
|
e397423c41 | ||
|
|
3388779570 | ||
|
|
3b995b8018 | ||
|
|
7e2ceba2fb | ||
|
|
7f41d49f49 | ||
|
|
61e831aa5e | ||
|
|
7ebe1bc901 | ||
|
|
e7e2288ff4 | ||
|
|
d17780c6b8 | ||
|
|
1fb7a9d9e5 | ||
|
|
7ea50a47d1 | ||
|
|
bac7d5951d | ||
|
|
70d2ff38c0 | ||
|
|
1316cafbe9 | ||
|
|
5f766b32cf | ||
|
|
5d93892d4a | ||
|
|
8f3d2d5e11 | ||
|
|
2e3791b421 | ||
|
|
84c239c4e5 | ||
|
|
20d61a2553 | ||
|
|
deaf304ee6 | ||
|
|
44c460954b | ||
|
|
253d10f840 | ||
|
|
bcf9556b8f | ||
|
|
a1f06e2fae | ||
|
|
62888e9c76 | ||
|
|
5ab4d44a3b | ||
|
|
f8ef030737 | ||
|
|
c66e015698 | ||
|
|
9b41118b9c | ||
|
|
440ced192a | ||
|
|
d20490f76d | ||
|
|
019fa6f8ee | ||
|
|
1e2e12f19c | ||
|
|
6370c20d39 | ||
|
|
056eb0a880 | ||
|
|
babde3da55 | ||
|
|
232f779db4 | ||
|
|
b6e6ea2d65 | ||
|
|
e552103027 | ||
|
|
846ae8d49d | ||
|
|
c575c1c9ff | ||
|
|
36210c2b49 | ||
|
|
50c56ade2a | ||
|
|
61c321d110 | ||
|
|
26f94d9119 | ||
|
|
9e45ad04b0 | ||
|
|
245d7fcd59 | ||
|
|
fa4ce13e3f | ||
|
|
c3aa2988d1 | ||
|
|
7581cc20c9 | ||
|
|
b9926fb1be | ||
|
|
2f615e73de | ||
|
|
0e3e974bff | ||
|
|
bbdcdc12b2 | ||
|
|
e9b2148dab | ||
|
|
34bde8b6c7 | ||
|
|
f90c3d69ce | ||
|
|
67bdae0697 | ||
|
|
50fb24f5c2 | ||
|
|
ffd959d2c0 | ||
|
|
343d80a7fe | ||
|
|
a611f24751 | ||
|
|
4ae481bb30 | ||
|
|
2cd30c0d44 | ||
|
|
010062cf03 | ||
|
|
df00a62fd0 | ||
|
|
796efef15e | ||
|
|
50ab7b3ceb | ||
|
|
719ab4da05 | ||
|
|
2c46c60155 | ||
|
|
4b7bcf3ed4 | ||
|
|
cf426744ae | ||
|
|
f1be01c7ef | ||
|
|
8b741b3bba | ||
|
|
5ee3d6dbdf | ||
|
|
9a8bff003b | ||
|
|
963af243bf | ||
|
|
8be8b994c6 | ||
|
|
20d94e4072 | ||
|
|
bc200e0b16 | ||
|
|
36b8b9ed5c | ||
|
|
cd39b67b7e | ||
|
|
96fd312e85 | ||
|
|
f53cce1804 | ||
|
|
e298a87f71 | ||
|
|
c285314763 | ||
|
|
4e99308b7c | ||
|
|
c37aa7881d | ||
|
|
c65f3fd8df | ||
|
|
c24fa7b7b7 | ||
|
|
3fe2610cff | ||
|
|
889c88e9da | ||
|
|
f50af80199 | ||
|
|
219c4c2ce2 | ||
|
|
45ee63ede9 | ||
|
|
8632aa5fd3 | ||
|
|
a0b30eadd1 | ||
|
|
a087da2f51 | ||
|
|
1f970f590f | ||
|
|
61358d92cb | ||
|
|
5d6bf1efb2 | ||
|
|
2327f3997b | ||
|
|
9fcda0d975 | ||
|
|
f758d16b30 | ||
|
|
444dedea23 | ||
|
|
92f1c888e0 | ||
|
|
a57b92dec3 | ||
|
|
8d3e01ff4f | ||
|
|
0585754593 | ||
|
|
6cad4eba9b | ||
|
|
44b98d77ec | ||
|
|
1349b61bb7 | ||
|
|
2e51535b18 | ||
|
|
2caae8a572 | ||
|
|
2694f93bb4 | ||
|
|
e147786bac | ||
|
|
1c07c54829 | ||
|
|
6b12930860 | ||
|
|
402b41f58d | ||
|
|
560dd9c552 | ||
|
|
4e5761487e | ||
|
|
3954034b15 | ||
|
|
ad86cda4d7 | ||
|
|
36523a398d | ||
|
|
e4f72e6655 | ||
|
|
8bcd482cc5 | ||
|
|
93de9b59c2 | ||
|
|
e03bdd7556 | ||
|
|
c4a6b9ded0 | ||
|
|
4743c4900d | ||
|
|
c6e079cda3 | ||
|
|
f55b8e387f | ||
|
|
53fcd4fd8f | ||
|
|
ba629ceea1 | ||
|
|
e5cdb114a6 | ||
|
|
73d1646a00 | ||
|
|
881f49a767 | ||
|
|
474963573a | ||
|
|
9e438b4bc6 | ||
|
|
fdb014f02f | ||
|
|
4a3e1ac740 | ||
|
|
f39141ebc1 | ||
|
|
5ddd1ead2d | ||
|
|
b387d026bd | ||
|
|
a178ad0858 | ||
|
|
7550665ba4 | ||
|
|
3d980172b0 | ||
|
|
e3c8cebd87 | ||
|
|
2f846697fc | ||
|
|
cff9bff0af | ||
|
|
143aca25da | ||
|
|
1e9c409a3e | ||
|
|
e1cc409ae6 | ||
|
|
721a172edf | ||
|
|
23478d9d21 | ||
|
|
b0e1019add | ||
|
|
9aedf68c32 | ||
|
|
ea036ecfd3 | ||
|
|
1650c10438 | ||
|
|
b13ebfa4c2 | ||
|
|
b62c0787de | ||
|
|
ff2bf11360 | ||
|
|
7232458b6c | ||
|
|
8bea252a63 | ||
|
|
66665f5e42 | ||
|
|
5cf1c61152 | ||
|
|
2cd6cd3439 | ||
|
|
82e7426028 | ||
|
|
862899cc88 | ||
|
|
09aafb61e3 | ||
|
|
3b42cdad0c | ||
|
|
49813abc00 | ||
|
|
788d89c412 | ||
|
|
e0a176f49a | ||
|
|
24186cd9ce | ||
|
|
2806e6265f | ||
|
|
02a5921cdb | ||
|
|
b61c89b52b | ||
|
|
78c937552a | ||
|
|
a311684c4a | ||
|
|
f3a87a2c2e | ||
|
|
1727df7c98 | ||
|
|
29ae8b8ca5 | ||
|
|
e80ca65d30 | ||
|
|
d6bce03615 | ||
|
|
8623e33651 | ||
|
|
c31e6b0aca | ||
|
|
cb7766bc14 | ||
|
|
1308572a87 | ||
|
|
adf9bf80a3 | ||
|
|
f633d68c54 | ||
|
|
c733e96445 | ||
|
|
3669c33af4 | ||
|
|
e2ae1f2d71 | ||
|
|
3aeff09bd7 | ||
|
|
d5a5792b30 | ||
|
|
a397b69ce3 | ||
|
|
a8921be641 | ||
|
|
9d7afaaab8 | ||
|
|
71b9cb8e0f | ||
|
|
057d866889 | ||
|
|
e79e092f8b | ||
|
|
4729b4af0b | ||
|
|
f3be66c002 | ||
|
|
2047d405af | ||
|
|
1370277ea7 | ||
|
|
f38cfd09c4 | ||
|
|
515867bbad | ||
|
|
bcf1aa99e6 | ||
|
|
b41b112a4b | ||
|
|
559cf0cd1e | ||
|
|
228e331e27 | ||
|
|
3ead62e24b | ||
|
|
fa025cdd9a | ||
|
|
f5d1f4f086 | ||
|
|
699bf86090 | ||
|
|
03d6cfdd99 | ||
|
|
6064b9f1b2 | ||
|
|
6d4f36c2c7 | ||
|
|
63289b54c7 | ||
|
|
0a726a7e26 | ||
|
|
b79f1e176f | ||
|
|
81d954df4e | ||
|
|
7cbee7e9cf | ||
|
|
717957ddc5 | ||
|
|
9b04851fc5 | ||
|
|
dcf8f3111a | ||
|
|
ece0b131e5 | ||
|
|
519f4453a5 | ||
|
|
bc6ae7030a | ||
|
|
167aa34926 | ||
|
|
8fc64c5ee6 | ||
|
|
8d44cd3e47 | ||
|
|
40f57155a3 | ||
|
|
1bef4dfab3 | ||
|
|
e974f6866a | ||
|
|
a93699ece9 | ||
|
|
e4bb94a93e | ||
|
|
93ac80037a | ||
|
|
c9e5e6800c | ||
|
|
f0f68791f3 | ||
|
|
b39c26ddc3 | ||
|
|
d1ae1455b4 | ||
|
|
c115d92287 | ||
|
|
ece117ee10 | ||
|
|
590a1ebcf7 | ||
|
|
863a2e693e | ||
|
|
8dbfdb5b73 | ||
|
|
675b94a11b | ||
|
|
850e95f24a | ||
|
|
083f162e8e | ||
|
|
7f56908c2b | ||
|
|
427e8ba3e3 | ||
|
|
6a5575e959 | ||
|
|
57cde6063f | ||
|
|
d0cb672466 | ||
|
|
75886f59e4 | ||
|
|
1d2de5dd13 | ||
|
|
df0797db8c | ||
|
|
2d077286b9 | ||
|
|
f5ea02ffee | ||
|
|
262a42025f | ||
|
|
d5234e1b7e | ||
|
|
a188b1e513 | ||
|
|
9764ee0b3f | ||
|
|
322d4ed05e | ||
|
|
a01e1fec0f | ||
|
|
0e42ebd6d4 | ||
|
|
fe1cabfa34 | ||
|
|
cb5405ded8 | ||
|
|
f8ce9bf3bc | ||
|
|
9fda169077 | ||
|
|
9799c8da07 | ||
|
|
613466aa8f | ||
|
|
813a83b2d6 | ||
|
|
fa8d5e4e81 | ||
|
|
b93aded021 | ||
|
|
efa281685a | ||
|
|
ab27d5dc2a | ||
|
|
bd872064a2 | ||
|
|
d1b652143a | ||
|
|
e7bb508809 | ||
|
|
de2863739f | ||
|
|
c26bde42af | ||
|
|
0e03c68619 | ||
|
|
3374a59250 | ||
|
|
6afb911252 | ||
|
|
a8d59404f7 | ||
|
|
a1a89a453f | ||
|
|
ed749cdb5b | ||
|
|
5502f72e41 | ||
|
|
c527a0cbfc | ||
|
|
63d4983890 | ||
|
|
a991664dec | ||
|
|
ab1aa0a4fb | ||
|
|
d910f75d89 | ||
|
|
94362423c4 | ||
|
|
acf40f5587 | ||
|
|
227a0d7336 | ||
|
|
a41968c4b4 | ||
|
|
672b8c196b | ||
|
|
cc96eea029 | ||
|
|
5f648406b0 | ||
|
|
3ebc745f53 | ||
|
|
acd2c6f256 | ||
|
|
b10b462fde | ||
|
|
a75eb8d74c | ||
|
|
0569add94c | ||
|
|
12dfd0ed02 | ||
|
|
ad10d42671 | ||
|
|
f7645995da | ||
|
|
4ed9b07380 | ||
|
|
0174ba692c | ||
|
|
48594d007a | ||
|
|
50a603de6f | ||
|
|
e4fe0d1b8f | ||
|
|
951676a59e | ||
|
|
4456d9aa77 | ||
|
|
b394a9f63f | ||
|
|
9e296c9c6f | ||
|
|
5b87f5fb72 | ||
|
|
bb384f8488 | ||
|
|
82feb5f111 | ||
|
|
66990bc7c8 | ||
|
|
6fcb2ba440 | ||
|
|
b8a7f6ba3d | ||
|
|
0851ee5301 | ||
|
|
df8eef7096 | ||
|
|
c1dbb22ba4 | ||
|
|
99cddd67a9 | ||
|
|
814dd84e07 | ||
|
|
d5bcc56eef | ||
|
|
f7ffba204e | ||
|
|
90e419c645 | ||
|
|
49147cbaa7 | ||
|
|
69907e0780 | ||
|
|
b90d4b38e5 | ||
|
|
befdfc245b | ||
|
|
0d78e4c1e9 | ||
|
|
763c65314e | ||
|
|
24aee732a5 | ||
|
|
ba6ed5c90c | ||
|
|
e0c94d883a | ||
|
|
39e3b5d8ac | ||
|
|
39fc98d731 | ||
|
|
5503699c37 | ||
|
|
e0bfc946cb | ||
|
|
9546edeef9 | ||
|
|
716199334c | ||
|
|
4479228d32 | ||
|
|
4afb5971b9 | ||
|
|
dd075e93c1 | ||
|
|
d4fd39f64c | ||
|
|
acb784e2a8 | ||
|
|
8a0af1bec8 | ||
|
|
8bd9a89c14 | ||
|
|
a30e622279 | ||
|
|
76075ff55d | ||
|
|
bfb904af1c | ||
|
|
d88376ca78 | ||
|
|
6283f5ea3f | ||
|
|
43ce357ebc | ||
|
|
d136790bab | ||
|
|
214de62b5d | ||
|
|
e9c0a64fb5 | ||
|
|
7ac8e21f3c | ||
|
|
fdb362b998 | ||
|
|
06accf1395 | ||
|
|
d3dcca639c | ||
|
|
98eb9e5754 | ||
|
|
347c807f86 | ||
|
|
1e5f6887b1 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -25,30 +25,19 @@ make.tmpl
|
|||||||
|
|
||||||
/autom4te.cache/
|
/autom4te.cache/
|
||||||
/autoscan.log
|
/autoscan.log
|
||||||
/build/
|
|
||||||
/config.cache
|
|
||||||
/config.log
|
/config.log
|
||||||
/config.status
|
/config.status
|
||||||
/configure.scan
|
/configure.scan
|
||||||
/cscope.*
|
/cscope.*
|
||||||
/html/
|
/html/
|
||||||
/python/
|
|
||||||
/reports/
|
/reports/
|
||||||
/tags
|
/tags
|
||||||
/tmp/
|
/tmp/
|
||||||
|
|
||||||
coverity/coverity_model.xml
|
|
||||||
|
|
||||||
# gcov files:
|
|
||||||
*.gcda
|
|
||||||
*.gcno
|
|
||||||
|
|
||||||
tools/man-generator
|
tools/man-generator
|
||||||
tools/man-generator.c
|
tools/man-generator.c
|
||||||
|
|
||||||
test/.lib-dir-stamp
|
|
||||||
test/.tests-stamp
|
|
||||||
test/lib/dmsecuretest
|
|
||||||
test/lib/lvchange
|
test/lib/lvchange
|
||||||
test/lib/lvconvert
|
test/lib/lvconvert
|
||||||
test/lib/lvcreate
|
test/lib/lvcreate
|
||||||
@@ -73,7 +62,6 @@ test/lib/pvremove
|
|||||||
test/lib/pvresize
|
test/lib/pvresize
|
||||||
test/lib/pvs
|
test/lib/pvs
|
||||||
test/lib/pvscan
|
test/lib/pvscan
|
||||||
test/lib/securetest
|
|
||||||
test/lib/vgcfgbackup
|
test/lib/vgcfgbackup
|
||||||
test/lib/vgcfgrestore
|
test/lib/vgcfgrestore
|
||||||
test/lib/vgchange
|
test/lib/vgchange
|
||||||
|
|||||||
113
Makefile.in
113
Makefile.in
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
|||||||
abs_top_builddir = @abs_top_builddir@
|
abs_top_builddir = @abs_top_builddir@
|
||||||
abs_top_srcdir = @abs_top_srcdir@
|
abs_top_srcdir = @abs_top_srcdir@
|
||||||
|
|
||||||
SUBDIRS = libdm conf daemons include lib libdaemon man scripts tools
|
SUBDIRS = conf daemons include lib libdaemon libdm man scripts device_mapper tools
|
||||||
|
|
||||||
ifeq ("@UDEV_RULES@", "yes")
|
ifeq ("@UDEV_RULES@", "yes")
|
||||||
SUBDIRS += udev
|
SUBDIRS += udev
|
||||||
@@ -28,6 +28,14 @@ ifeq ("@INTL@", "yes")
|
|||||||
SUBDIRS += po
|
SUBDIRS += po
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@APPLIB@", "yes")
|
||||||
|
SUBDIRS += liblvm
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||||
|
SUBDIRS += python
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),clean)
|
ifeq ($(MAKECMDGOALS),clean)
|
||||||
SUBDIRS += test
|
SUBDIRS += test
|
||||||
endif
|
endif
|
||||||
@@ -35,7 +43,7 @@ endif
|
|||||||
ifeq ($(MAKECMDGOALS),distclean)
|
ifeq ($(MAKECMDGOALS),distclean)
|
||||||
SUBDIRS = conf include man test scripts \
|
SUBDIRS = conf include man test scripts \
|
||||||
libdaemon lib tools daemons libdm \
|
libdaemon lib tools daemons libdm \
|
||||||
udev po
|
udev po liblvm python device_mapper
|
||||||
tools.distclean: test.distclean
|
tools.distclean: test.distclean
|
||||||
endif
|
endif
|
||||||
DISTCLEAN_DIRS += lcov_reports*
|
DISTCLEAN_DIRS += lcov_reports*
|
||||||
@@ -44,23 +52,28 @@ DISTCLEAN_TARGETS += config.cache config.log config.status make.tmpl
|
|||||||
include make.tmpl
|
include make.tmpl
|
||||||
|
|
||||||
include $(top_srcdir)/base/Makefile
|
include $(top_srcdir)/base/Makefile
|
||||||
include $(top_srcdir)/device_mapper/Makefile
|
|
||||||
include $(top_srcdir)/test/unit/Makefile
|
|
||||||
|
|
||||||
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
|
libdm: include $(top_builddir)/base/libbase.a
|
||||||
daemons: lib libdaemon tools
|
libdaemon: include $(top_builddir)/base/libbase.a
|
||||||
scripts: lib
|
lib: libdm libdaemon $(top_builddir)/base/libbase.a
|
||||||
tools: lib libdaemon
|
liblvm: lib $(top_builddir)/base/libbase.a
|
||||||
|
daemons: lib libdaemon tools $(top_builddir)/base/libbase.a
|
||||||
|
tools: lib libdaemon device-mapper $(top_builddir)/base/libbase.a
|
||||||
po: tools daemons
|
po: tools daemons
|
||||||
man: tools
|
man: tools
|
||||||
all_man: tools
|
all_man: tools
|
||||||
test: tools daemons
|
scripts: liblvm libdm
|
||||||
unit-test run-unit-test: test
|
test: tools daemons $(top_builddir)/base/libbase.a
|
||||||
|
unit-test: lib $(top_builddir)/base/libbase.a
|
||||||
|
run-unit-test: unit-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
|
daemons.device-mapper: libdm.device-mapper
|
||||||
tools.device-mapper: libdm.device-mapper
|
tools.device-mapper: libdm.device-mapper
|
||||||
|
scripts.device-mapper: include.device-mapper
|
||||||
device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper
|
device-mapper: tools.device-mapper daemons.device-mapper man.device-mapper
|
||||||
device_mapper: device-mapper
|
|
||||||
|
|
||||||
ifeq ("@INTL@", "yes")
|
ifeq ("@INTL@", "yes")
|
||||||
lib.pofile: include.pofile
|
lib.pofile: include.pofile
|
||||||
@@ -70,22 +83,25 @@ po.pofile: tools.pofile daemons.pofile
|
|||||||
pofile: po.pofile
|
pofile: po.pofile
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||||
|
python: liblvm
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ("$(CFLOW_CMD)", "")
|
ifneq ("$(CFLOW_CMD)", "")
|
||||||
tools.cflow: libdm.cflow lib.cflow
|
tools.cflow: libdm.cflow lib.cflow
|
||||||
daemons.cflow: tools.cflow
|
daemons.cflow: tools.cflow
|
||||||
cflow: include.cflow
|
cflow: include.cflow
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CSCOPE_DIRS = base daemons device_mapper include lib libdaemon scripts tools libdm test
|
|
||||||
ifneq ("@CSCOPE_CMD@", "")
|
ifneq ("@CSCOPE_CMD@", "")
|
||||||
cscope.out:
|
cscope.out:
|
||||||
@CSCOPE_CMD@ -b -R $(patsubst %,-s%,$(addprefix $(srcdir)/,$(CSCOPE_DIRS)))
|
@CSCOPE_CMD@ -b -R -s$(top_srcdir)
|
||||||
all: cscope.out
|
all: cscope.out
|
||||||
endif
|
endif
|
||||||
DISTCLEAN_TARGETS += cscope.out
|
DISTCLEAN_TARGETS += cscope.out
|
||||||
CLEAN_DIRS += autom4te.cache
|
CLEAN_DIRS += autom4te.cache
|
||||||
|
|
||||||
check check_system check_cluster check_local check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock: test
|
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test run-unit-test: test
|
||||||
$(MAKE) -C test $(@)
|
$(MAKE) -C test $(@)
|
||||||
|
|
||||||
conf.generate man.generate: tools
|
conf.generate man.generate: tools
|
||||||
@@ -110,13 +126,13 @@ rpm: dist
|
|||||||
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
|
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
|
||||||
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
||||||
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
||||||
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
|
DM_VER=$$(cut -d' ' -f1 $(top_srcdir)/VERSION_DM | cut -d- -f1);\
|
||||||
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
|
GIT_VER=$$(cd $(top_srcdir); git describe | cut -s -d- --output-delimiter=. -f2,3);\
|
||||||
$(SED) -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
sed -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
||||||
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
||||||
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
|
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $${GIT_VER:-"0"}," \
|
||||||
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
||||||
V=$(V) rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||||
|
|
||||||
generate: conf.generate man.generate
|
generate: conf.generate man.generate
|
||||||
$(MAKE) -C conf generate
|
$(MAKE) -C conf generate
|
||||||
@@ -147,36 +163,27 @@ install_systemd_units:
|
|||||||
install_all_man:
|
install_all_man:
|
||||||
$(MAKE) -C man 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:
|
install_tmpfiles_configuration:
|
||||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||||
|
|
||||||
help:
|
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||||
@echo -e "\nAvailable targets:"
|
libdaemon/client.info libdaemon/server.info \
|
||||||
@echo " all Default target."
|
test/unit.info \
|
||||||
@echo " all_man Build all man pages with generators."
|
daemons/clvmd.info \
|
||||||
@echo " clean Remove all compile files."
|
daemons/dmeventd.info \
|
||||||
@echo " device-mapper Device mapper part of lvm2."
|
daemons/lvmetad.info \
|
||||||
@echo " dist Generate distributable file."
|
daemons/lvmlockd.info \
|
||||||
@echo " distclean Remove all build files."
|
daemons/lvmpolld.info
|
||||||
@echo " generate Generate man pages for sources."
|
|
||||||
@echo " help Display callable targets."
|
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||||
@echo " install Install all files."
|
|
||||||
@echo " install_all_man Install all man pages."
|
|
||||||
@echo " install_cluster Install cmirrord."
|
|
||||||
@echo " install_device-mapper Install device mapper files."
|
|
||||||
@echo " install_initscripts Install initialization scripts."
|
|
||||||
@echo " install_lvm2 Install lvm2 files."
|
|
||||||
@echo " install_systemd_units Install systemd units."
|
|
||||||
@echo " lcov Generate lcov output."
|
|
||||||
@echo " lcov-dated Generate lcov with timedate suffix."
|
|
||||||
@echo " lcov-reset Reset lcov counters"
|
|
||||||
@echo " man Build man pages."
|
|
||||||
@echo " rpm Build rpm."
|
|
||||||
@echo " run-unit-test Run unit tests."
|
|
||||||
@echo " tags Generate c/etags."
|
|
||||||
|
|
||||||
ifneq ("$(LCOV)", "")
|
ifneq ("$(LCOV)", "")
|
||||||
.PHONY: lcov-reset lcov lcov-dated
|
.PHONY: lcov-reset lcov lcov-dated $(LCOV_TRACES)
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),lcov-dated)
|
ifeq ($(MAKECMDGOALS),lcov-dated)
|
||||||
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
|
LCOV_REPORTS_DIR := lcov_reports-$(shell date +%Y%m%d%k%M%S)
|
||||||
@@ -186,10 +193,18 @@ LCOV_REPORTS_DIR := lcov_reports
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
lcov-reset:
|
lcov-reset:
|
||||||
$(LCOV) --zerocounters --directory $(top_builddir)
|
$(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/" \
|
||||||
|
>$@
|
||||||
|
|
||||||
ifneq ("$(GENHTML)", "")
|
ifneq ("$(GENHTML)", "")
|
||||||
lcov:
|
lcov: $(LCOV_TRACES)
|
||||||
$(RM) -rf $(LCOV_REPORTS_DIR)
|
$(RM) -rf $(LCOV_REPORTS_DIR)
|
||||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||||
$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
|
$(LCOV) --capture --directory $(top_builddir) --ignore-errors source \
|
||||||
@@ -201,11 +216,11 @@ endif
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(shell which ctags 2>/dev/null),)
|
ifneq ($(shell which ctags),)
|
||||||
.PHONY: tags
|
.PHONY: tags
|
||||||
tags:
|
tags:
|
||||||
test -z "$(shell find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||||
test -f tags || find $(addprefix $(top_srcdir)/,$(CSCOPE_DIRS)) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||||
|
|
||||||
CLEAN_TARGETS += tags
|
CLEAN_TARGETS += tags
|
||||||
endif
|
endif
|
||||||
|
|||||||
2
README
2
README
@@ -1,7 +1,5 @@
|
|||||||
This tree contains the LVM2 and device-mapper tools and libraries.
|
This tree contains the LVM2 and device-mapper tools and libraries.
|
||||||
|
|
||||||
This is development branch, for stable 2.02 release see stable-2.02 branch.
|
|
||||||
|
|
||||||
For more information about LVM2 read the changelog in the WHATS_NEW file.
|
For more information about LVM2 read the changelog in the WHATS_NEW file.
|
||||||
Installation instructions are in INSTALL.
|
Installation instructions are in INSTALL.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.02.185-git (2022-02-07)
|
1.02.172 (2021-05-07)
|
||||||
|
|||||||
331
WHATS_NEW
331
WHATS_NEW
@@ -1,315 +1,152 @@
|
|||||||
Version 2.03.16 -
|
Version 2.02.188 - 07th May 2021
|
||||||
====================================
|
================================
|
||||||
|
|
||||||
Version 2.03.15 - 07th February 2022
|
|
||||||
====================================
|
|
||||||
Remove service based autoactivation. global/event_activation = 0 is NOOP.
|
|
||||||
Improve support for metadata profiles for --type writecache.
|
|
||||||
Use cache or active DM device when available with new kernels.
|
|
||||||
Introduce function to utilize UUIDs from DM_DEVICE_LIST.
|
|
||||||
Increase some hash table size to better support large device sets.
|
|
||||||
|
|
||||||
Version 2.03.14 - 20th October 2021
|
|
||||||
===================================
|
|
||||||
Device scanning is skipping directories on different filesystems.
|
|
||||||
Print info message with too many or too large archived files.
|
|
||||||
Reduce metadata readings during scanning phase.
|
|
||||||
Optimize computation of crc32 check sum with multiple PVs.
|
|
||||||
Enhance recover path on cache creation failure.
|
|
||||||
Filter out unsupported MQ/SMQ cache policy setting.
|
|
||||||
Fix memleak in mpath filter.
|
|
||||||
Support newer location for VDO statistics.
|
|
||||||
Add support for VDO async-unsafe write policy.
|
|
||||||
Improve lvm_import_vdo script.
|
|
||||||
Support VDO LV with lvcreate -ky.
|
|
||||||
Fix lvconvert for VDO LV bigger then 2T.
|
|
||||||
Create VDO LVs automatically without zeroing.
|
|
||||||
Rename vdoimport to lvm_import_vdo.
|
|
||||||
|
|
||||||
Version 2.03.13 - 11th August 2021
|
|
||||||
==================================
|
|
||||||
Changes in udev support:
|
|
||||||
- obtain_device_list_from_udev defaults to 0.
|
|
||||||
- see devices/external_device_info_source,
|
|
||||||
devices/obtain_device_list_from_udev, and devices/multipath_wwids_file help
|
|
||||||
in lvm.conf
|
|
||||||
Fix devices file handling of loop with deleted backing file.
|
|
||||||
Fix devices file handling of scsi_debug WWIDs.
|
|
||||||
Fix many static analysis issues.
|
|
||||||
Support --poolmetadataspare with vgsplit and vgmerge.
|
|
||||||
Fix detection of active components of external origin volume.
|
|
||||||
Add vdoimport tool to support conversion of VDO volumes.
|
|
||||||
Support configurable allocation/vdo_pool_header_size.
|
|
||||||
Fix handling of lvconvert --type vdo-pool --virtualsize.
|
|
||||||
Simplified handling of archive() and backup() internal calls.
|
|
||||||
Add 'idm' locking type for IDM lock manager.
|
|
||||||
Fix load of kvdo target when it is not present in memory (2.03.12).
|
|
||||||
|
|
||||||
Version 2.03.12 - 07th May 2021
|
|
||||||
===============================
|
|
||||||
Allow attaching cache to thin data volume.
|
|
||||||
Fix memleak when generating list of outdated pvs.
|
|
||||||
Better hyphenation usage in man pages.
|
|
||||||
Replace use of deprecated security_context_t with char*.
|
|
||||||
Configure supports AIO_LIBS and AIO_CFLAGS.
|
|
||||||
Improve build process for static builds.
|
|
||||||
New --setautoactivation option to modify LV or VG auto activation.
|
|
||||||
New metadata based autoactivation property for LVs and VGs.
|
|
||||||
Improve signal handling with lvmpolld.
|
|
||||||
Signal handler can interrupt command also for SIGTERM.
|
|
||||||
Lvreduce --yes support.
|
|
||||||
Add configure option --with/out-symvers for non-glibc builds.
|
|
||||||
Report error when the filesystem is missing on fsadm resized volume.
|
|
||||||
Handle better blockdev with --getsize64 support for fsadm.
|
|
||||||
Do not include editline/history.h when using editline library.
|
|
||||||
Support error and zero segtype for thin-pool data for testing.
|
|
||||||
Support mixed extension for striped, error and zero segtypes.
|
|
||||||
Support resize also for stacked virtual volumes.
|
|
||||||
Skip dm-zero devices just like with dm-error target.
|
|
||||||
Reduce ioctl() calls when checking target status.
|
|
||||||
Merge polling does not fail, when LV is found to be already merged.
|
|
||||||
Poll volumes with at least 100ms delays.
|
|
||||||
Do not flush dm cache when cached LV is going to be removed.
|
|
||||||
New lvmlockctl_kill_command configuration option.
|
|
||||||
Support interruption while waiting on device close before deactivation.
|
|
||||||
Flush thin-pool messages before removing more thin volumes.
|
|
||||||
Improve hash function with less collisions and make it faster.
|
|
||||||
Reduce ioctl count when deactivating volumes.
|
|
||||||
Reduce number of metadata parsing.
|
|
||||||
Enhance performance of lvremove and vgremove commands.
|
|
||||||
Support interruption when taking archive and backup.
|
|
||||||
Accelerate large lvremoves.
|
|
||||||
Speedup search for cached device nodes.
|
|
||||||
Speedup command initialization.
|
|
||||||
Add devices file feature, off by default for now.
|
|
||||||
Support extension of writecached volumes.
|
|
||||||
Fix problem with unbound variable usage within fsadm.
|
Fix problem with unbound variable usage within fsadm.
|
||||||
Fix IMSM MD RAID detection on 4k devices.
|
|
||||||
Check for presence of VDO target before starting any conversion.
|
|
||||||
Support metatadata profiles with volume VDO pool conversions.
|
|
||||||
Support -Zn for conversion of already formated VDO pools.
|
|
||||||
Avoid removing LVs on error path of lvconvert during creation volumes.
|
Avoid removing LVs on error path of lvconvert during creation volumes.
|
||||||
Fix crashing lvdisplay when thin volume was waiting for merge.
|
Fix crashing lvdisplay when thin volume was waiting for merge.
|
||||||
Support option --errorwhenfull when converting volume to thin-pool.
|
Support option --errorwhenfull when converting volume to thin-pool.
|
||||||
Improve thin-performance profile support conversion to thin-pool.
|
Improve thin-performance profile support conversion to thin-pool.
|
||||||
Add workaround to avoid read of internal 'converted' devices.
|
|
||||||
Prohibit merging snapshot into the read-only thick snapshot origin.
|
|
||||||
Restore support for flipping rw/r permissions for thin snapshot origin.
|
|
||||||
Support resize of cached volumes.
|
Support resize of cached volumes.
|
||||||
Disable autoactivation with global/event_activation=0.
|
|
||||||
Check if lvcreate passes read_only_volume_list with tags and skips zeroing.
|
|
||||||
Allocation prints better error when metadata cannot fit on a single PV.
|
Allocation prints better error when metadata cannot fit on a single PV.
|
||||||
Pvmove can better resolve full thin-pool tree move.
|
Pvmove can better resolve full thin-pool tree move.
|
||||||
Limit pool metadata spare to 16GiB.
|
Limit pool metadata spare to 16GiB.
|
||||||
Improves conversion and allocation of pool metadata.
|
Improves convertsion and allocation of pool metadata.
|
||||||
Support thin pool metadata 15.88GiB, adds 64MiB, thin_pool_crop_metadata=0.
|
Support thin pool metadata 15.88GiB, adds 64MiB, thin_pool_crop_metadata=0.
|
||||||
Enhance lvdisplay to report raid available/partial.
|
Enhance lvdisplay to report raid availiable/partial.
|
||||||
Support online rename of VDO pools.
|
Enhance error handling for fsadm and hanled correct fsck result.
|
||||||
Improve removal of pmspare when last pool is removed.
|
Stop logging rename errors from persintent filter.
|
||||||
Fix problem with wiping of converted LVs.
|
|
||||||
Fix memleak in scanning (2.03.11).
|
|
||||||
Fix corner case allocation for thin-pools.
|
|
||||||
|
|
||||||
Version 2.03.11 - 08th January 2021
|
|
||||||
===================================
|
|
||||||
Fix pvck handling MDA at offset different from 4096.
|
|
||||||
Partial or degraded activation of writecache is not allowed.
|
|
||||||
Enhance error handling for fsadm and handle correct fsck result.
|
|
||||||
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
|
Dmeventd lvm plugin ignores higher reserved_stack lvm.conf values.
|
||||||
Support using BLKZEROOUT for clearing devices.
|
Support using BLKZEROOUT for clearing devices.
|
||||||
Support interruption when wipping LVs.
|
Support interruption when wipping LVs.
|
||||||
|
Add configure --enable-editline support as an alternative to readline.
|
||||||
|
Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
|
||||||
|
Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
|
||||||
|
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
|
||||||
Support interruption for bcache waiting.
|
Support interruption for bcache waiting.
|
||||||
Fix bcache when device has too many failing writes.
|
Fix bcache when device has too many failing writes.
|
||||||
Fix bcache waiting for IO completion with failing disks.
|
Fix bcache waiting for IO completion with failing disks.
|
||||||
Configure use own python path name order to prefer using python3.
|
Configure use own python path name order to prefer using python3.
|
||||||
Add configure --enable-editline support as an alternative to readline.
|
|
||||||
Enhance reporting and error handling when creating thin volumes.
|
Enhance reporting and error handling when creating thin volumes.
|
||||||
Enable vgsplit for VDO volumes.
|
|
||||||
Lvextend of vdo pool volumes ensure at least 1 new VDO slab is added.
|
|
||||||
Use revert_lv() on reload error path after vg_revert().
|
Use revert_lv() on reload error path after vg_revert().
|
||||||
Configure --with-integrity enabled.
|
|
||||||
Restore lost signal blocking while VG lock is held.
|
|
||||||
Improve estimation of needed extents when creating thin-pool.
|
Improve estimation of needed extents when creating thin-pool.
|
||||||
Use extra 1% when resizing thin-pool metadata LV with --use-policy.
|
Use extra 1% when resizing thin-pool metadata LV with --use-policy.
|
||||||
Enhance --use-policy percentage rounding.
|
Enhance --use-policy percentage rounding.
|
||||||
Configure --with-vdo and --with-writecache as internal segments.
|
|
||||||
Improving VDO man page examples.
|
|
||||||
Allow pvmove of writecache origin.
|
|
||||||
Report integrity fields.
|
|
||||||
Integrity volumes defaults to journal mode.
|
|
||||||
Switch code base to use flexible array syntax.
|
Switch code base to use flexible array syntax.
|
||||||
Fix 64bit math when calculation cachevol size.
|
|
||||||
Preserve uint32_t for seqno handling.
|
Preserve uint32_t for seqno handling.
|
||||||
Switch from mmap to plain read when loading regular files.
|
Switch from mmap to plain read when loading regular files.
|
||||||
Update lvmvdo man page and better explain DISCARD usage.
|
Fix running out of free buffers for async writing for larger writes.
|
||||||
|
|
||||||
Version 2.03.10 - 09th August 2020
|
|
||||||
==================================
|
|
||||||
Add writecache and integrity support to lvmdbusd.
|
|
||||||
Generate unique cachevol name when default required from lvcreate.
|
|
||||||
Converting RAID1 volume to one with same number of legs now succeeds with a
|
|
||||||
warning.
|
|
||||||
Fix conversion to raid from striped lagging type.
|
Fix conversion to raid from striped lagging type.
|
||||||
Fix conversion to 'mirrored' mirror log with larger regionsize.
|
Fix conversion to 'mirrored' mirror log with larger regionsize.
|
||||||
Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
|
|
||||||
Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
|
|
||||||
Add lvcreate of new cache or writecache lv with single command.
|
|
||||||
Fix running out of free buffers for async writing for larger writes.
|
|
||||||
Add integrity with raid capability.
|
|
||||||
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
|
Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
|
||||||
|
|
||||||
Version 2.03.09 - 26th March 2020
|
Version 2.02.187 - 24th March 2020
|
||||||
=================================
|
==================================
|
||||||
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
|
|
||||||
Fix showing of a dm kernel error when uncaching a volume with cachevol.
|
|
||||||
|
|
||||||
Version 2.03.08 - 11th February 2020
|
|
||||||
====================================
|
|
||||||
Prevent problematic snapshots of writecache volumes.
|
|
||||||
Add error handling for failing allocation in _reserve_area().
|
|
||||||
Fix memleak in syncing of internal cache.
|
|
||||||
Fix pvck dump_current_text memleak.
|
|
||||||
Fix lvmlockd result code on error path for _query_lock_lv().
|
|
||||||
Update pvck man page and help output.
|
|
||||||
Reject invalid writecache high/low_watermark setting.
|
|
||||||
Report writecache status.
|
|
||||||
Accept more output lines from vdo_format.
|
|
||||||
Prohibit reshaping of stacked raid LVs.
|
|
||||||
Avoid running cache input arg validation when creating vdo pool.
|
Avoid running cache input arg validation when creating vdo pool.
|
||||||
Prevent raid reshaping of stacked volumes.
|
Prevent raid reshaping of stacked volumes.
|
||||||
Added VDO lvmdbusd methods for enable/disable compression & dedupe.
|
|
||||||
Added VDO lvmdbusd method for converting LV to VDO pool.
|
|
||||||
|
|
||||||
Version 2.03.07 - 30th November 2019
|
|
||||||
====================================
|
|
||||||
Subcommand in vgck for repairing headers and metadata.
|
|
||||||
Ensure minimum required region size on striped RaidLV creation.
|
Ensure minimum required region size on striped RaidLV creation.
|
||||||
Fix resize of thin-pool with data and metadata of different segtype.
|
Fix resize of thin-pool with data and metadata of different segtype.
|
||||||
Improve mirror type leg splitting.
|
Fix splitting mirror leg in cluster.
|
||||||
Improve error path handling in daemons on shutdown.
|
|
||||||
Fix activation order when removing merged snapshot.
|
Fix activation order when removing merged snapshot.
|
||||||
Experimental VDO support for lvmdbusd.
|
|
||||||
|
|
||||||
Version 2.03.06 - 23rd October 2019
|
|
||||||
===================================
|
|
||||||
Add _cpool suffix to cache-pool LV name when used by caching LV.
|
|
||||||
No longer store extra UUID for cmeta and cdata cachevol layer.
|
|
||||||
Enhance activation of cache devices with cachevols.
|
|
||||||
Add _cvol in list of protected suffixes and start use it with DM UUID.
|
|
||||||
Rename LV converted to cachevol to use _cvol suffix.
|
|
||||||
Use normal LVs for wiping of cachevols.
|
|
||||||
Reload cleanered cache DM only with cleaner policy.
|
|
||||||
Fix cmd return when zeroing of cachevol fails.
|
|
||||||
Extend lvs to show all VDO properties.
|
|
||||||
Preserve VDO write policy with vdopool.
|
|
||||||
Increase default vdo bio threads to 4.
|
|
||||||
Continue report when cache_status fails.
|
|
||||||
Add support for DM_DEVICE_GET_TARGET_VERSION into device_mapper.
|
Add support for DM_DEVICE_GET_TARGET_VERSION into device_mapper.
|
||||||
Fix cmirrord usage of header files from device_mapper subdir.
|
Add lvextend-raid.sh to check on RaidLV extensions synchronization.
|
||||||
Allow standalone activation of VDO pool just like for thin-pools.
|
Fix lvmetad shutdown and avoid lenghty timeouts when rebooting system.
|
||||||
|
Prevent creating VGs with PVs with different logical block sizes.
|
||||||
|
Pvmove runs in exlusively activating mode for exclusively active LVs.
|
||||||
Activate thin-pool layered volume as 'read-only' device.
|
Activate thin-pool layered volume as 'read-only' device.
|
||||||
Ignore crypto devices with UUID signature CRYPT-SUBDEV.
|
Ignore crypto devices with UUID signature CRYPT-SUBDEV.
|
||||||
Enhance validation for thin and cache pool conversion and swapping.
|
Enhance validation for thin and cache pool conversion and swapping.
|
||||||
|
Fixed activation on boot - lvm2 no longer activates incomplete VGs.
|
||||||
|
|
||||||
|
Version 2.02.186 - 27th August 2019
|
||||||
|
===================================
|
||||||
Improve internal removal of cached devices.
|
Improve internal removal of cached devices.
|
||||||
Synchronize with udev when dropping snapshot.
|
Synchronize with udev when dropping snapshot.
|
||||||
Add missing device synchronization point before removing pvmove node.
|
Add missing device synchronization point before removing pvmove node.
|
||||||
Correctly set read_ahead for LVs when pvmove is finished.
|
Correctly set read_ahead for LVs when pvmove is finished.
|
||||||
Remove unsupported OPTIONS+="event_timeout" udev rule from 11-dm-lvm.rules.
|
|
||||||
Prevent creating VGs with PVs with different logical block sizes.
|
|
||||||
Fix metadata writes from corrupting with large physical block size.
|
Fix metadata writes from corrupting with large physical block size.
|
||||||
|
|
||||||
Version 2.03.05 - 15th June 2019
|
|
||||||
================================
|
|
||||||
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.
|
Report no_discard_passdown for cache LVs with lvs -o+kernel_discards.
|
||||||
Add pvck --dump option to extract metadata.
|
Prevent shared active mirror LVs with lvmlockd.
|
||||||
|
|
||||||
|
Version 2.02.185 - 13th May 2019
|
||||||
|
================================
|
||||||
|
Fix change of monitoring in clustered volumes.
|
||||||
|
Improve -lXXX%VG modifier which improves cache segment estimation.
|
||||||
|
Add synchronization with udev before removing cached devices.
|
||||||
|
Fix missing growth of _pmspare volume when extending _tmeta volume.
|
||||||
|
Automatically grow thin metadata, when thin data gets too big.
|
||||||
|
Add support for vgsplit with cached devices.
|
||||||
Fix signal delivery checking race in libdaemon (lvmetad).
|
Fix signal delivery checking race in libdaemon (lvmetad).
|
||||||
Add missing Before=shutdown.target to LVM2 services to fix shutdown ordering.
|
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.
|
Version 2.02.184 - 22nd March 2019
|
||||||
Add remote refresh through lvmlockd/dlm for shared LVs after lvextend.
|
==================================
|
||||||
Ignore foreign and shared PVs for pvscan online files.
|
Fix (de)activation of RaidLVs with visible SubLVs
|
||||||
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.
|
Change scan_lvs default to 0 so LVs are not scanned for PVs.
|
||||||
Thin-pool selects power-of-2 chunk size by default.
|
Add scan_lvs config setting to control if lvm scans LVs for PVs.
|
||||||
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 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.
|
Version 2.02.183 - 07th December 2018
|
||||||
|
=====================================
|
||||||
|
Avoid disabling lvmetad when repair does nothing.
|
||||||
|
Fix component detection for md version 0.90.
|
||||||
Use sync io if async io_setup fails, or use_aio=0 is set in config.
|
Use sync io if async io_setup fails, or use_aio=0 is set in config.
|
||||||
Fix more issues reported by coverity scan.
|
Avoid opening devices to get block size by using existing open fd.
|
||||||
|
|
||||||
Version 2.03.01 - 31st October 2018
|
Version 2.02.182 - 30th October 2018
|
||||||
===================================
|
====================================
|
||||||
|
Fix possible write race between last metadata block and the first extent.
|
||||||
Version 2.03.00 - 10th October 2018
|
Fix filtering of md 1.0 devices so they are not seen as duplicate PVs.
|
||||||
===================================
|
|
||||||
Add hot fix to avoiding locking collision when monitoring thin-pools.
|
|
||||||
Allow raid4 -> linear conversion request.
|
|
||||||
Fix lvconvert striped/raid0/raid0_meta -> raid6 regression.
|
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.
|
Add After=rbdmap.service to {lvm2-activation-net,blk-availability}.service.
|
||||||
|
Fix pvs with lvmetad to avoid too many open files from filter reads.
|
||||||
|
Fix pvscan --cache to avoid too many open files from filter reads.
|
||||||
Reduce max concurrent aios to avoid EMFILE with many devices.
|
Reduce max concurrent aios to avoid EMFILE with many devices.
|
||||||
Fix lvconvert conversion attempts to linear.
|
Fix lvconvert conversion attempts to linear.
|
||||||
Fix lvconvert raid0/raid0_meta -> striped regression.
|
Fix lvconvert raid0/raid0_meta -> striped regression.
|
||||||
Fix lvconvert --splitmirror for mirror type (2.02.178).
|
Fix lvconvert --splitmirror for mirror type (2.02.178).
|
||||||
Do not pair cache policy and cache metadata format.
|
Do not pair cache policy and cache metadata format.
|
||||||
lvconvert: reject conversions on raid1 LVs with split tracked SubLVs
|
Fix mirrors honoring read_only_volume_list.
|
||||||
lvconvert: reject conversions on raid1 split tracked SubLVs
|
|
||||||
Add basic creation support for VDO target.
|
Version 2.02.181 - 01 August 2018
|
||||||
|
=================================
|
||||||
|
Reject conversions on raid1 LVs with split tracked SubLVs.
|
||||||
|
Reject conversions on raid1 split tracked SubLVs.
|
||||||
|
Fix dmstats list failing when no regions exist.
|
||||||
|
Reject conversions of LVs under snapshot.
|
||||||
|
Limit suggested options on incorrect option for lvconvert subcommand.
|
||||||
|
|
||||||
|
Version 2.02.180 - 19th July 2018
|
||||||
|
=================================
|
||||||
Never send any discard ioctl with test mode.
|
Never send any discard ioctl with test mode.
|
||||||
Fix thin-pool alloc which needs same PV for data and metadata.
|
Fix thin-pool alloc which needs same PV for data and metadata.
|
||||||
Extend list of non-memlocked areas with newly linked libs.
|
Extend list of non-memlocked areas with newly linked libs.
|
||||||
Enhance vgcfgrestore to check for active LVs in restored VG.
|
Enhance vgcfgrestore to check for active LVs in restored VG.
|
||||||
Configure supports --disable-silent-rules for verbose builds.
|
lvconvert: provide possible layouts between linear and striped/raid
|
||||||
Fix unmonitoring of merging snapshots.
|
Fix unmonitoring of merging snapshots.
|
||||||
|
Add missing -l description in fsadm man page.
|
||||||
Cache can uses metadata format 2 with cleaner policy.
|
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.
|
Avoid showing internal error in lvs output or pvmoved LVs.
|
||||||
Remove clvmd
|
Fix check if resized PV can also fit metadata area.
|
||||||
Remove lvmlib (api)
|
Reopen devices RDWR only before writing to avoid udev issues.
|
||||||
Remove lvmetad
|
Change pvresize output confusing when no resize took place.
|
||||||
|
Fix lvmetad hanging on shutdown.
|
||||||
|
Fix mem leak in clvmd and more coverity issues.
|
||||||
|
|
||||||
|
Version 2.02.179 - 18th June 2018
|
||||||
|
=================================
|
||||||
|
Allow forced vgchange to lock type none on clustered VG.
|
||||||
|
Add the report field "shared".
|
||||||
|
Enable automatic metadata consistency repair on a shared VG.
|
||||||
|
Fix pvremove force on a PV with a shared VG.
|
||||||
|
Fixed vgimportclone of a PV with a shared VG.
|
||||||
|
Enable previously disallowed thin/cache commands in shared VGs.
|
||||||
|
Enable metadata-related changes on LVs active with shared lock.
|
||||||
|
Do not continue trying to use a device that cannot be opened.
|
||||||
|
Fix problems opening a device that fails and returns.
|
||||||
Use versionsort to fix archive file expiry beyond 100000 files.
|
Use versionsort to fix archive file expiry beyond 100000 files.
|
||||||
|
|
||||||
|
Version 2.02.178 - 13th June 2018
|
||||||
|
=================================
|
||||||
|
|
||||||
Version 2.02.178-rc1 - 24th May 2018
|
Version 2.02.178-rc1 - 24th May 2018
|
||||||
====================================
|
====================================
|
||||||
Add libaio dependency for build.
|
Add libaio dependency for build.
|
||||||
@@ -1827,7 +1664,7 @@ Version 2.02.105 - 20th January 2014
|
|||||||
Allow lvmetad to reuse stale socket.
|
Allow lvmetad to reuse stale socket.
|
||||||
Only unlink lvmetad socket on error if created by the same process.
|
Only unlink lvmetad socket on error if created by the same process.
|
||||||
Append missing newline to lvmetad missing socket path error message.
|
Append missing newline to lvmetad missing socket path error message.
|
||||||
Check for non-zero alignment in _text_pv_add_metadata_area() to not div by 0.
|
Check for non-zero aligment in _text_pv_add_metadata_area() to not div by 0.
|
||||||
Add allocation/use_blkid_wiping to lvm.conf to enable blkid wiping.
|
Add allocation/use_blkid_wiping to lvm.conf to enable blkid wiping.
|
||||||
Enable blkid_wiping by default if the blkid library is present.
|
Enable blkid_wiping by default if the blkid library is present.
|
||||||
Add configure --disable-blkid_wiping to disable libblkid signature detection.
|
Add configure --disable-blkid_wiping to disable libblkid signature detection.
|
||||||
|
|||||||
73
WHATS_NEW_DM
73
WHATS_NEW_DM
@@ -1,75 +1,36 @@
|
|||||||
Version 1.02.185 -
|
Version 1.02.172 - 07th May 2021
|
||||||
=====================================
|
|
||||||
|
|
||||||
Version 1.02.183 - 07th February 2022
|
|
||||||
=====================================
|
|
||||||
Unmangle UUIDs for DM_DEVICE_LIST ioctl.
|
|
||||||
|
|
||||||
Version 1.02.181 - 20th October 2021
|
|
||||||
====================================
|
|
||||||
Add IMA support with 'dmsetup measure' command.
|
|
||||||
Add defines DM_NAME_LIST_FLAG_HAS_UUID, DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID.
|
|
||||||
Enhance tracking of activated devices when preloading dm tree.
|
|
||||||
Fix bug in construction of cache table line (regression from 1.02.159).
|
|
||||||
|
|
||||||
Version 1.02.179 - 11th August 2021
|
|
||||||
===================================
|
|
||||||
|
|
||||||
Version 1.02.177 - 07th May 2021
|
|
||||||
================================
|
================================
|
||||||
Configure proceeds without libaio to allow build of device-mapper only.
|
|
||||||
Fix symbol versioning build with -O2 -flto.
|
|
||||||
Add dm_tree_node_add_thin_pool_target_v1 with crop_metadata support.
|
Add dm_tree_node_add_thin_pool_target_v1 with crop_metadata support.
|
||||||
|
|
||||||
Version 1.02.175 - 08th January 2021
|
|
||||||
====================================
|
|
||||||
|
|
||||||
Version 1.02.173 - 09th August 2020
|
|
||||||
===================================
|
|
||||||
Add support for VDO in blkdeactivate script.
|
Add support for VDO in blkdeactivate script.
|
||||||
|
|
||||||
Version 1.02.171 - 26th March 2020
|
|
||||||
==================================
|
|
||||||
Try to remove all created devices on dm preload tree error path.
|
Try to remove all created devices on dm preload tree error path.
|
||||||
Fix dm_list interators with gcc 10 optimization (-ftree-pta).
|
Fix dm_list interators with gcc 10 optimization (-ftree-pta).
|
||||||
Dmeventd handles timer without looping on short intervals.
|
Dmeventd handles timer without looping on short intervals.
|
||||||
|
|
||||||
Version 1.02.169 - 11th February 2020
|
Version 1.02.170 - 24th March 2020
|
||||||
=====================================
|
==================================
|
||||||
Enhance error messages for device creation.
|
|
||||||
|
|
||||||
Version 1.02.167 - 30th November 2019
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
Version 1.02.165 - 23rd October 2019
|
|
||||||
====================================
|
|
||||||
Add support for DM_DEVICE_GET_TARGET_VERSION.
|
Add support for DM_DEVICE_GET_TARGET_VERSION.
|
||||||
|
|
||||||
|
Version 1.02.164 - 27th August 2019
|
||||||
|
===================================
|
||||||
Add debug of dmsetup udevcomplete with hexa print DM_COOKIE_COMPLETED.
|
Add debug of dmsetup udevcomplete with hexa print DM_COOKIE_COMPLETED.
|
||||||
Fix versioning of dm_stats_create_region and dm_stats_create_region.
|
Fix versioning of dm_stats_create_region and dm_stats_create_region.
|
||||||
|
|
||||||
Version 1.02.163 - 15th June 2019
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.161 - 10th June 2019
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Version 1.02.159 - 07th June 2019
|
|
||||||
=================================
|
|
||||||
Parsing of cache status understand no_discard_passdown.
|
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
|
Version 1.02.158 - 13th May 2019
|
||||||
=====================================
|
================================
|
||||||
Include correct internal header inside libdm list.c.
|
|
||||||
|
Version 1.02.156 - 22nd March 2019
|
||||||
|
==================================
|
||||||
|
Ensure migration_threshold for cache is at least 8 chunks.
|
||||||
Enhance ioctl flattening and add parameters only when needed.
|
Enhance ioctl flattening and add parameters only when needed.
|
||||||
Add DM_DEVICE_ARM_POLL for API completness matching kernel.
|
Add DM_DEVICE_ARM_POLL for API completness matching kernel.
|
||||||
|
|
||||||
|
Version 1.02.154 - 07th December 2018
|
||||||
|
=====================================
|
||||||
Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
|
Do not add parameters for RESUME with DM_DEVICE_CREATE dm task.
|
||||||
Fix dmstats report printing no output.
|
Fix dmstats report printing no output.
|
||||||
|
|
||||||
Version 1.02.153 - 31st October 2018
|
Version 1.02.152 - 30th October 2018
|
||||||
====================================
|
|
||||||
|
|
||||||
Version 1.02.151 - 10th October 2018
|
|
||||||
====================================
|
====================================
|
||||||
Add hot fix to avoiding locking collision when monitoring thin-pools.
|
Add hot fix to avoiding locking collision when monitoring thin-pools.
|
||||||
|
|
||||||
@@ -574,7 +535,7 @@ Version 1.02.86 - 23rd June 2014
|
|||||||
Add DM_REPORT_FIELD_TYPE_STRING_LIST: separate string and string list fields.
|
Add DM_REPORT_FIELD_TYPE_STRING_LIST: separate string and string list fields.
|
||||||
Add dm_str_list to libdevmapper for string list type definition and its reuse.
|
Add dm_str_list to libdevmapper for string list type definition and its reuse.
|
||||||
Add dmsetup -S/--select to define selection criteria for dmsetup reports.
|
Add dmsetup -S/--select to define selection criteria for dmsetup reports.
|
||||||
Add dm_report_init_with_selection to initialize report with selection criteria.
|
Add dm_report_init_with_selection to intialize report with selection criteria.
|
||||||
Add DM_REPORT_FIELD_TYPE_SIZE: separate number and size reporting fields.
|
Add DM_REPORT_FIELD_TYPE_SIZE: separate number and size reporting fields.
|
||||||
Use RemoveOnStop for dm-event.socket systemd unit.
|
Use RemoveOnStop for dm-event.socket systemd unit.
|
||||||
Document env var 'DM_DEFAULT_NAME_MANGLING_MODE' in dmsetup man page.
|
Document env var 'DM_DEFAULT_NAME_MANGLING_MODE' in dmsetup man page.
|
||||||
|
|||||||
10
aclocal.m4
vendored
10
aclocal.m4
vendored
@@ -496,14 +496,12 @@ AC_DEFUN([AM_PATH_PYTHON],
|
|||||||
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
|
||||||
else
|
else
|
||||||
|
|
||||||
dnl Query Python for its version number. Although site.py simply uses
|
dnl Query Python for its version number. Getting [:3] seems to be
|
||||||
dnl sys.version[:3], printing that failed with Python 3.10, since the
|
dnl the best way to do this; it's what "site.py" does in the standard
|
||||||
dnl trailing zero was eliminated. So now we output just the major
|
dnl library.
|
||||||
dnl and minor version numbers, as numbers. Apparently the tertiary
|
|
||||||
dnl version is not of interest.
|
|
||||||
|
|
||||||
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
|
||||||
[am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`])
|
[am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`])
|
||||||
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
|
||||||
|
|
||||||
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
dnl Use the values of $prefix and $exec_prefix for the corresponding
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
# which defined all top_* variables
|
# which defined all top_* variables
|
||||||
|
|
||||||
BASE_SOURCE=\
|
BASE_SOURCE=\
|
||||||
base/data-struct/hash.c \
|
|
||||||
base/data-struct/list.c \
|
|
||||||
base/data-struct/radix-tree.c
|
base/data-struct/radix-tree.c
|
||||||
|
|
||||||
BASE_TARGET = base/libbase.a
|
BASE_TARGET = base/libbase.a
|
||||||
@@ -35,6 +33,12 @@ $(BASE_TARGET): $(BASE_OBJECTS)
|
|||||||
$(Q) $(RM) $@
|
$(Q) $(RM) $@
|
||||||
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
$(Q) $(AR) rsv $@ $(BASE_OBJECTS) > /dev/null
|
||||||
|
|
||||||
|
ifneq (,$(findstring $(MAKECMDGOALS),clean distclean))
|
||||||
|
BASE_SOURCE += \
|
||||||
|
base/data-struct/hash.c \
|
||||||
|
base/data-struct/list.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ("$(DEPENDS)","yes")
|
ifeq ("$(DEPENDS)","yes")
|
||||||
-include $(BASE_DEPENDS)
|
-include $(BASE_DEPENDS)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,477 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
unsigned hash;
|
|
||||||
char key[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dm_hash_table {
|
|
||||||
unsigned num_nodes;
|
|
||||||
unsigned num_hint;
|
|
||||||
unsigned mask_slots; /* (slots - 1) -> used as hash mask */
|
|
||||||
unsigned collisions; /* Collissions of hash keys */
|
|
||||||
unsigned search; /* How many keys were searched */
|
|
||||||
unsigned found; /* How many nodes were found */
|
|
||||||
unsigned same_hash; /* Was there a colision with same masked hash and len ? */
|
|
||||||
struct dm_hash_node **slots;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if 0 /* TO BE REMOVED */
|
|
||||||
static unsigned _hash(const void *key, unsigned len)
|
|
||||||
{
|
|
||||||
/* 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
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t *str = key;
|
|
||||||
unsigned h = 0, g;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
h <<= 4;
|
|
||||||
h += _nums[*str++];
|
|
||||||
g = h & ((unsigned) 0xf << 16u);
|
|
||||||
if (g) {
|
|
||||||
h ^= g >> 16u;
|
|
||||||
h ^= g >> 5u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In-kernel DM hashing, still lots of collisions */
|
|
||||||
static unsigned _hash_in_kernel(const char *key, unsigned len)
|
|
||||||
{
|
|
||||||
const unsigned char *str = (unsigned char *)key;
|
|
||||||
const unsigned hash_mult = 2654435387U;
|
|
||||||
unsigned hash = 0, i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; ++i)
|
|
||||||
hash = (hash + str[i]) * hash_mult;
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef get16bits
|
|
||||||
#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
|
|
||||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined (get16bits)
|
|
||||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
|
||||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adapted Bob Jenkins hash to read by 2 bytes if possible.
|
|
||||||
* https://secure.wikimedia.org/wikipedia/en/wiki/Jenkins_hash_function
|
|
||||||
*
|
|
||||||
* Reduces amount of hash collisions
|
|
||||||
*/
|
|
||||||
static unsigned _hash(const void *key, unsigned len)
|
|
||||||
{
|
|
||||||
const uint8_t *str = (uint8_t*) key;
|
|
||||||
unsigned hash = 0, i;
|
|
||||||
unsigned sz = len / 2;
|
|
||||||
|
|
||||||
for(i = 0; i < sz; ++i) {
|
|
||||||
hash += get16bits(str + 2 * i);
|
|
||||||
hash += (hash << 10);
|
|
||||||
hash ^= (hash >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len & 1) {
|
|
||||||
hash += str[len - 1];
|
|
||||||
hash += (hash << 10);
|
|
||||||
hash ^= (hash >> 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
hash += (hash << 3);
|
|
||||||
hash ^= (hash >> 11);
|
|
||||||
hash += (hash << 15);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dm_hash_node *_create_node(const void *key, unsigned len)
|
|
||||||
{
|
|
||||||
struct dm_hash_node *n = malloc(sizeof(*n) + len);
|
|
||||||
|
|
||||||
if (n) {
|
|
||||||
memcpy(n->key, key, len);
|
|
||||||
n->keylen = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
log_error("Failed to allocate memory for hash.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hc->num_hint = size_hint;
|
|
||||||
|
|
||||||
/* round size hint up to a power of two */
|
|
||||||
while (new_size < size_hint)
|
|
||||||
new_size = new_size << 1;
|
|
||||||
|
|
||||||
hc->mask_slots = new_size - 1;
|
|
||||||
len = sizeof(*(hc->slots)) * new_size;
|
|
||||||
if (!(hc->slots = zalloc(len))) {
|
|
||||||
free(hc);
|
|
||||||
log_error("Failed to allocate slots for hash.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _free_nodes(struct dm_hash_table *t)
|
|
||||||
{
|
|
||||||
struct dm_hash_node *c, *n;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
log_debug("Free hash hint:%d slots:%d nodes:%d (s:%d f:%d c:%d h:%d)",
|
|
||||||
t->num_hint, t->mask_slots + 1, t->num_nodes,
|
|
||||||
t->search, t->found, t->collisions, t->same_hash);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!t->num_nodes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i <= t->mask_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 **_findh(struct dm_hash_table *t, const void *key,
|
|
||||||
uint32_t len, unsigned hash)
|
|
||||||
{
|
|
||||||
struct dm_hash_node **c;
|
|
||||||
|
|
||||||
++t->search;
|
|
||||||
for (c = &t->slots[hash & t->mask_slots]; *c; c = &((*c)->next)) {
|
|
||||||
if ((*c)->keylen == len && (*c)->hash == hash) {
|
|
||||||
if (!memcmp(key, (*c)->key, len)) {
|
|
||||||
++t->found;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++t->same_hash;
|
|
||||||
}
|
|
||||||
++t->collisions;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const void *key,
|
|
||||||
uint32_t len)
|
|
||||||
{
|
|
||||||
return _findh(t, key, len, _hash(key, len));
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
unsigned hash = _hash(key, len);
|
|
||||||
struct dm_hash_node **c = _findh(t, key, len, hash);
|
|
||||||
|
|
||||||
if (*c)
|
|
||||||
(*c)->data = data;
|
|
||||||
else {
|
|
||||||
struct dm_hash_node *n = _create_node(key, len);
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
n->data = data;
|
|
||||||
n->hash = hash;
|
|
||||||
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->mask_slots;
|
|
||||||
|
|
||||||
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->mask_slots;
|
|
||||||
|
|
||||||
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->mask_slots;
|
|
||||||
|
|
||||||
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->mask_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->mask_slots + 1));
|
|
||||||
t->num_nodes = t->collisions = t->search = t->same_hash = 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->mask_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)
|
|
||||||
{
|
|
||||||
return n->next ? n->next : _next_slot(t, (n->hash & t->mask_slots) + 1);
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
#ifndef BASE_DATA_STRUCT_LIST_H
|
|
||||||
#define BASE_DATA_STRUCT_LIST_H
|
|
||||||
|
|
||||||
#include "base/memory/container_of.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) \
|
|
||||||
container_of(v, t, 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) - offsetof(t, 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
|
|
||||||
@@ -14,12 +14,16 @@
|
|||||||
#define BASE_MEMORY_ZALLOC_H
|
#define BASE_MEMORY_ZALLOC_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
static inline void *zalloc(size_t len)
|
static inline void *zalloc(size_t len)
|
||||||
{
|
{
|
||||||
return calloc(1, len);
|
void *ptr = malloc(len);
|
||||||
|
if (ptr)
|
||||||
|
memset(ptr, 0, len);
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is part of LVM2.
|
# This file is part of LVM2.
|
||||||
#
|
#
|
||||||
@@ -25,7 +25,6 @@ PROFILES=$(PROFILE_TEMPLATES) \
|
|||||||
$(srcdir)/cache-smq.profile \
|
$(srcdir)/cache-smq.profile \
|
||||||
$(srcdir)/thin-generic.profile \
|
$(srcdir)/thin-generic.profile \
|
||||||
$(srcdir)/thin-performance.profile \
|
$(srcdir)/thin-performance.profile \
|
||||||
$(srcdir)/vdo-small.profile \
|
|
||||||
$(srcdir)/lvmdbusd.profile
|
$(srcdir)/lvmdbusd.profile
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
@@ -33,8 +32,8 @@ include $(top_builddir)/make.tmpl
|
|||||||
.PHONY: install_conf install_localconf install_profiles
|
.PHONY: install_conf install_localconf install_profiles
|
||||||
|
|
||||||
generate:
|
generate:
|
||||||
$(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 --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
|
||||||
$(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --withcomments --withspaces local > lvmlocal.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
|
||||||
|
|
||||||
install_conf: $(CONFSRC)
|
install_conf: $(CONFSRC)
|
||||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||||
@@ -49,9 +48,8 @@ install_localconf: $(CONFLOCAL)
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
install_profiles: $(PROFILES)
|
install_profiles: $(PROFILES)
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_DIR) $(profiledir)
|
||||||
$(Q) $(INSTALL_DIR) $(profiledir)
|
$(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
||||||
$(Q) $(INSTALL_DATA) $(PROFILES) $(profiledir)/
|
|
||||||
|
|
||||||
install_lvm2: install_conf install_localconf install_profiles
|
install_lvm2: install_conf install_localconf install_profiles
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
|||||||
# 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
|
|
||||||
}
|
|
||||||
969
configure.ac
969
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,11 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
.PHONY: dmeventd cmirrord lvmpolld lvmlockd
|
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
|
||||||
|
|
||||||
|
ifneq ("@CLVMD@", "none")
|
||||||
|
SUBDIRS += clvmd
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ("@BUILD_CMIRRORD@", "yes")
|
ifeq ("@BUILD_CMIRRORD@", "yes")
|
||||||
SUBDIRS += cmirrord
|
SUBDIRS += cmirrord
|
||||||
@@ -28,6 +32,10 @@ daemons.cflow: dmeventd.cflow
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_LVMETAD@", "yes")
|
||||||
|
SUBDIRS += lvmetad
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||||
SUBDIRS += lvmpolld
|
SUBDIRS += lvmpolld
|
||||||
endif
|
endif
|
||||||
@@ -40,8 +48,12 @@ ifeq ("@BUILD_LVMDBUSD@", "yes")
|
|||||||
SUBDIRS += lvmdbusd
|
SUBDIRS += lvmdbusd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@BUILD_DMFILEMAPD@", "yes")
|
||||||
|
SUBDIRS += dmfilemapd
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),distclean)
|
ifeq ($(MAKECMDGOALS),distclean)
|
||||||
SUBDIRS = cmirrord dmeventd lvmpolld lvmlockd lvmdbusd
|
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|||||||
1
daemons/clvmd/.gitignore
vendored
Normal file
1
daemons/clvmd/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
clvmd
|
||||||
94
daemons/clvmd/Makefile.in
Normal file
94
daemons/clvmd/Makefile.in
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#
|
||||||
|
# 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)
|
||||||
85
daemons/clvmd/clvm.h
Normal file
85
daemons/clvmd/clvm.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
505
daemons/clvmd/clvmd-cman.c
Normal file
505
daemons/clvmd/clvmd-cman.c
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
415
daemons/clvmd/clvmd-command.c
Normal file
415
daemons/clvmd/clvmd-command.c
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* 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,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is part of LVM2.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
@@ -12,11 +12,16 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LIBDM_KDEV_H
|
/*
|
||||||
#define _LIBDM_KDEV_H
|
* This file must be included first by every clvmd source file.
|
||||||
|
*/
|
||||||
|
#ifndef _LVM_CLVMD_COMMON_H
|
||||||
|
#define _LVM_CLVMD_COMMON_H
|
||||||
|
|
||||||
#define MAJOR(dev) ((dev & 0xfff00) >> 8)
|
#define _REENTRANT
|
||||||
#define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
|
|
||||||
#define MKDEV(ma,mi) (((dev_t)mi & 0xff) | ((dev_t)ma << 8) | (((dev_t)mi & ~0xff) << 12))
|
#include "tool.h"
|
||||||
|
|
||||||
|
#include "lvm-logging.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
119
daemons/clvmd/clvmd-comms.h
Normal file
119
daemons/clvmd/clvmd-comms.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
662
daemons/clvmd/clvmd-corosync.c
Normal file
662
daemons/clvmd/clvmd-corosync.c
Normal file
@@ -0,0 +1,662 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
687
daemons/clvmd/clvmd-openais.c
Normal file
687
daemons/clvmd/clvmd-openais.c
Normal file
@@ -0,0 +1,687 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
382
daemons/clvmd/clvmd-singlenode.c
Normal file
382
daemons/clvmd/clvmd-singlenode.c
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
2424
daemons/clvmd/clvmd.c
Normal file
2424
daemons/clvmd/clvmd.c
Normal file
File diff suppressed because it is too large
Load Diff
126
daemons/clvmd/clvmd.h
Normal file
126
daemons/clvmd/clvmd.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
927
daemons/clvmd/lvm-functions.c
Normal file
927
daemons/clvmd/lvm-functions.c
Normal file
@@ -0,0 +1,927 @@
|
|||||||
|
/*
|
||||||
|
* 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, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
daemons/clvmd/lvm-functions.h
Normal file
40
daemons/clvmd/lvm-functions.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
382
daemons/clvmd/refresh_clvmd.c
Normal file
382
daemons/clvmd/refresh_clvmd.c
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
19
daemons/clvmd/refresh_clvmd.h
Normal file
19
daemons/clvmd/refresh_clvmd.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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,27 +17,23 @@ top_builddir = @top_builddir@
|
|||||||
|
|
||||||
CPG_LIBS = @CPG_LIBS@
|
CPG_LIBS = @CPG_LIBS@
|
||||||
CPG_CFLAGS = @CPG_CFLAGS@
|
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
|
SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
|
||||||
|
|
||||||
TARGETS = cmirrord
|
TARGETS = cmirrord
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
|
||||||
CFLOW_TARGET := $(TARGETS)
|
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
LMLIBS += $(CPG_LIBS)
|
LIBS += -ldevmapper
|
||||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
|
||||||
|
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
|
|
||||||
cmirrord: $(OBJECTS)
|
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||||
@echo " [CC] $@"
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
$(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||||
$(LMLIBS) -L$(top_builddir)/libdm -ldevmapper $(LIBS)
|
|
||||||
|
|
||||||
install_cluster: $(TARGETS)
|
install: $(TARGETS)
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D cmirrord $(usrsbindir)/cmirrord
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(usrsbindir)/$(<F)
|
|
||||||
|
|
||||||
install: install_cluster
|
|
||||||
|
|||||||
@@ -245,7 +245,6 @@ static void daemonize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
||||||
/* coverity[leaked_handle] devnull cannot leak here */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -16,11 +16,7 @@
|
|||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "link_mon.h"
|
#include "link_mon.h"
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
#include "lib/mm/xlate.h"
|
#include "xlate.h"
|
||||||
#include "base/memory/zalloc.h"
|
|
||||||
|
|
||||||
/* FIXME: remove this and the code */
|
|
||||||
#define CMIRROR_HAS_CHECKPOINT 0
|
|
||||||
|
|
||||||
#include <corosync/cpg.h>
|
#include <corosync/cpg.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -108,7 +104,7 @@ static SaVersionT version = { 'B', 1, 1 };
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUGGING_HISTORY 100
|
#define DEBUGGING_HISTORY 100
|
||||||
#define DEBUGGING_BUFLEN 270
|
#define DEBUGGING_BUFLEN 128
|
||||||
#define LOG_SPRINT(cc, f, arg...) do { \
|
#define LOG_SPRINT(cc, f, arg...) do { \
|
||||||
cc->idx++; \
|
cc->idx++; \
|
||||||
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
||||||
@@ -403,12 +399,13 @@ static struct checkpoint_data *prepare_checkpoint(struct clog_cpg *entry,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = zalloc(sizeof(*new));
|
new = malloc(sizeof(*new));
|
||||||
if (!new) {
|
if (!new) {
|
||||||
LOG_ERROR("Unable to create checkpoint data for %u",
|
LOG_ERROR("Unable to create checkpoint data for %u",
|
||||||
cp_requester);
|
cp_requester);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
new->requester = cp_requester;
|
new->requester = cp_requester;
|
||||||
strncpy(new->uuid, entry->name.value, entry->name.length);
|
strncpy(new->uuid, entry->name.value, entry->name.length);
|
||||||
|
|
||||||
@@ -643,12 +640,13 @@ static int export_checkpoint(struct checkpoint_data *cp)
|
|||||||
rq_size += RECOVERING_REGION_SECTION_SIZE;
|
rq_size += RECOVERING_REGION_SECTION_SIZE;
|
||||||
rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
|
rq_size += cp->bitmap_size * 2; /* clean|sync_bits */
|
||||||
|
|
||||||
rq = zalloc(rq_size);
|
rq = malloc(rq_size);
|
||||||
if (!rq) {
|
if (!rq) {
|
||||||
LOG_ERROR("export_checkpoint: "
|
LOG_ERROR("export_checkpoint: "
|
||||||
"Unable to allocate transfer structs");
|
"Unable to allocate transfer structs");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
memset(rq, 0, rq_size);
|
||||||
|
|
||||||
dm_list_init(&rq->u.list);
|
dm_list_init(&rq->u.list);
|
||||||
rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
|
rq->u_rq.request_type = DM_ULOG_CHECKPOINT_READY;
|
||||||
@@ -1383,7 +1381,7 @@ static void cpg_leave_callback(struct clog_cpg *match,
|
|||||||
size_t member_list_entries)
|
size_t member_list_entries)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
int j, fd = -1;
|
int j, fd;
|
||||||
uint32_t lowest = match->lowest_id;
|
uint32_t lowest = match->lowest_id;
|
||||||
struct clog_request *rq, *n;
|
struct clog_request *rq, *n;
|
||||||
struct checkpoint_data *p_cp, *c_cp;
|
struct checkpoint_data *p_cp, *c_cp;
|
||||||
@@ -1548,7 +1546,7 @@ static void cpg_config_callback(cpg_handle_t handle, const struct cpg_name *gnam
|
|||||||
member_list, member_list_entries);
|
member_list, member_list_entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static cpg_callbacks_t cpg_callbacks = {
|
cpg_callbacks_t cpg_callbacks = {
|
||||||
.cpg_deliver_fn = cpg_message_callback,
|
.cpg_deliver_fn = cpg_message_callback,
|
||||||
.cpg_confchg_fn = cpg_config_callback,
|
.cpg_confchg_fn = cpg_config_callback,
|
||||||
};
|
};
|
||||||
@@ -1620,11 +1618,12 @@ int create_cluster_cpg(char *uuid, uint64_t luid)
|
|||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = zalloc(sizeof(*new));
|
new = malloc(sizeof(*new));
|
||||||
if (!new) {
|
if (!new) {
|
||||||
LOG_ERROR("Unable to allocate memory for clog_cpg");
|
LOG_ERROR("Unable to allocate memory for clog_cpg");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
memset(new, 0, sizeof(*new));
|
||||||
dm_list_init(&new->list);
|
dm_list_init(&new->list);
|
||||||
new->lowest_id = 0xDEAD;
|
new->lowest_id = 0xDEAD;
|
||||||
dm_list_init(&new->startup_list);
|
dm_list_init(&new->startup_list);
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
#ifndef _LVM_CLOG_CLUSTER_H
|
#ifndef _LVM_CLOG_CLUSTER_H
|
||||||
#define _LVM_CLOG_CLUSTER_H
|
#define _LVM_CLOG_CLUSTER_H
|
||||||
|
|
||||||
#include "libdm/libdevmapper.h"
|
#include "dm-log-userspace.h"
|
||||||
#include "libdm/misc/dm-log-userspace.h"
|
#include "libdevmapper.h"
|
||||||
|
|
||||||
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
#define DM_ULOG_RESPONSE 0x1000U /* in last byte of 32-bit value */
|
||||||
#define DM_ULOG_CHECKPOINT_READY 21
|
#define DM_ULOG_CHECKPOINT_READY 21
|
||||||
@@ -39,7 +39,7 @@ struct clog_request {
|
|||||||
* machine. If the two are equal, there is no need
|
* machine. If the two are equal, there is no need
|
||||||
* to do endian conversions.
|
* to do endian conversions.
|
||||||
*/
|
*/
|
||||||
union version_u {
|
union {
|
||||||
uint64_t version[2]; /* LE version and native version */
|
uint64_t version[2]; /* LE version and native version */
|
||||||
struct dm_list list;
|
struct dm_list list;
|
||||||
} u;
|
} u;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "cluster.h"
|
#include "cluster.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "lib/mm/xlate.h"
|
#include "xlate.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "base/memory/zalloc.h"
|
|
||||||
|
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@@ -34,7 +33,7 @@
|
|||||||
#define LOG_OFFSET 2
|
#define LOG_OFFSET 2
|
||||||
|
|
||||||
#define RESYNC_HISTORY 50
|
#define RESYNC_HISTORY 50
|
||||||
#define RESYNC_BUFLEN 270
|
#define RESYNC_BUFLEN 128
|
||||||
//static char resync_history[RESYNC_HISTORY][128];
|
//static char resync_history[RESYNC_HISTORY][128];
|
||||||
//static int idx = 0;
|
//static int idx = 0;
|
||||||
#define LOG_SPRINT(_lc, f, arg...) do { \
|
#define LOG_SPRINT(_lc, f, arg...) do { \
|
||||||
@@ -378,7 +377,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
uint32_t block_on_error = 0;
|
uint32_t block_on_error = 0;
|
||||||
|
|
||||||
int disk_log;
|
int disk_log;
|
||||||
char disk_path[PATH_MAX] = { 0 };
|
char disk_path[PATH_MAX];
|
||||||
int unlink_path = 0;
|
int unlink_path = 0;
|
||||||
long page_size;
|
long page_size;
|
||||||
int pages;
|
int pages;
|
||||||
@@ -436,7 +435,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
|
|||||||
block_on_error = 1;
|
block_on_error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lc = zalloc(sizeof(*lc));
|
lc = dm_zalloc(sizeof(*lc));
|
||||||
if (!lc) {
|
if (!lc) {
|
||||||
LOG_ERROR("Unable to allocate cluster log context");
|
LOG_ERROR("Unable to allocate cluster log context");
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
@@ -533,9 +532,9 @@ fail:
|
|||||||
LOG_ERROR("Close device error, %s: %s",
|
LOG_ERROR("Close device error, %s: %s",
|
||||||
disk_path, strerror(errno));
|
disk_path, strerror(errno));
|
||||||
free(lc->disk_buffer);
|
free(lc->disk_buffer);
|
||||||
free(lc->sync_bits);
|
dm_free(lc->sync_bits);
|
||||||
free(lc->clean_bits);
|
dm_free(lc->clean_bits);
|
||||||
free(lc);
|
dm_free(lc);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -658,10 +657,11 @@ static int clog_dtr(struct dm_ulog_request *rq)
|
|||||||
if (lc->disk_fd != -1 && close(lc->disk_fd))
|
if (lc->disk_fd != -1 && close(lc->disk_fd))
|
||||||
LOG_ERROR("Failed to close disk log: %s",
|
LOG_ERROR("Failed to close disk log: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
if (lc->disk_buffer)
|
||||||
free(lc->disk_buffer);
|
free(lc->disk_buffer);
|
||||||
free(lc->clean_bits);
|
dm_free(lc->clean_bits);
|
||||||
free(lc->sync_bits);
|
dm_free(lc->sync_bits);
|
||||||
free(lc);
|
dm_free(lc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,7 @@
|
|||||||
#ifndef _LVM_CLOG_FUNCTIONS_H
|
#ifndef _LVM_CLOG_FUNCTIONS_H
|
||||||
#define _LVM_CLOG_FUNCTIONS_H
|
#define _LVM_CLOG_FUNCTIONS_H
|
||||||
|
|
||||||
#include "libdm/libdevmapper.h"
|
#include "dm-log-userspace.h"
|
||||||
#include "libdm/misc/dm-log-userspace.h"
|
|
||||||
#include "cluster.h"
|
#include "cluster.h"
|
||||||
|
|
||||||
#define LOG_RESUMED 1
|
#define LOG_RESUMED 1
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#ifndef _LVM_CLOG_LOGGING_H
|
#ifndef _LVM_CLOG_LOGGING_H
|
||||||
#define _LVM_CLOG_LOGGING_H
|
#define _LVM_CLOG_LOGGING_H
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "configure.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|||||||
@@ -14,21 +14,11 @@
|
|||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
abs_srcdir = @abs_srcdir@
|
|
||||||
|
|
||||||
SOURCES = libdevmapper-event.c
|
SOURCES = libdevmapper-event.c
|
||||||
SOURCES2 = dmeventd.c
|
SOURCES2 = dmeventd.c
|
||||||
|
|
||||||
TARGETS = dmeventd
|
TARGETS = dmeventd
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES) $(SOURCES2) \
|
|
||||||
plugins/lvm2/dmeventd_lvm.c \
|
|
||||||
plugins/mirror/dmeventd_mirror.c \
|
|
||||||
plugins/raid/dmeventd_raid.c \
|
|
||||||
plugins/snapshot/dmeventd_snapshot.c \
|
|
||||||
plugins/thin/dmeventd_thin.c \
|
|
||||||
plugins/vdo/dmeventd_vdo.c \
|
|
||||||
)
|
|
||||||
CFLOW_TARGET := $(TARGETS)
|
|
||||||
|
|
||||||
.PHONY: install_lib_dynamic install_lib_static install_include \
|
.PHONY: install_lib_dynamic install_lib_static install_include \
|
||||||
install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \
|
install_pkgconfig install_dmeventd_dynamic install_dmeventd_static \
|
||||||
@@ -47,7 +37,6 @@ endif
|
|||||||
|
|
||||||
LIB_VERSION = $(LIB_VERSION_DM)
|
LIB_VERSION = $(LIB_VERSION_DM)
|
||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIBS = $(PTHREAD_LIBS) -L$(interfacebuilddir) -ldevmapper
|
|
||||||
|
|
||||||
CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
|
CLEAN_TARGETS = dmeventd.static $(LIB_NAME).a
|
||||||
|
|
||||||
@@ -57,6 +46,7 @@ endif
|
|||||||
|
|
||||||
CFLOW_LIST = $(SOURCES)
|
CFLOW_LIST = $(SOURCES)
|
||||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
CFLOW_TARGET = dmeventd
|
||||||
|
|
||||||
EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
|
EXPORTED_HEADER = $(srcdir)/libdevmapper-event.h
|
||||||
EXPORTED_FN_PREFIX = dm_event
|
EXPORTED_FN_PREFIX = dm_event
|
||||||
@@ -65,47 +55,49 @@ include $(top_builddir)/make.tmpl
|
|||||||
|
|
||||||
all: device-mapper
|
all: device-mapper
|
||||||
device-mapper: $(TARGETS)
|
device-mapper: $(TARGETS)
|
||||||
plugins.device-mapper: $(LIB_SHARED)
|
|
||||||
|
|
||||||
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
|
||||||
|
LIBS += -ldevmapper $(PTHREAD_LIBS)
|
||||||
|
|
||||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||||
@echo " [CC] $@"
|
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
|
|
||||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
|
||||||
|
|
||||||
dmeventd.static: $(LIB_STATIC) dmeventd.o
|
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
|
||||||
@echo " [CC] $@"
|
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static dmeventd.o \
|
|
||||||
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
|
||||||
|
|
||||||
ifeq ("@PKGCONFIG@", "yes")
|
ifeq ("@PKGCONFIG@", "yes")
|
||||||
INSTALL_LIB_TARGETS += install_pkgconfig
|
INSTALL_LIB_TARGETS += install_pkgconfig
|
||||||
endif
|
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
|
||||||
|
-include $(top_builddir)/daemons/dmeventd/plugins/mirror/$(LIB_NAME)-lvm2mirror.cflow
|
||||||
|
endif
|
||||||
|
|
||||||
install_include: $(srcdir)/libdevmapper-event.h
|
install_include: $(srcdir)/libdevmapper-event.h
|
||||||
@echo " [INSTALL] $(<F)"
|
$(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
|
|
||||||
|
|
||||||
install_pkgconfig: libdevmapper-event.pc
|
install_pkgconfig: libdevmapper-event.pc
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(pkgconfigdir)/devmapper-event.pc
|
|
||||||
|
|
||||||
install_lib_dynamic: install_lib_shared
|
install_lib_dynamic: install_lib_shared
|
||||||
|
|
||||||
install_lib_static: $(LIB_STATIC)
|
install_lib_static: $(LIB_STATIC)
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
|
||||||
$(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/$(<F)
|
|
||||||
|
|
||||||
install_lib: $(INSTALL_LIB_TARGETS)
|
install_lib: $(INSTALL_LIB_TARGETS)
|
||||||
|
|
||||||
install_dmeventd_dynamic: dmeventd
|
install_dmeventd_dynamic: dmeventd
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_dmeventd_static: dmeventd.static
|
install_dmeventd_static: dmeventd.static
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
|
||||||
|
|
||||||
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
install_dmeventd: $(INSTALL_DMEVENTD_TARGETS)
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
* dmeventd - dm event daemon to monitor active mapped devices
|
* dmeventd - dm event daemon to monitor active mapped devices
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "dm-logging.h"
|
||||||
|
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
#include "dmeventd.h"
|
#include "dmeventd.h"
|
||||||
|
|
||||||
#include "libdm/misc/dm-logging.h"
|
#include "tool.h"
|
||||||
#include "base/memory/zalloc.h"
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@@ -33,8 +33,6 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||||
#include <fcntl.h> /* for musl libc */
|
#include <fcntl.h> /* for musl libc */
|
||||||
#include <unistd.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/*
|
/*
|
||||||
@@ -62,6 +60,8 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#define DM_SIGNALED_EXIT 1
|
#define DM_SIGNALED_EXIT 1
|
||||||
#define DM_SCHEDULED_EXIT 2
|
#define DM_SCHEDULED_EXIT 2
|
||||||
static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given to exit */
|
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. */
|
/* DSO data allocate/free. */
|
||||||
static void _free_dso_data(struct dso_data *data)
|
static void _free_dso_data(struct dso_data *data)
|
||||||
{
|
{
|
||||||
free(data->dso_name);
|
dm_free(data->dso_name);
|
||||||
free(data);
|
dm_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dso_data *_alloc_dso_data(struct message_data *data)
|
static struct dso_data *_alloc_dso_data(struct message_data *data)
|
||||||
{
|
{
|
||||||
struct dso_data *ret = (typeof(ret)) zalloc(sizeof(*ret));
|
struct dso_data *ret = (typeof(ret)) dm_zalloc(sizeof(*ret));
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return_NULL;
|
return_NULL;
|
||||||
|
|
||||||
if (!(ret->dso_name = strdup(data->dso_name))) {
|
if (!(ret->dso_name = dm_strdup(data->dso_name))) {
|
||||||
free(ret);
|
dm_free(ret);
|
||||||
return_NULL;
|
return_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,9 +397,9 @@ static void _free_thread_status(struct thread_status *thread)
|
|||||||
_lib_put(thread->dso_data);
|
_lib_put(thread->dso_data);
|
||||||
if (thread->wait_task)
|
if (thread->wait_task)
|
||||||
dm_task_destroy(thread->wait_task);
|
dm_task_destroy(thread->wait_task);
|
||||||
free(thread->device.uuid);
|
dm_free(thread->device.uuid);
|
||||||
free(thread->device.name);
|
dm_free(thread->device.name);
|
||||||
free(thread);
|
dm_free(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: events_field must not be 0, ensured by caller */
|
/* 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;
|
struct thread_status *thread;
|
||||||
|
|
||||||
if (!(thread = zalloc(sizeof(*thread)))) {
|
if (!(thread = dm_zalloc(sizeof(*thread)))) {
|
||||||
log_error("Cannot create new thread, out of memory.");
|
log_error("Cannot create new thread, out of memory.");
|
||||||
return NULL;
|
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))
|
if (!dm_task_set_uuid(thread->wait_task, data->device_uuid))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (!(thread->device.uuid = strdup(data->device_uuid)))
|
if (!(thread->device.uuid = dm_strdup(data->device_uuid)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
/* Until real name resolved, use UUID */
|
/* Until real name resolved, use UUID */
|
||||||
if (!(thread->device.name = strdup(data->device_uuid)))
|
if (!(thread->device.name = dm_strdup(data->device_uuid)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
/* runs ioctl and may register lvm2 pluging */
|
/* 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 ((p = strchr(*src, delimiter))) {
|
||||||
if (*src < p) {
|
if (*src < p) {
|
||||||
*p = 0; /* Temporary exit with \0 */
|
*p = 0; /* Temporary exit with \0 */
|
||||||
if (!(*ptr = strdup(*src))) {
|
if (!(*ptr = dm_strdup(*src))) {
|
||||||
log_error("Failed to fetch item %s.", *src);
|
log_error("Failed to fetch item %s.", *src);
|
||||||
ret = 0; /* Allocation fail */
|
ret = 0; /* Allocation fail */
|
||||||
}
|
}
|
||||||
@@ -525,7 +525,7 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
|
|||||||
(*src)++; /* Skip delmiter, next field */
|
(*src)++; /* Skip delmiter, next field */
|
||||||
} else if ((len = strlen(*src))) {
|
} else if ((len = strlen(*src))) {
|
||||||
/* No delimiter, item ends with '\0' */
|
/* No delimiter, item ends with '\0' */
|
||||||
if (!(*ptr = strdup(*src))) {
|
if (!(*ptr = dm_strdup(*src))) {
|
||||||
log_error("Failed to fetch last item %s.", *src);
|
log_error("Failed to fetch last item %s.", *src);
|
||||||
ret = 0; /* Fail */
|
ret = 0; /* Fail */
|
||||||
}
|
}
|
||||||
@@ -538,11 +538,11 @@ out:
|
|||||||
/* Free message memory. */
|
/* Free message memory. */
|
||||||
static void _free_message(struct message_data *message_data)
|
static void _free_message(struct message_data *message_data)
|
||||||
{
|
{
|
||||||
free(message_data->id);
|
dm_free(message_data->id);
|
||||||
free(message_data->dso_name);
|
dm_free(message_data->dso_name);
|
||||||
free(message_data->device_uuid);
|
dm_free(message_data->device_uuid);
|
||||||
free(message_data->events_str);
|
dm_free(message_data->events_str);
|
||||||
free(message_data->timeout_str);
|
dm_free(message_data->timeout_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a register message from the client. */
|
/* Parse a register message from the client. */
|
||||||
@@ -574,7 +574,7 @@ static int _parse_message(struct message_data *message_data)
|
|||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -608,8 +608,8 @@ static int _fill_device_data(struct thread_status *ts)
|
|||||||
if (!dm_task_run(dmt))
|
if (!dm_task_run(dmt))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
free(ts->device.name);
|
dm_free(ts->device.name);
|
||||||
if (!(ts->device.name = strdup(dm_task_get_name(dmt))))
|
if (!(ts->device.name = dm_strdup(dm_task_get_name(dmt))))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &dmi))
|
if (!dm_task_get_info(dmt, &dmi))
|
||||||
@@ -678,9 +678,6 @@ static int _get_status(struct message_data *message_data)
|
|||||||
char **buffers;
|
char **buffers;
|
||||||
char *message;
|
char *message;
|
||||||
|
|
||||||
if (!message_data->id)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
_lock_mutex();
|
_lock_mutex();
|
||||||
count = dm_list_size(&_thread_registry);
|
count = dm_list_size(&_thread_registry);
|
||||||
buffers = alloca(sizeof(char*) * count);
|
buffers = alloca(sizeof(char*) * count);
|
||||||
@@ -699,8 +696,8 @@ static int _get_status(struct message_data *message_data)
|
|||||||
|
|
||||||
len = strlen(message_data->id);
|
len = strlen(message_data->id);
|
||||||
msg->size = size + len + 1;
|
msg->size = size + len + 1;
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
if (!(msg->data = malloc(msg->size)))
|
if (!(msg->data = dm_malloc(msg->size)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
memcpy(msg->data, message_data->id, len);
|
memcpy(msg->data, message_data->id, len);
|
||||||
@@ -715,7 +712,7 @@ static int _get_status(struct message_data *message_data)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
for (j = 0; j < i; ++j)
|
for (j = 0; j < i; ++j)
|
||||||
free(buffers[j]);
|
dm_free(buffers[j]);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -724,7 +721,7 @@ static int _get_parameters(struct message_data *message_data) {
|
|||||||
struct dm_event_daemon_message *msg = message_data->msg;
|
struct dm_event_daemon_message *msg = message_data->msg;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
|
if ((size = dm_asprintf(&msg->data, "%s pid=%d daemon=%s exec_method=%s",
|
||||||
message_data->id, getpid(),
|
message_data->id, getpid(),
|
||||||
_foreground ? "no" : "yes",
|
_foreground ? "no" : "yes",
|
||||||
@@ -1075,7 +1072,6 @@ out:
|
|||||||
* "label at end of compound statement" */
|
* "label at end of compound statement" */
|
||||||
;
|
;
|
||||||
|
|
||||||
/* coverity[lock_order] _global_mutex is kept locked */
|
|
||||||
pthread_cleanup_pop(1);
|
pthread_cleanup_pop(1);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1238,7 +1234,7 @@ static int _registered_device(struct message_data *message_data,
|
|||||||
int r;
|
int r;
|
||||||
struct dm_event_daemon_message *msg = message_data->msg;
|
struct dm_event_daemon_message *msg = message_data->msg;
|
||||||
|
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
|
|
||||||
if ((r = dm_asprintf(&(msg->data), "%s %s %s %u",
|
if ((r = dm_asprintf(&(msg->data), "%s %s %s %u",
|
||||||
message_data->id,
|
message_data->id,
|
||||||
@@ -1378,7 +1374,7 @@ static int _get_timeout(struct message_data *message_data)
|
|||||||
if (!thread)
|
if (!thread)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
|
msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
|
||||||
message_data->id, thread->timeout);
|
message_data->id, thread->timeout);
|
||||||
|
|
||||||
@@ -1498,34 +1494,37 @@ static int _client_read(struct dm_event_fifos *fifos,
|
|||||||
t.tv_usec = 0;
|
t.tv_usec = 0;
|
||||||
ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
|
ret = select(fifos->client + 1, &fds, NULL, NULL, &t);
|
||||||
|
|
||||||
if (!ret && bytes)
|
if (!ret && !bytes) /* nothing to read */
|
||||||
continue; /* trying to finish read */
|
return 0;
|
||||||
|
|
||||||
if (ret <= 0) /* nothing to read */
|
if (!ret) /* trying to finish read */
|
||||||
goto bad;
|
continue;
|
||||||
|
|
||||||
|
if (ret < 0) /* error */
|
||||||
|
return 0;
|
||||||
|
|
||||||
ret = read(fifos->client, buf + bytes, size - bytes);
|
ret = read(fifos->client, buf + bytes, size - bytes);
|
||||||
bytes += ret > 0 ? ret : 0;
|
bytes += ret > 0 ? ret : 0;
|
||||||
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
|
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||||
msg->cmd = ntohl(header[0]);
|
msg->cmd = ntohl(header[0]);
|
||||||
|
size = msg->size = ntohl(header[1]);
|
||||||
bytes = 0;
|
bytes = 0;
|
||||||
|
if (!size)
|
||||||
if (!(size = msg->size = ntohl(header[1])))
|
break; /* No data -> error */
|
||||||
break;
|
buf = msg->data = dm_malloc(msg->size);
|
||||||
|
if (!buf)
|
||||||
if (!(buf = msg->data = malloc(msg->size)))
|
break; /* No mem -> error */
|
||||||
goto bad;
|
header = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes == size)
|
if (bytes != size) {
|
||||||
return 1;
|
dm_free(msg->data);
|
||||||
|
|
||||||
bad:
|
|
||||||
free(msg->data);
|
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1540,7 +1539,7 @@ static int _client_write(struct dm_event_fifos *fifos,
|
|||||||
fd_set fds;
|
fd_set fds;
|
||||||
|
|
||||||
size_t size = 2 * sizeof(uint32_t) + ((msg->data) ? msg->size : 0);
|
size_t size = 2 * sizeof(uint32_t) + ((msg->data) ? msg->size : 0);
|
||||||
uint32_t *header = malloc(size);
|
uint32_t *header = dm_malloc(size);
|
||||||
char *buf = (char *)header;
|
char *buf = (char *)header;
|
||||||
|
|
||||||
if (!header) {
|
if (!header) {
|
||||||
@@ -1570,7 +1569,7 @@ static int _client_write(struct dm_event_fifos *fifos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (header != temp)
|
if (header != temp)
|
||||||
free(header);
|
dm_free(header);
|
||||||
|
|
||||||
return (bytes == size);
|
return (bytes == size);
|
||||||
}
|
}
|
||||||
@@ -1632,7 +1631,7 @@ static int _do_process_request(struct dm_event_daemon_message *msg)
|
|||||||
msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
|
msg->size = dm_asprintf(&(msg->data), "%s %s %d", answer,
|
||||||
(msg->cmd == DM_EVENT_CMD_DIE) ? "DYING" : "HELLO",
|
(msg->cmd == DM_EVENT_CMD_DIE) ? "DYING" : "HELLO",
|
||||||
DM_EVENT_PROTOCOL_VERSION);
|
DM_EVENT_PROTOCOL_VERSION);
|
||||||
free(answer);
|
dm_free(answer);
|
||||||
}
|
}
|
||||||
} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
|
} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
|
||||||
stack;
|
stack;
|
||||||
@@ -1674,7 +1673,7 @@ static void _process_request(struct dm_event_fifos *fifos)
|
|||||||
|
|
||||||
DEBUGLOG("<<< CMD:%s (0x%x) completed (result %d).", decode_cmd(cmd), cmd, msg.cmd);
|
DEBUGLOG("<<< CMD:%s (0x%x) completed (result %d).", decode_cmd(cmd), cmd, msg.cmd);
|
||||||
|
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
|
|
||||||
if (cmd == DM_EVENT_CMD_DIE) {
|
if (cmd == DM_EVENT_CMD_DIE) {
|
||||||
if (unlink(DMEVENTD_PIDFILE))
|
if (unlink(DMEVENTD_PIDFILE))
|
||||||
@@ -1746,8 +1745,7 @@ static void _init_thread_signals(void)
|
|||||||
sigset_t my_sigset;
|
sigset_t my_sigset;
|
||||||
struct sigaction act = { .sa_handler = _sig_alarm };
|
struct sigaction act = { .sa_handler = _sig_alarm };
|
||||||
|
|
||||||
if (sigaction(SIGALRM, &act, NULL))
|
sigaction(SIGALRM, &act, NULL);
|
||||||
log_sys_debug("sigaction", "SIGLARM");
|
|
||||||
sigfillset(&my_sigset);
|
sigfillset(&my_sigset);
|
||||||
|
|
||||||
/* These are used for exiting */
|
/* These are used for exiting */
|
||||||
@@ -1756,8 +1754,7 @@ static void _init_thread_signals(void)
|
|||||||
sigdelset(&my_sigset, SIGHUP);
|
sigdelset(&my_sigset, SIGHUP);
|
||||||
sigdelset(&my_sigset, SIGQUIT);
|
sigdelset(&my_sigset, SIGQUIT);
|
||||||
|
|
||||||
if (pthread_sigmask(SIG_BLOCK, &my_sigset, NULL))
|
pthread_sigmask(SIG_BLOCK, &my_sigset, NULL);
|
||||||
log_sys_error("pthread_sigmask", "SIG_BLOCK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1987,7 +1984,7 @@ static int _reinstate_registrations(struct dm_event_fifos *fifos)
|
|||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
ret = daemon_talk(fifos, &msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
msg.data = NULL;
|
msg.data = NULL;
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -2073,18 +2070,19 @@ static void _restart_dmeventd(void)
|
|||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(_initial_registrations = zalloc(sizeof(char*) * (count + 1)))) {
|
if (!(_initial_registrations = dm_malloc(sizeof(char*) * (count + 1)))) {
|
||||||
fprintf(stderr, "Memory allocation registration failed.\n");
|
fprintf(stderr, "Memory allocation registration failed.\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
if (!(_initial_registrations[i] = strdup(message))) {
|
if (!(_initial_registrations[i] = dm_strdup(message))) {
|
||||||
fprintf(stderr, "Memory allocation for message failed.\n");
|
fprintf(stderr, "Memory allocation for message failed.\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
message += strlen(message) + 1;
|
message += strlen(message) + 1;
|
||||||
}
|
}
|
||||||
|
_initial_registrations[count] = NULL;
|
||||||
|
|
||||||
if (version >= 2) {
|
if (version >= 2) {
|
||||||
if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
|
if (daemon_talk(&fifos, &msg, DM_EVENT_CMD_GET_PARAMETERS, "-", "-", 0, 0)) {
|
||||||
@@ -2247,8 +2245,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
_init_thread_signals();
|
_init_thread_signals();
|
||||||
|
|
||||||
if (pthread_mutex_init(&_global_mutex, NULL))
|
pthread_mutex_init(&_global_mutex, NULL);
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
|
||||||
if (!_systemd_activation && !_open_fifos(&fifos))
|
if (!_systemd_activation && !_open_fifos(&fifos))
|
||||||
exit(EXIT_FIFO_FAILURE);
|
exit(EXIT_FIFO_FAILURE);
|
||||||
|
|||||||
@@ -12,12 +12,10 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "dm-logging.h"
|
||||||
|
#include "dmlib.h"
|
||||||
#include "libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
#include "dmeventd.h"
|
#include "dmeventd.h"
|
||||||
#include "libdm/misc/dm-logging.h"
|
|
||||||
#include "base/memory/zalloc.h"
|
|
||||||
|
|
||||||
#include "lib/misc/intl.h"
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
@@ -27,7 +25,6 @@
|
|||||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
static int _debug_level = 0;
|
static int _debug_level = 0;
|
||||||
static int _use_syslog = 0;
|
static int _use_syslog = 0;
|
||||||
@@ -50,8 +47,8 @@ struct dm_event_handler {
|
|||||||
|
|
||||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
|
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
|
||||||
{
|
{
|
||||||
free(dmevh->dev_name);
|
dm_free(dmevh->dev_name);
|
||||||
free(dmevh->uuid);
|
dm_free(dmevh->uuid);
|
||||||
dmevh->dev_name = dmevh->uuid = NULL;
|
dmevh->dev_name = dmevh->uuid = NULL;
|
||||||
dmevh->major = dmevh->minor = 0;
|
dmevh->major = dmevh->minor = 0;
|
||||||
}
|
}
|
||||||
@@ -60,7 +57,7 @@ struct dm_event_handler *dm_event_handler_create(void)
|
|||||||
{
|
{
|
||||||
struct dm_event_handler *dmevh;
|
struct dm_event_handler *dmevh;
|
||||||
|
|
||||||
if (!(dmevh = zalloc(sizeof(*dmevh)))) {
|
if (!(dmevh = dm_zalloc(sizeof(*dmevh)))) {
|
||||||
log_error("Failed to allocate event handler.");
|
log_error("Failed to allocate event handler.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -71,9 +68,9 @@ struct dm_event_handler *dm_event_handler_create(void)
|
|||||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
|
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
|
||||||
{
|
{
|
||||||
_dm_event_handler_clear_dev_info(dmevh);
|
_dm_event_handler_clear_dev_info(dmevh);
|
||||||
free(dmevh->dso);
|
dm_free(dmevh->dso);
|
||||||
free(dmevh->dmeventd_path);
|
dm_free(dmevh->dmeventd_path);
|
||||||
free(dmevh);
|
dm_free(dmevh);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
|
int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const char *dmeventd_path)
|
||||||
@@ -81,9 +78,9 @@ int dm_event_handler_set_dmeventd_path(struct dm_event_handler *dmevh, const cha
|
|||||||
if (!dmeventd_path) /* noop */
|
if (!dmeventd_path) /* noop */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free(dmevh->dmeventd_path);
|
dm_free(dmevh->dmeventd_path);
|
||||||
|
|
||||||
if (!(dmevh->dmeventd_path = strdup(dmeventd_path)))
|
if (!(dmevh->dmeventd_path = dm_strdup(dmeventd_path)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -94,9 +91,9 @@ int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
|
|||||||
if (!path) /* noop */
|
if (!path) /* noop */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free(dmevh->dso);
|
dm_free(dmevh->dso);
|
||||||
|
|
||||||
if (!(dmevh->dso = strdup(path)))
|
if (!(dmevh->dso = dm_strdup(path)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -109,7 +106,7 @@ int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *de
|
|||||||
|
|
||||||
_dm_event_handler_clear_dev_info(dmevh);
|
_dm_event_handler_clear_dev_info(dmevh);
|
||||||
|
|
||||||
if (!(dmevh->dev_name = strdup(dev_name)))
|
if (!(dmevh->dev_name = dm_strdup(dev_name)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -122,7 +119,7 @@ int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
|
|||||||
|
|
||||||
_dm_event_handler_clear_dev_info(dmevh);
|
_dm_event_handler_clear_dev_info(dmevh);
|
||||||
|
|
||||||
if (!(dmevh->uuid = strdup(uuid)))
|
if (!(dmevh->uuid = dm_strdup(uuid)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -237,16 +234,16 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
|||||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||||
if (ret < 0 && errno != EINTR) {
|
if (ret < 0 && errno != EINTR) {
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((ret == 0) && (i > 4) && !bytes) {
|
if ((ret == 0) && (i > 4) && !bytes) {
|
||||||
log_error("No input from event server.");
|
log_error("No input from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 1) {
|
if (ret < 1) {
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = read(fifos->server, buf + bytes, size);
|
ret = read(fifos->server, buf + bytes, size);
|
||||||
@@ -255,32 +252,25 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
log_error("Unable to read from event server.");
|
log_error("Unable to read from event server.");
|
||||||
goto bad;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes += ret;
|
bytes += ret;
|
||||||
if (!msg->data && (bytes == 2 * sizeof(uint32_t))) {
|
if (header && (bytes == 2 * sizeof(uint32_t))) {
|
||||||
msg->cmd = ntohl(header[0]);
|
msg->cmd = ntohl(header[0]);
|
||||||
|
msg->size = ntohl(header[1]);
|
||||||
|
buf = msg->data = dm_malloc(msg->size);
|
||||||
|
size = msg->size;
|
||||||
bytes = 0;
|
bytes = 0;
|
||||||
|
header = 0;
|
||||||
if (!(size = msg->size = ntohl(header[1])))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!(buf = msg->data = malloc(msg->size))) {
|
|
||||||
log_error("Unable to allocate message data.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes == size)
|
if (bytes != size) {
|
||||||
return 1;
|
dm_free(msg->data);
|
||||||
|
|
||||||
bad:
|
|
||||||
free(msg->data);
|
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
|
}
|
||||||
return 0;
|
return bytes == size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write message to daemon. */
|
/* Write message to daemon. */
|
||||||
@@ -380,13 +370,13 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
|||||||
*/
|
*/
|
||||||
if (!_daemon_write(fifos, msg)) {
|
if (!_daemon_write(fifos, msg)) {
|
||||||
stack;
|
stack;
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
msg->data = NULL;
|
msg->data = NULL;
|
||||||
|
|
||||||
if (!_daemon_read(fifos, msg)) {
|
if (!_daemon_read(fifos, msg)) {
|
||||||
@@ -629,7 +619,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);
|
ret = daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, NULL, NULL, 0, 0);
|
||||||
|
|
||||||
free(msg->data);
|
dm_free(msg->data);
|
||||||
msg->data = 0;
|
msg->data = 0;
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@@ -670,7 +660,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
|
|
||||||
dm_task_destroy(dmt);
|
dm_task_destroy(dmt);
|
||||||
|
|
||||||
@@ -697,7 +687,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
|
|
||||||
dm_task_destroy(dmt);
|
dm_task_destroy(dmt);
|
||||||
|
|
||||||
@@ -709,11 +699,15 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
|||||||
static char *_fetch_string(char **src, const int delimiter)
|
static char *_fetch_string(char **src, const int delimiter)
|
||||||
{
|
{
|
||||||
char *p, *ret;
|
char *p, *ret;
|
||||||
size_t len = (p = strchr(*src, delimiter)) ?
|
|
||||||
(size_t)(p - *src) : strlen(*src);
|
|
||||||
|
|
||||||
if ((ret = strndup(*src, len)))
|
if ((p = strchr(*src, delimiter)))
|
||||||
*src += len + 1;
|
*p = 0;
|
||||||
|
|
||||||
|
if ((ret = dm_strdup(*src)))
|
||||||
|
*src += strlen(ret) + 1;
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
*p = delimiter;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -729,11 +723,11 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
|||||||
(*dso_name = _fetch_string(&p, ' ')) &&
|
(*dso_name = _fetch_string(&p, ' ')) &&
|
||||||
(*uuid = _fetch_string(&p, ' '))) {
|
(*uuid = _fetch_string(&p, ' '))) {
|
||||||
*evmask = atoi(p);
|
*evmask = atoi(p);
|
||||||
free(id);
|
dm_free(id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(id);
|
dm_free(id);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -775,7 +769,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
dm_task_destroy(dmt);
|
dm_task_destroy(dmt);
|
||||||
dmt = NULL;
|
dmt = NULL;
|
||||||
|
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
msg.data = NULL;
|
msg.data = NULL;
|
||||||
|
|
||||||
_dm_event_handler_clear_dev_info(dmevh);
|
_dm_event_handler_clear_dev_info(dmevh);
|
||||||
@@ -784,7 +778,7 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(dmevh->uuid = strdup(reply_uuid))) {
|
if (!(dmevh->uuid = dm_strdup(reply_uuid))) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -797,13 +791,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_dso(dmevh, reply_dso);
|
||||||
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||||
|
|
||||||
free(reply_dso);
|
dm_free(reply_dso);
|
||||||
reply_dso = NULL;
|
reply_dso = NULL;
|
||||||
|
|
||||||
free(reply_uuid);
|
dm_free(reply_uuid);
|
||||||
reply_uuid = NULL;
|
reply_uuid = NULL;
|
||||||
|
|
||||||
if (!(dmevh->dev_name = strdup(dm_task_get_name(dmt)))) {
|
if (!(dmevh->dev_name = dm_strdup(dm_task_get_name(dmt)))) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -821,9 +815,9 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
free(reply_dso);
|
dm_free(reply_dso);
|
||||||
free(reply_uuid);
|
dm_free(reply_uuid);
|
||||||
_dm_event_handler_clear_dev_info(dmevh);
|
_dm_event_handler_clear_dev_info(dmevh);
|
||||||
if (dmt)
|
if (dmt)
|
||||||
dm_task_destroy(dmt);
|
dm_task_destroy(dmt);
|
||||||
@@ -988,12 +982,12 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
|||||||
if (!p) {
|
if (!p) {
|
||||||
log_error("Malformed reply from dmeventd '%s'.",
|
log_error("Malformed reply from dmeventd '%s'.",
|
||||||
msg.data);
|
msg.data);
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
*timeout = atoi(p);
|
*timeout = atoi(p);
|
||||||
}
|
}
|
||||||
free(msg.data);
|
dm_free(msg.data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#ifndef LIB_DMEVENT_H
|
#ifndef LIB_DMEVENT_H
|
||||||
#define LIB_DMEVENT_H
|
#define LIB_DMEVENT_H
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ Description: device-mapper event library
|
|||||||
Version: @DM_LIB_PATCHLEVEL@
|
Version: @DM_LIB_PATCHLEVEL@
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
Libs: -L${libdir} -ldevmapper-event
|
Libs: -L${libdir} -ldevmapper-event
|
||||||
|
Requires.private: devmapper
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ top_srcdir = @top_srcdir@
|
|||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
CLDFLAGS += -L$(top_builddir)/tools
|
CLDFLAGS += -L$(top_builddir)/tools
|
||||||
LIBS += $(DMEVENT_LIBS) $(PTHREAD_LIBS) @LVM2CMD_LIB@
|
|
||||||
|
|
||||||
SOURCES = dmeventd_lvm.c
|
SOURCES = dmeventd_lvm.c
|
||||||
|
|
||||||
@@ -25,6 +24,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
|||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_lib_shared
|
install_lvm2: install_lib_shared
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib.h"
|
||||||
#include "dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
#include "tools/lvm2cmd.h"
|
#include "lvm2cmd.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_mirror.c
|
SOURCES = dmeventd_mirror.c
|
||||||
|
|
||||||
@@ -25,8 +25,13 @@ LIB_NAME = libdevmapper-event-lvm2mirror
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "libdevmapper-event.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "lib/activate/activate.h"
|
#include "activate.h" /* For TARGET_NAME* */
|
||||||
|
|
||||||
/* FIXME Reformat to 80 char lines. */
|
/* FIXME Reformat to 80 char lines. */
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_raid.c
|
SOURCES = dmeventd_raid.c
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ LIB_NAME = libdevmapper-event-lvm2raid
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "defaults.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "lib/config/defaults.h"
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
/* Hold enough elements for the mximum number of RAID images */
|
/* Hold enough elements for the mximum number of RAID images */
|
||||||
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
|
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
|
||||||
@@ -77,7 +77,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
|
|||||||
|
|
||||||
if (dead) {
|
if (dead) {
|
||||||
/*
|
/*
|
||||||
* Use the first event to run a repair ignoring any additional ones.
|
* Use the first event to run a repair ignoring any additonal ones.
|
||||||
*
|
*
|
||||||
* We presume lvconvert to do pre-repair
|
* We presume lvconvert to do pre-repair
|
||||||
* checks to avoid bloat in this plugin.
|
* checks to avoid bloat in this plugin.
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_snapshot.c
|
SOURCES = dmeventd_snapshot.c
|
||||||
|
|
||||||
@@ -26,6 +26,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
|
|||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
@@ -175,7 +175,6 @@ void process_event(struct dm_task *dmt,
|
|||||||
const char *device = dm_task_get_name(dmt);
|
const char *device = dm_task_get_name(dmt);
|
||||||
int percent;
|
int percent;
|
||||||
struct dm_info info;
|
struct dm_info info;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* No longer monitoring, waiting for remove */
|
/* No longer monitoring, waiting for remove */
|
||||||
if (!state->percent_check)
|
if (!state->percent_check)
|
||||||
@@ -206,8 +205,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
/* Maybe configurable ? */
|
/* Maybe configurable ? */
|
||||||
_remove(dm_task_get_uuid(dmt));
|
_remove(dm_task_get_uuid(dmt));
|
||||||
#endif
|
#endif
|
||||||
if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
log_sys_error("pthread_kill", "self");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,8 +213,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
/* TODO eventually recognize earlier when room is enough */
|
/* TODO eventually recognize earlier when room is enough */
|
||||||
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
||||||
device);
|
device);
|
||||||
if ((ret = pthread_kill(pthread_self(), SIGALRM)) && (ret != ESRCH))
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
log_sys_error("pthread_kill", "self");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_thin.c
|
SOURCES = dmeventd_thin.c
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ LIB_NAME = libdevmapper-event-lvm2thin
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 -ldevmapper
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -12,16 +12,16 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib.h" /* using here lvm log */
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
/* TODO - move this mountinfo code into library to be reusable */
|
/* TODO - move this mountinfo code into library to be reusable */
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# include "libdm/misc/kdev_t.h"
|
# include "kdev_t.h"
|
||||||
#else
|
#else
|
||||||
# define MAJOR(x) major((x))
|
# define MAJOR(x) major((x))
|
||||||
# define MINOR(x) minor((x))
|
# define MINOR(x) minor((x))
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_srcdir)/daemons/dmeventd/plugins/lvm2
|
||||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd/plugins/lvm2
|
||||||
LIBS += -ldevmapper-event-lvm2
|
|
||||||
|
|
||||||
SOURCES = dmeventd_vdo.c
|
SOURCES = dmeventd_vdo.c
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ LIB_NAME = libdevmapper-event-lvm2vdo
|
|||||||
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
LIB_SHARED = $(LIB_NAME).$(LIB_SUFFIX)
|
||||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
|
LIBS += -ldevmapper-event-lvm2 $(INTERNAL_LIBS)
|
||||||
|
|
||||||
install_lvm2: install_dm_plugin
|
install_lvm2: install_dm_plugin
|
||||||
|
|
||||||
install: install_lvm2
|
install: install_lvm2
|
||||||
|
|||||||
@@ -12,18 +12,9 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/misc/lib.h"
|
#include "lib.h"
|
||||||
#include "daemons/dmeventd/plugins/lvm2/dmeventd_lvm.h"
|
#include "dmeventd_lvm.h"
|
||||||
#include "daemons/dmeventd/libdevmapper-event.h"
|
#include "libdevmapper-event.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Use parser from new device_mapper library.
|
|
||||||
* Although during compilation we can see dm_vdo_status_parse()
|
|
||||||
* in runtime we are linked agains systems libdm 'older' library
|
|
||||||
* which does not provide this symbol and plugin fails to load
|
|
||||||
*/
|
|
||||||
/* coverity[unnecessary_header] used for parsing */
|
|
||||||
#include "device_mapper/vdo/status.c"
|
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -54,6 +45,23 @@ struct dso_state {
|
|||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vdo_status {
|
||||||
|
uint64_t used_blocks;
|
||||||
|
uint64_t total_blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _vdo_status_parse(const char *params, struct vdo_status *status)
|
||||||
|
{
|
||||||
|
if (sscanf(params, "%*s %*s %*s %*s %*s %" PRIu64 " %" PRIu64,
|
||||||
|
&status->used_blocks,
|
||||||
|
&status->total_blocks) < 2) {
|
||||||
|
log_error("Failed to parse vdo params: %s.", params);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
DM_EVENT_LOG_FN("vdo")
|
DM_EVENT_LOG_FN("vdo")
|
||||||
|
|
||||||
static int _run_command(struct dso_state *state)
|
static int _run_command(struct dso_state *state)
|
||||||
@@ -157,7 +165,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
char *params;
|
char *params;
|
||||||
int needs_policy = 0;
|
int needs_policy = 0;
|
||||||
struct dm_task *new_dmt = NULL;
|
struct dm_task *new_dmt = NULL;
|
||||||
struct dm_vdo_status_parse_result vdop = { .status = NULL };
|
struct vdo_status status;
|
||||||
|
|
||||||
#if VDO_DEBUG
|
#if VDO_DEBUG
|
||||||
log_debug("Watch for VDO %s:%.2f%%.", state->name,
|
log_debug("Watch for VDO %s:%.2f%%.", state->name,
|
||||||
@@ -203,24 +211,24 @@ void process_event(struct dm_task *dmt,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_vdo_status_parse(state->mem, params, &vdop)) {
|
if (!_vdo_status_parse(params, &status)) {
|
||||||
log_error("Failed to parse status.");
|
log_error("Failed to parse status.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->percent = dm_make_percent(vdop.status->used_blocks,
|
state->percent = dm_make_percent(status.used_blocks,
|
||||||
vdop.status->total_blocks);
|
status.total_blocks);
|
||||||
|
|
||||||
#if VDO_DEBUG
|
#if VDO_DEBUG
|
||||||
log_debug("VDO %s status %.2f%% " FMTu64 "/" FMTu64 ".",
|
log_debug("VDO %s status %.2f%% " FMTu64 "/" FMTu64 ".",
|
||||||
state->name, dm_percent_to_round_float(state->percent, 2),
|
state->name, dm_percent_to_round_float(state->percent, 2),
|
||||||
vdop.status->used_blocks, vdop.status->total_blocks);
|
status.used_blocks, status.total_blocks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* VDO pool size had changed. Clear the threshold. */
|
/* VDO pool size had changed. Clear the threshold. */
|
||||||
if (state->known_data_size != vdop.status->total_blocks) {
|
if (state->known_data_size != status.total_blocks) {
|
||||||
state->percent_check = CHECK_MINIMUM;
|
state->percent_check = CHECK_MINIMUM;
|
||||||
state->known_data_size = vdop.status->total_blocks;
|
state->known_data_size = status.total_blocks;
|
||||||
state->fails = 0;
|
state->fails = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,12 +269,10 @@ void process_event(struct dm_task *dmt,
|
|||||||
} else
|
} else
|
||||||
state->max_fails = 1; /* Reset on success */
|
state->max_fails = 1; /* Reset on success */
|
||||||
|
|
||||||
if (needs_policy)
|
/* FIXME: ATM nothing can be done, drop 0, once it becomes useful */
|
||||||
|
if (0 && needs_policy)
|
||||||
_use_policy(dmt, state);
|
_use_policy(dmt, state);
|
||||||
out:
|
out:
|
||||||
if (vdop.status)
|
|
||||||
dm_pool_free(state->mem, vdop.status);
|
|
||||||
|
|
||||||
if (new_dmt)
|
if (new_dmt)
|
||||||
dm_task_destroy(new_dmt);
|
dm_task_destroy(new_dmt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
dmsetup
|
|
||||||
dmfilemapd
|
dmfilemapd
|
||||||
66
daemons/dmfilemapd/Makefile.in
Normal file
66
daemons/dmfilemapd/Makefile.in
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
@@ -14,8 +14,11 @@
|
|||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "util.h"
|
#include "tool.h"
|
||||||
#include "libdm/misc/dm-logging.h"
|
|
||||||
|
#include "dm-logging.h"
|
||||||
|
|
||||||
|
#include "defaults.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -26,15 +29,13 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# include "libdm/misc/kdev_t.h"
|
# include "kdev_t.h"
|
||||||
#else
|
#else
|
||||||
# define MAJOR(x) major((x))
|
# define MAJOR(x) major((x))
|
||||||
# define MINOR(x) minor((x))
|
# define MINOR(x) minor((x))
|
||||||
# define MKDEV(x,y) makedev((x),(y))
|
# define MKDEV(x,y) makedev((dev_t)(x),(dev_t)(y))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEFAULT_PROC_DIR "/proc"
|
|
||||||
|
|
||||||
/* limit to two updates/sec */
|
/* limit to two updates/sec */
|
||||||
#define FILEMAPD_WAIT_USECS 500000
|
#define FILEMAPD_WAIT_USECS 500000
|
||||||
|
|
||||||
@@ -180,14 +181,14 @@ static int _is_open_in_pid(pid_t pid, const char *path)
|
|||||||
link_buf[len] = '\0';
|
link_buf[len] = '\0';
|
||||||
if (!strcmp(deleted_path, link_buf)) {
|
if (!strcmp(deleted_path, link_buf)) {
|
||||||
if (closedir(pid_d))
|
if (closedir(pid_d))
|
||||||
log_sys_debug("closedir", path_buf);
|
log_sys_error("closedir", path_buf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
if (closedir(pid_d))
|
if (closedir(pid_d))
|
||||||
log_sys_debug("closedir", path_buf);
|
log_sys_error("closedir", path_buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -230,13 +231,13 @@ static int _is_open(const char *path)
|
|||||||
continue;
|
continue;
|
||||||
if (_is_open_in_pid(pid, path)) {
|
if (_is_open_in_pid(pid, path)) {
|
||||||
if (closedir(proc_d))
|
if (closedir(proc_d))
|
||||||
log_sys_debug("closedir", DEFAULT_PROC_DIR);
|
log_sys_error("closedir", DEFAULT_PROC_DIR);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closedir(proc_d))
|
if (closedir(proc_d))
|
||||||
log_sys_debug("closedir", DEFAULT_PROC_DIR);
|
log_sys_error("closedir", DEFAULT_PROC_DIR);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -310,7 +311,7 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fm->path = strdup(argv[0]);
|
fm->path = dm_strdup(argv[0]);
|
||||||
if (!fm->path) {
|
if (!fm->path) {
|
||||||
_early_log("Could not allocate memory for path argument.");
|
_early_log("Could not allocate memory for path argument.");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -537,8 +538,8 @@ static void _filemap_monitor_destroy(struct filemap_monitor *fm)
|
|||||||
_filemap_monitor_end_notify(fm);
|
_filemap_monitor_end_notify(fm);
|
||||||
_filemap_monitor_close_fd(fm);
|
_filemap_monitor_close_fd(fm);
|
||||||
}
|
}
|
||||||
free((void *) fm->program_id);
|
dm_free((void *) fm->program_id);
|
||||||
free(fm->path);
|
dm_free(fm->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _filemap_monitor_check_same_file(int fd1, int fd2)
|
static int _filemap_monitor_check_same_file(int fd1, int fd2)
|
||||||
@@ -629,7 +630,7 @@ check_unlinked:
|
|||||||
static int _daemonise(struct filemap_monitor *fm)
|
static int _daemonise(struct filemap_monitor *fm)
|
||||||
{
|
{
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
int fd, ffd;
|
int fd;
|
||||||
|
|
||||||
if (!setsid()) {
|
if (!setsid()) {
|
||||||
_early_log("setsid failed.");
|
_early_log("setsid failed.");
|
||||||
@@ -653,29 +654,26 @@ static int _daemonise(struct filemap_monitor *fm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!_verbose) {
|
if (!_verbose) {
|
||||||
if ((fd = open("/dev/null", O_RDWR)) == -1) {
|
if (close(STDIN_FILENO))
|
||||||
_early_log("Error opening /dev/null.");
|
_early_log("Error closing stdin");
|
||||||
|
if (close(STDOUT_FILENO))
|
||||||
|
_early_log("Error closing stdout");
|
||||||
|
if (close(STDERR_FILENO))
|
||||||
|
_early_log("Error closing stderr");
|
||||||
|
if ((open("/dev/null", O_RDONLY) < 0) ||
|
||||||
|
(open("/dev/null", O_WRONLY) < 0) ||
|
||||||
|
(open("/dev/null", O_WRONLY) < 0)) {
|
||||||
|
_early_log("Error opening stdio streams.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dup2(fd, STDIN_FILENO) == -1) ||
|
|
||||||
(dup2(fd, STDOUT_FILENO) == -1) ||
|
|
||||||
(dup2(fd, STDERR_FILENO) == -1)) {
|
|
||||||
if (fd > STDERR_FILENO)
|
|
||||||
(void) close(fd);
|
|
||||||
_early_log("Error redirecting stdin/out/err to null.");
|
|
||||||
/* coverity[leaked_handle] no leak */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (fd > STDERR_FILENO)
|
|
||||||
(void) close(fd);
|
|
||||||
}
|
}
|
||||||
/* TODO: Use libdaemon/server/daemon-server.c _daemonise() */
|
/* TODO: Use libdaemon/server/daemon-server.c _daemonise() */
|
||||||
for (ffd = (int) sysconf(_SC_OPEN_MAX) - 1; ffd > STDERR_FILENO; --ffd)
|
for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) {
|
||||||
if (ffd != fm->fd)
|
if (fd == fm->fd)
|
||||||
(void) close(ffd);
|
continue;
|
||||||
|
(void) close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
/* coverity[leaked_handle] no leak */
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +699,7 @@ static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm)
|
|||||||
fm->group_id, regions[0]);
|
fm->group_id, regions[0]);
|
||||||
fm->group_id = regions[0];
|
fm->group_id = regions[0];
|
||||||
}
|
}
|
||||||
free(regions);
|
dm_free(regions);
|
||||||
fm->nr_regions = nr_regions;
|
fm->nr_regions = nr_regions;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -743,7 +741,7 @@ static int _dmfilemapd(struct filemap_monitor *fm)
|
|||||||
*/
|
*/
|
||||||
program_id = dm_stats_get_region_program_id(dms, fm->group_id);
|
program_id = dm_stats_get_region_program_id(dms, fm->group_id);
|
||||||
if (program_id)
|
if (program_id)
|
||||||
fm->program_id = strdup(program_id);
|
fm->program_id = dm_strdup(program_id);
|
||||||
else
|
else
|
||||||
fm->program_id = NULL;
|
fm->program_id = NULL;
|
||||||
dm_stats_set_program_id(dms, 1, program_id);
|
dm_stats_set_program_id(dms, 1, program_id);
|
||||||
@@ -819,7 +817,7 @@ int main(int argc, char **argv)
|
|||||||
memset(&fm, 0, sizeof(fm));
|
memset(&fm, 0, sizeof(fm));
|
||||||
|
|
||||||
if (!_parse_args(argc, argv, &fm)) {
|
if (!_parse_args(argc, argv, &fm)) {
|
||||||
free(fm.path);
|
dm_free(fm.path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -830,7 +828,7 @@ int main(int argc, char **argv)
|
|||||||
_mode_names[fm.mode], fm.path);
|
_mode_names[fm.mode], fm.path);
|
||||||
|
|
||||||
if (!_foreground && !_daemonise(&fm)) {
|
if (!_foreground && !_daemonise(&fm)) {
|
||||||
free(fm.path);
|
dm_free(fm.path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,8 +15,7 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
lvmdbuspydir = $(python3dir)/lvmdbusd
|
lvmdbusdir = $(python3dir)/lvmdbusd
|
||||||
lvmdbusdir = $(DESTDIR)$(lvmdbuspydir)
|
|
||||||
|
|
||||||
LVMDBUS_SRCDIR_FILES = \
|
LVMDBUS_SRCDIR_FILES = \
|
||||||
automatedproperties.py \
|
automatedproperties.py \
|
||||||
@@ -24,10 +23,11 @@ LVMDBUS_SRCDIR_FILES = \
|
|||||||
cfg.py \
|
cfg.py \
|
||||||
cmdhandler.py \
|
cmdhandler.py \
|
||||||
fetch.py \
|
fetch.py \
|
||||||
|
__init__.py \
|
||||||
job.py \
|
job.py \
|
||||||
loader.py \
|
loader.py \
|
||||||
lv.py \
|
|
||||||
main.py \
|
main.py \
|
||||||
|
lv.py \
|
||||||
manager.py \
|
manager.py \
|
||||||
objectmanager.py \
|
objectmanager.py \
|
||||||
pv.py \
|
pv.py \
|
||||||
@@ -35,8 +35,7 @@ LVMDBUS_SRCDIR_FILES = \
|
|||||||
state.py \
|
state.py \
|
||||||
udevwatch.py \
|
udevwatch.py \
|
||||||
utils.py \
|
utils.py \
|
||||||
vg.py \
|
vg.py
|
||||||
__init__.py
|
|
||||||
|
|
||||||
LVMDBUS_BUILDDIR_FILES = \
|
LVMDBUS_BUILDDIR_FILES = \
|
||||||
lvmdb.py \
|
lvmdb.py \
|
||||||
@@ -52,18 +51,17 @@ include $(top_builddir)/make.tmpl
|
|||||||
.PHONY: install_lvmdbusd
|
.PHONY: install_lvmdbusd
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(Q) test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
test -x $(LVMDBUSD) || chmod 755 $(LVMDBUSD)
|
||||||
|
|
||||||
install_lvmdbusd: $(LVMDBUSD)
|
install_lvmdbusd:
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_DIR) $(sbindir)
|
||||||
$(Q) $(INSTALL_DIR) $(sbindir)
|
$(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
||||||
$(Q) $(INSTALL_SCRIPT) $(LVMDBUSD) $(sbindir)
|
$(INSTALL_DIR) $(DESTDIR)$(lvmdbusdir)
|
||||||
$(Q) $(INSTALL_DIR) $(lvmdbusdir)
|
(cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(DESTDIR)$(lvmdbusdir))
|
||||||
$(Q) (cd $(srcdir); $(INSTALL_DATA) $(LVMDBUS_SRCDIR_FILES) $(lvmdbusdir))
|
$(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(DESTDIR)$(lvmdbusdir)
|
||||||
$(Q) $(INSTALL_DATA) $(LVMDBUS_BUILDDIR_FILES) $(lvmdbusdir)
|
PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbusdir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
||||||
$(Q) PYTHON=$(PYTHON3) $(PYCOMPILE) --destdir "$(DESTDIR)" --basedir "$(lvmdbuspydir)" $(LVMDBUS_SRCDIR_FILES) $(LVMDBUS_BUILDDIR_FILES)
|
$(CHMOD) 755 $(DESTDIR)$(lvmdbusdir)/__pycache__
|
||||||
$(Q) $(CHMOD) 755 $(lvmdbusdir)/__pycache__
|
$(CHMOD) 444 $(DESTDIR)$(lvmdbusdir)/__pycache__/*.py[co]
|
||||||
$(Q) $(CHMOD) 444 $(lvmdbusdir)/__pycache__/*.py[co]
|
|
||||||
|
|
||||||
install_lvm2: install_lvmdbusd
|
install_lvm2: install_lvmdbusd
|
||||||
|
|
||||||
|
|||||||
@@ -155,17 +155,16 @@ class AutomatedProperties(dbus.service.Object):
|
|||||||
# through all dbus objects as some don't have a search method, like
|
# through all dbus objects as some don't have a search method, like
|
||||||
# 'Manager' object.
|
# 'Manager' object.
|
||||||
if not self._ap_search_method:
|
if not self._ap_search_method:
|
||||||
return 0
|
return
|
||||||
|
|
||||||
|
search = self.lvm_id
|
||||||
|
if search_key:
|
||||||
|
search = search_key
|
||||||
|
|
||||||
# Either we have the new object state or we need to go fetch it
|
# Either we have the new object state or we need to go fetch it
|
||||||
if object_state:
|
if object_state:
|
||||||
new_state = object_state
|
new_state = object_state
|
||||||
else:
|
else:
|
||||||
if search_key:
|
|
||||||
search = search_key
|
|
||||||
else:
|
|
||||||
search = self.lvm_id
|
|
||||||
|
|
||||||
new_state = self._ap_search_method([search])[0]
|
new_state = self._ap_search_method([search])[0]
|
||||||
assert isinstance(new_state, State)
|
assert isinstance(new_state, State)
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,13 @@
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
|
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
|
||||||
import dbus
|
import dbus
|
||||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
|
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
|
||||||
mt_async_call
|
add_no_notify
|
||||||
from .request import RequestEntry
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
def pv_move_lv_cmd(move_options, lv_full_name,
|
||||||
@@ -40,50 +39,58 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
|||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def _load_wrapper(ignored):
|
|
||||||
cfg.load()
|
|
||||||
|
|
||||||
|
|
||||||
def _move_callback(job_state, line_str):
|
|
||||||
try:
|
|
||||||
if line_str.count(':') == 2:
|
|
||||||
(device, ignore, percentage) = line_str.split(':')
|
|
||||||
|
|
||||||
job_state.Percent = int(round(
|
|
||||||
float(percentage.strip()[:-1]), 1))
|
|
||||||
|
|
||||||
# While the move is in progress we need to periodically update
|
|
||||||
# the state to reflect where everything is at. we will do this
|
|
||||||
# by scheduling the load to occur in the main work queue.
|
|
||||||
r = RequestEntry(
|
|
||||||
-1, _load_wrapper, ("_move_callback: load",), None, None, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
except ValueError:
|
|
||||||
log_error("Trying to parse percentage which failed for %s" % line_str)
|
|
||||||
|
|
||||||
|
|
||||||
def _move_merge(interface_name, command, job_state):
|
def _move_merge(interface_name, command, job_state):
|
||||||
# We need to execute these command stand alone by forking & exec'ing
|
# We need to execute these command stand alone by forking & exec'ing
|
||||||
# the command always as we will be getting periodic output from them on
|
# the command always as we will be getting periodic output from them on
|
||||||
# the status of the long running operation.
|
# the status of the long running operation.
|
||||||
|
command.insert(0, cfg.LVM_CMD)
|
||||||
|
|
||||||
|
# Instruct lvm to not register an event with us
|
||||||
|
command = add_no_notify(command)
|
||||||
|
|
||||||
|
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
|
||||||
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
|
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
|
||||||
|
|
||||||
cfg.blackbox.add(meta)
|
cfg.blackbox.add(meta)
|
||||||
|
|
||||||
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
|
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||||
cb_data=job_state)
|
env=os.environ,
|
||||||
|
stderr=subprocess.PIPE, close_fds=True)
|
||||||
|
|
||||||
|
log_debug("Background process for %s is %d" %
|
||||||
|
(str(command), process.pid))
|
||||||
|
|
||||||
|
lines_iterator = iter(process.stdout.readline, b"")
|
||||||
|
for line in lines_iterator:
|
||||||
|
line_str = line.decode("utf-8")
|
||||||
|
|
||||||
|
# Check to see if the line has the correct number of separators
|
||||||
|
try:
|
||||||
|
if line_str.count(':') == 2:
|
||||||
|
(device, ignore, percentage) = line_str.split(':')
|
||||||
|
job_state.Percent = round(
|
||||||
|
float(percentage.strip()[:-1]), 1)
|
||||||
|
|
||||||
|
# While the move is in progress we need to periodically update
|
||||||
|
# the state to reflect where everything is at.
|
||||||
|
cfg.load()
|
||||||
|
except ValueError:
|
||||||
|
log_error("Trying to parse percentage which failed for %s" %
|
||||||
|
line_str)
|
||||||
|
|
||||||
|
out = process.communicate()
|
||||||
|
|
||||||
with meta.lock:
|
with meta.lock:
|
||||||
meta.ended = time.time()
|
meta.ended = time.time()
|
||||||
meta.ec = ec
|
meta.ec = process.returncode
|
||||||
meta.stderr_txt = stderr
|
meta.stderr_txt = out[1]
|
||||||
|
|
||||||
if ec == 0:
|
if process.returncode == 0:
|
||||||
job_state.Percent = 100
|
job_state.Percent = 100
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
interface_name,
|
interface_name,
|
||||||
'Exit code %s, stderr = %s' % (str(ec), stderr))
|
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||||
|
|
||||||
cfg.load()
|
cfg.load()
|
||||||
return '/'
|
return '/'
|
||||||
|
|||||||
@@ -47,11 +47,9 @@ BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
|||||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||||
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
PV_INTERFACE = BASE_INTERFACE + '.Pv'
|
||||||
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
VG_INTERFACE = BASE_INTERFACE + '.Vg'
|
||||||
VG_VDO_INTERFACE = BASE_INTERFACE + '.VgVdo'
|
|
||||||
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
LV_INTERFACE = BASE_INTERFACE + '.Lv'
|
||||||
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
LV_COMMON_INTERFACE = BASE_INTERFACE + '.LvCommon'
|
||||||
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
THIN_POOL_INTERFACE = BASE_INTERFACE + '.ThinPool'
|
||||||
VDO_POOL_INTERFACE = BASE_INTERFACE + '.VdoPool'
|
|
||||||
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
CACHE_POOL_INTERFACE = BASE_INTERFACE + '.CachePool'
|
||||||
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
LV_CACHED = BASE_INTERFACE + '.CachedLv'
|
||||||
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
SNAPSHOT_INTERFACE = BASE_INTERFACE + '.Snapshot'
|
||||||
@@ -63,7 +61,6 @@ PV_OBJ_PATH = BASE_OBJ_PATH + '/Pv'
|
|||||||
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
VG_OBJ_PATH = BASE_OBJ_PATH + '/Vg'
|
||||||
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
LV_OBJ_PATH = BASE_OBJ_PATH + '/Lv'
|
||||||
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
THIN_POOL_PATH = BASE_OBJ_PATH + "/ThinPool"
|
||||||
VDO_POOL_PATH = BASE_OBJ_PATH + "/VdoPool"
|
|
||||||
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
CACHE_POOL_PATH = BASE_OBJ_PATH + "/CachePool"
|
||||||
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
HIDDEN_LV_PATH = BASE_OBJ_PATH + "/HiddenLv"
|
||||||
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
MANAGER_OBJ_PATH = BASE_OBJ_PATH + '/Manager'
|
||||||
@@ -74,7 +71,6 @@ pv_id = itertools.count()
|
|||||||
vg_id = itertools.count()
|
vg_id = itertools.count()
|
||||||
lv_id = itertools.count()
|
lv_id = itertools.count()
|
||||||
thin_id = itertools.count()
|
thin_id = itertools.count()
|
||||||
vdo_id = itertools.count()
|
|
||||||
cache_pool_id = itertools.count()
|
cache_pool_id = itertools.count()
|
||||||
job_id = itertools.count()
|
job_id = itertools.count()
|
||||||
hidden_lv = itertools.count()
|
hidden_lv = itertools.count()
|
||||||
@@ -83,9 +79,6 @@ hidden_lv = itertools.count()
|
|||||||
load = None
|
load = None
|
||||||
event = None
|
event = None
|
||||||
|
|
||||||
# Boolean to denote if lvm supports VDO integration
|
|
||||||
vdo_support = False
|
|
||||||
|
|
||||||
# Global cached state
|
# Global cached state
|
||||||
db = None
|
db = None
|
||||||
|
|
||||||
@@ -94,13 +87,3 @@ blackbox = None
|
|||||||
|
|
||||||
# RequestEntry ctor
|
# RequestEntry ctor
|
||||||
create_request_entry = None
|
create_request_entry = None
|
||||||
|
|
||||||
|
|
||||||
def exit_daemon():
|
|
||||||
"""
|
|
||||||
Exit the daemon cleanly
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if run and loop:
|
|
||||||
run.value = 0
|
|
||||||
loop.quit()
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
import select
|
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
@@ -17,8 +16,7 @@ import traceback
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from lvmdbusd import cfg
|
from lvmdbusd import cfg
|
||||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
|
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
|
||||||
make_non_block, read_decoded
|
|
||||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -69,7 +67,7 @@ class LvmFlightRecorder(object):
|
|||||||
with cmd_lock:
|
with cmd_lock:
|
||||||
if len(self.queue):
|
if len(self.queue):
|
||||||
log_error("LVM dbus flight recorder START")
|
log_error("LVM dbus flight recorder START")
|
||||||
for c in reversed(self.queue):
|
for c in self.queue:
|
||||||
log_error(str(c))
|
log_error(str(c))
|
||||||
log_error("LVM dbus flight recorder END")
|
log_error("LVM dbus flight recorder END")
|
||||||
|
|
||||||
@@ -84,23 +82,16 @@ def _debug_c(cmd, exit_code, out):
|
|||||||
log_error(("STDERR=\n %s\n" % out[1]))
|
log_error(("STDERR=\n %s\n" % out[1]))
|
||||||
|
|
||||||
|
|
||||||
def call_lvm(command, debug=False, line_cb=None,
|
def call_lvm(command, debug=False):
|
||||||
cb_data=None):
|
|
||||||
"""
|
"""
|
||||||
Call an executable and return a tuple of exitcode, stdout, stderr
|
Call an executable and return a tuple of exitcode, stdout, stderr
|
||||||
:param command: Command to execute
|
:param command: Command to execute
|
||||||
:param debug: Dump debug to stdout
|
:param debug: Dump debug to stdout
|
||||||
:param line_cb: Call the supplied function for each line read from
|
|
||||||
stdin, CALL MUST EXECUTE QUICKLY and not *block*
|
|
||||||
otherwise call_lvm function will fail to read
|
|
||||||
stdin/stdout. Return value of call back is ignored
|
|
||||||
:param cb_data: Supplied to callback to allow caller access to
|
|
||||||
its own data
|
|
||||||
|
|
||||||
# Callback signature
|
|
||||||
def my_callback(my_context, line_read_stdin)
|
|
||||||
pass
|
|
||||||
"""
|
"""
|
||||||
|
# print 'STACK:'
|
||||||
|
# for line in traceback.format_stack():
|
||||||
|
# print line.strip()
|
||||||
|
|
||||||
# Prepend the full lvm executable so that we can run different versions
|
# Prepend the full lvm executable so that we can run different versions
|
||||||
# in different locations on the same box
|
# in different locations on the same box
|
||||||
command.insert(0, cfg.LVM_CMD)
|
command.insert(0, cfg.LVM_CMD)
|
||||||
@@ -108,44 +99,10 @@ def call_lvm(command, debug=False, line_cb=None,
|
|||||||
|
|
||||||
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
|
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
|
||||||
env=os.environ)
|
env=os.environ)
|
||||||
|
out = process.communicate()
|
||||||
|
|
||||||
stdout_text = ""
|
stdout_text = bytes(out[0]).decode("utf-8")
|
||||||
stderr_text = ""
|
stderr_text = bytes(out[1]).decode("utf-8")
|
||||||
stdout_index = 0
|
|
||||||
make_non_block(process.stdout)
|
|
||||||
make_non_block(process.stderr)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
|
|
||||||
ready = select.select(rd_fd, [], [], 2)
|
|
||||||
|
|
||||||
for r in ready[0]:
|
|
||||||
if r == process.stdout.fileno():
|
|
||||||
stdout_text += read_decoded(process.stdout)
|
|
||||||
elif r == process.stderr.fileno():
|
|
||||||
stderr_text += read_decoded(process.stderr)
|
|
||||||
|
|
||||||
if line_cb is not None:
|
|
||||||
# Process the callback for each line read!
|
|
||||||
while True:
|
|
||||||
i = stdout_text.find("\n", stdout_index)
|
|
||||||
if i != -1:
|
|
||||||
try:
|
|
||||||
line_cb(cb_data, stdout_text[stdout_index:i])
|
|
||||||
except:
|
|
||||||
st = traceback.format_exc()
|
|
||||||
log_error("call_lvm: line_cb exception: \n %s" % st)
|
|
||||||
stdout_index = i + 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Check to see if process has terminated, None when running
|
|
||||||
if process.poll() is not None:
|
|
||||||
break
|
|
||||||
except IOError as ioe:
|
|
||||||
log_debug("call_lvm:" + str(ioe))
|
|
||||||
pass
|
|
||||||
|
|
||||||
if debug or process.returncode != 0:
|
if debug or process.returncode != 0:
|
||||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
||||||
@@ -260,9 +217,6 @@ def options_to_cli_args(options):
|
|||||||
else:
|
else:
|
||||||
rc.append("--%s" % k)
|
rc.append("--%s" % k)
|
||||||
if v != "":
|
if v != "":
|
||||||
if isinstance(v, int):
|
|
||||||
rc.append(str(int(v)))
|
|
||||||
else:
|
|
||||||
rc.append(str(v))
|
rc.append(str(v))
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
@@ -309,10 +263,10 @@ def lv_tag(lv_name, add, rm, tag_options):
|
|||||||
return _tag('lvchange', lv_name, add, rm, tag_options)
|
return _tag('lvchange', lv_name, add, rm, tag_options)
|
||||||
|
|
||||||
|
|
||||||
def vg_rename(vg_uuid, new_name, rename_options):
|
def vg_rename(vg, new_name, rename_options):
|
||||||
cmd = ['vgrename']
|
cmd = ['vgrename']
|
||||||
cmd.extend(options_to_cli_args(rename_options))
|
cmd.extend(options_to_cli_args(rename_options))
|
||||||
cmd.extend([vg_uuid, new_name])
|
cmd.extend([vg, new_name])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
@@ -326,7 +280,7 @@ def vg_remove(vg_name, remove_options):
|
|||||||
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
|
def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
|
||||||
cmd = ['lvcreate']
|
cmd = ['lvcreate']
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
cmd.extend(['--name', name, vg_name, '--yes'])
|
cmd.extend(['--name', name, vg_name, '--yes'])
|
||||||
pv_dest_ranges(cmd, pv_dests)
|
pv_dest_ranges(cmd, pv_dests)
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -338,7 +292,7 @@ def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
|
|||||||
cmd.extend(["-s"])
|
cmd.extend(["-s"])
|
||||||
|
|
||||||
if size_bytes != 0:
|
if size_bytes != 0:
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
cmd.extend(['--name', name, vg_name])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -349,9 +303,9 @@ def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
if not thin_pool:
|
if not thin_pool:
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
else:
|
else:
|
||||||
cmd.extend(['--thin', '--size', '%dB' % size_bytes])
|
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
cmd.extend(['--yes'])
|
cmd.extend(['--yes'])
|
||||||
return cmd
|
return cmd
|
||||||
@@ -366,10 +320,10 @@ def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
|
|||||||
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
|
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
|
||||||
num_stripes, stripe_size_kb, thin_pool):
|
num_stripes, stripe_size_kb, thin_pool):
|
||||||
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
|
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
|
||||||
cmd.extend(['--stripes', str(int(num_stripes))])
|
cmd.extend(['--stripes', str(num_stripes)])
|
||||||
|
|
||||||
if stripe_size_kb != 0:
|
if stripe_size_kb != 0:
|
||||||
cmd.extend(['--stripesize', str(int(stripe_size_kb))])
|
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name])
|
cmd.extend(['--name', name, vg_name])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -382,13 +336,13 @@ def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
cmd.extend(['--type', raid_type])
|
cmd.extend(['--type', raid_type])
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
if num_stripes != 0:
|
if num_stripes != 0:
|
||||||
cmd.extend(['--stripes', str(int(num_stripes))])
|
cmd.extend(['--stripes', str(num_stripes)])
|
||||||
|
|
||||||
if stripe_size_kb != 0:
|
if stripe_size_kb != 0:
|
||||||
cmd.extend(['--stripesize', str(int(stripe_size_kb))])
|
cmd.extend(['--stripesize', str(stripe_size_kb)])
|
||||||
|
|
||||||
cmd.extend(['--name', name, vg_name, '--yes'])
|
cmd.extend(['--name', name, vg_name, '--yes'])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -409,8 +363,8 @@ def vg_lv_create_mirror(
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
cmd.extend(['--type', 'mirror'])
|
cmd.extend(['--type', 'mirror'])
|
||||||
cmd.extend(['--mirrors', str(int(num_copies))])
|
cmd.extend(['--mirrors', str(num_copies)])
|
||||||
cmd.extend(['--size', '%dB' % size_bytes])
|
cmd.extend(['--size', str(size_bytes) + 'B'])
|
||||||
cmd.extend(['--name', name, vg_name, '--yes'])
|
cmd.extend(['--name', name, vg_name, '--yes'])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
@@ -431,24 +385,6 @@ def vg_create_thin_pool(md_full_name, data_full_name, create_options):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def vg_create_vdo_pool_lv_and_lv(vg_name, pool_name, lv_name, data_size,
|
|
||||||
virtual_size, create_options):
|
|
||||||
cmd = ['lvcreate']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['-y', '--type', 'vdo', '-n', lv_name,
|
|
||||||
'-L', '%dB' % data_size, '-V', '%dB' % virtual_size,
|
|
||||||
"%s/%s" % (vg_name, pool_name)])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def vg_create_vdo_pool(pool_full_name, lv_name, virtual_size, create_options):
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
|
||||||
cmd.extend(['--type', 'vdo-pool', '-n', lv_name, '--force', '-y',
|
|
||||||
'-V', '%dB' % virtual_size, pool_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_remove(lv_path, remove_options):
|
def lv_remove(lv_path, remove_options):
|
||||||
cmd = ['lvremove']
|
cmd = ['lvremove']
|
||||||
cmd.extend(options_to_cli_args(remove_options))
|
cmd.extend(options_to_cli_args(remove_options))
|
||||||
@@ -482,7 +418,7 @@ def lv_resize(lv_full_name, size_change, pv_dests,
|
|||||||
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
|
def lv_lv_create(lv_full_name, create_options, name, size_bytes):
|
||||||
cmd = ['lvcreate']
|
cmd = ['lvcreate']
|
||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
cmd.extend(['--virtualsize', '%dB' % size_bytes, '-T'])
|
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
|
||||||
cmd.extend(['--name', name, lv_full_name, '--yes'])
|
cmd.extend(['--name', name, lv_full_name, '--yes'])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
@@ -496,15 +432,6 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options):
|
|
||||||
# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV
|
|
||||||
cmd = ['lvconvert']
|
|
||||||
cmd.extend(options_to_cli_args(cache_options))
|
|
||||||
cmd.extend(['-y', '--type', 'writecache', '--cachevol',
|
|
||||||
cache_lv_full_name, lv_full_name])
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
||||||
cmd = ['lvconvert']
|
cmd = ['lvconvert']
|
||||||
if destroy_cache:
|
if destroy_cache:
|
||||||
@@ -520,28 +447,6 @@ def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
|
|||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|
||||||
def lv_vdo_compression(lv_path, enable, comp_options):
|
|
||||||
cmd = ['lvchange', '--compression']
|
|
||||||
if enable:
|
|
||||||
cmd.append('y')
|
|
||||||
else:
|
|
||||||
cmd.append('n')
|
|
||||||
cmd.extend(options_to_cli_args(comp_options))
|
|
||||||
cmd.append(lv_path)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def lv_vdo_deduplication(lv_path, enable, dedup_options):
|
|
||||||
cmd = ['lvchange', '--deduplication']
|
|
||||||
if enable:
|
|
||||||
cmd.append('y')
|
|
||||||
else:
|
|
||||||
cmd.append('n')
|
|
||||||
cmd.extend(options_to_cli_args(dedup_options))
|
|
||||||
cmd.append(lv_path)
|
|
||||||
return call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def supports_json():
|
def supports_json():
|
||||||
cmd = ['help']
|
cmd = ['help']
|
||||||
rc, out, err = call(cmd)
|
rc, out, err = call(cmd)
|
||||||
@@ -554,16 +459,6 @@ def supports_json():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def supports_vdo():
|
|
||||||
cmd = ['segtypes']
|
|
||||||
rc, out, err = call(cmd)
|
|
||||||
if rc == 0:
|
|
||||||
if "vdo" in out:
|
|
||||||
log_debug("We have VDO support")
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def lvm_full_report_json():
|
def lvm_full_report_json():
|
||||||
pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
pv_columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
|
||||||
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
|
||||||
@@ -591,22 +486,6 @@ def lvm_full_report_json():
|
|||||||
|
|
||||||
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
|
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
|
||||||
|
|
||||||
if cfg.vdo_support:
|
|
||||||
lv_columns.extend(
|
|
||||||
['vdo_operating_mode', 'vdo_compression_state', 'vdo_index_state',
|
|
||||||
'vdo_used_size', 'vdo_saving_percent']
|
|
||||||
)
|
|
||||||
|
|
||||||
lv_seg_columns.extend(
|
|
||||||
['vdo_compression', 'vdo_deduplication',
|
|
||||||
'vdo_use_metadata_hints', 'vdo_minimum_io_size',
|
|
||||||
'vdo_block_map_cache_size', 'vdo_block_map_era_length',
|
|
||||||
'vdo_use_sparse_index', 'vdo_index_memory_size',
|
|
||||||
'vdo_slab_size', 'vdo_ack_threads', 'vdo_bio_threads',
|
|
||||||
'vdo_bio_rotation', 'vdo_cpu_threads', 'vdo_hash_zone_threads',
|
|
||||||
'vdo_logical_threads', 'vdo_physical_threads',
|
|
||||||
'vdo_max_discard', 'vdo_write_policy', 'vdo_header_size'])
|
|
||||||
|
|
||||||
cmd = _dc('fullreport', [
|
cmd = _dc('fullreport', [
|
||||||
'-a', # Need hidden too
|
'-a', # Need hidden too
|
||||||
'--configreport', 'pv', '-o', ','.join(pv_columns),
|
'--configreport', 'pv', '-o', ','.join(pv_columns),
|
||||||
@@ -618,8 +497,7 @@ def lvm_full_report_json():
|
|||||||
])
|
])
|
||||||
|
|
||||||
rc, out, err = call(cmd)
|
rc, out, err = call(cmd)
|
||||||
# When we have an exported vg the exit code of lvs or fullreport will be 5
|
if rc == 0:
|
||||||
if rc == 0 or rc == 5:
|
|
||||||
# With the current implementation, if we are using the shell then we
|
# 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
|
# are using JSON and JSON is returned back to us as it was parsed to
|
||||||
# figure out if we completed OK or not
|
# figure out if we completed OK or not
|
||||||
@@ -627,13 +505,7 @@ def lvm_full_report_json():
|
|||||||
assert(type(out) == dict)
|
assert(type(out) == dict)
|
||||||
return out
|
return out
|
||||||
else:
|
else:
|
||||||
try:
|
|
||||||
return json.loads(out)
|
return json.loads(out)
|
||||||
except json.decoder.JSONDecodeError as joe:
|
|
||||||
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
|
|
||||||
(str(joe), out))
|
|
||||||
raise joe
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -683,7 +555,7 @@ def pv_resize(device, size_bytes, create_options):
|
|||||||
cmd.extend(options_to_cli_args(create_options))
|
cmd.extend(options_to_cli_args(create_options))
|
||||||
|
|
||||||
if size_bytes != 0:
|
if size_bytes != 0:
|
||||||
cmd.extend(['--yes', '--setphysicalvolumesize', '%dB' % size_bytes])
|
cmd.extend(['--yes', '--setphysicalvolumesize', str(size_bytes) + 'B'])
|
||||||
|
|
||||||
cmd.extend([device])
|
cmd.extend([device])
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
@@ -779,12 +651,12 @@ def vg_allocation_policy(vg_name, policy, policy_options):
|
|||||||
|
|
||||||
|
|
||||||
def vg_max_pv(vg_name, number, max_options):
|
def vg_max_pv(vg_name, number, max_options):
|
||||||
return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(int(number))],
|
return _vg_value_set(vg_name, ['--maxphysicalvolumes', str(number)],
|
||||||
max_options)
|
max_options)
|
||||||
|
|
||||||
|
|
||||||
def vg_max_lv(vg_name, number, max_options):
|
def vg_max_lv(vg_name, number, max_options):
|
||||||
return _vg_value_set(vg_name, ['-l', str(int(number))], max_options)
|
return _vg_value_set(vg_name, ['-l', str(number)], max_options)
|
||||||
|
|
||||||
|
|
||||||
def vg_uuid_gen(vg_name, ignore, options):
|
def vg_uuid_gen(vg_name, ignore, options):
|
||||||
@@ -826,7 +698,6 @@ def activate_deactivate(op, name, activate, control_flags, options):
|
|||||||
op += 'n'
|
op += 'n'
|
||||||
|
|
||||||
cmd.append(op)
|
cmd.append(op)
|
||||||
cmd.append("-y")
|
|
||||||
cmd.append(name)
|
cmd.append(name)
|
||||||
return call(cmd)
|
return call(cmd)
|
||||||
|
|
||||||
|
|||||||
@@ -14,61 +14,24 @@ from . import cfg
|
|||||||
from .utils import MThreadRunner, log_debug, log_error
|
from .utils import MThreadRunner, log_debug, log_error
|
||||||
import threading
|
import threading
|
||||||
import queue
|
import queue
|
||||||
import time
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
def _main_thread_load(refresh=True, emit_signal=True):
|
def _main_thread_load(refresh=True, emit_signal=True):
|
||||||
num_total_changes = 0
|
num_total_changes = 0
|
||||||
to_remove = []
|
|
||||||
|
|
||||||
(changes, remove) = load_pvs(
|
num_total_changes += load_pvs(
|
||||||
refresh=refresh,
|
refresh=refresh,
|
||||||
emit_signal=emit_signal,
|
emit_signal=emit_signal,
|
||||||
cache_refresh=False)[1:]
|
cache_refresh=False)[1]
|
||||||
num_total_changes += changes
|
num_total_changes += load_vgs(
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
(changes, remove) = load_vgs(
|
|
||||||
refresh=refresh,
|
refresh=refresh,
|
||||||
emit_signal=emit_signal,
|
emit_signal=emit_signal,
|
||||||
cache_refresh=False)[1:]
|
cache_refresh=False)[1]
|
||||||
|
num_total_changes += load_lvs(
|
||||||
num_total_changes += changes
|
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
(lv_changes, remove) = load_lvs(
|
|
||||||
refresh=refresh,
|
refresh=refresh,
|
||||||
emit_signal=emit_signal,
|
emit_signal=emit_signal,
|
||||||
cache_refresh=False)[1:]
|
cache_refresh=False)[1]
|
||||||
|
|
||||||
num_total_changes += lv_changes
|
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
# When the LVs change it can cause another change in the VGs which is
|
|
||||||
# missed if we don't scan through the VGs again. We could achieve this
|
|
||||||
# the other way and re-scan the LVs, but in general there are more LVs than
|
|
||||||
# VGs, thus this should be more efficient. This happens when a LV interface
|
|
||||||
# changes causing the dbus object representing it to be removed and
|
|
||||||
# recreated.
|
|
||||||
if refresh and lv_changes > 0:
|
|
||||||
(changes, remove) = load_vgs(
|
|
||||||
refresh=refresh,
|
|
||||||
emit_signal=emit_signal,
|
|
||||||
cache_refresh=False)[1:]
|
|
||||||
|
|
||||||
num_total_changes += changes
|
|
||||||
to_remove.extend(remove)
|
|
||||||
|
|
||||||
# Remove any objects that are no longer needed. We do this after we process
|
|
||||||
# all the objects to ensure that references still exist for objects that
|
|
||||||
# are processed after them.
|
|
||||||
to_remove.reverse()
|
|
||||||
for i in to_remove:
|
|
||||||
dbus_obj = cfg.om.get_object_by_path(i)
|
|
||||||
if dbus_obj:
|
|
||||||
cfg.om.remove_object(dbus_obj, True)
|
|
||||||
num_total_changes += 1
|
|
||||||
|
|
||||||
return num_total_changes
|
return num_total_changes
|
||||||
|
|
||||||
@@ -119,8 +82,6 @@ class StateUpdate(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_thread(obj):
|
def update_thread(obj):
|
||||||
exception_count = 0
|
|
||||||
|
|
||||||
queued_requests = []
|
queued_requests = []
|
||||||
while cfg.run.value != 0:
|
while cfg.run.value != 0:
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
@@ -175,26 +136,12 @@ class StateUpdate(object):
|
|||||||
# wake up if we get an exception
|
# wake up if we get an exception
|
||||||
queued_requests = []
|
queued_requests = []
|
||||||
|
|
||||||
# We retrieved OK, clear exception count
|
|
||||||
exception_count = 0
|
|
||||||
|
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception:
|
||||||
st = traceback.format_exc()
|
st = traceback.format_exc()
|
||||||
log_error("update_thread exception: \n%s" % st)
|
log_error("update_thread exception: \n%s" % st)
|
||||||
cfg.blackbox.dump()
|
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):
|
def __init__(self):
|
||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
|
|||||||
@@ -75,10 +75,11 @@ def common(retrieve, o_type, search_keys,
|
|||||||
|
|
||||||
object_path = None
|
object_path = None
|
||||||
|
|
||||||
to_remove = []
|
|
||||||
if refresh:
|
if refresh:
|
||||||
to_remove = list(existing_paths.keys())
|
for k in list(existing_paths.keys()):
|
||||||
|
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
|
||||||
|
num_changes += 1
|
||||||
|
|
||||||
num_changes += len(rc)
|
num_changes += len(rc)
|
||||||
|
|
||||||
return rc, num_changes, to_remove
|
return rc, num_changes
|
||||||
|
|||||||
@@ -10,22 +10,20 @@
|
|||||||
from .automatedproperties import AutomatedProperties
|
from .automatedproperties import AutomatedProperties
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .utils import vg_obj_path_generate, log_error, _handle_execute
|
from .utils import vg_obj_path_generate
|
||||||
import dbus
|
import dbus
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
|
from .cfg import LV_INTERFACE, THIN_POOL_INTERFACE, SNAPSHOT_INTERFACE, \
|
||||||
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED, VDO_POOL_INTERFACE
|
LV_COMMON_INTERFACE, CACHE_POOL_INTERFACE, LV_CACHED
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from .utils import n, n32, d
|
from .utils import n, n32
|
||||||
from .loader import common
|
from .loader import common
|
||||||
from .state import State
|
from .state import State
|
||||||
from . import background
|
from . import background
|
||||||
from .utils import round_size, mt_remove_dbus_objects
|
from .utils import round_size, mt_remove_dbus_objects
|
||||||
from .job import JobState
|
from .job import JobState
|
||||||
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
# Try and build a key for a LV, so that we sort the LVs with least dependencies
|
# 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
|
# first. This may be error prone because of the flexibility LVM
|
||||||
@@ -74,49 +72,6 @@ def lvs_state_retrieve(selection, cache_refresh=True):
|
|||||||
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
|
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
|
||||||
|
|
||||||
for l in lvs:
|
for l in lvs:
|
||||||
if cfg.vdo_support:
|
|
||||||
rc.append(LvStateVdo(
|
|
||||||
l['lv_uuid'], l['lv_name'],
|
|
||||||
l['lv_path'], n(l['lv_size']),
|
|
||||||
l['vg_name'],
|
|
||||||
l['vg_uuid'], l['pool_lv_uuid'],
|
|
||||||
l['pool_lv'], l['origin_uuid'], l['origin'],
|
|
||||||
n32(l['data_percent']), l['lv_attr'],
|
|
||||||
l['lv_tags'], l['lv_active'], l['data_lv'],
|
|
||||||
l['metadata_lv'], l['segtype'], l['lv_role'],
|
|
||||||
l['lv_layout'],
|
|
||||||
n32(l['snap_percent']),
|
|
||||||
n32(l['metadata_percent']),
|
|
||||||
n32(l['copy_percent']),
|
|
||||||
n32(l['sync_percent']),
|
|
||||||
n(l['lv_metadata_size']),
|
|
||||||
l['move_pv'],
|
|
||||||
l['move_pv_uuid'],
|
|
||||||
l['vdo_operating_mode'],
|
|
||||||
l['vdo_compression_state'],
|
|
||||||
l['vdo_index_state'],
|
|
||||||
n(l['vdo_used_size']),
|
|
||||||
d(l['vdo_saving_percent']),
|
|
||||||
l['vdo_compression'],
|
|
||||||
l['vdo_deduplication'],
|
|
||||||
l['vdo_use_metadata_hints'],
|
|
||||||
n32(l['vdo_minimum_io_size']),
|
|
||||||
n(l['vdo_block_map_cache_size']),
|
|
||||||
n32(l['vdo_block_map_era_length']),
|
|
||||||
l['vdo_use_sparse_index'],
|
|
||||||
n(l['vdo_index_memory_size']),
|
|
||||||
n(l['vdo_slab_size']),
|
|
||||||
n32(l['vdo_ack_threads']),
|
|
||||||
n32(l['vdo_bio_threads']),
|
|
||||||
n32(l['vdo_bio_rotation']),
|
|
||||||
n32(l['vdo_cpu_threads']),
|
|
||||||
n32(l['vdo_hash_zone_threads']),
|
|
||||||
n32(l['vdo_logical_threads']),
|
|
||||||
n32(l['vdo_physical_threads']),
|
|
||||||
n32(l['vdo_max_discard']),
|
|
||||||
l['vdo_write_policy'],
|
|
||||||
n32(l['vdo_header_size'])))
|
|
||||||
else:
|
|
||||||
rc.append(LvState(
|
rc.append(LvState(
|
||||||
l['lv_uuid'], l['lv_name'],
|
l['lv_uuid'], l['lv_name'],
|
||||||
l['lv_path'], n(l['lv_size']),
|
l['lv_path'], n(l['lv_size']),
|
||||||
@@ -237,8 +192,6 @@ class LvState(State):
|
|||||||
def _object_type_create(self):
|
def _object_type_create(self):
|
||||||
if self.Attr[0] == 't':
|
if self.Attr[0] == 't':
|
||||||
return LvThinPool
|
return LvThinPool
|
||||||
elif self.Attr[0] == 'd':
|
|
||||||
return LvVdoPool
|
|
||||||
elif self.Attr[0] == 'C':
|
elif self.Attr[0] == 'C':
|
||||||
if 'pool' in self.layout:
|
if 'pool' in self.layout:
|
||||||
return LvCachePool
|
return LvCachePool
|
||||||
@@ -265,34 +218,6 @@ class LvState(State):
|
|||||||
return (klass, path_method)
|
return (klass, path_method)
|
||||||
|
|
||||||
|
|
||||||
class LvStateVdo(LvState):
|
|
||||||
|
|
||||||
def __init__(self, Uuid, Name, Path, SizeBytes,
|
|
||||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
|
||||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
|
||||||
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
|
|
||||||
MetaDataPercent, CopyPercent, SyncPercent,
|
|
||||||
MetaDataSizeBytes, move_pv, move_pv_uuid,
|
|
||||||
vdo_operating_mode, vdo_compression_state, vdo_index_state,
|
|
||||||
vdo_used_size,vdo_saving_percent,vdo_compression,
|
|
||||||
vdo_deduplication,vdo_use_metadata_hints,
|
|
||||||
vdo_minimum_io_size,vdo_block_map_cache_size,
|
|
||||||
vdo_block_map_era_length,vdo_use_sparse_index,
|
|
||||||
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
|
|
||||||
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
|
|
||||||
vdo_hash_zone_threads,vdo_logical_threads,
|
|
||||||
vdo_physical_threads,vdo_max_discard,
|
|
||||||
vdo_write_policy,vdo_header_size):
|
|
||||||
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
|
|
||||||
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
|
|
||||||
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
|
|
||||||
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
|
|
||||||
MetaDataPercent, CopyPercent, SyncPercent,
|
|
||||||
MetaDataSizeBytes, move_pv, move_pv_uuid)
|
|
||||||
|
|
||||||
utils.init_class_from_arguments(self, "vdo_", snake_to_pascal=True)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
|
@utils.dbus_property(LV_COMMON_INTERFACE, 'Uuid', 's')
|
||||||
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
|
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
|
||||||
@@ -348,7 +273,13 @@ class LvCommon(AutomatedProperties):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
_handle_execute(rc, out, err, LV_INTERFACE)
|
if rc == 0:
|
||||||
|
cfg.load()
|
||||||
|
else:
|
||||||
|
# Need to work on error handling, need consistent
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
LV_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_dbus_object(lv_uuid, lv_name):
|
def validate_dbus_object(lv_uuid, lv_name):
|
||||||
@@ -360,22 +291,6 @@ class LvCommon(AutomatedProperties):
|
|||||||
(lv_uuid, lv_name))
|
(lv_uuid, lv_name))
|
||||||
return dbo
|
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
|
@property
|
||||||
def VolumeType(self):
|
def VolumeType(self):
|
||||||
type_map = {'C': 'Cache', 'm': 'mirrored',
|
type_map = {'C': 'Cache', 'm': 'mirrored',
|
||||||
@@ -388,16 +303,17 @@ class LvCommon(AutomatedProperties):
|
|||||||
'l': 'mirror log device', 'c': 'under conversion',
|
'l': 'mirror log device', 'c': 'under conversion',
|
||||||
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
|
||||||
'e': 'raid or pool metadata or pool metadata spare',
|
'e': 'raid or pool metadata or pool metadata spare',
|
||||||
'd': 'vdo pool', 'D': 'vdo pool data', 'g': 'integrity',
|
|
||||||
'-': 'Unspecified'}
|
'-': 'Unspecified'}
|
||||||
return self.attr_struct(0, type_map)
|
return dbus.Struct((self.state.Attr[0], type_map[self.state.Attr[0]]),
|
||||||
|
signature="as")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def Permissions(self):
|
def Permissions(self):
|
||||||
type_map = {'w': 'writable', 'r': 'read-only',
|
type_map = {'w': 'writable', 'r': 'read-only',
|
||||||
'R': 'Read-only activation of non-read-only volume',
|
'R': 'Read-only activation of non-read-only volume',
|
||||||
'-': 'Unspecified'}
|
'-': 'Unspecified'}
|
||||||
return self.attr_struct(1, type_map)
|
return dbus.Struct((self.state.Attr[1], type_map[self.state.Attr[1]]),
|
||||||
|
signature="(ss)")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def AllocationPolicy(self):
|
def AllocationPolicy(self):
|
||||||
@@ -406,7 +322,8 @@ class LvCommon(AutomatedProperties):
|
|||||||
'i': 'inherited', 'I': 'inherited locked',
|
'i': 'inherited', 'I': 'inherited locked',
|
||||||
'l': 'cling', 'L': 'cling locked',
|
'l': 'cling', 'L': 'cling locked',
|
||||||
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
|
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
|
||||||
return self.attr_struct(2, type_map)
|
return dbus.Struct((self.state.Attr[2], type_map[self.state.Attr[2]]),
|
||||||
|
signature="(ss)")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def FixedMinor(self):
|
def FixedMinor(self):
|
||||||
@@ -414,20 +331,15 @@ class LvCommon(AutomatedProperties):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def State(self):
|
def State(self):
|
||||||
type_map = {'a': 'active',
|
type_map = {'a': 'active', 's': 'suspended', 'I': 'Invalid snapshot',
|
||||||
's': 'suspended',
|
|
||||||
'I': 'Invalid snapshot',
|
|
||||||
'S': 'invalid Suspended snapshot',
|
'S': 'invalid Suspended snapshot',
|
||||||
'm': 'snapshot merge failed',
|
'm': 'snapshot merge failed',
|
||||||
'M': 'suspended snapshot (M)erge failed',
|
'M': 'suspended snapshot (M)erge failed',
|
||||||
'd': 'mapped device present without tables',
|
'd': 'mapped device present without tables',
|
||||||
'i': 'mapped device present with inactive table',
|
'i': 'mapped device present with inactive table',
|
||||||
'h': 'historical',
|
'X': 'unknown', '-': 'Unspecified'}
|
||||||
'c': 'check needed suspended thin-pool',
|
return dbus.Struct((self.state.Attr[4], type_map[self.state.Attr[4]]),
|
||||||
'C': 'check needed',
|
signature="(ss)")
|
||||||
'X': 'unknown',
|
|
||||||
'-': 'Unspecified'}
|
|
||||||
return self.attr_struct(4, type_map)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TargetType(self):
|
def TargetType(self):
|
||||||
@@ -443,18 +355,11 @@ class LvCommon(AutomatedProperties):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def Health(self):
|
def Health(self):
|
||||||
type_map = {'p': 'partial',
|
type_map = {'p': 'partial', 'r': 'refresh',
|
||||||
'r': 'refresh needed',
|
'm': 'mismatches', 'w': 'writemostly',
|
||||||
'm': 'mismatches',
|
'X': 'X unknown', '-': 'Unspecified'}
|
||||||
'w': 'writemostly',
|
return dbus.Struct((self.state.Attr[8], type_map[self.state.Attr[8]]),
|
||||||
'X': 'unknown',
|
signature="(ss)")
|
||||||
'-': 'unspecified',
|
|
||||||
's': 'reshaping',
|
|
||||||
'F': 'failed',
|
|
||||||
'D': 'Data space',
|
|
||||||
'R': 'Remove',
|
|
||||||
'M': 'Metadata'}
|
|
||||||
return self.attr_struct(8, type_map)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SkipActivation(self):
|
def SkipActivation(self):
|
||||||
@@ -524,7 +429,8 @@ class Lv(LvCommon):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
# Remove the LV, if successful then remove from the model
|
# Remove the LV, if successful then remove from the model
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_remove(lv_name, remove_options))
|
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -544,8 +450,9 @@ class Lv(LvCommon):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
# Rename the logical volume
|
# Rename the logical volume
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_rename(lv_name, new_name,
|
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
|
||||||
rename_options))
|
rename_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -594,11 +501,13 @@ class Lv(LvCommon):
|
|||||||
remainder = space % 512
|
remainder = space % 512
|
||||||
optional_size = space + 512 - remainder
|
optional_size = space + 512 - remainder
|
||||||
|
|
||||||
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
|
rc, out, err = cmdhandler.vg_lv_snapshot(
|
||||||
lv_name, snapshot_options,name, optional_size))
|
lv_name, snapshot_options, name, optional_size)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||||
|
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=LV_INTERFACE,
|
dbus_interface=LV_INTERFACE,
|
||||||
in_signature='stia{sv}',
|
in_signature='stia{sv}',
|
||||||
@@ -634,8 +543,9 @@ class Lv(LvCommon):
|
|||||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||||
|
|
||||||
size_change = new_size_bytes - dbo.SizeBytes
|
size_change = new_size_bytes - dbo.SizeBytes
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_resize(
|
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
|
||||||
dbo.lvm_id, size_change,pv_dests, resize_options))
|
pv_dests, resize_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return "/"
|
return "/"
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -670,8 +580,9 @@ class Lv(LvCommon):
|
|||||||
options):
|
options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(uuid, lv_name)
|
LvCommon.validate_dbus_object(uuid, lv_name)
|
||||||
LvCommon.handle_execute(*cmdhandler.activate_deactivate(
|
rc, out, err = cmdhandler.activate_deactivate(
|
||||||
'lvchange', lv_name, activate, control_flags, options))
|
'lvchange', lv_name, activate, control_flags, options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -705,8 +616,9 @@ class Lv(LvCommon):
|
|||||||
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
|
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
LvCommon.validate_dbus_object(uuid, lv_name)
|
LvCommon.validate_dbus_object(uuid, lv_name)
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_tag(
|
rc, out, err = cmdhandler.lv_tag(
|
||||||
lv_name, tags_add, tags_del, tag_options))
|
lv_name, tags_add, tags_del, tag_options)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -743,152 +655,6 @@ class Lv(LvCommon):
|
|||||||
cb, cbe, return_tuple=False)
|
cb, cbe, return_tuple=False)
|
||||||
cfg.worker_q.put(r)
|
cfg.worker_q.put(r)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
|
||||||
|
|
||||||
# Make sure we have dbus object representing lv to cache
|
|
||||||
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
|
|
||||||
|
|
||||||
if lv_to_cache:
|
|
||||||
fcn = lv_to_cache.lv_full_name()
|
|
||||||
rc, out, err = cmdhandler.lv_writecache_lv(
|
|
||||||
dbo.lv_full_name(), fcn, cache_options)
|
|
||||||
if rc == 0:
|
|
||||||
# When we cache an LV, the cache pool and the lv that is getting
|
|
||||||
# cached need to be removed from the object manager and
|
|
||||||
# re-created as their interfaces have changed!
|
|
||||||
mt_remove_dbus_objects((dbo, lv_to_cache))
|
|
||||||
cfg.load()
|
|
||||||
|
|
||||||
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
|
|
||||||
else:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
LV_INTERFACE,
|
|
||||||
'Exit code %s, stderr = %s' % (str(rc), err))
|
|
||||||
else:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
LV_INTERFACE, 'LV to cache with object path %s not present!' %
|
|
||||||
lv_object_path)
|
|
||||||
return lv_converted
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=LV_INTERFACE,
|
|
||||||
in_signature='oia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def WriteCacheLv(self, lv_object, tmo, cache_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, Lv._writecache_lv,
|
|
||||||
(self.Uuid, self.lvm_id, lv_object,
|
|
||||||
cache_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CompressionState', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexState', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UsedSize', 't')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SavingPercent', 'd')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Compression', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'Deduplication', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseMetadataHints', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MinimumIoSize', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapCacheSize', "t")
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BlockMapEraLength', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'UseSparseIndex', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'IndexMemorySize', 't')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'SlabSize', 't')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'AckThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'BioRotation', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'CpuThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HashZoneThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'LogicalThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'PhysicalThreads', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'MaxDiscard', 'u')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'WritePolicy', 's')
|
|
||||||
@utils.dbus_property(VDO_POOL_INTERFACE, 'HeaderSize', 'u')
|
|
||||||
class LvVdoPool(Lv):
|
|
||||||
_DataLv_meta = ("o", VDO_POOL_INTERFACE)
|
|
||||||
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(LvVdoPool, self).__init__(object_path, object_state)
|
|
||||||
self.set_interface(VDO_POOL_INTERFACE)
|
|
||||||
self._data_lv, _ = self._get_data_meta()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def DataLv(self):
|
|
||||||
return dbus.ObjectPath(self._data_lv)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _enable_disable_compression(pool_uuid, pool_name, enable, comp_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
LvCommon.validate_dbus_object(pool_uuid, pool_name)
|
|
||||||
# Rename the logical volume
|
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_vdo_compression(
|
|
||||||
pool_name, enable, comp_options))
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def EnableCompression(self, tmo, comp_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_compression,
|
|
||||||
(self.Uuid, self.lvm_id, True, comp_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def DisableCompression(self, tmo, comp_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_compression,
|
|
||||||
(self.Uuid, self.lvm_id, False, comp_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _enable_disable_deduplication(pool_uuid, pool_name, enable, dedup_options):
|
|
||||||
# Make sure we have a dbus object representing it
|
|
||||||
LvCommon.validate_dbus_object(pool_uuid, pool_name)
|
|
||||||
# Rename the logical volume
|
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_vdo_deduplication(
|
|
||||||
pool_name, enable, dedup_options))
|
|
||||||
return '/'
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def EnableDeduplication(self, tmo, dedup_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_deduplication,
|
|
||||||
(self.Uuid, self.lvm_id, True, dedup_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VDO_POOL_INTERFACE,
|
|
||||||
in_signature='ia{sv}',
|
|
||||||
out_signature='o',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
|
|
||||||
r = RequestEntry(
|
|
||||||
tmo, LvVdoPool._enable_disable_deduplication,
|
|
||||||
(self.Uuid, self.lvm_id, False, dedup_options),
|
|
||||||
cb, cbe, False)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
class LvThinPool(Lv):
|
class LvThinPool(Lv):
|
||||||
@@ -912,8 +678,10 @@ class LvThinPool(Lv):
|
|||||||
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
|
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
|
||||||
LvCommon.handle_execute(*cmdhandler.lv_lv_create(
|
|
||||||
lv_name, create_options, name, size_bytes))
|
rc, out, err = cmdhandler.lv_lv_create(
|
||||||
|
lv_name, create_options, name, size_bytes)
|
||||||
|
LvCommon.handle_execute(rc, out, err)
|
||||||
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
|
||||||
return cfg.om.get_object_path_by_lvm_id(full_name)
|
return cfg.om.get_object_path_by_lvm_id(full_name)
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
|
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
@@ -28,8 +29,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
from lvmdbusd.cfg import LVM_CMD
|
from lvmdbusd.cfg import LVM_CMD
|
||||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
|
from lvmdbusd.utils import log_debug, log_error, add_no_notify
|
||||||
read_decoded
|
|
||||||
|
|
||||||
SHELL_PROMPT = "lvm> "
|
SHELL_PROMPT = "lvm> "
|
||||||
|
|
||||||
@@ -43,6 +43,13 @@ def _quote_arg(arg):
|
|||||||
|
|
||||||
class LVMShellProxy(object):
|
class LVMShellProxy(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _read(stream):
|
||||||
|
tmp = stream.read()
|
||||||
|
if tmp:
|
||||||
|
return tmp.decode("utf-8")
|
||||||
|
return ''
|
||||||
|
|
||||||
# Read until we get prompt back and a result
|
# Read until we get prompt back and a result
|
||||||
# @param: no_output Caller expects no output to report FD
|
# @param: no_output Caller expects no output to report FD
|
||||||
# Returns stdout, report, stderr (report is JSON!)
|
# Returns stdout, report, stderr (report is JSON!)
|
||||||
@@ -68,11 +75,11 @@ class LVMShellProxy(object):
|
|||||||
|
|
||||||
for r in ready[0]:
|
for r in ready[0]:
|
||||||
if r == self.lvm_shell.stdout.fileno():
|
if r == self.lvm_shell.stdout.fileno():
|
||||||
stdout += read_decoded(self.lvm_shell.stdout)
|
stdout += LVMShellProxy._read(self.lvm_shell.stdout)
|
||||||
elif r == self.report_stream.fileno():
|
elif r == self.report_stream.fileno():
|
||||||
report += read_decoded(self.report_stream)
|
report += LVMShellProxy._read(self.report_stream)
|
||||||
elif r == self.lvm_shell.stderr.fileno():
|
elif r == self.lvm_shell.stderr.fileno():
|
||||||
stderr += read_decoded(self.lvm_shell.stderr)
|
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
|
||||||
|
|
||||||
# Check to see if the lvm process died on us
|
# Check to see if the lvm process died on us
|
||||||
if self.lvm_shell.poll():
|
if self.lvm_shell.poll():
|
||||||
@@ -117,6 +124,11 @@ class LVMShellProxy(object):
|
|||||||
assert (num_written == len(cmd_bytes))
|
assert (num_written == len(cmd_bytes))
|
||||||
self.lvm_shell.stdin.flush()
|
self.lvm_shell.stdin.flush()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _make_non_block(stream):
|
||||||
|
flags = fcntl(stream, F_GETFL)
|
||||||
|
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Create a temp directory
|
# Create a temp directory
|
||||||
@@ -150,8 +162,8 @@ class LVMShellProxy(object):
|
|||||||
stderr=subprocess.PIPE, close_fds=True, shell=True)
|
stderr=subprocess.PIPE, close_fds=True, shell=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
make_non_block(self.lvm_shell.stdout)
|
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
|
||||||
make_non_block(self.lvm_shell.stderr)
|
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
|
||||||
|
|
||||||
# wait for the first prompt
|
# wait for the first prompt
|
||||||
errors = self._read_until_prompt(no_output=True)[2]
|
errors = self._read_until_prompt(no_output=True)[2]
|
||||||
@@ -208,10 +220,7 @@ class LVMShellProxy(object):
|
|||||||
|
|
||||||
# Parse the report to see what happened
|
# Parse the report to see what happened
|
||||||
if 'log' in report_json:
|
if 'log' in report_json:
|
||||||
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
|
if report_json['log'][-1:][0]['log_ret_code'] == '1':
|
||||||
# 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
|
rc = 0
|
||||||
else:
|
else:
|
||||||
error_msg = self.get_error_msg()
|
error_msg = self.get_error_msg()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from lvmdbusd.utils import log_debug, log_error
|
|||||||
|
|
||||||
|
|
||||||
class DataStore(object):
|
class DataStore(object):
|
||||||
def __init__(self, usejson=True, vdo_support=False):
|
def __init__(self, usejson=True):
|
||||||
self.pvs = {}
|
self.pvs = {}
|
||||||
self.vgs = {}
|
self.vgs = {}
|
||||||
self.lvs = {}
|
self.lvs = {}
|
||||||
@@ -43,8 +43,6 @@ class DataStore(object):
|
|||||||
else:
|
else:
|
||||||
self.json = usejson
|
self.json = usejson
|
||||||
|
|
||||||
self.vdo_support = vdo_support
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _insert_record(table, key, record, allowed_multiple):
|
def _insert_record(table, key, record, allowed_multiple):
|
||||||
if key in table:
|
if key in table:
|
||||||
@@ -143,22 +141,13 @@ class DataStore(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_vgs(_vgs):
|
def _parse_vgs(_vgs):
|
||||||
vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
|
vgs = sorted(_vgs, key=lambda vk: vk['vg_name'])
|
||||||
|
|
||||||
c_vgs = OrderedDict()
|
c_vgs = OrderedDict()
|
||||||
c_lookup = {}
|
c_lookup = {}
|
||||||
|
|
||||||
for i in vgs:
|
for i in vgs:
|
||||||
vg_name = i['vg_name']
|
c_lookup[i['vg_name']] = i['vg_uuid']
|
||||||
|
|
||||||
# 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, [])
|
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
|
||||||
|
|
||||||
return c_vgs, c_lookup
|
return c_vgs, c_lookup
|
||||||
@@ -173,22 +162,13 @@ class DataStore(object):
|
|||||||
tmp_vg.extend(r['vg'])
|
tmp_vg.extend(r['vg'])
|
||||||
|
|
||||||
# Sort for consistent output, however this is optional
|
# Sort for consistent output, however this is optional
|
||||||
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_uuid'])
|
vgs = sorted(tmp_vg, key=lambda vk: vk['vg_name'])
|
||||||
|
|
||||||
c_vgs = OrderedDict()
|
c_vgs = OrderedDict()
|
||||||
c_lookup = {}
|
c_lookup = {}
|
||||||
|
|
||||||
for i in vgs:
|
for i in vgs:
|
||||||
vg_name = i['vg_name']
|
c_lookup[i['vg_name']] = i['vg_uuid']
|
||||||
|
|
||||||
# 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
|
c_vgs[i['vg_uuid']] = i
|
||||||
|
|
||||||
return c_vgs, c_lookup
|
return c_vgs, c_lookup
|
||||||
@@ -243,7 +223,8 @@ class DataStore(object):
|
|||||||
|
|
||||||
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||||
|
|
||||||
def _parse_lvs_json(self, _all):
|
@staticmethod
|
||||||
|
def _parse_lvs_json(_all):
|
||||||
|
|
||||||
c_lvs = OrderedDict()
|
c_lvs = OrderedDict()
|
||||||
c_lv_full_lookup = {}
|
c_lv_full_lookup = {}
|
||||||
@@ -263,13 +244,8 @@ class DataStore(object):
|
|||||||
if 'seg' in r:
|
if 'seg' in r:
|
||||||
for s in r['seg']:
|
for s in r['seg']:
|
||||||
r = c_lvs[s['lv_uuid']]
|
r = c_lvs[s['lv_uuid']]
|
||||||
r.setdefault('seg_pe_ranges', []).\
|
r.setdefault('seg_pe_ranges', []).append(s['seg_pe_ranges'])
|
||||||
append(s['seg_pe_ranges'])
|
|
||||||
r.setdefault('segtype', []).append(s['segtype'])
|
r.setdefault('segtype', []).append(s['segtype'])
|
||||||
if self.vdo_support:
|
|
||||||
for seg_key, seg_val in s.items():
|
|
||||||
if seg_key.startswith("vdo_"):
|
|
||||||
r[seg_key] = seg_val
|
|
||||||
|
|
||||||
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
|
||||||
|
|
||||||
@@ -545,10 +521,6 @@ if __name__ == "__main__":
|
|||||||
for v in ds.vgs.values():
|
for v in ds.vgs.values():
|
||||||
pp.pprint(v)
|
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")
|
print("LVS")
|
||||||
for v in ds.lvs.values():
|
for v in ds.lvs.values():
|
||||||
pp.pprint(v)
|
pp.pprint(v)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from .utils import log_debug, log_error
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from .cmdhandler import LvmFlightRecorder, supports_vdo
|
from .cmdhandler import LvmFlightRecorder
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
|
|
||||||
|
|
||||||
@@ -44,10 +44,10 @@ def process_request():
|
|||||||
try:
|
try:
|
||||||
req = cfg.worker_q.get(True, 5)
|
req = cfg.worker_q.get(True, 5)
|
||||||
log_debug(
|
log_debug(
|
||||||
"Method start: %s with args %s (callback = %s)" %
|
"Running method: %s with args %s" %
|
||||||
(str(req.method), str(req.arguments), str(req.cb)))
|
(str(req.method), str(req.arguments)))
|
||||||
req.run_cmd()
|
req.run_cmd()
|
||||||
log_debug("Method complete: %s" % str(req.method))
|
log_debug("Method complete ")
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -127,14 +127,6 @@ def main():
|
|||||||
log_error("You cannot specify --lvmshell and --nojson")
|
log_error("You cannot specify --lvmshell and --nojson")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# We will dynamically add interfaces which support vdo if it
|
|
||||||
# exists.
|
|
||||||
cfg.vdo_support = supports_vdo()
|
|
||||||
|
|
||||||
if cfg.vdo_support and not cfg.args.use_json:
|
|
||||||
log_error("You cannot specify --nojson when lvm has VDO support")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# List of threads that we start up
|
# List of threads that we start up
|
||||||
thread_list = []
|
thread_list = []
|
||||||
|
|
||||||
@@ -155,12 +147,12 @@ def main():
|
|||||||
cfg.om = Lvm(BASE_OBJ_PATH)
|
cfg.om = Lvm(BASE_OBJ_PATH)
|
||||||
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
|
||||||
|
|
||||||
cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
|
cfg.db = lvmdb.DataStore(cfg.args.use_json)
|
||||||
|
|
||||||
# Using a thread to process requests, we cannot hang the dbus library
|
# Using a thread to process requests, we cannot hang the dbus library
|
||||||
# thread that is handling the dbus interface
|
# thread that is handling the dbus interface
|
||||||
thread_list.append(
|
thread_list.append(threading.Thread(target=process_request,
|
||||||
threading.Thread(target=process_request, name='process_request'))
|
name='process_request'))
|
||||||
|
|
||||||
# Have a single thread handling updating lvm and the dbus model so we
|
# Have a single thread handling updating lvm and the dbus model so we
|
||||||
# don't have multiple threads doing this as the same time
|
# don't have multiple threads doing this as the same time
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Manager(AutomatedProperties):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def Version(self):
|
def Version(self):
|
||||||
return dbus.String('1.1.0')
|
return dbus.String('1.0.0')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
@@ -107,10 +107,10 @@ class Manager(AutomatedProperties):
|
|||||||
rc = cfg.load(log=False)
|
rc = cfg.load(log=False)
|
||||||
|
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc),
|
utils.log_debug('Manager.Refresh - exit %d' % (rc),
|
||||||
'bg_black', 'fg_light_red')
|
'bg_black', 'fg_light_red')
|
||||||
else:
|
else:
|
||||||
utils.log_debug('Manager.Refresh - exit %d %d' % (rc, lc))
|
utils.log_debug('Manager.Refresh - exit %d' % (rc))
|
||||||
return rc + lc
|
return rc + lc
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -164,8 +164,6 @@ class Manager(AutomatedProperties):
|
|||||||
return the object path in O(1) time.
|
return the object path in O(1) time.
|
||||||
|
|
||||||
:param key: The lookup value
|
: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 '/'
|
:return: Return the object path. If object not found you will get '/'
|
||||||
"""
|
"""
|
||||||
r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
|
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()
|
path = dbus_object.dbus_object_path()
|
||||||
interfaces = dbus_object.interface()
|
interfaces = dbus_object.interface()
|
||||||
|
|
||||||
# print('UN-Registering object path %s for %s' %
|
# print 'UN-Registering object path %s for %s' % \
|
||||||
# (path, dbus_object.lvm_id))
|
# (path, dbus_object.lvm_id)
|
||||||
|
|
||||||
self._lookup_remove(path)
|
self._lookup_remove(path)
|
||||||
|
|
||||||
@@ -240,17 +240,37 @@ class ObjectManager(AutomatedProperties):
|
|||||||
return lookup_rc
|
return lookup_rc
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
def _id_verify(self, path, uuid, lvm_id):
|
def _uuid_verify(self, path, uuid, lvm_id):
|
||||||
"""
|
"""
|
||||||
Ensure our lookups are correct
|
Ensure uuid is present for a successful lvm_id lookup
|
||||||
NOTE: Internal call, assumes under object manager lock
|
NOTE: Internal call, assumes under object manager lock
|
||||||
:param path: Path to object we looked up
|
:param path: Path to object we looked up
|
||||||
:param uuid: uuid lookup
|
:param uuid: lvm uuid to verify
|
||||||
:param lvm_id: lvm_id lookup
|
:param lvm_id: lvm_id used to find object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
# There is no durable non-changeable name in lvm
|
# 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
|
||||||
if lvm_id != uuid:
|
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)
|
obj = self.get_object_by_path(path)
|
||||||
self._lookup_add(obj, path, lvm_id, uuid)
|
self._lookup_add(obj, path, lvm_id, uuid)
|
||||||
|
|
||||||
@@ -319,22 +339,22 @@ class ObjectManager(AutomatedProperties):
|
|||||||
# Lets check for the uuid first
|
# Lets check for the uuid first
|
||||||
path = self._id_lookup(uuid)
|
path = self._id_lookup(uuid)
|
||||||
if path:
|
if path:
|
||||||
# Ensure table lookups are correct
|
# Verify the lvm_id is sane
|
||||||
self._id_verify(path, uuid, lvm_id)
|
self._lvm_id_verify(path, uuid, lvm_id)
|
||||||
else:
|
else:
|
||||||
# Unable to find by UUID, lets lookup by lvm_id
|
# Unable to find by UUID, lets lookup by lvm_id
|
||||||
path = self._id_lookup(lvm_id)
|
path = self._id_lookup(lvm_id)
|
||||||
if path:
|
if path:
|
||||||
# Ensure table lookups are correct
|
# Verify the uuid is sane
|
||||||
self._id_verify(path, uuid, lvm_id)
|
self._uuid_verify(path, uuid, lvm_id)
|
||||||
else:
|
else:
|
||||||
# We have exhausted all lookups, let's create if we can
|
# We have exhausted all lookups, let's create if we can
|
||||||
if path_create:
|
if path_create:
|
||||||
path = path_create()
|
path = path_create()
|
||||||
self._lookup_add(None, path, lvm_id, uuid)
|
self._lookup_add(None, path, lvm_id, uuid)
|
||||||
|
|
||||||
# print('get_object_path_by_lvm_id(%s, %s, %s): return %s' %
|
# print('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
|
||||||
# (uuid, lvm_id, str(path_create), path))
|
# (uuid, lvm_id, str(path_create), str(gen_new), path))
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import dbus
|
|||||||
from .cfg import PV_INTERFACE
|
from .cfg import PV_INTERFACE
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
|
||||||
lv_object_path_method, _handle_execute
|
lv_object_path_method
|
||||||
from .loader import common
|
from .loader import common
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from .state import State
|
from .state import State
|
||||||
@@ -138,12 +138,19 @@ class Pv(AutomatedProperties):
|
|||||||
# Remove the PV, if successful then remove from the model
|
# Remove the PV, if successful then remove from the model
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||||
Pv.handle_execute(*cmdhandler.pv_remove(pv_name, remove_options))
|
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
|
||||||
|
Pv.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
return _handle_execute(rc, out, err, PV_INTERFACE)
|
if rc == 0:
|
||||||
|
cfg.load()
|
||||||
|
else:
|
||||||
|
# Need to work on error handling, need consistent
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
PV_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_dbus_object(pv_uuid, pv_name):
|
def validate_dbus_object(pv_uuid, pv_name):
|
||||||
@@ -171,8 +178,10 @@ class Pv(AutomatedProperties):
|
|||||||
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
|
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||||
Pv.handle_execute(*cmdhandler.pv_resize(pv_name, new_size_bytes,
|
|
||||||
resize_options))
|
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
|
||||||
|
resize_options)
|
||||||
|
Pv.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -191,8 +200,9 @@ class Pv(AutomatedProperties):
|
|||||||
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
|
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Pv.validate_dbus_object(pv_uuid, pv_name)
|
Pv.validate_dbus_object(pv_uuid, pv_name)
|
||||||
Pv.handle_execute(*cmdhandler.pv_allocatable(pv_name, yes_no,
|
rc, out, err = cmdhandler.pv_allocatable(
|
||||||
allocation_options))
|
pv_name, yes_no, allocation_options)
|
||||||
|
Pv.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ def filter_event(action, device):
|
|||||||
# when appropriate.
|
# when appropriate.
|
||||||
refresh = False
|
refresh = False
|
||||||
|
|
||||||
if 'ID_FS_TYPE' in device:
|
if '.ID_FS_TYPE_NEW' in device:
|
||||||
fs_type_new = device['ID_FS_TYPE']
|
fs_type_new = device['.ID_FS_TYPE_NEW']
|
||||||
|
|
||||||
if 'LVM' in fs_type_new:
|
if 'LVM' in fs_type_new:
|
||||||
refresh = True
|
refresh = True
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import ctypes
|
|||||||
import os
|
import os
|
||||||
import string
|
import string
|
||||||
import datetime
|
import datetime
|
||||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
|
||||||
|
|
||||||
import dbus
|
import dbus
|
||||||
from lvmdbusd import cfg
|
from lvmdbusd import cfg
|
||||||
@@ -27,15 +26,6 @@ import signal
|
|||||||
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
STDOUT_TTY = os.isatty(sys.stdout.fileno())
|
||||||
|
|
||||||
|
|
||||||
def _handle_execute(rc, out, err, interface):
|
|
||||||
if rc == 0:
|
|
||||||
cfg.load()
|
|
||||||
else:
|
|
||||||
# Need to work on error handling, need consistent
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
interface, 'Exit code %s, stderr = %s' % (str(rc), err))
|
|
||||||
|
|
||||||
|
|
||||||
def rtype(dbus_type):
|
def rtype(dbus_type):
|
||||||
"""
|
"""
|
||||||
Decorator making sure that the decorated function returns a value of
|
Decorator making sure that the decorated function returns a value of
|
||||||
@@ -67,20 +57,8 @@ def n32(v):
|
|||||||
return int(float(v))
|
return int(float(v))
|
||||||
|
|
||||||
|
|
||||||
@rtype(dbus.Double)
|
|
||||||
def d(v):
|
|
||||||
if not v:
|
|
||||||
return 0.0
|
|
||||||
return float(v)
|
|
||||||
|
|
||||||
|
|
||||||
def _snake_to_pascal(s):
|
|
||||||
return ''.join(x.title() for x in s.split('_'))
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
def init_class_from_arguments(
|
def init_class_from_arguments(obj_instance):
|
||||||
obj_instance, begin_suffix=None, snake_to_pascal=False):
|
|
||||||
for k, v in list(sys._getframe(1).f_locals.items()):
|
for k, v in list(sys._getframe(1).f_locals.items()):
|
||||||
if k != 'self':
|
if k != 'self':
|
||||||
nt = k
|
nt = k
|
||||||
@@ -91,16 +69,7 @@ def init_class_from_arguments(
|
|||||||
cur = getattr(obj_instance, nt, v)
|
cur = getattr(obj_instance, nt, v)
|
||||||
|
|
||||||
# print 'Init class %s = %s' % (nt, str(v))
|
# print 'Init class %s = %s' % (nt, str(v))
|
||||||
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0)\
|
if not (cur and len(str(cur)) and (v is None or len(str(v))) == 0):
|
||||||
and (begin_suffix is None or nt.startswith(begin_suffix)):
|
|
||||||
|
|
||||||
if begin_suffix and nt.startswith(begin_suffix):
|
|
||||||
name = nt[len(begin_suffix):]
|
|
||||||
if snake_to_pascal:
|
|
||||||
name = _snake_to_pascal(name)
|
|
||||||
|
|
||||||
setattr(obj_instance, name, v)
|
|
||||||
else:
|
|
||||||
setattr(obj_instance, nt, v)
|
setattr(obj_instance, nt, v)
|
||||||
|
|
||||||
|
|
||||||
@@ -369,8 +338,6 @@ def lv_object_path_method(name, meta):
|
|||||||
return _hidden_lv_obj_path_generate
|
return _hidden_lv_obj_path_generate
|
||||||
elif meta[0][0] == 't':
|
elif meta[0][0] == 't':
|
||||||
return _thin_pool_obj_path_generate
|
return _thin_pool_obj_path_generate
|
||||||
elif meta[0][0] == 'd':
|
|
||||||
return _vdo_pool_object_path_generate
|
|
||||||
elif meta[0][0] == 'C' and 'pool' in meta[1]:
|
elif meta[0][0] == 'C' and 'pool' in meta[1]:
|
||||||
return _cache_pool_obj_path_generate
|
return _cache_pool_obj_path_generate
|
||||||
|
|
||||||
@@ -388,10 +355,6 @@ def _thin_pool_obj_path_generate():
|
|||||||
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
|
return cfg.THIN_POOL_PATH + "/%d" % next(cfg.thin_id)
|
||||||
|
|
||||||
|
|
||||||
def _vdo_pool_object_path_generate():
|
|
||||||
return cfg.VDO_POOL_PATH + "/%d" % next(cfg.vdo_id)
|
|
||||||
|
|
||||||
|
|
||||||
def _cache_pool_obj_path_generate():
|
def _cache_pool_obj_path_generate():
|
||||||
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
|
return cfg.CACHE_POOL_PATH + "/%d" % next(cfg.cache_pool_id)
|
||||||
|
|
||||||
@@ -483,7 +446,7 @@ _ALLOWABLE_CH_SET = set(_ALLOWABLE_CH)
|
|||||||
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
|
_ALLOWABLE_VG_LV_CH = string.ascii_letters + string.digits + '.-_+'
|
||||||
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
|
_ALLOWABLE_VG_LV_CH_SET = set(_ALLOWABLE_VG_LV_CH)
|
||||||
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
|
_LV_NAME_RESERVED = ("_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
|
||||||
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin", "_vdata")
|
"_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta", "_vorigin")
|
||||||
|
|
||||||
# Tags can have the characters, based on the code
|
# Tags can have the characters, based on the code
|
||||||
# a-zA-Z0-9._-+/=!:&#
|
# a-zA-Z0-9._-+/=!:&#
|
||||||
@@ -682,16 +645,3 @@ def _remove_objects(dbus_objects_rm):
|
|||||||
# Remove dbus objects from main thread
|
# Remove dbus objects from main thread
|
||||||
def mt_remove_dbus_objects(objs):
|
def mt_remove_dbus_objects(objs):
|
||||||
MThreadRunner(_remove_objects, objs).done()
|
MThreadRunner(_remove_objects, objs).done()
|
||||||
|
|
||||||
|
|
||||||
# Make stream non-blocking
|
|
||||||
def make_non_block(stream):
|
|
||||||
flags = fcntl(stream, F_GETFL)
|
|
||||||
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
|
|
||||||
|
|
||||||
def read_decoded(stream):
|
|
||||||
tmp = stream.read()
|
|
||||||
if tmp:
|
|
||||||
return tmp.decode("utf-8")
|
|
||||||
return ''
|
|
||||||
|
|||||||
@@ -10,11 +10,10 @@
|
|||||||
from .automatedproperties import AutomatedProperties
|
from .automatedproperties import AutomatedProperties
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
from .utils import pv_obj_path_generate, vg_obj_path_generate, n, \
|
from .utils import pv_obj_path_generate, vg_obj_path_generate, n
|
||||||
_handle_execute
|
|
||||||
import dbus
|
import dbus
|
||||||
from . import cfg
|
from . import cfg
|
||||||
from .cfg import VG_INTERFACE, VG_VDO_INTERFACE
|
from .cfg import VG_INTERFACE
|
||||||
from . import cmdhandler
|
from . import cmdhandler
|
||||||
from .request import RequestEntry
|
from .request import RequestEntry
|
||||||
from .loader import common
|
from .loader import common
|
||||||
@@ -47,29 +46,24 @@ def vgs_state_retrieve(selection, cache_refresh=True):
|
|||||||
|
|
||||||
def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
def load_vgs(vg_specific=None, object_path=None, refresh=False,
|
||||||
emit_signal=False, cache_refresh=True):
|
emit_signal=False, cache_refresh=True):
|
||||||
return common(vgs_state_retrieve, (Vg, VgVdo, ), vg_specific, object_path, refresh,
|
return common(vgs_state_retrieve, (Vg,), vg_specific, object_path, refresh,
|
||||||
emit_signal, cache_refresh)
|
emit_signal, cache_refresh)
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
# noinspection PyPep8Naming,PyUnresolvedReferences,PyUnusedLocal
|
||||||
class VgState(State):
|
class VgState(State):
|
||||||
|
|
||||||
@property
|
|
||||||
def internal_name(self):
|
|
||||||
return self.Name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lvm_id(self):
|
def lvm_id(self):
|
||||||
return self.internal_name
|
return self.Name
|
||||||
|
|
||||||
def identifiers(self):
|
def identifiers(self):
|
||||||
return (self.Uuid, self.internal_name)
|
return (self.Uuid, self.Name)
|
||||||
|
|
||||||
def _lv_paths_build(self):
|
def _lv_paths_build(self):
|
||||||
rc = []
|
rc = []
|
||||||
for lv in cfg.db.lvs_in_vg(self.Uuid):
|
for lv in cfg.db.lvs_in_vg(self.Uuid):
|
||||||
(lv_name, meta, lv_uuid) = lv
|
(lv_name, meta, lv_uuid) = lv
|
||||||
full_name = "%s/%s" % (self.internal_name, lv_name)
|
full_name = "%s/%s" % (self.Name, lv_name)
|
||||||
|
|
||||||
gen = utils.lv_object_path_method(lv_name, meta)
|
gen = utils.lv_object_path_method(lv_name, meta)
|
||||||
|
|
||||||
@@ -98,11 +92,7 @@ class VgState(State):
|
|||||||
def create_dbus_object(self, path):
|
def create_dbus_object(self, path):
|
||||||
if not path:
|
if not path:
|
||||||
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
path = cfg.om.get_object_path_by_uuid_lvm_id(
|
||||||
self.Uuid, self.internal_name, vg_obj_path_generate)
|
self.Uuid, self.Name, vg_obj_path_generate)
|
||||||
|
|
||||||
if cfg.vdo_support:
|
|
||||||
return VgVdo(path, self)
|
|
||||||
else:
|
|
||||||
return Vg(path, self)
|
return Vg(path, self)
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -112,6 +102,7 @@ class VgState(State):
|
|||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
@utils.dbus_property(VG_INTERFACE, 'Uuid', 's')
|
@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, 'Fmt', 's')
|
||||||
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
|
@utils.dbus_property(VG_INTERFACE, 'SizeBytes', 't', 0)
|
||||||
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
|
@utils.dbus_property(VG_INTERFACE, 'FreeBytes', 't', 0)
|
||||||
@@ -144,7 +135,6 @@ class Vg(AutomatedProperties):
|
|||||||
_AllocNormal_meta = ('b', VG_INTERFACE)
|
_AllocNormal_meta = ('b', VG_INTERFACE)
|
||||||
_AllocAnywhere_meta = ('b', VG_INTERFACE)
|
_AllocAnywhere_meta = ('b', VG_INTERFACE)
|
||||||
_Clustered_meta = ('b', VG_INTERFACE)
|
_Clustered_meta = ('b', VG_INTERFACE)
|
||||||
_Name_meta = ('s', VG_INTERFACE)
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
# noinspection PyUnusedLocal,PyPep8Naming
|
||||||
def __init__(self, object_path, object_state):
|
def __init__(self, object_path, object_state):
|
||||||
@@ -159,7 +149,13 @@ class Vg(AutomatedProperties):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_execute(rc, out, err):
|
def handle_execute(rc, out, err):
|
||||||
return _handle_execute(rc, out, err, VG_INTERFACE)
|
if rc == 0:
|
||||||
|
cfg.load()
|
||||||
|
else:
|
||||||
|
# Need to work on error handling, need consistent
|
||||||
|
raise dbus.exceptions.DBusException(
|
||||||
|
VG_INTERFACE,
|
||||||
|
'Exit code %s, stderr = %s' % (str(rc), err))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_dbus_object(vg_uuid, vg_name):
|
def validate_dbus_object(vg_uuid, vg_name):
|
||||||
@@ -175,8 +171,9 @@ class Vg(AutomatedProperties):
|
|||||||
def _rename(uuid, vg_name, new_name, rename_options):
|
def _rename(uuid, vg_name, new_name, rename_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_rename(
|
rc, out, err = cmdhandler.vg_rename(
|
||||||
uuid, new_name, rename_options))
|
vg_name, new_name, rename_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -195,7 +192,8 @@ class Vg(AutomatedProperties):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
# Remove the VG, if successful then remove from the model
|
# Remove the VG, if successful then remove from the model
|
||||||
Vg.handle_execute(*cmdhandler.vg_remove(vg_name, remove_options))
|
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -211,13 +209,14 @@ class Vg(AutomatedProperties):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _change(uuid, vg_name, change_options):
|
def _change(uuid, vg_name, change_options):
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_change(change_options, vg_name))
|
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
# TODO: This should be broken into a number of different methods
|
# TODO: This should be broken into a number of different methods
|
||||||
# instead of having one method that takes a hash for parameters. Some of
|
# 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
|
# the changes that vgchange does works on entire system, not just a
|
||||||
# specific vg, thus that should be in the Manager interface.
|
# specfic vg, thus that should be in the Manager interface.
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
dbus_interface=VG_INTERFACE,
|
dbus_interface=VG_INTERFACE,
|
||||||
in_signature='ia{sv}',
|
in_signature='ia{sv}',
|
||||||
@@ -247,8 +246,9 @@ class Vg(AutomatedProperties):
|
|||||||
VG_INTERFACE,
|
VG_INTERFACE,
|
||||||
'PV Object path not found = %s!' % pv_op)
|
'PV Object path not found = %s!' % pv_op)
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_reduce(
|
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
|
||||||
vg_name, missing, pv_devices, reduce_options))
|
reduce_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -278,8 +278,9 @@ class Vg(AutomatedProperties):
|
|||||||
VG_INTERFACE, 'PV Object path not found = %s!' % i)
|
VG_INTERFACE, 'PV Object path not found = %s!' % i)
|
||||||
|
|
||||||
if len(extend_devices):
|
if len(extend_devices):
|
||||||
Vg.handle_execute(*cmdhandler.vg_extend(
|
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
|
||||||
vg_name, extend_devices, extend_options))
|
extend_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
VG_INTERFACE, 'No pv_object_paths provided!')
|
VG_INTERFACE, 'No pv_object_paths provided!')
|
||||||
@@ -333,8 +334,10 @@ class Vg(AutomatedProperties):
|
|||||||
|
|
||||||
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create(
|
rc, out, err = cmdhandler.vg_lv_create(
|
||||||
vg_name, create_options, name, size_bytes, pv_dests))
|
vg_name, create_options, name, size_bytes, pv_dests)
|
||||||
|
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -372,8 +375,11 @@ class Vg(AutomatedProperties):
|
|||||||
thin_pool, create_options):
|
thin_pool, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_linear(
|
|
||||||
vg_name, create_options, name, size_bytes, thin_pool))
|
rc, out, err = cmdhandler.vg_lv_create_linear(
|
||||||
|
vg_name, create_options, name, size_bytes, thin_pool)
|
||||||
|
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -395,9 +401,10 @@ class Vg(AutomatedProperties):
|
|||||||
stripe_size_kb, thin_pool, create_options):
|
stripe_size_kb, thin_pool, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_striped(
|
rc, out, err = cmdhandler.vg_lv_create_striped(
|
||||||
vg_name, create_options, name, size_bytes,
|
vg_name, create_options, name, size_bytes,
|
||||||
num_stripes, stripe_size_kb, thin_pool))
|
num_stripes, stripe_size_kb, thin_pool)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -422,8 +429,9 @@ class Vg(AutomatedProperties):
|
|||||||
num_copies, create_options):
|
num_copies, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_mirror(
|
rc, out, err = cmdhandler.vg_lv_create_mirror(
|
||||||
vg_name, create_options, name, size_bytes, num_copies))
|
vg_name, create_options, name, size_bytes, num_copies)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -446,9 +454,10 @@ class Vg(AutomatedProperties):
|
|||||||
num_stripes, stripe_size_kb, create_options):
|
num_stripes, stripe_size_kb, create_options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.vg_lv_create_raid(
|
rc, out, err = cmdhandler.vg_lv_create_raid(
|
||||||
vg_name, create_options, name, raid_type, size_bytes,
|
vg_name, create_options, name, raid_type, size_bytes,
|
||||||
num_stripes, stripe_size_kb))
|
num_stripes, stripe_size_kb)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return Vg.fetch_new_lv(vg_name, name)
|
return Vg.fetch_new_lv(vg_name, name)
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -546,8 +555,9 @@ class Vg(AutomatedProperties):
|
|||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
VG_INTERFACE, 'PV object path = %s not found' % p)
|
VG_INTERFACE, 'PV object path = %s not found' % p)
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.pv_tag(
|
rc, out, err = cmdhandler.pv_tag(
|
||||||
pv_devices, tags_add, tags_del, tag_options))
|
pv_devices, tags_add, tags_del, tag_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -588,8 +598,9 @@ class Vg(AutomatedProperties):
|
|||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_tag(
|
rc, out, err = cmdhandler.vg_tag(
|
||||||
vg_name, tags_add, tags_del, tag_options))
|
vg_name, tags_add, tags_del, tag_options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -628,7 +639,8 @@ class Vg(AutomatedProperties):
|
|||||||
def _vg_change_set(uuid, vg_name, method, value, options):
|
def _vg_change_set(uuid, vg_name, method, value, options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*method(vg_name, value, options))
|
rc, out, err = method(vg_name, value, options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -688,8 +700,9 @@ class Vg(AutomatedProperties):
|
|||||||
options):
|
options):
|
||||||
# Make sure we have a dbus object representing it
|
# Make sure we have a dbus object representing it
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
Vg.validate_dbus_object(uuid, vg_name)
|
||||||
Vg.handle_execute(*cmdhandler.activate_deactivate(
|
rc, out, err = cmdhandler.activate_deactivate(
|
||||||
'vgchange', vg_name, activate, control_flags, options))
|
'vgchange', vg_name, activate, control_flags, options)
|
||||||
|
Vg.handle_execute(rc, out, err)
|
||||||
return '/'
|
return '/'
|
||||||
|
|
||||||
@dbus.service.method(
|
@dbus.service.method(
|
||||||
@@ -716,12 +729,6 @@ class Vg(AutomatedProperties):
|
|||||||
cb, cbe, return_tuple=False)
|
cb, cbe, return_tuple=False)
|
||||||
cfg.worker_q.put(r)
|
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
|
@property
|
||||||
def Tags(self):
|
def Tags(self):
|
||||||
return utils.parse_tags(self.state.tags)
|
return utils.parse_tags(self.state.tags)
|
||||||
@@ -777,71 +784,3 @@ class Vg(AutomatedProperties):
|
|||||||
@property
|
@property
|
||||||
def Clustered(self):
|
def Clustered(self):
|
||||||
return self._attribute(5, 'c')
|
return self._attribute(5, 'c')
|
||||||
|
|
||||||
|
|
||||||
class VgVdo(Vg):
|
|
||||||
|
|
||||||
# noinspection PyUnusedLocal,PyPep8Naming
|
|
||||||
def __init__(self, object_path, object_state):
|
|
||||||
super(VgVdo, self).__init__(object_path, vgs_state_retrieve)
|
|
||||||
self.set_interface(VG_VDO_INTERFACE)
|
|
||||||
self._object_path = object_path
|
|
||||||
self.state = object_state
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _lv_vdo_pool_create_with_lv(uuid, vg_name, pool_name, lv_name,
|
|
||||||
data_size, virtual_size, create_options):
|
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool_lv_and_lv(
|
|
||||||
vg_name, pool_name, lv_name, data_size, virtual_size,
|
|
||||||
create_options))
|
|
||||||
return Vg.fetch_new_lv(vg_name, pool_name)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_VDO_INTERFACE,
|
|
||||||
in_signature='ssttia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CreateVdoPoolandLv(self, pool_name, lv_name, data_size, virtual_size,
|
|
||||||
tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, pool_name)
|
|
||||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, lv_name)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, VgVdo._lv_vdo_pool_create_with_lv,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
pool_name, lv_name, round_size(data_size),
|
|
||||||
round_size(virtual_size),
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _vdo_pool_create(uuid, vg_name, pool_lv, name, virtual_size, create_options):
|
|
||||||
Vg.validate_dbus_object(uuid, vg_name)
|
|
||||||
|
|
||||||
# Retrieve the full name of the pool lv
|
|
||||||
pool = cfg.om.get_object_by_path(pool_lv)
|
|
||||||
if not pool:
|
|
||||||
msg = 'LV with object path %s not present!' % \
|
|
||||||
(pool_lv)
|
|
||||||
raise dbus.exceptions.DBusException(VG_VDO_INTERFACE, msg)
|
|
||||||
|
|
||||||
Vg.handle_execute(*cmdhandler.vg_create_vdo_pool(
|
|
||||||
pool.lv_full_name(), name, virtual_size,
|
|
||||||
create_options))
|
|
||||||
return Vg.fetch_new_lv(vg_name, pool.Name)
|
|
||||||
|
|
||||||
@dbus.service.method(
|
|
||||||
dbus_interface=VG_VDO_INTERFACE,
|
|
||||||
in_signature='ostia{sv}',
|
|
||||||
out_signature='(oo)',
|
|
||||||
async_callbacks=('cb', 'cbe'))
|
|
||||||
def CreateVdoPool(self, pool_lv, name, virtual_size,
|
|
||||||
tmo, create_options, cb, cbe):
|
|
||||||
utils.validate_lv_name(VG_VDO_INTERFACE, self.Name, name)
|
|
||||||
|
|
||||||
r = RequestEntry(tmo, VgVdo._vdo_pool_create,
|
|
||||||
(self.state.Uuid, self.state.lvm_id,
|
|
||||||
pool_lv, name,
|
|
||||||
round_size(virtual_size),
|
|
||||||
create_options), cb, cbe)
|
|
||||||
cfg.worker_q.put(r)
|
|
||||||
|
|||||||
2
daemons/lvmetad/.gitignore
vendored
Normal file
2
daemons/lvmetad/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lvmetad
|
||||||
|
lvmetactl
|
||||||
62
daemons/lvmetad/Makefile.in
Normal file
62
daemons/lvmetad/Makefile.in
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
249
daemons/lvmetad/lvmetactl.c
Normal file
249
daemons/lvmetad/lvmetactl.c
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
90
daemons/lvmetad/lvmetad-client.h
Normal file
90
daemons/lvmetad/lvmetad-client.h
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
3021
daemons/lvmetad/lvmetad-core.c
Normal file
3021
daemons/lvmetad/lvmetad-core.c
Normal file
File diff suppressed because it is too large
Load Diff
16
daemons/lvmetad/test.sh
Executable file
16
daemons/lvmetad/test.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/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" .
|
||||||
147
daemons/lvmetad/testclient.c
Normal file
147
daemons/lvmetad/testclient.c
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* 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,8 +15,6 @@ srcdir = @srcdir@
|
|||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
top_builddir = @top_builddir@
|
top_builddir = @top_builddir@
|
||||||
|
|
||||||
USE_SD_NOTIFY=yes
|
|
||||||
|
|
||||||
SOURCES = lvmlockd-core.c
|
SOURCES = lvmlockd-core.c
|
||||||
|
|
||||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||||
@@ -27,50 +25,33 @@ endif
|
|||||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||||
SOURCES += lvmlockd-dlm.c
|
SOURCES += lvmlockd-dlm.c
|
||||||
LOCK_LIBS += -ldlm_lt
|
LOCK_LIBS += -ldlm_lt
|
||||||
LOCK_LIBS += -ldlmcontrol
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ("@BUILD_LOCKDIDM@", "yes")
|
|
||||||
SOURCES += lvmlockd-idm.c
|
|
||||||
LOCK_LIBS += -lseagate_ilm -lblkid
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SOURCES2 = lvmlockctl.c
|
SOURCES2 = lvmlockctl.c
|
||||||
|
|
||||||
TARGETS = lvmlockd lvmlockctl
|
TARGETS = lvmlockd lvmlockctl
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
.PHONY: install_lvmlockd
|
||||||
CFLOW_TARGET = lvmlockd
|
|
||||||
|
|
||||||
.PHONY: install_lvmlockd install_lvmlockctl
|
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
|
||||||
|
|
||||||
ifeq ($(USE_SD_NOTIFY),yes)
|
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
CFLAGS += $(shell pkg-config --cflags libsystemd) -DUSE_SD_NOTIFY
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
LIBS += $(shell pkg-config --libs libsystemd)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LOCK_LIBS) -ldaemonserver $(LIBS)
|
||||||
endif
|
|
||||||
|
|
||||||
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
|
||||||
@echo " [CC] $@"
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LIBS)
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LOCK_LIBS) $(LIBS)
|
|
||||||
|
|
||||||
lvmlockctl: lvmlockctl.o $(INTERNAL_LIBS)
|
|
||||||
@echo " [CC] $@"
|
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
|
||||||
|
|
||||||
install_lvmlockd: lvmlockd
|
install_lvmlockd: lvmlockd
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_lvmlockctl: lvmlockctl
|
install_lvmlockctl: lvmlockctl
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_lvm2: install_lvmlockd install_lvmlockctl
|
install_lvm2: install_lvmlockd install_lvmlockctl
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
* of the GNU Lesser General Public License v.2.1.
|
* of the GNU Lesser General Public License v.2.1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tools/tool.h"
|
#include "tool.h"
|
||||||
|
|
||||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
#include "lvmlockd-client.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@@ -18,22 +18,18 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
static int quit = 0;
|
static int quit = 0;
|
||||||
static int info = 0;
|
static int info = 0;
|
||||||
static int dump = 0;
|
static int dump = 0;
|
||||||
static int wait_opt = 1;
|
static int wait_opt = 0;
|
||||||
static int force_opt = 0;
|
static int force_opt = 0;
|
||||||
static int kill_vg = 0;
|
static int kill_vg = 0;
|
||||||
static int drop_vg = 0;
|
static int drop_vg = 0;
|
||||||
static int gl_enable = 0;
|
static int gl_enable = 0;
|
||||||
static int gl_disable = 0;
|
static int gl_disable = 0;
|
||||||
static int use_stderr = 0;
|
|
||||||
static int stop_lockspaces = 0;
|
static int stop_lockspaces = 0;
|
||||||
static char *arg_vg_name = NULL;
|
static char *arg_vg_name = NULL;
|
||||||
|
|
||||||
@@ -51,22 +47,6 @@ do { \
|
|||||||
printf(fmt "\n", ##args); \
|
printf(fmt "\n", ##args); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define log_sys_emerg(fmt, args...) \
|
|
||||||
do { \
|
|
||||||
if (use_stderr) \
|
|
||||||
fprintf(stderr, fmt "\n", ##args); \
|
|
||||||
else \
|
|
||||||
syslog(LOG_EMERG, fmt, ##args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define log_sys_warn(fmt, args...) \
|
|
||||||
do { \
|
|
||||||
if (use_stderr) \
|
|
||||||
fprintf(stderr, fmt "\n", ##args); \
|
|
||||||
else \
|
|
||||||
syslog(LOG_WARNING, fmt, ##args); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define MAX_LINE 512
|
#define MAX_LINE 512
|
||||||
|
|
||||||
/* copied from lvmlockd-internal.h */
|
/* copied from lvmlockd-internal.h */
|
||||||
@@ -300,12 +280,13 @@ static void format_info_line(char *line, char *r_name, char *r_type)
|
|||||||
|
|
||||||
static void format_info(void)
|
static void format_info(void)
|
||||||
{
|
{
|
||||||
char line[MAX_LINE] = { 0 };
|
char line[MAX_LINE];
|
||||||
char r_name[MAX_NAME+1] = { 0 };
|
char r_name[MAX_NAME+1];
|
||||||
char r_type[MAX_NAME+1] = { 0 };
|
char r_type[MAX_NAME+1];
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
|
memset(line, 0, sizeof(line));
|
||||||
|
|
||||||
for (i = 0; i < dump_len; i++) {
|
for (i = 0; i < dump_len; i++) {
|
||||||
line[j++] = dump_buf[i];
|
line[j++] = dump_buf[i];
|
||||||
@@ -345,8 +326,6 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
|
|||||||
{
|
{
|
||||||
int reply_result;
|
int reply_result;
|
||||||
|
|
||||||
*result = NO_LOCKD_RESULT;
|
|
||||||
|
|
||||||
if (reply.error) {
|
if (reply.error) {
|
||||||
log_error("lvmlockd_result reply error %d", reply.error);
|
log_error("lvmlockd_result reply error %d", reply.error);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -358,7 +337,7 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
|
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
|
||||||
if (reply_result == NO_LOCKD_RESULT) {
|
if (reply_result == -1000) {
|
||||||
log_error("lvmlockd_result no op_result");
|
log_error("lvmlockd_result no op_result");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -457,7 +436,6 @@ retry:
|
|||||||
if (count < dump_len)
|
if (count < dump_len)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
dump_buf[count] = 0;
|
|
||||||
rv = 0;
|
rv = 0;
|
||||||
if ((info && dump) || !strcmp(req_name, "dump"))
|
if ((info && dump) || !strcmp(req_name, "dump"))
|
||||||
printf("%s\n", dump_buf);
|
printf("%s\n", dump_buf);
|
||||||
@@ -523,274 +501,51 @@ static int do_stop_lockspaces(void)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _reopen_fd_to_null(int fd)
|
static int do_kill(void)
|
||||||
{
|
{
|
||||||
int null_fd;
|
daemon_reply reply;
|
||||||
int r = 0;
|
int result;
|
||||||
|
|
||||||
if ((null_fd = open("/dev/null", O_RDWR)) == -1) {
|
|
||||||
log_error("open error /dev/null %d", errno);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close(fd)) {
|
|
||||||
log_error("close error fd %d %d", fd, errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dup2(null_fd, fd) == -1) {
|
|
||||||
log_error("dup2 error %d", errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = 1;
|
|
||||||
out:
|
|
||||||
if (close(null_fd)) {
|
|
||||||
log_error("close error fd %d %d", null_fd, errno);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_AV_COUNT 32
|
|
||||||
#define ONE_ARG_LEN 1024
|
|
||||||
|
|
||||||
static void _run_command_pipe(const char *cmd_str, pid_t *pid_out, FILE **fp_out)
|
|
||||||
{
|
|
||||||
char arg[ONE_ARG_LEN];
|
|
||||||
char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
|
|
||||||
char *arg_dup;
|
|
||||||
int av_count = 0;
|
|
||||||
int cmd_len;
|
|
||||||
int arg_len;
|
|
||||||
pid_t pid = 0;
|
|
||||||
FILE *fp = NULL;
|
|
||||||
int pipefd[2];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_AV_COUNT + 1; i++)
|
|
||||||
av[i] = NULL;
|
|
||||||
|
|
||||||
cmd_len = strlen(cmd_str);
|
|
||||||
|
|
||||||
memset(&arg, 0, sizeof(arg));
|
|
||||||
arg_len = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < cmd_len; i++) {
|
|
||||||
if (!cmd_str[i])
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (av_count == MAX_AV_COUNT)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (cmd_str[i] == '\\') {
|
|
||||||
if (i == (cmd_len - 1))
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (cmd_str[i] == '\\') {
|
|
||||||
arg[arg_len++] = cmd_str[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isspace(cmd_str[i])) {
|
|
||||||
arg[arg_len++] = cmd_str[i];
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
|
|
||||||
arg[arg_len++] = cmd_str[i];
|
|
||||||
} else if (isspace(cmd_str[i])) {
|
|
||||||
if (arg_len) {
|
|
||||||
if (!(arg_dup = strdup(arg)))
|
|
||||||
goto out;
|
|
||||||
av[av_count++] = arg_dup;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(arg, 0, sizeof(arg));
|
|
||||||
arg_len = 0;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_len) {
|
|
||||||
if (av_count >= MAX_AV_COUNT)
|
|
||||||
goto out;
|
|
||||||
if (!(arg_dup = strdup(arg)))
|
|
||||||
goto out;
|
|
||||||
av[av_count++] = arg_dup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipe(pipefd)) {
|
|
||||||
log_error("pipe error %d", errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
|
|
||||||
if (pid < 0) {
|
|
||||||
log_error("fork error %d", errno);
|
|
||||||
pid = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid == 0) {
|
|
||||||
/* Child -> writer, convert pipe[0] to STDOUT */
|
|
||||||
if (!_reopen_fd_to_null(STDIN_FILENO))
|
|
||||||
log_error("reopen STDIN error");
|
|
||||||
else if (close(pipefd[0 /*read*/]))
|
|
||||||
log_error("close error pipe[0] %d", errno);
|
|
||||||
else if (close(STDOUT_FILENO))
|
|
||||||
log_error("close error STDOUT %d", errno);
|
|
||||||
else if (dup2(pipefd[1 /*write*/], STDOUT_FILENO) == -1)
|
|
||||||
log_error("dup2 error STDOUT %d", errno);
|
|
||||||
else if (close(pipefd[1]))
|
|
||||||
log_error("close error pipe[1] %d", errno);
|
|
||||||
else {
|
|
||||||
execvp(av[0], av);
|
|
||||||
log_error("execvp error %d", errno);
|
|
||||||
}
|
|
||||||
_exit(errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parent -> reader */
|
|
||||||
if (close(pipefd[1 /*write*/]))
|
|
||||||
log_error("close error STDOUT %d", errno);
|
|
||||||
|
|
||||||
if (!(fp = fdopen(pipefd[0 /*read*/], "r"))) {
|
|
||||||
log_error("fdopen STDIN error %d", errno);
|
|
||||||
if (close(pipefd[0]))
|
|
||||||
log_error("close error STDIN %d", errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
for (i = 0; i < MAX_AV_COUNT + 1; i++)
|
|
||||||
free(av[i]);
|
|
||||||
|
|
||||||
*pid_out = pid;
|
|
||||||
*fp_out = fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns -1 on error, 0 on success. */
|
|
||||||
|
|
||||||
static int _close_command_pipe(pid_t pid, FILE *fp)
|
|
||||||
{
|
|
||||||
int status, estatus;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (waitpid(pid, &status, 0) != pid) {
|
|
||||||
log_error("waitpid error pid %d %d", pid, errno);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
/* pid exited with an exit code */
|
|
||||||
estatus = WEXITSTATUS(status);
|
|
||||||
|
|
||||||
/* exit status 0: child success */
|
|
||||||
if (!estatus) {
|
|
||||||
ret = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* exit status not zero: child error */
|
|
||||||
log_error("child exit error %d", estatus);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WIFSIGNALED(status)) {
|
|
||||||
/* pid terminated due to a signal */
|
|
||||||
log_error("child exit from signal");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_error("child exit problem");
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (fp && fclose(fp))
|
|
||||||
log_error("fclose error STDIN %d", errno);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns -1 on error, 0 on success. */
|
|
||||||
|
|
||||||
static int _get_kill_command(char *kill_cmd)
|
|
||||||
{
|
|
||||||
char config_cmd[PATH_MAX + 128] = { 0 };
|
|
||||||
char config_val[1024] = { 0 };
|
|
||||||
char line[PATH_MAX] = { 0 };
|
|
||||||
pid_t pid = 0;
|
|
||||||
FILE *fp = NULL;
|
|
||||||
|
|
||||||
snprintf(config_cmd, PATH_MAX, "%s config --typeconfig full global/lvmlockctl_kill_command", LVM_PATH);
|
|
||||||
|
|
||||||
_run_command_pipe(config_cmd, &pid, &fp);
|
|
||||||
|
|
||||||
if (!pid) {
|
|
||||||
log_error("failed to run %s", config_cmd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp) {
|
|
||||||
log_error("failed to get output %s", config_cmd);
|
|
||||||
_close_command_pipe(pid, fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fgets(line, sizeof(line), fp)) {
|
|
||||||
log_error("no output from %s", config_cmd);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sscanf(line, "lvmlockctl_kill_command=\"%256[^\n\"]\"", config_val) != 1) {
|
|
||||||
log_error("unrecognized config value from %s", config_cmd);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config_val[0] || (config_val[0] == ' ')) {
|
|
||||||
log_error("invalid config value from %s", config_cmd);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_val[0] != '/') {
|
|
||||||
log_error("lvmlockctl_kill_command must be full path");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Found lvmlockctl_kill_command: %s\n", config_val);
|
|
||||||
|
|
||||||
snprintf(kill_cmd, PATH_MAX, "%s %s", config_val, arg_vg_name);
|
|
||||||
kill_cmd[PATH_MAX-1] = '\0';
|
|
||||||
|
|
||||||
_close_command_pipe(pid, fp);
|
|
||||||
return 0;
|
|
||||||
bad:
|
|
||||||
_close_command_pipe(pid, fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns -1 on error, 0 on success. */
|
|
||||||
|
|
||||||
static int _run_kill_command(char *kill_cmd)
|
|
||||||
{
|
|
||||||
pid_t pid = 0;
|
|
||||||
FILE *fp = NULL;
|
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
_run_command_pipe(kill_cmd, &pid, &fp);
|
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
|
||||||
rv = _close_command_pipe(pid, fp);
|
/* These two lines explain the manual alternative to the FIXME below. */
|
||||||
|
syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
|
||||||
|
syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
||||||
|
|
||||||
if (!pid)
|
/*
|
||||||
return -1;
|
* It may not be strictly necessary to notify lvmlockd of the kill, but
|
||||||
|
* lvmlockd can use this information to avoid attempting any new lock
|
||||||
|
* requests in the VG (which would fail anyway), and can return an
|
||||||
|
* error indicating that the VG has been killed.
|
||||||
|
*/
|
||||||
|
|
||||||
if (rv < 0)
|
reply = _lvmlockd_send("kill_vg",
|
||||||
return -1;
|
"cmd = %s", "lvmlockctl",
|
||||||
|
"pid = " FMTd64, (int64_t) getpid(),
|
||||||
|
"vg_name = %s", arg_vg_name,
|
||||||
|
NULL);
|
||||||
|
|
||||||
return 0;
|
if (!_lvmlockd_result(reply, &result)) {
|
||||||
|
log_error("lvmlockd result %d", result);
|
||||||
|
rv = result;
|
||||||
|
} else {
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
daemon_reply_destroy(reply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: here is where we should implement a strong form of
|
||||||
|
* blkdeactivate, and if it completes successfully, automatically call
|
||||||
|
* do_drop() afterward. (The drop step may not always be necessary
|
||||||
|
* if the lvm commands run while shutting things down release all the
|
||||||
|
* leases.)
|
||||||
|
*
|
||||||
|
* run_strong_blkdeactivate();
|
||||||
|
* do_drop();
|
||||||
|
*/
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_drop(void)
|
static int do_drop(void)
|
||||||
@@ -799,7 +554,7 @@ static int do_drop(void)
|
|||||||
int result;
|
int result;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
log_sys_warn("Dropping locks for VG %s.", arg_vg_name);
|
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for misuse by looking for any active LVs in the VG
|
* Check for misuse by looking for any active LVs in the VG
|
||||||
@@ -827,84 +582,6 @@ static int do_drop(void)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_kill(void)
|
|
||||||
{
|
|
||||||
char kill_cmd[PATH_MAX] = { 0 };
|
|
||||||
daemon_reply reply;
|
|
||||||
int no_kill_command = 0;
|
|
||||||
int result;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
log_sys_emerg("lvmlockd lost access to locks in VG %s.", arg_vg_name);
|
|
||||||
|
|
||||||
rv = _get_kill_command(kill_cmd);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_sys_emerg("Immediately deactivate LVs in VG %s.", arg_vg_name);
|
|
||||||
log_sys_emerg("Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
|
||||||
no_kill_command = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It may not be strictly necessary to notify lvmlockd of the kill, but
|
|
||||||
* lvmlockd can use this information to avoid attempting any new lock
|
|
||||||
* requests in the VG (which would fail anyway), and can return an
|
|
||||||
* error indicating that the VG has been killed.
|
|
||||||
*/
|
|
||||||
_lvmlockd = lvmlockd_open(NULL);
|
|
||||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
|
||||||
log_error("Cannot connect to lvmlockd for kill_vg.");
|
|
||||||
goto run;
|
|
||||||
}
|
|
||||||
reply = _lvmlockd_send("kill_vg",
|
|
||||||
"cmd = %s", "lvmlockctl",
|
|
||||||
"pid = " FMTd64, (int64_t) getpid(),
|
|
||||||
"vg_name = %s", arg_vg_name,
|
|
||||||
NULL);
|
|
||||||
if (!_lvmlockd_result(reply, &result))
|
|
||||||
log_error("lvmlockd result %d kill_vg", result);
|
|
||||||
daemon_reply_destroy(reply);
|
|
||||||
lvmlockd_close(_lvmlockd);
|
|
||||||
|
|
||||||
run:
|
|
||||||
if (no_kill_command)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rv = _run_kill_command(kill_cmd);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_sys_emerg("Failed to run VG %s kill command %s", arg_vg_name, kill_cmd);
|
|
||||||
log_sys_emerg("Immediately deactivate LVs in VG %s.", arg_vg_name);
|
|
||||||
log_sys_emerg("Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_sys_warn("Successful VG %s kill command %s", arg_vg_name, kill_cmd);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If kill command was successfully, call do_drop(). (The drop step
|
|
||||||
* may not always be necessary if the lvm commands run while shutting
|
|
||||||
* things down release all the leases.)
|
|
||||||
*/
|
|
||||||
rv = 0;
|
|
||||||
_lvmlockd = lvmlockd_open(NULL);
|
|
||||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
|
||||||
log_sys_emerg("Failed to connect to lvmlockd to drop locks in VG %s.", arg_vg_name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
reply = _lvmlockd_send("drop_vg",
|
|
||||||
"cmd = %s", "lvmlockctl",
|
|
||||||
"pid = " FMTd64, (int64_t) getpid(),
|
|
||||||
"vg_name = %s", arg_vg_name,
|
|
||||||
NULL);
|
|
||||||
if (!_lvmlockd_result(reply, &result)) {
|
|
||||||
log_sys_emerg("Failed to drop locks in VG %s", arg_vg_name);
|
|
||||||
rv = result;
|
|
||||||
}
|
|
||||||
daemon_reply_destroy(reply);
|
|
||||||
lvmlockd_close(_lvmlockd);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
printf("lvmlockctl options\n");
|
printf("lvmlockctl options\n");
|
||||||
@@ -922,7 +599,7 @@ static void print_usage(void)
|
|||||||
printf("--force | -f 0|1>\n");
|
printf("--force | -f 0|1>\n");
|
||||||
printf(" Force option for other commands.\n");
|
printf(" Force option for other commands.\n");
|
||||||
printf("--kill | -k <vgname>\n");
|
printf("--kill | -k <vgname>\n");
|
||||||
printf(" Kill access to the VG locks are lost (see lvmlockctl_kill_command).\n");
|
printf(" Kill access to the VG when sanlock cannot renew lease.\n");
|
||||||
printf("--drop | -r <vgname>\n");
|
printf("--drop | -r <vgname>\n");
|
||||||
printf(" Clear locks for the VG when it is unused after kill (-k).\n");
|
printf(" Clear locks for the VG when it is unused after kill (-k).\n");
|
||||||
printf("--gl-enable | -E <vgname>\n");
|
printf("--gl-enable | -E <vgname>\n");
|
||||||
@@ -931,8 +608,6 @@ static void print_usage(void)
|
|||||||
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
|
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
|
||||||
printf("--stop-lockspaces | -S\n");
|
printf("--stop-lockspaces | -S\n");
|
||||||
printf(" Stop all lockspaces.\n");
|
printf(" Stop all lockspaces.\n");
|
||||||
printf("--stderr | -e\n");
|
|
||||||
printf(" Send kill and drop messages to stderr instead of syslog\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_options(int argc, char *argv[])
|
static int read_options(int argc, char *argv[])
|
||||||
@@ -952,7 +627,6 @@ static int read_options(int argc, char *argv[])
|
|||||||
{"gl-enable", required_argument, 0, 'E' },
|
{"gl-enable", required_argument, 0, 'E' },
|
||||||
{"gl-disable", required_argument, 0, 'D' },
|
{"gl-disable", required_argument, 0, 'D' },
|
||||||
{"stop-lockspaces", no_argument, 0, 'S' },
|
{"stop-lockspaces", no_argument, 0, 'S' },
|
||||||
{"stderr", no_argument, 0, 'e' },
|
|
||||||
{0, 0, 0, 0 }
|
{0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -962,7 +636,7 @@ static int read_options(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", long_options, &option_index);
|
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -988,30 +662,23 @@ static int read_options(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
kill_vg = 1;
|
kill_vg = 1;
|
||||||
free(arg_vg_name);
|
|
||||||
arg_vg_name = strdup(optarg);
|
arg_vg_name = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
drop_vg = 1;
|
drop_vg = 1;
|
||||||
free(arg_vg_name);
|
|
||||||
arg_vg_name = strdup(optarg);
|
arg_vg_name = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
gl_enable = 1;
|
gl_enable = 1;
|
||||||
free(arg_vg_name);
|
|
||||||
arg_vg_name = strdup(optarg);
|
arg_vg_name = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
gl_disable = 1;
|
gl_disable = 1;
|
||||||
free(arg_vg_name);
|
|
||||||
arg_vg_name = strdup(optarg);
|
arg_vg_name = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
stop_lockspaces = 1;
|
stop_lockspaces = 1;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
|
||||||
use_stderr = 1;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -1030,12 +697,8 @@ int main(int argc, char **argv)
|
|||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
/* do_kill handles lvmlockd connections itself */
|
|
||||||
if (kill_vg)
|
|
||||||
return do_kill();
|
|
||||||
|
|
||||||
|
|
||||||
_lvmlockd = lvmlockd_open(NULL);
|
_lvmlockd = lvmlockd_open(NULL);
|
||||||
|
|
||||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
||||||
log_error("Cannot connect to lvmlockd.");
|
log_error("Cannot connect to lvmlockd.");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1056,6 +719,11 @@ int main(int argc, char **argv)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kill_vg) {
|
||||||
|
rv = do_kill();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (drop_vg) {
|
if (drop_vg) {
|
||||||
rv = do_drop();
|
rv = do_drop();
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -11,10 +11,9 @@
|
|||||||
#ifndef _LVM_LVMLOCKD_CLIENT_H
|
#ifndef _LVM_LVMLOCKD_CLIENT_H
|
||||||
#define _LVM_LVMLOCKD_CLIENT_H
|
#define _LVM_LVMLOCKD_CLIENT_H
|
||||||
|
|
||||||
#include "libdaemon/client/daemon-client.h"
|
#include "daemon-client.h"
|
||||||
|
|
||||||
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
|
||||||
#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
|
|
||||||
|
|
||||||
/* Wrappers to open/close connection */
|
/* Wrappers to open/close connection */
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,20 +11,19 @@
|
|||||||
#define _XOPEN_SOURCE 500 /* pthread */
|
#define _XOPEN_SOURCE 500 /* pthread */
|
||||||
#define _ISOC99_SOURCE
|
#define _ISOC99_SOURCE
|
||||||
|
|
||||||
#include "tools/tool.h"
|
#include "tool.h"
|
||||||
|
|
||||||
#include "daemon-server.h"
|
#include "daemon-server.h"
|
||||||
#include "lib/mm/xlate.h"
|
#include "xlate.h"
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
#include "lvmlockd-internal.h"
|
||||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
#include "lvmlockd-client.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Using synchronous _wait dlm apis so do not define _REENTRANT and
|
* Using synchronous _wait dlm apis so do not define _REENTRANT and
|
||||||
* link with non-threaded version of library, libdlm_lt.
|
* link with non-threaded version of library, libdlm_lt.
|
||||||
*/
|
*/
|
||||||
#include "libdlm.h"
|
#include "libdlm.h"
|
||||||
#include "libdlmcontrol.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
@@ -119,7 +118,6 @@ static int read_cluster_name(char *clustername)
|
|||||||
log_error(close_error_msg, fd);
|
log_error(close_error_msg, fd);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
clustername[rv] = 0;
|
|
||||||
|
|
||||||
n = strstr(clustername, "\n");
|
n = strstr(clustername, "\n");
|
||||||
if (n)
|
if (n)
|
||||||
@@ -129,18 +127,16 @@ static int read_cluster_name(char *clustername)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_VERSION 16
|
|
||||||
|
|
||||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
{
|
{
|
||||||
char clustername[MAX_ARGS+1];
|
char clustername[MAX_ARGS+1];
|
||||||
char lock_args_version[MAX_VERSION+1];
|
char lock_args_version[MAX_ARGS+1];
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
memset(clustername, 0, sizeof(clustername));
|
memset(clustername, 0, sizeof(clustername));
|
||||||
memset(lock_args_version, 0, sizeof(lock_args_version));
|
memset(lock_args_version, 0, sizeof(lock_args_version));
|
||||||
|
|
||||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||||
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||||
|
|
||||||
rv = read_cluster_name(clustername);
|
rv = read_cluster_name(clustername);
|
||||||
@@ -152,9 +148,7 @@ int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
|||||||
return -EARGS;
|
return -EARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
|
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;
|
rv = 0;
|
||||||
|
|
||||||
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
|
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
|
||||||
@@ -278,9 +272,10 @@ static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int wit
|
|||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||||
buf = zalloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
|
||||||
|
|
||||||
rdd->vb = (struct val_blk *)buf;
|
rdd->vb = (struct val_blk *)buf;
|
||||||
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
|
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
|
||||||
@@ -328,6 +323,7 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
|||||||
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
|
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
if (rdd->vb)
|
||||||
free(rdd->vb);
|
free(rdd->vb);
|
||||||
|
|
||||||
memset(rdd, 0, sizeof(struct rd_dlm));
|
memset(rdd, 0, sizeof(struct rd_dlm));
|
||||||
@@ -398,18 +394,12 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
(void *)1, (void *)1, (void *)1,
|
(void *)1, (void *)1, (void *)1,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
if (rv == -1 && (errno == EAGAIN)) {
|
if (rv == -1 && errno == -EAGAIN) {
|
||||||
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
||||||
ls->name, r->name, ld_mode);
|
ls->name, r->name, ld_mode);
|
||||||
rv = -EUCLEAN;
|
rv = -EUCLEAN;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (rv == -1 && (errno == ENOENT)) {
|
|
||||||
log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
|
|
||||||
ls->name, r->name, ld_mode);
|
|
||||||
rv = -ENOENT;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
|
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
|
||||||
ls->name, r->name, mode, flags, rv, errno);
|
ls->name, r->name, mode, flags, rv, errno);
|
||||||
@@ -787,108 +777,3 @@ int lm_is_running_dlm(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOCKDDLM_CONTROL_SUPPORT
|
|
||||||
|
|
||||||
int lm_refresh_lv_start_dlm(struct action *act)
|
|
||||||
{
|
|
||||||
char path[PATH_MAX] = { 0 };
|
|
||||||
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, PATH_MAX-1);
|
|
||||||
|
|
||||||
/* skip past dev */
|
|
||||||
if (!(p = strchr(path + 1, '/')))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
|
|||||||
@@ -1,837 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2020-2021 Seagate Ltd.
|
|
||||||
*
|
|
||||||
* This file is part of LVM2.
|
|
||||||
*
|
|
||||||
* This copyrighted material is made available to anyone wishing to use,
|
|
||||||
* modify, copy, or redistribute it subject to the terms and conditions
|
|
||||||
* of the GNU Lesser General Public License v.2.1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _XOPEN_SOURCE 500 /* pthread */
|
|
||||||
#define _ISOC99_SOURCE
|
|
||||||
|
|
||||||
#include "tools/tool.h"
|
|
||||||
|
|
||||||
#include "daemon-server.h"
|
|
||||||
#include "lib/mm/xlate.h"
|
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
|
||||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
|
||||||
|
|
||||||
#include "ilm.h"
|
|
||||||
|
|
||||||
#include <blkid/blkid.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define IDM_TIMEOUT 60000 /* unit: millisecond, 60 seconds */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Each lockspace thread has its own In-Drive Mutex (IDM) lock manager's
|
|
||||||
* connection. After established socket connection, the lockspace has
|
|
||||||
* been created in IDM lock manager and afterwards use the socket file
|
|
||||||
* descriptor to send any requests for lock related operations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct lm_idm {
|
|
||||||
int sock; /* IDM lock manager connection */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rd_idm {
|
|
||||||
struct idm_lock_id id;
|
|
||||||
struct idm_lock_op op;
|
|
||||||
uint64_t vb_timestamp;
|
|
||||||
struct val_blk *vb;
|
|
||||||
};
|
|
||||||
|
|
||||||
int lm_data_size_idm(void)
|
|
||||||
{
|
|
||||||
return sizeof(struct rd_idm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t read_utc_us(void)
|
|
||||||
{
|
|
||||||
struct timespec cur_time;
|
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &cur_time);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert to microseconds unit. IDM reserves the MSB in 8 bytes
|
|
||||||
* and the low 56 bits are used for timestamp; 56 bits can support
|
|
||||||
* calendar year to 2284, so it has 260 years for overflow. Thus it
|
|
||||||
* is quite safe for overflow issue when wrote this code.
|
|
||||||
*/
|
|
||||||
return cur_time.tv_sec * 1000000 + cur_time.tv_nsec / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int uuid_read_format(char *uuid_str, const char *buffer)
|
|
||||||
{
|
|
||||||
int out = 0;
|
|
||||||
|
|
||||||
/* just strip out any dashes */
|
|
||||||
while (*buffer) {
|
|
||||||
|
|
||||||
if (*buffer == '-') {
|
|
||||||
buffer++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out >= 32) {
|
|
||||||
log_error("Too many characters to be uuid.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uuid_str[out++] = *buffer;
|
|
||||||
buffer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out != 32) {
|
|
||||||
log_error("Couldn't read uuid: incorrect number of "
|
|
||||||
"characters.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SYSFS_ROOT "/sys"
|
|
||||||
#define BUS_SCSI_DEVS "/bus/scsi/devices"
|
|
||||||
|
|
||||||
static struct idm_lock_op glb_lock_op;
|
|
||||||
|
|
||||||
static void lm_idm_free_dir_list(struct dirent **dir_list, int dir_num)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < dir_num; ++i)
|
|
||||||
free(dir_list[i]);
|
|
||||||
free(dir_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_directory_select(const struct dirent *s)
|
|
||||||
{
|
|
||||||
regex_t regex;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Only select directory with the format x:x:x:x */
|
|
||||||
ret = regcomp(®ex, "^[0-9]+:[0-9]+:[0-9]+:[0-9]+$", REG_EXTENDED);
|
|
||||||
if (ret)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = regexec(®ex, s->d_name, 0, NULL, 0);
|
|
||||||
if (!ret) {
|
|
||||||
regfree(®ex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
regfree(®ex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_find_block_dirctory(const char *block_path)
|
|
||||||
{
|
|
||||||
struct stat stats;
|
|
||||||
|
|
||||||
if ((stat(block_path, &stats) >= 0) && S_ISDIR(stats.st_mode))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_block_node_select(const struct dirent *s)
|
|
||||||
{
|
|
||||||
if (DT_LNK != s->d_type && DT_DIR != s->d_type)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (DT_DIR == s->d_type) {
|
|
||||||
/* Skip this directory: '.' and parent: '..' */
|
|
||||||
if (!strcmp(s->d_name, ".") || !strcmp(s->d_name, ".."))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_find_block_node(const char *blk_path, char **blk_dev)
|
|
||||||
{
|
|
||||||
struct dirent **dir_list;
|
|
||||||
int dir_num;
|
|
||||||
|
|
||||||
dir_num = scandir(blk_path, &dir_list, lm_idm_scsi_block_node_select, NULL);
|
|
||||||
if (dir_num < 0) {
|
|
||||||
log_error("Cannot find valid directory entry in %s", blk_path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Should have only one block name under the path, if the dir_num is
|
|
||||||
* not 1 (e.g. 0 or any number bigger than 1), it must be wrong and
|
|
||||||
* should never happen.
|
|
||||||
*/
|
|
||||||
if (dir_num == 1)
|
|
||||||
*blk_dev = strdup(dir_list[0]->d_name);
|
|
||||||
else
|
|
||||||
*blk_dev = NULL;
|
|
||||||
|
|
||||||
lm_idm_free_dir_list(dir_list, dir_num);
|
|
||||||
|
|
||||||
if (!*blk_dev)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return dir_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_scsi_search_propeller_partition(char *dev)
|
|
||||||
{
|
|
||||||
int i, nparts;
|
|
||||||
blkid_probe pr;
|
|
||||||
blkid_partlist ls;
|
|
||||||
int found = -1;
|
|
||||||
|
|
||||||
pr = blkid_new_probe_from_filename(dev);
|
|
||||||
if (!pr) {
|
|
||||||
log_error("%s: failed to create a new libblkid probe", dev);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Binary interface */
|
|
||||||
ls = blkid_probe_get_partitions(pr);
|
|
||||||
if (!ls) {
|
|
||||||
log_error("%s: failed to read partitions", dev);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List partitions */
|
|
||||||
nparts = blkid_partlist_numof_partitions(ls);
|
|
||||||
if (!nparts)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
for (i = 0; i < nparts; i++) {
|
|
||||||
const char *p;
|
|
||||||
blkid_partition par = blkid_partlist_get_partition(ls, i);
|
|
||||||
|
|
||||||
p = blkid_partition_get_name(par);
|
|
||||||
if (p) {
|
|
||||||
log_debug("partition name='%s'", p);
|
|
||||||
|
|
||||||
if (!strcmp(p, "propeller"))
|
|
||||||
found = blkid_partition_get_partno(par);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found >= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
blkid_free_probe(pr);
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *lm_idm_scsi_get_block_device_node(const char *scsi_path)
|
|
||||||
{
|
|
||||||
char *blk_path = NULL;
|
|
||||||
char *blk_dev = NULL;
|
|
||||||
char *dev_node = NULL;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Locate the "block" directory, such like:
|
|
||||||
* /sys/bus/scsi/devices/1:0:0:0/block
|
|
||||||
*/
|
|
||||||
ret = asprintf(&blk_path, "%s/%s", scsi_path, "block");
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to allocate block path for %s", scsi_path);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lm_idm_scsi_find_block_dirctory(blk_path);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to find block path %s", blk_path);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Locate the block device name, such like:
|
|
||||||
* /sys/bus/scsi/devices/1:0:0:0/block/sdb
|
|
||||||
*
|
|
||||||
* After return from this function and if it makes success,
|
|
||||||
* the global variable "blk_dev" points to the block device
|
|
||||||
* name, in this example it points to string "sdb".
|
|
||||||
*/
|
|
||||||
ret = lm_idm_scsi_find_block_node(blk_path, &blk_dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to find block node");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = asprintf(&dev_node, "/dev/%s", blk_dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to allocate memory for blk node path");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lm_idm_scsi_search_propeller_partition(dev_node);
|
|
||||||
if (ret < 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
free(blk_path);
|
|
||||||
free(blk_dev);
|
|
||||||
return dev_node;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
free(blk_path);
|
|
||||||
free(blk_dev);
|
|
||||||
free(dev_node);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_idm_get_gl_lock_pv_list(void)
|
|
||||||
{
|
|
||||||
struct dirent **dir_list;
|
|
||||||
char scsi_bus_path[PATH_MAX];
|
|
||||||
char *drive_path;
|
|
||||||
int i, dir_num, ret;
|
|
||||||
|
|
||||||
if (glb_lock_op.drive_num)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
snprintf(scsi_bus_path, sizeof(scsi_bus_path), "%s%s",
|
|
||||||
SYSFS_ROOT, BUS_SCSI_DEVS);
|
|
||||||
|
|
||||||
dir_num = scandir(scsi_bus_path, &dir_list,
|
|
||||||
lm_idm_scsi_directory_select, NULL);
|
|
||||||
if (dir_num < 0) { /* scsi mid level may not be loaded */
|
|
||||||
log_error("Attached devices: none");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dir_num; i++) {
|
|
||||||
char *scsi_path;
|
|
||||||
|
|
||||||
ret = asprintf(&scsi_path, "%s/%s", scsi_bus_path,
|
|
||||||
dir_list[i]->d_name);
|
|
||||||
if (ret < 0) {
|
|
||||||
log_error("Fail to allocate memory for scsi directory");
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glb_lock_op.drive_num >= ILM_DRIVE_MAX_NUM) {
|
|
||||||
log_error("Global lock: drive number %d exceeds limitation (%d) ?!",
|
|
||||||
glb_lock_op.drive_num, ILM_DRIVE_MAX_NUM);
|
|
||||||
free(scsi_path);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
drive_path = lm_idm_scsi_get_block_device_node(scsi_path);
|
|
||||||
if (!drive_path) {
|
|
||||||
free(scsi_path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
glb_lock_op.drives[glb_lock_op.drive_num] = drive_path;
|
|
||||||
glb_lock_op.drive_num++;
|
|
||||||
|
|
||||||
free(scsi_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
lm_idm_free_dir_list(dir_list, dir_num);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
failed:
|
|
||||||
lm_idm_free_dir_list(dir_list, dir_num);
|
|
||||||
|
|
||||||
for (i = 0; i < glb_lock_op.drive_num; i++) {
|
|
||||||
if (glb_lock_op.drives[i]) {
|
|
||||||
free(glb_lock_op.drives[i]);
|
|
||||||
glb_lock_op.drives[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lm_idm_update_vb_timestamp(uint64_t *vb_timestamp)
|
|
||||||
{
|
|
||||||
uint64_t utc_us = read_utc_us();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It's possible that the multiple nodes have no clock
|
|
||||||
* synchronization with microsecond prcision and the time
|
|
||||||
* is going backward. For this case, simply increment the
|
|
||||||
* existing timestamp and write out to drive.
|
|
||||||
*/
|
|
||||||
if (*vb_timestamp >= utc_us)
|
|
||||||
(*vb_timestamp)++;
|
|
||||||
else
|
|
||||||
*vb_timestamp = utc_us;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_prepare_lockspace_idm(struct lockspace *ls)
|
|
||||||
{
|
|
||||||
struct lm_idm *lm = NULL;
|
|
||||||
|
|
||||||
lm = malloc(sizeof(struct lm_idm));
|
|
||||||
if (!lm) {
|
|
||||||
log_error("S %s prepare_lockspace_idm fail to allocate lm_idm for %s",
|
|
||||||
ls->name, ls->vg_name);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
memset(lm, 0x0, sizeof(struct lm_idm));
|
|
||||||
|
|
||||||
ls->lm_data = lm;
|
|
||||||
log_debug("S %s prepare_lockspace_idm done", ls->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
|
|
||||||
{
|
|
||||||
char killpath[IDM_FAILURE_PATH_LEN];
|
|
||||||
char killargs[IDM_FAILURE_ARGS_LEN];
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!strcmp(ls->name, S_NAME_GL_IDM)) {
|
|
||||||
/*
|
|
||||||
* Prepare the pv list for global lock, if the drive contains
|
|
||||||
* "propeller" partition, then this drive will be considered
|
|
||||||
* as a member of pv list.
|
|
||||||
*/
|
|
||||||
rv = lm_idm_get_gl_lock_pv_list();
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s add_lockspace_idm fail to get pv list for glb lock",
|
|
||||||
ls->name);
|
|
||||||
return -EIO;
|
|
||||||
} else {
|
|
||||||
log_error("S %s add_lockspace_idm get pv list for glb lock",
|
|
||||||
ls->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Construct the execution path for command "lvmlockctl" by using the
|
|
||||||
* path to the lvm binary and appending "lockctl".
|
|
||||||
*/
|
|
||||||
memset(killpath, 0, sizeof(killpath));
|
|
||||||
snprintf(killpath, IDM_FAILURE_PATH_LEN, "%slockctl", LVM_PATH);
|
|
||||||
|
|
||||||
/* Pass the argument "--kill vg_name" for killpath */
|
|
||||||
memset(killargs, 0, sizeof(killargs));
|
|
||||||
snprintf(killargs, IDM_FAILURE_ARGS_LEN, "--kill %s", ls->vg_name);
|
|
||||||
|
|
||||||
/* Connect with IDM lock manager per every lockspace. */
|
|
||||||
rv = ilm_connect(&lmi->sock);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s add_lockspace_idm fail to connect the lock manager %d",
|
|
||||||
ls->name, lmi->sock);
|
|
||||||
lmi->sock = 0;
|
|
||||||
rv = -EMANAGER;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ilm_set_killpath(lmi->sock, killpath, killargs);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s add_lockspace_idm fail to set kill path %d",
|
|
||||||
ls->name, rv);
|
|
||||||
rv = -EMANAGER;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s add_lockspace_idm kill path is: \"%s %s\"",
|
|
||||||
ls->name, killpath, killargs);
|
|
||||||
|
|
||||||
log_debug("S %s add_lockspace_idm done", ls->name);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
if (lmi && lmi->sock)
|
|
||||||
close(lmi->sock);
|
|
||||||
|
|
||||||
free(lmi);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
int i, rv = 0;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
rv = ilm_disconnect(lmi->sock);
|
|
||||||
if (rv < 0)
|
|
||||||
log_error("S %s rem_lockspace_idm error %d", ls->name, rv);
|
|
||||||
|
|
||||||
/* Release pv list for global lock */
|
|
||||||
if (!strcmp(ls->name, "lvm_global")) {
|
|
||||||
for (i = 0; i < glb_lock_op.drive_num; i++) {
|
|
||||||
if (glb_lock_op.drives[i]) {
|
|
||||||
free(glb_lock_op.drives[i]);
|
|
||||||
glb_lock_op.drives[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(lmi);
|
|
||||||
ls->lm_data = NULL;
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm_add_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
|
|
||||||
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
|
||||||
rdi->vb = zalloc(sizeof(struct val_blk));
|
|
||||||
if (!rdi->vb)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_rem_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
|
|
||||||
free(rdi->vb);
|
|
||||||
|
|
||||||
memset(rdi, 0, sizeof(struct rd_idm));
|
|
||||||
r->lm_init = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int to_idm_mode(int ld_mode)
|
|
||||||
{
|
|
||||||
switch (ld_mode) {
|
|
||||||
case LD_LK_EX:
|
|
||||||
return IDM_MODE_EXCLUSIVE;
|
|
||||||
case LD_LK_SH:
|
|
||||||
return IDM_MODE_SHAREABLE;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
|
||||||
int adopt)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
char **drive_path = NULL;
|
|
||||||
uint64_t timestamp;
|
|
||||||
int reset_vb = 0;
|
|
||||||
int rv, i;
|
|
||||||
|
|
||||||
if (!r->lm_init) {
|
|
||||||
rv = lm_add_resource_idm(ls, r);
|
|
||||||
if (rv < 0)
|
|
||||||
return rv;
|
|
||||||
r->lm_init = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdi->op.mode = to_idm_mode(ld_mode);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("lock_idm invalid mode %d", ld_mode);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s R %s lock_idm", ls->name, r->name);
|
|
||||||
|
|
||||||
if (daemon_test) {
|
|
||||||
if (rdi->vb) {
|
|
||||||
vb_out->version = le16_to_cpu(rdi->vb->version);
|
|
||||||
vb_out->flags = le16_to_cpu(rdi->vb->flags);
|
|
||||||
vb_out->r_version = le32_to_cpu(rdi->vb->r_version);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdi->op.timeout = IDM_TIMEOUT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate the UUID string, for RT_VG, it only needs to generate
|
|
||||||
* UUID string for VG level, for RT_LV, it needs to generate
|
|
||||||
* UUID strings for both VG and LV levels. At the end, these IDs
|
|
||||||
* are used as identifier for IDM in drive firmware.
|
|
||||||
*/
|
|
||||||
if (r->type == LD_RT_VG || r->type == LD_RT_LV)
|
|
||||||
log_debug("S %s R %s VG uuid %s", ls->name, r->name, ls->vg_uuid);
|
|
||||||
if (r->type == LD_RT_LV)
|
|
||||||
log_debug("S %s R %s LV uuid %s", ls->name, r->name, lv_uuid);
|
|
||||||
|
|
||||||
memset(&rdi->id, 0x0, sizeof(struct idm_lock_id));
|
|
||||||
if (r->type == LD_RT_VG) {
|
|
||||||
uuid_read_format(rdi->id.vg_uuid, ls->vg_uuid);
|
|
||||||
} else if (r->type == LD_RT_LV) {
|
|
||||||
uuid_read_format(rdi->id.vg_uuid, ls->vg_uuid);
|
|
||||||
uuid_read_format(rdi->id.lv_uuid, lv_uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Establish the drive path list for lock, since different lock type
|
|
||||||
* has different drive list; the GL lock uses the global pv list,
|
|
||||||
* the VG lock uses the pv list spanned for the whole volume group,
|
|
||||||
* the LV lock uses the pv list for the logical volume.
|
|
||||||
*/
|
|
||||||
switch (r->type) {
|
|
||||||
case LD_RT_GL:
|
|
||||||
drive_path = glb_lock_op.drives;
|
|
||||||
rdi->op.drive_num = glb_lock_op.drive_num;
|
|
||||||
break;
|
|
||||||
case LD_RT_VG:
|
|
||||||
drive_path = (char **)ls->pvs.path;
|
|
||||||
rdi->op.drive_num = ls->pvs.num;
|
|
||||||
break;
|
|
||||||
case LD_RT_LV:
|
|
||||||
drive_path = (char **)pvs->path;
|
|
||||||
rdi->op.drive_num = pvs->num;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drive_path) {
|
|
||||||
log_error("S %s R %s cannot find the valid drive path array",
|
|
||||||
ls->name, r->name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdi->op.drive_num >= ILM_DRIVE_MAX_NUM) {
|
|
||||||
log_error("S %s R %s exceeds limitation for drive path array",
|
|
||||||
ls->name, r->name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < rdi->op.drive_num; i++)
|
|
||||||
rdi->op.drives[i] = drive_path[i];
|
|
||||||
|
|
||||||
log_debug("S %s R %s mode %d drive_num %d timeout %d",
|
|
||||||
ls->name, r->name, rdi->op.mode,
|
|
||||||
rdi->op.drive_num, rdi->op.timeout);
|
|
||||||
|
|
||||||
for (i = 0; i < rdi->op.drive_num; i++)
|
|
||||||
log_debug("S %s R %s drive path[%d] %s",
|
|
||||||
ls->name, r->name, i, rdi->op.drives[i]);
|
|
||||||
|
|
||||||
rv = ilm_lock(lmi->sock, &rdi->id, &rdi->op);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_debug("S %s R %s lock_idm acquire mode %d rv %d",
|
|
||||||
ls->name, r->name, ld_mode, rv);
|
|
||||||
return -ELOCKIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rdi->vb) {
|
|
||||||
rv = ilm_read_lvb(lmi->sock, &rdi->id, (char *)×tamp,
|
|
||||||
sizeof(uint64_t));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If fail to read value block, which might be caused by drive
|
|
||||||
* failure, notify up layer to invalidate metadata.
|
|
||||||
*/
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s R %s lock_idm get_lvb error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
reset_vb = 1;
|
|
||||||
|
|
||||||
/* Reset timestamp */
|
|
||||||
rdi->vb_timestamp = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the cached timestamp mismatches with the stored value
|
|
||||||
* in the IDM, this means another host has updated timestamp
|
|
||||||
* for the new VB. Let's reset VB and notify up layer to
|
|
||||||
* invalidate metadata.
|
|
||||||
*/
|
|
||||||
} else if (rdi->vb_timestamp != timestamp) {
|
|
||||||
log_debug("S %s R %s lock_idm get lvb timestamp %lu:%lu",
|
|
||||||
ls->name, r->name, rdi->vb_timestamp,
|
|
||||||
timestamp);
|
|
||||||
|
|
||||||
rdi->vb_timestamp = timestamp;
|
|
||||||
reset_vb = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reset_vb == 1) {
|
|
||||||
memset(rdi->vb, 0, sizeof(struct val_blk));
|
|
||||||
memset(vb_out, 0, sizeof(struct val_blk));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The lock is still acquired, but the vb values has
|
|
||||||
* been invalidated.
|
|
||||||
*/
|
|
||||||
rv = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, copy the cached VB to up layer */
|
|
||||||
memcpy(vb_out, rdi->vb, sizeof(struct val_blk));
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
int ld_mode, uint32_t r_version)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
int mode, rv;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
if (!rdi->vb->version) {
|
|
||||||
/* first time vb has been written */
|
|
||||||
rdi->vb->version = VAL_BLK_VERSION;
|
|
||||||
}
|
|
||||||
rdi->vb->r_version = r_version;
|
|
||||||
|
|
||||||
log_debug("S %s R %s convert_idm set r_version %u",
|
|
||||||
ls->name, r->name, r_version);
|
|
||||||
|
|
||||||
lm_idm_update_vb_timestamp(&rdi->vb_timestamp);
|
|
||||||
log_debug("S %s R %s convert_idm vb %x %x %u timestamp %lu",
|
|
||||||
ls->name, r->name, rdi->vb->version, rdi->vb->flags,
|
|
||||||
rdi->vb->r_version, rdi->vb_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
mode = to_idm_mode(ld_mode);
|
|
||||||
if (mode < 0) {
|
|
||||||
log_error("S %s R %s convert_idm invalid mode %d",
|
|
||||||
ls->name, r->name, ld_mode);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s R %s convert_idm", ls->name, r->name);
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
|
||||||
(char *)rdi->vb_timestamp, sizeof(uint64_t));
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s R %s convert_idm write lvb error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
return -ELMERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ilm_convert(lmi->sock, &rdi->id, mode);
|
|
||||||
if (rv < 0)
|
|
||||||
log_error("S %s R %s convert_idm convert error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
uint32_t r_version, uint32_t lmu_flags)
|
|
||||||
{
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
if (!rdi->vb->version) {
|
|
||||||
/* first time vb has been written */
|
|
||||||
rdi->vb->version = VAL_BLK_VERSION;
|
|
||||||
}
|
|
||||||
if (r_version)
|
|
||||||
rdi->vb->r_version = r_version;
|
|
||||||
|
|
||||||
lm_idm_update_vb_timestamp(&rdi->vb_timestamp);
|
|
||||||
log_debug("S %s R %s unlock_idm vb %x %x %u timestamp %lu",
|
|
||||||
ls->name, r->name, rdi->vb->version, rdi->vb->flags,
|
|
||||||
rdi->vb->r_version, rdi->vb_timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("S %s R %s unlock_idm", ls->name, r->name);
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (rdi->vb && r_version && (r->mode == LD_LK_EX)) {
|
|
||||||
rv = ilm_write_lvb(lmi->sock, &rdi->id,
|
|
||||||
(char *)&rdi->vb_timestamp, sizeof(uint64_t));
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s R %s unlock_idm set_lvb error %d",
|
|
||||||
ls->name, r->name, rv);
|
|
||||||
return -ELMERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ilm_unlock(lmi->sock, &rdi->id);
|
|
||||||
if (rv < 0)
|
|
||||||
log_error("S %s R %s unlock_idm error %d", ls->name, r->name, rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_hosts_idm(struct lockspace *ls, int notify)
|
|
||||||
{
|
|
||||||
struct resource *r;
|
|
||||||
struct lm_idm *lmi = (struct lm_idm *)ls->lm_data;
|
|
||||||
struct rd_idm *rdi;
|
|
||||||
int count, self, found_others = 0;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
list_for_each_entry(r, &ls->resources, list) {
|
|
||||||
if (!r->lm_init)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rdi = (struct rd_idm *)r->lm_data;
|
|
||||||
|
|
||||||
rv = ilm_get_host_count(lmi->sock, &rdi->id, &rdi->op,
|
|
||||||
&count, &self);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("S %s lm_hosts_idm error %d", ls->name, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fixup: need to reduce self count */
|
|
||||||
if (count > found_others)
|
|
||||||
found_others = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found_others;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_get_lockspaces_idm(struct list_head *ls_rejoin)
|
|
||||||
{
|
|
||||||
/* TODO: Need to add support for adoption. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lm_is_running_idm(void)
|
|
||||||
{
|
|
||||||
int sock, rv;
|
|
||||||
|
|
||||||
if (daemon_test)
|
|
||||||
return gl_use_idm;
|
|
||||||
|
|
||||||
rv = ilm_connect(&sock);
|
|
||||||
if (rv < 0) {
|
|
||||||
log_error("Fail to connect seagate IDM lock manager %d", rv);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ilm_disconnect(sock);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -11,8 +11,6 @@
|
|||||||
#ifndef _LVM_LVMLOCKD_INTERNAL_H
|
#ifndef _LVM_LVMLOCKD_INTERNAL_H
|
||||||
#define _LVM_LVMLOCKD_INTERNAL_H
|
#define _LVM_LVMLOCKD_INTERNAL_H
|
||||||
|
|
||||||
#include "base/memory/container_of.h"
|
|
||||||
|
|
||||||
#define MAX_NAME 64
|
#define MAX_NAME 64
|
||||||
#define MAX_ARGS 64
|
#define MAX_ARGS 64
|
||||||
|
|
||||||
@@ -20,7 +18,6 @@
|
|||||||
#define R_NAME_GL "GLLK"
|
#define R_NAME_GL "GLLK"
|
||||||
#define R_NAME_VG "VGLK"
|
#define R_NAME_VG "VGLK"
|
||||||
#define S_NAME_GL_DLM "lvm_global"
|
#define S_NAME_GL_DLM "lvm_global"
|
||||||
#define S_NAME_GL_IDM "lvm_global"
|
|
||||||
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
|
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
|
||||||
/* global lockspace name for sanlock is a vg name */
|
/* global lockspace name for sanlock is a vg name */
|
||||||
|
|
||||||
@@ -30,7 +27,6 @@ enum {
|
|||||||
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
|
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
|
||||||
LD_LM_DLM = 2,
|
LD_LM_DLM = 2,
|
||||||
LD_LM_SANLOCK = 3,
|
LD_LM_SANLOCK = 3,
|
||||||
LD_LM_IDM = 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* operation types */
|
/* operation types */
|
||||||
@@ -57,8 +53,6 @@ enum {
|
|||||||
LD_OP_KILL_VG,
|
LD_OP_KILL_VG,
|
||||||
LD_OP_DROP_VG,
|
LD_OP_DROP_VG,
|
||||||
LD_OP_BUSY,
|
LD_OP_BUSY,
|
||||||
LD_OP_QUERY_LOCK,
|
|
||||||
LD_OP_REFRESH_LV,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* resource types */
|
/* resource types */
|
||||||
@@ -111,7 +105,6 @@ struct client {
|
|||||||
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||||
#define LD_AF_LV_LOCK 0x00040000
|
#define LD_AF_LV_LOCK 0x00040000
|
||||||
#define LD_AF_LV_UNLOCK 0x00080000
|
#define LD_AF_LV_UNLOCK 0x00080000
|
||||||
#define LD_AF_SH_EXISTS 0x00100000
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of times to repeat a lock request after
|
* Number of times to repeat a lock request after
|
||||||
@@ -120,11 +113,6 @@ struct client {
|
|||||||
*/
|
*/
|
||||||
#define DEFAULT_MAX_RETRIES 4
|
#define DEFAULT_MAX_RETRIES 4
|
||||||
|
|
||||||
struct pvs {
|
|
||||||
char **path;
|
|
||||||
int num;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct action {
|
struct action {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
uint32_t client_id;
|
uint32_t client_id;
|
||||||
@@ -139,7 +127,6 @@ struct action {
|
|||||||
int max_retries;
|
int max_retries;
|
||||||
int result;
|
int result;
|
||||||
int lm_rv; /* return value from lm_ function */
|
int lm_rv; /* return value from lm_ function */
|
||||||
char *path;
|
|
||||||
char vg_uuid[64];
|
char vg_uuid[64];
|
||||||
char vg_name[MAX_NAME+1];
|
char vg_name[MAX_NAME+1];
|
||||||
char lv_name[MAX_NAME+1];
|
char lv_name[MAX_NAME+1];
|
||||||
@@ -147,7 +134,6 @@ struct action {
|
|||||||
char vg_args[MAX_ARGS+1];
|
char vg_args[MAX_ARGS+1];
|
||||||
char lv_args[MAX_ARGS+1];
|
char lv_args[MAX_ARGS+1];
|
||||||
char vg_sysid[MAX_NAME+1];
|
char vg_sysid[MAX_NAME+1];
|
||||||
struct pvs pvs; /* PV list for idm */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct resource {
|
struct resource {
|
||||||
@@ -155,7 +141,6 @@ struct resource {
|
|||||||
char name[MAX_NAME+1]; /* vg name or lv name */
|
char name[MAX_NAME+1]; /* vg name or lv name */
|
||||||
int8_t type; /* resource type LD_RT_ */
|
int8_t type; /* resource type LD_RT_ */
|
||||||
int8_t mode;
|
int8_t mode;
|
||||||
int8_t adopt_mode;
|
|
||||||
unsigned int sh_count; /* number of sh locks on locks list */
|
unsigned int sh_count; /* number of sh locks on locks list */
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
||||||
@@ -189,10 +174,7 @@ struct lockspace {
|
|||||||
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
||||||
void *lm_data;
|
void *lm_data;
|
||||||
uint64_t host_id;
|
uint64_t host_id;
|
||||||
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
|
uint64_t free_lock_offset; /* start search for free lock here */
|
||||||
int free_lock_sector_size; /* for sanlock */
|
|
||||||
int free_lock_align_size; /* for sanlock */
|
|
||||||
struct pvs pvs; /* for idm: PV list */
|
|
||||||
|
|
||||||
uint32_t start_client_id; /* client_id that started the lockspace */
|
uint32_t start_client_id; /* client_id that started the lockspace */
|
||||||
pthread_t thread; /* makes synchronous lock requests */
|
pthread_t thread; /* makes synchronous lock requests */
|
||||||
@@ -228,6 +210,10 @@ struct val_blk {
|
|||||||
/* lm_unlock flags */
|
/* lm_unlock flags */
|
||||||
#define LMUF_FREE_VG 0x00000001
|
#define LMUF_FREE_VG 0x00000001
|
||||||
|
|
||||||
|
#define container_of(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||||
|
|
||||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||||
{
|
{
|
||||||
list->next = list;
|
list->next = list;
|
||||||
@@ -334,13 +320,10 @@ static inline int list_empty(const struct list_head *head)
|
|||||||
EXTERN int gl_type_static;
|
EXTERN int gl_type_static;
|
||||||
EXTERN int gl_use_dlm;
|
EXTERN int gl_use_dlm;
|
||||||
EXTERN int gl_use_sanlock;
|
EXTERN int gl_use_sanlock;
|
||||||
EXTERN int gl_use_idm;
|
|
||||||
EXTERN int gl_vg_removed;
|
EXTERN int gl_vg_removed;
|
||||||
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||||
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||||
EXTERN char gl_lsname_idm[MAX_NAME+1];
|
|
||||||
EXTERN int global_dlm_lockspace_exists;
|
EXTERN int global_dlm_lockspace_exists;
|
||||||
EXTERN int global_idm_lockspace_exists;
|
|
||||||
|
|
||||||
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||||
EXTERN int daemon_debug;
|
EXTERN int daemon_debug;
|
||||||
@@ -404,8 +387,6 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
|||||||
int lm_data_size_dlm(void);
|
int lm_data_size_dlm(void);
|
||||||
int lm_is_running_dlm(void);
|
int lm_is_running_dlm(void);
|
||||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
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)
|
static inline int lm_support_dlm(void)
|
||||||
{
|
{
|
||||||
@@ -482,22 +463,12 @@ static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
|||||||
return 0;
|
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 */
|
#endif /* dlm support */
|
||||||
|
|
||||||
#ifdef LOCKDSANLOCK_SUPPORT
|
#ifdef LOCKDSANLOCK_SUPPORT
|
||||||
|
|
||||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
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, int sector_size, int align_size, uint64_t free_offset);
|
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
|
||||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
int lm_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_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||||
@@ -517,7 +488,7 @@ int lm_gl_is_enabled(struct lockspace *ls);
|
|||||||
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
||||||
int lm_data_size_sanlock(void);
|
int lm_data_size_sanlock(void);
|
||||||
int lm_is_running_sanlock(void);
|
int lm_is_running_sanlock(void);
|
||||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size);
|
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
|
||||||
|
|
||||||
static inline int lm_support_sanlock(void)
|
static inline int lm_support_sanlock(void)
|
||||||
{
|
{
|
||||||
@@ -531,7 +502,7 @@ static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flag
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -619,7 +590,7 @@ static inline int lm_is_running_sanlock(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
|
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -631,102 +602,4 @@ static inline int lm_support_sanlock(void)
|
|||||||
|
|
||||||
#endif /* sanlock support */
|
#endif /* sanlock support */
|
||||||
|
|
||||||
#ifdef LOCKDIDM_SUPPORT
|
|
||||||
|
|
||||||
int lm_data_size_idm(void);
|
|
||||||
int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
|
||||||
int lm_prepare_lockspace_idm(struct lockspace *ls);
|
|
||||||
int lm_add_lockspace_idm(struct lockspace *ls, int adopt);
|
|
||||||
int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg);
|
|
||||||
int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
|
||||||
int adopt);
|
|
||||||
int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
int ld_mode, uint32_t r_version);
|
|
||||||
int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
uint32_t r_version, uint32_t lmu_flags);
|
|
||||||
int lm_hosts_idm(struct lockspace *ls, int notify);
|
|
||||||
int lm_get_lockspaces_idm(struct list_head *ls_rejoin);
|
|
||||||
int lm_is_running_idm(void);
|
|
||||||
int lm_rem_resource_idm(struct lockspace *ls, struct resource *r);
|
|
||||||
|
|
||||||
static inline int lm_support_idm(void)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int lm_data_size_idm(void)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_init_vg_idm(char *ls_name, char *vg_name, uint32_t flags,
|
|
||||||
char *vg_args)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_prepare_lockspace_idm(struct lockspace *ls)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_add_lockspace_idm(struct lockspace *ls, int adopt)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_rem_lockspace_idm(struct lockspace *ls, int free_vg)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_lock_idm(struct lockspace *ls, struct resource *r, int ld_mode,
|
|
||||||
struct val_blk *vb_out, char *lv_uuid, struct pvs *pvs,
|
|
||||||
int adopt)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_convert_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
int ld_mode, uint32_t r_version)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_unlock_idm(struct lockspace *ls, struct resource *r,
|
|
||||||
uint32_t r_version, uint32_t lmu_flags)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_hosts_idm(struct lockspace *ls, int notify)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_get_lockspaces_idm(struct list_head *ls_rejoin)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_is_running_idm(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_rem_resource_idm(struct lockspace *ls, struct resource *r)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lm_support_idm(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Seagate IDM support */
|
|
||||||
|
|
||||||
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
||||||
|
|||||||
@@ -11,42 +11,23 @@
|
|||||||
#define _XOPEN_SOURCE 500 /* pthread */
|
#define _XOPEN_SOURCE 500 /* pthread */
|
||||||
#define _ISOC99_SOURCE
|
#define _ISOC99_SOURCE
|
||||||
|
|
||||||
#include "tools/tool.h"
|
#include "tool.h"
|
||||||
|
|
||||||
#include "daemon-server.h"
|
#include "daemon-server.h"
|
||||||
#include "lib/mm/xlate.h"
|
#include "xlate.h"
|
||||||
|
|
||||||
#include "lvmlockd-internal.h"
|
#include "lvmlockd-internal.h"
|
||||||
#include "daemons/lvmlockd/lvmlockd-client.h"
|
#include "lvmlockd-client.h"
|
||||||
|
|
||||||
#include "sanlock.h"
|
#include "sanlock.h"
|
||||||
#include "sanlock_rv.h"
|
#include "sanlock_rv.h"
|
||||||
#include "sanlock_admin.h"
|
#include "sanlock_admin.h"
|
||||||
#include "sanlock_resource.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 <stddef.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <blkid/blkid.h>
|
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
|
|
||||||
#define ONE_MB 1048576
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@@ -158,7 +139,6 @@ release all the leases for the VG.
|
|||||||
|
|
||||||
struct lm_sanlock {
|
struct lm_sanlock {
|
||||||
struct sanlk_lockspace ss;
|
struct sanlk_lockspace ss;
|
||||||
int sector_size;
|
|
||||||
int align_size;
|
int align_size;
|
||||||
int sock; /* sanlock daemon connection */
|
int sock; /* sanlock daemon connection */
|
||||||
};
|
};
|
||||||
@@ -221,23 +201,13 @@ int lm_data_size_sanlock(void)
|
|||||||
* ...
|
* ...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define LS_BEGIN 0
|
||||||
#define GL_LOCK_BEGIN UINT64_C(65)
|
#define GL_LOCK_BEGIN UINT64_C(65)
|
||||||
#define VG_LOCK_BEGIN UINT64_C(66)
|
#define VG_LOCK_BEGIN UINT64_C(66)
|
||||||
#define LV_LOCK_BEGIN UINT64_C(67)
|
#define LV_LOCK_BEGIN UINT64_C(67)
|
||||||
|
|
||||||
static uint64_t daemon_test_lv_count;
|
static uint64_t daemon_test_lv_count;
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy a null-terminated string "str" into a fixed
|
|
||||||
* size (SANLK_NAME_LEN) struct field "buf" which is
|
|
||||||
* not null terminated.
|
|
||||||
*/
|
|
||||||
static void strcpy_name_len(char *buf, char *str, int len)
|
|
||||||
{
|
|
||||||
/* coverity[buffer_size_warning] */
|
|
||||||
strncpy(buf, str, SANLK_NAME_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
|
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
|
||||||
{
|
{
|
||||||
return last_string_from_args(vg_args, lock_lv_name);
|
return last_string_from_args(vg_args, lock_lv_name);
|
||||||
@@ -318,8 +288,7 @@ static int read_host_id_file(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fclose(file))
|
if (fclose(file))
|
||||||
log_debug("Failed to fclose host id file %s (%s).",
|
log_error("failed to close host id file %s", daemon_host_id_file);
|
||||||
daemon_host_id_file, strerror(errno));
|
|
||||||
out:
|
out:
|
||||||
log_debug("host_id %d from %s", host_id, daemon_host_id_file);
|
log_debug("host_id %d from %s", host_id, daemon_host_id_file);
|
||||||
return host_id;
|
return host_id;
|
||||||
@@ -355,154 +324,6 @@ fail:
|
|||||||
return rv;
|
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
|
* vgcreate
|
||||||
*
|
*
|
||||||
@@ -511,21 +332,18 @@ static int get_sizes_lockspace(char *path, int *sector_size, int *align_size)
|
|||||||
* version and lv name, and returns the real lock_args in vg_args.
|
* 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)
|
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||||
{
|
{
|
||||||
struct sanlk_lockspace ss;
|
struct sanlk_lockspace ss;
|
||||||
struct sanlk_resourced rd;
|
struct sanlk_resourced rd;
|
||||||
struct sanlk_disk disk;
|
struct sanlk_disk disk;
|
||||||
char lock_lv_name[MAX_ARGS+1];
|
char lock_lv_name[MAX_ARGS+1];
|
||||||
char lock_args_version[MAX_VERSION+1];
|
char lock_args_version[MAX_ARGS+1];
|
||||||
const char *gl_name = NULL;
|
const char *gl_name = NULL;
|
||||||
uint32_t daemon_version;
|
uint32_t daemon_version;
|
||||||
uint32_t daemon_proto;
|
uint32_t daemon_proto;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
int sector_size = 0;
|
int align_size;
|
||||||
int align_size = 0;
|
|
||||||
int i, rv;
|
int i, rv;
|
||||||
|
|
||||||
memset(&ss, 0, sizeof(ss));
|
memset(&ss, 0, sizeof(ss));
|
||||||
@@ -539,7 +357,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
|||||||
return -EARGS;
|
return -EARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||||
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
|
||||||
|
|
||||||
/* see comment above about input vg_args being only lock_lv_name */
|
/* see comment above about input vg_args being only lock_lv_name */
|
||||||
@@ -556,9 +374,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
|||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
if (!gl_lsname_sanlock[0])
|
if (!gl_lsname_sanlock[0])
|
||||||
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
|
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
|
||||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,25 +387,23 @@ 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",
|
log_debug("sanlock daemon version %08x proto %08x",
|
||||||
daemon_version, daemon_proto);
|
daemon_version, daemon_proto);
|
||||||
|
|
||||||
/* Nothing formatted on disk yet, use what the device reports. */
|
rv = sanlock_align(&disk);
|
||||||
rv = get_sizes_device(disk.path, §or_size, &align_size);
|
if (rv <= 0) {
|
||||||
if (rv < 0) {
|
|
||||||
if (rv == -EACCES) {
|
if (rv == -EACCES) {
|
||||||
log_error("S %s init_vg_san sanlock error -EACCES: no permission to access %s",
|
log_error("S %s init_vg_san sanlock error -EACCES: no permission to access %s",
|
||||||
ls_name, disk.path);
|
ls_name, disk.path);
|
||||||
return -EDEVOPEN;
|
return -EDEVOPEN;
|
||||||
} else {
|
} else {
|
||||||
log_error("S %s init_vg_san sanlock error %d trying to get sector/align size of %s",
|
log_error("S %s init_vg_san sanlock error %d trying to get align size of %s",
|
||||||
ls_name, rv, disk.path);
|
ls_name, rv, disk.path);
|
||||||
return -EARGS;
|
return -EARGS;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
align_size = rv;
|
||||||
|
|
||||||
strcpy_name_len(ss.name, ls_name, SANLK_NAME_LEN);
|
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
|
||||||
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
||||||
ss.host_id_disk.offset = 0;
|
ss.host_id_disk.offset = LS_BEGIN * align_size;
|
||||||
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);
|
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -618,12 +432,10 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
|||||||
gl_name = R_NAME_GL;
|
gl_name = R_NAME_GL;
|
||||||
|
|
||||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rd.rs.name, (char *)gl_name, SANLK_NAME_LEN);
|
strncpy(rd.rs.name, gl_name, SANLK_NAME_LEN);
|
||||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||||
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
|
rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN;
|
||||||
rd.rs.num_disks = 1;
|
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);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -633,12 +445,10 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rd.rs.name, (char *)R_NAME_VG, SANLK_NAME_LEN);
|
strncpy(rd.rs.name, R_NAME_VG, SANLK_NAME_LEN);
|
||||||
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||||
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
|
rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN;
|
||||||
rd.rs.num_disks = 1;
|
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);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -650,9 +460,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
|||||||
if (!strcmp(gl_name, R_NAME_GL))
|
if (!strcmp(gl_name, R_NAME_GL))
|
||||||
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
|
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
|
||||||
|
|
||||||
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
|
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);
|
log_debug("S %s init_vg_san done vg_args %s", ls_name, vg_args);
|
||||||
|
|
||||||
@@ -664,11 +472,9 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
|||||||
|
|
||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
rd.rs.num_disks = 1;
|
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);
|
memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN);
|
||||||
strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rd.rs.name, (char *)"#unused", SANLK_NAME_LEN);
|
strcpy(rd.rs.name, "#unused");
|
||||||
|
|
||||||
offset = align_size * LV_LOCK_BEGIN;
|
offset = align_size * LV_LOCK_BEGIN;
|
||||||
|
|
||||||
@@ -704,13 +510,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,
|
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||||
char *vg_args, char *lv_args,
|
char *vg_args, char *lv_args, uint64_t free_offset)
|
||||||
int sector_size, int align_size, uint64_t free_offset)
|
|
||||||
{
|
{
|
||||||
struct sanlk_resourced rd;
|
struct sanlk_resourced rd;
|
||||||
char lock_lv_name[MAX_ARGS+1];
|
char lock_lv_name[MAX_ARGS+1];
|
||||||
char lock_args_version[MAX_VERSION+1];
|
char lock_args_version[MAX_ARGS+1];
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
|
int align_size;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
@@ -724,11 +530,11 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
|
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
|
||||||
LV_LOCK_ARGS_MAJOR, LV_LOCK_ARGS_MINOR, LV_LOCK_ARGS_PATCH);
|
LV_LOCK_ARGS_MAJOR, LV_LOCK_ARGS_MINOR, LV_LOCK_ARGS_PATCH);
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
align_size = ONE_MB;
|
align_size = 1048576;
|
||||||
snprintf(lv_args, MAX_ARGS, "%s:%llu",
|
snprintf(lv_args, MAX_ARGS, "%s:%llu",
|
||||||
lock_args_version,
|
lock_args_version,
|
||||||
(unsigned long long)((align_size * LV_LOCK_BEGIN) + (align_size * daemon_test_lv_count)));
|
(unsigned long long)((align_size * LV_LOCK_BEGIN) + (align_size * daemon_test_lv_count)));
|
||||||
@@ -736,39 +542,16 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||||
rd.rs.num_disks = 1;
|
rd.rs.num_disks = 1;
|
||||||
if ((rv = build_dm_path(rd.rs.disks[0].path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
|
if ((rv = build_dm_path(rd.rs.disks[0].path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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]);
|
align_size = sanlock_align(&rd.rs.disks[0]);
|
||||||
if (align_size <= 0) {
|
if (align_size <= 0) {
|
||||||
log_error("S %s init_lv_san align error %d", ls_name, align_size);
|
log_error("S %s init_lv_san align error %d", ls_name, align_size);
|
||||||
return -EINVAL;
|
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)
|
if (free_offset)
|
||||||
offset = free_offset;
|
offset = free_offset;
|
||||||
@@ -811,9 +594,7 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
|||||||
log_debug("S %s init_lv_san %s found unused area at %llu",
|
log_debug("S %s init_lv_san %s found unused area at %llu",
|
||||||
ls_name, lv_name, (unsigned long long)offset);
|
ls_name, lv_name, (unsigned long long)offset);
|
||||||
|
|
||||||
strcpy_name_len(rd.rs.name, lv_name, SANLK_NAME_LEN);
|
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);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (!rv) {
|
if (!rv) {
|
||||||
@@ -845,8 +626,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
|||||||
char lock_lv_name[MAX_ARGS+1];
|
char lock_lv_name[MAX_ARGS+1];
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
uint32_t io_timeout;
|
uint32_t io_timeout;
|
||||||
int sector_size = 0;
|
int align_size;
|
||||||
int align_size = 0;
|
|
||||||
int i, rv;
|
int i, rv;
|
||||||
|
|
||||||
memset(&disk, 0, sizeof(disk));
|
memset(&disk, 0, sizeof(disk));
|
||||||
@@ -875,13 +655,20 @@ 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 */
|
/* FIXME: device is not always ready for us here */
|
||||||
sleep(1);
|
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
|
* Lockspace
|
||||||
*/
|
*/
|
||||||
|
|
||||||
memset(&ss, 0, sizeof(ss));
|
memset(&ss, 0, sizeof(ss));
|
||||||
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN);
|
||||||
ss.host_id_disk.offset = 0;
|
ss.host_id_disk.offset = LS_BEGIN * align_size;
|
||||||
|
|
||||||
rv = sanlock_read_lockspace(&ss, 0, &io_timeout);
|
rv = sanlock_read_lockspace(&ss, 0, &io_timeout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -890,27 +677,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN8M)) {
|
strncpy(ss.name, ls_name, SANLK_NAME_LEN);
|
||||||
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;
|
|
||||||
|
|
||||||
strcpy_name_len(ss.name, ls_name, SANLK_NAME_LEN);
|
|
||||||
|
|
||||||
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
|
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -935,7 +702,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||||
|
|
||||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -960,7 +727,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||||
|
|
||||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -994,7 +761,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN);
|
||||||
|
|
||||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
@@ -1020,7 +787,7 @@ int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
|
|||||||
if (daemon_test)
|
if (daemon_test)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
strcpy_name_len(rs->name, (char *)"#unused", SANLK_NAME_LEN);
|
strcpy(rs->name, "#unused");
|
||||||
|
|
||||||
rv = sanlock_write_resource(rs, 0, 0, 0);
|
rv = sanlock_write_resource(rs, 0, 0, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -1054,21 +821,16 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
|||||||
memset(&rd1, 0, sizeof(rd1));
|
memset(&rd1, 0, sizeof(rd1));
|
||||||
memset(&rd2, 0, sizeof(rd2));
|
memset(&rd2, 0, sizeof(rd2));
|
||||||
|
|
||||||
strcpy_name_len(rd1.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
strncpy(rd1.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rd1.rs.name, (char *)R_NAME_GL, SANLK_NAME_LEN);
|
strncpy(rd1.rs.name, R_NAME_GL, SANLK_NAME_LEN);
|
||||||
|
|
||||||
strcpy_name_len(rd2.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
strncpy(rd2.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rd2.rs.name, (char *)R_NAME_GL_DISABLED, SANLK_NAME_LEN);
|
strncpy(rd2.rs.name, R_NAME_GL_DISABLED, SANLK_NAME_LEN);
|
||||||
|
|
||||||
rd1.rs.num_disks = 1;
|
rd1.rs.num_disks = 1;
|
||||||
memcpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
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.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);
|
rv = sanlock_acquire(lms->sock, -1, 0, 1, &rs1, NULL);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("S %s ex_disable_gl_san acquire error %d",
|
log_error("S %s ex_disable_gl_san acquire error %d",
|
||||||
@@ -1123,14 +885,12 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
|||||||
|
|
||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
|
|
||||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rd.rs.name, (char *)gl_name, SANLK_NAME_LEN);
|
strncpy(rd.rs.name, gl_name, SANLK_NAME_LEN);
|
||||||
|
|
||||||
rd.rs.num_disks = 1;
|
rd.rs.num_disks = 1;
|
||||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-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.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);
|
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -1164,20 +924,19 @@ static int gl_is_enabled(struct lockspace *ls, struct lm_sanlock *lms)
|
|||||||
|
|
||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
|
|
||||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||||
|
|
||||||
/* leave rs.name empty, it is what we're checking */
|
/* leave rs.name empty, it is what we're checking */
|
||||||
|
|
||||||
rd.rs.num_disks = 1;
|
rd.rs.num_disks = 1;
|
||||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||||
|
|
||||||
offset = lms->align_size * GL_LOCK_BEGIN;
|
offset = lms->align_size * GL_LOCK_BEGIN;
|
||||||
rd.rs.disks[0].offset = offset;
|
rd.rs.disks[0].offset = offset;
|
||||||
|
|
||||||
rv = sanlock_read_resource(&rd.rs, 0);
|
rv = sanlock_read_resource(&rd.rs, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
log_error("gl_is_enabled read_resource align_size %d offset %llu error %d",
|
log_error("gl_is_enabled read_resource error %d", rv);
|
||||||
lms->align_size, (unsigned long long)offset, rv);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1214,7 +973,7 @@ int lm_gl_is_enabled(struct lockspace *ls)
|
|||||||
* been disabled.)
|
* been disabled.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *sector_size, int *align_size)
|
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||||
{
|
{
|
||||||
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||||
struct sanlk_resourced rd;
|
struct sanlk_resourced rd;
|
||||||
@@ -1224,22 +983,15 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset, int *
|
|||||||
int round = 0;
|
int round = 0;
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
*free_offset = (ONE_MB * LV_LOCK_BEGIN) + (ONE_MB * (daemon_test_lv_count + 1));
|
*free_offset = (1048576 * LV_LOCK_BEGIN) + (1048576 * (daemon_test_lv_count + 1));
|
||||||
*sector_size = 512;
|
|
||||||
*align_size = ONE_MB;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*sector_size = lms->sector_size;
|
|
||||||
*align_size = lms->align_size;
|
|
||||||
|
|
||||||
memset(&rd, 0, sizeof(rd));
|
memset(&rd, 0, sizeof(rd));
|
||||||
|
|
||||||
strcpy_name_len(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||||
rd.rs.num_disks = 1;
|
rd.rs.num_disks = 1;
|
||||||
memcpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-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)
|
if (ls->free_lock_offset)
|
||||||
offset = ls->free_lock_offset;
|
offset = ls->free_lock_offset;
|
||||||
@@ -1339,8 +1091,6 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
char disk_path[SANLK_PATH_LEN];
|
char disk_path[SANLK_PATH_LEN];
|
||||||
char killpath[SANLK_PATH_LEN];
|
char killpath[SANLK_PATH_LEN];
|
||||||
char killargs[SANLK_PATH_LEN];
|
char killargs[SANLK_PATH_LEN];
|
||||||
int sector_size = 0;
|
|
||||||
int align_size = 0;
|
|
||||||
int gl_found;
|
int gl_found;
|
||||||
int ret, rv;
|
int ret, rv;
|
||||||
|
|
||||||
@@ -1410,7 +1160,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
lms = zalloc(sizeof(struct lm_sanlock));
|
lms = malloc(sizeof(struct lm_sanlock));
|
||||||
if (!lms) {
|
if (!lms) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -1419,10 +1169,11 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
memset(lsname, 0, sizeof(lsname));
|
memset(lsname, 0, sizeof(lsname));
|
||||||
strncpy(lsname, ls->name, SANLK_NAME_LEN);
|
strncpy(lsname, ls->name, SANLK_NAME_LEN);
|
||||||
|
|
||||||
|
memset(lms, 0, sizeof(struct lm_sanlock));
|
||||||
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
|
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
|
||||||
lms->ss.host_id_disk.offset = 0;
|
lms->ss.host_id_disk.offset = 0;
|
||||||
lms->ss.host_id = ls->host_id;
|
lms->ss.host_id = ls->host_id;
|
||||||
memcpy(lms->ss.host_id_disk.path, disk_path, SANLK_PATH_LEN-1);
|
strncpy(lms->ss.host_id_disk.path, disk_path, SANLK_PATH_LEN-1);
|
||||||
|
|
||||||
if (daemon_test) {
|
if (daemon_test) {
|
||||||
if (!gl_lsname_sanlock[0]) {
|
if (!gl_lsname_sanlock[0]) {
|
||||||
@@ -1456,34 +1207,13 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = get_sizes_lockspace(disk_path, §or_size, &align_size);
|
lms->align_size = sanlock_align(&lms->ss.host_id_disk);
|
||||||
if (rv < 0) {
|
if (lms->align_size <= 0) {
|
||||||
log_error("S %s prepare_lockspace_san cannot get sector/align sizes %d", lsname, rv);
|
log_error("S %s prepare_lockspace_san align error %d", lsname, lms->align_size);
|
||||||
ret = -EMANAGER;
|
ret = -EMANAGER;
|
||||||
goto fail;
|
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);
|
gl_found = gl_is_enabled(ls, lms);
|
||||||
if (gl_found < 0) {
|
if (gl_found < 0) {
|
||||||
log_error("S %s prepare_lockspace_san gl_enabled error %d", lsname, gl_found);
|
log_error("S %s prepare_lockspace_san gl_enabled error %d", lsname, gl_found);
|
||||||
@@ -1514,6 +1244,7 @@ out:
|
|||||||
fail:
|
fail:
|
||||||
if (lms && lms->sock)
|
if (lms && lms->sock)
|
||||||
close(lms->sock);
|
close(lms->sock);
|
||||||
|
if (lms)
|
||||||
free(lms);
|
free(lms);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1576,8 +1307,10 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rv = sanlock_rem_lockspace(&lms->ss, 0);
|
rv = sanlock_rem_lockspace(&lms->ss, 0);
|
||||||
if (rv < 0)
|
if (rv < 0) {
|
||||||
log_error("S %s rem_lockspace_san error %d", ls->name, rv);
|
log_error("S %s rem_lockspace_san error %d", ls->name, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
if (free_vg) {
|
if (free_vg) {
|
||||||
/*
|
/*
|
||||||
@@ -1586,7 +1319,7 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
|||||||
* This shouldn't be generally necessary, but there may some races
|
* This shouldn't be generally necessary, but there may some races
|
||||||
* between nodes starting and removing a vg which this could help.
|
* between nodes starting and removing a vg which this could help.
|
||||||
*/
|
*/
|
||||||
strcpy_name_len(lms->ss.name, (char *)"#unused", SANLK_NAME_LEN);
|
strncpy(lms->ss.name, "#unused", SANLK_NAME_LEN);
|
||||||
|
|
||||||
rv = sanlock_write_lockspace(&lms->ss, 0, 0, sanlock_io_timeout);
|
rv = sanlock_write_lockspace(&lms->ss, 0, 0, sanlock_io_timeout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
@@ -1614,11 +1347,10 @@ static int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r)
|
|||||||
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||||
|
|
||||||
strcpy_name_len(rds->rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
strncpy(rds->rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||||
strcpy_name_len(rds->rs.name, r->name, SANLK_NAME_LEN);
|
strncpy(rds->rs.name, r->name, SANLK_NAME_LEN);
|
||||||
rds->rs.num_disks = 1;
|
rds->rs.num_disks = 1;
|
||||||
memcpy(rds->rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
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)
|
if (r->type == LD_RT_GL)
|
||||||
rds->rs.disks[0].offset = GL_LOCK_BEGIN * lms->align_size;
|
rds->rs.disks[0].offset = GL_LOCK_BEGIN * lms->align_size;
|
||||||
@@ -1628,9 +1360,10 @@ 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. */
|
/* 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) {
|
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
|
||||||
rds->vb = zalloc(sizeof(struct val_blk));
|
rds->vb = malloc(sizeof(struct val_blk));
|
||||||
if (!rds->vb)
|
if (!rds->vb)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
memset(rds->vb, 0, sizeof(struct val_blk));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1642,6 +1375,7 @@ int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
|||||||
|
|
||||||
/* FIXME: assert r->mode == UN or unlock if it's not? */
|
/* FIXME: assert r->mode == UN or unlock if it's not? */
|
||||||
|
|
||||||
|
if (rds->vb)
|
||||||
free(rds->vb);
|
free(rds->vb);
|
||||||
|
|
||||||
memset(rds, 0, sizeof(struct rd_sanlock));
|
memset(rds, 0, sizeof(struct rd_sanlock));
|
||||||
@@ -1658,7 +1392,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
|||||||
struct sanlk_options opt;
|
struct sanlk_options opt;
|
||||||
uint64_t lock_lv_offset;
|
uint64_t lock_lv_offset;
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
struct val_blk vb = { 0 };
|
struct val_blk vb;
|
||||||
int added = 0;
|
int added = 0;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
@@ -2044,7 +1778,7 @@ static int release_rename(struct lockspace *ls, struct resource *r)
|
|||||||
res1 = (struct sanlk_resource *)&rd1;
|
res1 = (struct sanlk_resource *)&rd1;
|
||||||
res2 = (struct sanlk_resource *)&rd2;
|
res2 = (struct sanlk_resource *)&rd2;
|
||||||
|
|
||||||
strcpy_name_len(res2->name, (char *)"invalid_removed", SANLK_NAME_LEN);
|
strcpy(res2->name, "invalid_removed");
|
||||||
|
|
||||||
res_args[0] = res1;
|
res_args[0] = res1;
|
||||||
res_args[1] = res2;
|
res_args[1] = res2;
|
||||||
@@ -2126,20 +1860,12 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
|||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
|
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
|
||||||
|
|
||||||
/*
|
if (rv == -EIO)
|
||||||
* sanlock may return an error here if it fails to release the lease on
|
rv = -ELOCKIO;
|
||||||
* disk because of an io timeout. But, sanlock will continue trying to
|
else if (rv < 0)
|
||||||
* release the lease after this call returns. We shouldn't return an
|
rv = -ELMERR;
|
||||||
* 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 0;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lm_hosts_sanlock(struct lockspace *ls, int notify)
|
int lm_hosts_sanlock(struct lockspace *ls, int notify)
|
||||||
@@ -2237,8 +1963,8 @@ int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin)
|
|||||||
|
|
||||||
ls->lm_type = LD_LM_SANLOCK;
|
ls->lm_type = LD_LM_SANLOCK;
|
||||||
ls->host_id = ss->host_id;
|
ls->host_id = ss->host_id;
|
||||||
memcpy(ls->name, ss->name, SANLK_NAME_LEN);
|
strncpy(ls->name, ss->name, MAX_NAME);
|
||||||
memcpy(ls->vg_name, ss->name + strlen(LVM_LS_PREFIX), SANLK_NAME_LEN - strlen(LVM_LS_PREFIX));
|
strncpy(ls->vg_name, ss->name + strlen(LVM_LS_PREFIX), MAX_NAME);
|
||||||
list_add_tail(&ls->list, ls_rejoin);
|
list_add_tail(&ls->list, ls_rejoin);
|
||||||
|
|
||||||
ss++;
|
ss++;
|
||||||
|
|||||||
@@ -19,25 +19,25 @@ SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
|
|||||||
|
|
||||||
TARGETS = lvmpolld
|
TARGETS = lvmpolld
|
||||||
|
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
|
||||||
CFLOW_TARGET := $(TARGETS)
|
|
||||||
|
|
||||||
.PHONY: install_lvmpolld
|
.PHONY: install_lvmpolld
|
||||||
|
|
||||||
|
CFLOW_LIST = $(SOURCES)
|
||||||
|
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||||
|
CFLOW_TARGET = lvmpolld
|
||||||
|
|
||||||
include $(top_builddir)/make.tmpl
|
include $(top_builddir)/make.tmpl
|
||||||
|
|
||||||
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||||
LIBS += $(DAEMON_LIBS) $(PTHREAD_LIBS)
|
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
|
||||||
|
|
||||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/server/libdaemonserver.a $(INTERNAL_LIBS)
|
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||||
@echo " [CC] $@"
|
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||||
$(Q) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
|
||||||
|
|
||||||
install_lvmpolld: lvmpolld
|
install_lvmpolld: lvmpolld
|
||||||
@echo " [INSTALL] $<"
|
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||||
$(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
|
||||||
|
|
||||||
install_lvm2: install_lvmpolld
|
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;
|
const char **newargv;
|
||||||
|
|
||||||
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
|
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
|
||||||
newargv = realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||||
if (!newargv)
|
if (!newargv)
|
||||||
return 0;
|
return 0;
|
||||||
*cmdargv = newargv;
|
*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)
|
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
const char **cmd_argv = malloc(MIN_ARGV_SIZE * sizeof(char *));
|
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||||
|
|
||||||
if (!cmd_argv)
|
if (!cmd_argv)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -92,19 +92,13 @@ const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary,
|
|||||||
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (pdlv->devicesfile) {
|
|
||||||
if (!add_to_cmd_arr(&cmd_argv, "--devicesfile", &i) ||
|
|
||||||
!add_to_cmd_arr(&cmd_argv, pdlv->devicesfile, &i))
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* terminating NULL */
|
/* terminating NULL */
|
||||||
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
return cmd_argv;
|
return cmd_argv;
|
||||||
err:
|
err:
|
||||||
free(cmd_argv);
|
dm_free(cmd_argv);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,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)
|
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
const char **cmd_envp = malloc(MIN_ARGV_SIZE * sizeof(char *));
|
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||||
|
|
||||||
if (!cmd_envp)
|
if (!cmd_envp)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -147,6 +141,6 @@ const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
|||||||
|
|
||||||
return cmd_envp;
|
return cmd_envp;
|
||||||
err:
|
err:
|
||||||
free(cmd_envp);
|
dm_free(cmd_envp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,12 @@
|
|||||||
#ifndef _LVM_LVMPOLLD_COMMON_H
|
#ifndef _LVM_LVMPOLLD_COMMON_H
|
||||||
#define _LVM_LVMPOLLD_COMMON_H
|
#define _LVM_LVMPOLLD_COMMON_H
|
||||||
|
|
||||||
#include "tools/tool.h"
|
#define _REENTRANT
|
||||||
|
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
#include "lvmpolld-cmd-utils.h"
|
#include "lvmpolld-cmd-utils.h"
|
||||||
#include "daemons/lvmpolld/lvmpolld-protocol.h"
|
#include "lvmpolld-protocol.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
|||||||
static int _fini(struct daemon_state *s)
|
static int _fini(struct daemon_state *s)
|
||||||
{
|
{
|
||||||
int done;
|
int done;
|
||||||
const struct timespec t = { .tv_nsec = 10000000 }; /* .01 sec */
|
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
|
||||||
struct lvmpolld_state *ls = s->private;
|
struct lvmpolld_state *ls = s->private;
|
||||||
|
|
||||||
DEBUGLOG(s, "fini");
|
DEBUGLOG(s, "fini");
|
||||||
@@ -236,7 +236,9 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
do {
|
||||||
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
||||||
|
} while (r < 0 && errno == EINTR);
|
||||||
|
|
||||||
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -372,7 +374,7 @@ static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
|
|||||||
|
|
||||||
static void *fork_and_poll(void *args)
|
static void *fork_and_poll(void *args)
|
||||||
{
|
{
|
||||||
int outfd, errfd, state = 0;
|
int outfd, errfd, state;
|
||||||
struct lvmpolld_thread_data *data;
|
struct lvmpolld_thread_data *data;
|
||||||
pid_t r;
|
pid_t r;
|
||||||
|
|
||||||
@@ -528,7 +530,7 @@ static response progress_info(client_handle h, struct lvmpolld_state *ls, reques
|
|||||||
|
|
||||||
pdst_unlock(pdst);
|
pdst_unlock(pdst);
|
||||||
|
|
||||||
free(id);
|
dm_free(id);
|
||||||
|
|
||||||
if (pdlv) {
|
if (pdlv) {
|
||||||
if (st.error)
|
if (st.error)
|
||||||
@@ -553,15 +555,14 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
|||||||
const char *interval, const char *id,
|
const char *interval, const char *id,
|
||||||
const char *vgname, const char *lvname,
|
const char *vgname, const char *lvname,
|
||||||
const char *sysdir, enum poll_type type,
|
const char *sysdir, enum poll_type type,
|
||||||
unsigned abort_polling, unsigned uinterval,
|
unsigned abort_polling, unsigned uinterval)
|
||||||
const char *devicesfile)
|
|
||||||
{
|
{
|
||||||
const char **cmdargv, **cmdenvp;
|
const char **cmdargv, **cmdenvp;
|
||||||
struct lvmpolld_lv *pdlv;
|
struct lvmpolld_lv *pdlv;
|
||||||
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
||||||
|
|
||||||
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
||||||
interval, uinterval, pdst, devicesfile);
|
interval, uinterval, pdst);
|
||||||
|
|
||||||
if (!pdlv) {
|
if (!pdlv) {
|
||||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
||||||
@@ -620,7 +621,6 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
|||||||
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
||||||
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
||||||
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||||
const char *devicesfile = daemon_request_str(req, LVMPD_PARM_DEVICESFILE, NULL);
|
|
||||||
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||||
|
|
||||||
assert(type < POLL_TYPE_MAX);
|
assert(type < POLL_TYPE_MAX);
|
||||||
@@ -673,24 +673,24 @@ static response poll_init(client_handle h, struct lvmpolld_state *ls, request re
|
|||||||
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
|
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
|
||||||
id,
|
id,
|
||||||
polling_op(pdlv_get_type(pdlv)), polling_op(type));
|
polling_op(pdlv_get_type(pdlv)), polling_op(type));
|
||||||
free(id);
|
dm_free(id);
|
||||||
return reply(LVMPD_RESP_EINVAL,
|
return reply(LVMPD_RESP_EINVAL,
|
||||||
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
|
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
|
||||||
}
|
}
|
||||||
pdlv->init_rq_count++; /* safe. protected by store lock */
|
pdlv->init_rq_count++; /* safe. protected by store lock */
|
||||||
} else {
|
} else {
|
||||||
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
||||||
lvname, sysdir, type, abort_polling, 2 * uinterval, devicesfile);
|
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||||
if (!pdlv) {
|
if (!pdlv) {
|
||||||
pdst_unlock(pdst);
|
pdst_unlock(pdst);
|
||||||
free(id);
|
dm_free(id);
|
||||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
}
|
}
|
||||||
if (!pdst_locked_insert(pdst, id, pdlv)) {
|
if (!pdst_locked_insert(pdst, id, pdlv)) {
|
||||||
pdlv_destroy(pdlv);
|
pdlv_destroy(pdlv);
|
||||||
pdst_unlock(pdst);
|
pdst_unlock(pdst);
|
||||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
|
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
|
||||||
free(id);
|
dm_free(id);
|
||||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||||
}
|
}
|
||||||
if (!spawn_detached_thread(pdlv)) {
|
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);
|
pdst_locked_remove(pdst, id);
|
||||||
pdlv_destroy(pdlv);
|
pdlv_destroy(pdlv);
|
||||||
pdst_unlock(pdst);
|
pdst_unlock(pdst);
|
||||||
free(id);
|
dm_free(id);
|
||||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
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);
|
pdst_unlock(pdst);
|
||||||
|
|
||||||
free(id);
|
dm_free(id);
|
||||||
|
|
||||||
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
|
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 *buf;
|
||||||
char *pos;
|
char *pos;
|
||||||
|
|
||||||
buf = strdup(msg);
|
buf = dm_strdup(msg);
|
||||||
pos = buf;
|
pos = buf;
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
@@ -819,7 +819,7 @@ static int printout_raw_response(const char *prefix, const char *msg)
|
|||||||
_log_line(pos, &b);
|
_log_line(pos, &b);
|
||||||
pos = next ? next + 1 : 0;
|
pos = next ? next + 1 : 0;
|
||||||
}
|
}
|
||||||
free(buf);
|
dm_free(buf);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user