mirror of
git://sourceware.org/git/lvm2.git
synced 2025-08-17 09:49:28 +03:00
Compare commits
699 Commits
v2_02_124
...
dev-mcsont
Author | SHA1 | Date | |
---|---|---|---|
cf06d942b8 | |||
83d3cc76f3 | |||
89574055f7 | |||
7831a65091 | |||
15a97cc610 | |||
3f1c63c812 | |||
dd52721b68 | |||
7f125c1116 | |||
5b04eda93f | |||
77c31d0c39 | |||
baf320455b | |||
bb4d3fa7a7 | |||
3e18b101a0 | |||
df190dcfa5 | |||
e149fe7fdf | |||
77605457e7 | |||
0d5b1294f0 | |||
097d14e64e | |||
17196103e0 | |||
ccfc09f79b | |||
9a3b64e81a | |||
c2e88d1107 | |||
406d8ff332 | |||
00348c0a63 | |||
ccb8da404d | |||
28e54032c0 | |||
bca55c9b20 | |||
f104a81932 | |||
3720eb63be | |||
8b5525383f | |||
f58c634103 | |||
175119fdcd | |||
33a8a2febf | |||
f32f0bd2a7 | |||
99237f0908 | |||
099466939e | |||
b3c81d02c9 | |||
5886ff64eb | |||
a4418b34c1 | |||
65ec00ce20 | |||
6e1e0e8813 | |||
4159680a0e | |||
76cff10a73 | |||
1af2ab10d0 | |||
729f489009 | |||
5d76bdcdbd | |||
3b5939bbbb | |||
a2dd1f6e19 | |||
c301cc5d38 | |||
ba41ee1dc9 | |||
b702d67747 | |||
44ba862674 | |||
6624833839 | |||
b29593378f | |||
428ca9b120 | |||
f898cf7539 | |||
844b009584 | |||
9ef820a2a5 | |||
40eea582ae | |||
b780d329aa | |||
8f269697d2 | |||
98d81a43ea | |||
1a74171ca5 | |||
51735f09f7 | |||
3a42c13ccf | |||
8b965bd3d5 | |||
1a7bea0f0f | |||
b5b2a54834 | |||
21748a8630 | |||
e5b686d693 | |||
87a39d8bac | |||
cff1c728d8 | |||
2786cd27da | |||
1a2d0a0c72 | |||
b1319e0402 | |||
8be60e6a65 | |||
39cffa4e9b | |||
2af696c32f | |||
4284ba65eb | |||
aeec62ad19 | |||
12aa56d298 | |||
9156c5d088 | |||
466a1c72b7 | |||
81e9ab3156 | |||
15dbd4b56a | |||
e2ea2a8147 | |||
941c6354db | |||
02eb000f51 | |||
efc76ca33d | |||
590091a4fa | |||
9488cbdd0b | |||
fa9e41d2e3 | |||
6b0bc5b2d9 | |||
7ff5b03e5e | |||
91350f5c6a | |||
9c5c9e2355 | |||
cde12cbe9e | |||
ab6d16a8a5 | |||
09a62cca0c | |||
075f85dcb5 | |||
d2c4ce254b | |||
7b78d496bf | |||
19e272ba53 | |||
73e679f33f | |||
a0d819172f | |||
0aee04288e | |||
ef4d69f456 | |||
c15649b3af | |||
f67a52677b | |||
392248186e | |||
33465066c5 | |||
a5c4c4efbd | |||
83d475626a | |||
1ea7e2634d | |||
23d9b17a7b | |||
c3bfe07f2a | |||
508f0f5a21 | |||
df34fcdafd | |||
a6d1c8ac65 | |||
7c36d7c90c | |||
bbef4edd06 | |||
3f1a3b7090 | |||
a91fbe9d27 | |||
ccc39be053 | |||
0cf787a377 | |||
acc70de439 | |||
cf1c2da836 | |||
c4cc5eabfe | |||
8cc21354c2 | |||
2cb1f6eafe | |||
9322918406 | |||
83f00e9156 | |||
4f9e7f692e | |||
4b586ad3c2 | |||
256e432e78 | |||
51ff7d5ed8 | |||
49e11102c7 | |||
a11cd2ca2d | |||
f9926e7e6c | |||
76ea01dd20 | |||
362558cd66 | |||
09a8479cb7 | |||
0a633750f1 | |||
0e2261dbd1 | |||
842a7a17e3 | |||
f4fb97c850 | |||
8b9533f38f | |||
903e9af1b2 | |||
e261af52eb | |||
3f03d46fc1 | |||
0e27210308 | |||
13086c2523 | |||
42a9c8b4a6 | |||
e50583d721 | |||
c90363b585 | |||
915f0faac1 | |||
0641e3a5fd | |||
11a084cf42 | |||
d60794c3a3 | |||
1b1c01a27b | |||
72d700b064 | |||
86b04ebd19 | |||
7e1c08bb6a | |||
c7b4359ff4 | |||
5695c6aca6 | |||
5ac81657e5 | |||
5bd63df237 | |||
75420282e1 | |||
38df48d108 | |||
21a8ac0cd3 | |||
1f30ba6178 | |||
8733a8d890 | |||
5446d17756 | |||
c9ff5c8223 | |||
d99dd4086d | |||
09981afc1c | |||
3d03e504cd | |||
e04424e87e | |||
277dd0aa7a | |||
ded9452174 | |||
4b1cadbd87 | |||
2506275c3b | |||
5f7a94a03e | |||
df59db6048 | |||
b33d7586e7 | |||
fb957ef322 | |||
5e5d48348b | |||
26da6a3e10 | |||
4c2cc782aa | |||
05e7fdd5ce | |||
796e3fb7e4 | |||
867a36b419 | |||
a139275eca | |||
efcb3bbc8d | |||
309979d578 | |||
c805fa7c40 | |||
634bf8c953 | |||
be393f6722 | |||
d94ff20927 | |||
0173c260d8 | |||
9d815e5f5a | |||
7097663ddd | |||
eab099b221 | |||
3036620b48 | |||
d40830a2b1 | |||
028715b0f0 | |||
4a74e19f80 | |||
e773e71910 | |||
39a97d86f0 | |||
41fe225b0d | |||
1945a0f504 | |||
4e60e62444 | |||
96a6210198 | |||
192d9ad977 | |||
cb82919b0d | |||
28aff5d240 | |||
532b2d2d4e | |||
214e2cddf6 | |||
0ce150280e | |||
3a8a37187d | |||
629398d0f2 | |||
fd773dffb2 | |||
001f747963 | |||
2081071bee | |||
47f623d64b | |||
7e63364529 | |||
2e5bde4a77 | |||
cfe869692f | |||
a61f3c5316 | |||
ce80d73684 | |||
804c25a81a | |||
a54b4bba35 | |||
0a01c5aa36 | |||
f01b7afa19 | |||
ffa7b37b28 | |||
f61a394be4 | |||
c2ea5b3dee | |||
199697accf | |||
cb8f29d147 | |||
0e3042f488 | |||
f644431346 | |||
83a52c07b7 | |||
7d1dd5f52d | |||
330d584617 | |||
11d6f81316 | |||
f9c8cefd06 | |||
791e76ff70 | |||
e0d915a873 | |||
90ad817a43 | |||
5bc8c713e2 | |||
6c0b4a2769 | |||
afdae26c71 | |||
b5022102bb | |||
b7410c95cf | |||
fcfca57e2e | |||
0ac10bb23a | |||
a729b1aa29 | |||
548c09acfc | |||
2ce8ee0214 | |||
cee9ed2244 | |||
e7e15631dd | |||
ffeeb5c1e7 | |||
c356991fa8 | |||
e42ee69988 | |||
226e7d7b3c | |||
cd2e4310b3 | |||
fd3d795b93 | |||
729b035edd | |||
fda853b573 | |||
280a6275ce | |||
95b5d24f43 | |||
19443035a6 | |||
8b8103efef | |||
6bc3d72a65 | |||
854a559a49 | |||
18dfbbb150 | |||
0a26c20b88 | |||
0889cff5d5 | |||
9b8c876293 | |||
e94ab01940 | |||
54c982081f | |||
a631fa20d0 | |||
5911fa1d91 | |||
e1edb5676e | |||
3670f095c7 | |||
f11d690967 | |||
15ae237d2c | |||
36d16fed1f | |||
30e489db5e | |||
2296999cf6 | |||
d323acdfec | |||
81b0e9de7c | |||
587fd6a0e4 | |||
6cb7f21e38 | |||
8ff43c3705 | |||
026db90621 | |||
b77497cbd8 | |||
596ec5c74b | |||
0ec64370b2 | |||
d7f45ebca5 | |||
daa94eb792 | |||
5f990473e4 | |||
4bc7a86f3a | |||
ffbf12504d | |||
330cad1567 | |||
fa4d2ec241 | |||
acfc56957c | |||
3ba431e79e | |||
d62448cb45 | |||
1999e368f1 | |||
fc4f0d3fce | |||
9403edbb93 | |||
ab1b54c3e3 | |||
0f5933ecc1 | |||
e75b4bc2df | |||
36b09fd147 | |||
a26523330e | |||
2a022e9e6e | |||
fb12308416 | |||
f5a3b05c7a | |||
f868624f85 | |||
10ccbc5efa | |||
43d6b5b375 | |||
869c0bdeb8 | |||
c71af0895d | |||
b00ee99a21 | |||
55c13f3de4 | |||
9694854082 | |||
cdca2782d2 | |||
cebbb0feaf | |||
6240a7639d | |||
9e8b3d4a98 | |||
c27015368b | |||
5da497d0a8 | |||
dc261f17e9 | |||
ee8200f1c6 | |||
0a389691dc | |||
32d6ca9196 | |||
20e317cf92 | |||
2b9843c20b | |||
872ea3b987 | |||
df110bccbe | |||
a01eb9c451 | |||
81a9da8f61 | |||
a3c7e326c3 | |||
5ce334923f | |||
49b5022993 | |||
84d88cb2cf | |||
f09e4f7b10 | |||
0a73a5012a | |||
96dc03b337 | |||
d1d00fdeec | |||
00b610e542 | |||
fc35b6988d | |||
b86bd3b074 | |||
3414601788 | |||
d31c4e0bc1 | |||
031cd2bb0d | |||
3c0fc6f0da | |||
a0cf3d47f1 | |||
c4f3732c91 | |||
a9d954cb3c | |||
6e4f2da9b3 | |||
ab5df4bc5c | |||
7bbc128c3d | |||
cb57f4f89b | |||
8b6226997e | |||
f0b3e05add | |||
09b2649c5f | |||
cc17210bce | |||
e5d99cb9e6 | |||
3c1924c9c0 | |||
e4d5d05119 | |||
e3f1b1dccb | |||
fd238f3c0e | |||
58713d34dd | |||
32e22a0037 | |||
231b7df6cc | |||
521136181b | |||
fda19b55b1 | |||
de4db6a93b | |||
d797f4d590 | |||
a37fd93fbb | |||
8740b7cb77 | |||
746b1bcf2a | |||
34c956afc1 | |||
d0ff35c5a6 | |||
1307fafe0f | |||
9886fd236e | |||
a4fdfc098d | |||
cbe81ad393 | |||
8c09f12943 | |||
19ef3e0f31 | |||
463f59eca4 | |||
e4145ebc47 | |||
567189cc76 | |||
f4262026b6 | |||
82a27a85b5 | |||
ba898b9ab6 | |||
d827dd8b05 | |||
e53758c5f6 | |||
1f27c9f6a4 | |||
d310e1f907 | |||
81d4c4a84c | |||
1c811bfcd9 | |||
6d9e7d48fb | |||
c868609cff | |||
e4b9ac46d7 | |||
45f3e8bbef | |||
1fae121b22 | |||
180f92d3dc | |||
5476ee8655 | |||
3c396cf1e1 | |||
1ea1cb6dc9 | |||
8821cc416e | |||
92a4b5cc3c | |||
c0d6056870 | |||
23770214a9 | |||
386e91addb | |||
62a87c84ed | |||
ce2e60ab45 | |||
9c5a85ce24 | |||
c09dad71fb | |||
d08427030d | |||
7b570840cd | |||
c1bd76d6fc | |||
a7abade088 | |||
abb24370e9 | |||
6e1feb0f73 | |||
ef7264807f | |||
bc39506792 | |||
28b4fa3e27 | |||
b193809987 | |||
a8fd88463e | |||
3a3e17d603 | |||
40af31729f | |||
58f8f29c41 | |||
3d08a49790 | |||
55a9262bdb | |||
ba94d0f144 | |||
ae4db9f302 | |||
70db1d523d | |||
8e229cb7ea | |||
13d3eeb2ee | |||
dece918bc8 | |||
b091c37595 | |||
ca70770cfd | |||
5243a81c29 | |||
12acf852c5 | |||
074b5de771 | |||
69fa16048a | |||
b01e9651b0 | |||
8967776713 | |||
d1c65d1b28 | |||
be1db6b6c1 | |||
4227b2ebb4 | |||
15e20bb5c0 | |||
80bc87e377 | |||
77357081c8 | |||
4b28383b1c | |||
94c56559ca | |||
427d0a5e92 | |||
623b46a17d | |||
a606966029 | |||
79ea81b8a8 | |||
d4c024c836 | |||
b297d78367 | |||
4a6d5e2012 | |||
9d5cd4ca14 | |||
0b487802a0 | |||
f3891e90e3 | |||
0f3b81bb2e | |||
00ed523659 | |||
77fae3d852 | |||
16ff2d927f | |||
fc7a27bc3d | |||
666722324f | |||
bfb58b7e1c | |||
8852b25fc7 | |||
4d5b618d52 | |||
e6724f0303 | |||
37dd26e322 | |||
f10ad95c36 | |||
9b3dc72506 | |||
4534f0fbcf | |||
6a93206882 | |||
043fb32c4b | |||
b3cd5d2945 | |||
6b81ac5807 | |||
988ca74351 | |||
86adb6ca63 | |||
b22b7d7ba9 | |||
7995eedd35 | |||
098528513f | |||
829384f46d | |||
e96041e18f | |||
0f45aa7f31 | |||
2cf3336130 | |||
a8b9e2eccd | |||
99f55abc56 | |||
c2d814e78d | |||
9e3ef2809a | |||
48ed8ac50c | |||
ece758457d | |||
79e9bde0ea | |||
08f047eb51 | |||
9edd2258ff | |||
13c7bbf8a9 | |||
533ac4d47d | |||
f0c18fceb4 | |||
22a1337a9b | |||
969ee25a74 | |||
6cde12a013 | |||
feb8e9a790 | |||
8a74d1ec79 | |||
694c88e031 | |||
036d90bba6 | |||
664a9f4830 | |||
3ea396e9d2 | |||
819dc1845e | |||
53c08f0bba | |||
597de9d586 | |||
f072a76326 | |||
856f9cced8 | |||
ec87e88c52 | |||
f9f5aac123 | |||
1134de3c89 | |||
3b74824985 | |||
6bd5bf3cb5 | |||
1aa7fa354e | |||
5383697c78 | |||
0b05048341 | |||
41001dbfdd | |||
d62a8d2f15 | |||
f06d866110 | |||
3638c05ec9 | |||
54815fff06 | |||
666c77c0f2 | |||
cafe145ba2 | |||
974e7b9220 | |||
b59cdf0892 | |||
993fe07a3c | |||
2bbf2fa8eb | |||
1c013e7ae2 | |||
fd1782b5fc | |||
559ca8bc65 | |||
2f334afb98 | |||
88551add97 | |||
23e8e849e4 | |||
362a1a5a82 | |||
ce1528359a | |||
f02cdcff00 | |||
1f3d04cddf | |||
c78033233a | |||
83541123c8 | |||
46e6b2b86e | |||
6ac5689ce4 | |||
d11f8d4228 | |||
71dbe47619 | |||
a5b476a7d3 | |||
b3997469b5 | |||
519c309952 | |||
a161e29c59 | |||
72f754e2bc | |||
439a579aa2 | |||
649c9d4719 | |||
51f89f2fbd | |||
e06d188f0d | |||
fef3cb3f21 | |||
027fe112ec | |||
f54198eed6 | |||
0dae377fbf | |||
8bc90a25c2 | |||
b40ccdd57c | |||
78135c24b4 | |||
d9c67a9b21 | |||
e6834b3237 | |||
c0629c13fe | |||
f6473baffc | |||
3e343ba5ef | |||
6b0c464a34 | |||
9aabf441bd | |||
772b54a08b | |||
e593213b87 | |||
3cd644aeb5 | |||
a28fb37b9e | |||
a5491d3698 | |||
ca0d9a70d1 | |||
cf700151eb | |||
af1c7bf0c7 | |||
fa11ddd7df | |||
3e333e9b5c | |||
1568ed4d20 | |||
3934ade5a2 | |||
f4fa3e1a6b | |||
ce6a0f4469 | |||
33eb7d7dfb | |||
705caa8c32 | |||
c1f5ac3eca | |||
bcb875dcb1 | |||
be66243933 | |||
57534733b7 | |||
1612c570b6 | |||
b92e502695 | |||
27e6aee390 | |||
8bfcefe11a | |||
00d24511bc | |||
03762f42c1 | |||
ae88bf03a1 | |||
c3fddb0fbb | |||
697fb353dc | |||
2a7c2539c6 | |||
500fd8b9bf | |||
b4be988732 | |||
b785a50da4 | |||
2bc0525e93 | |||
85b42d7c95 | |||
c7fc06a262 | |||
268f53ed0d | |||
b93b85378d | |||
e15db15926 | |||
2972604f0c | |||
d947a815e8 | |||
d10fb73f63 | |||
64c4106219 | |||
c45e6e3c78 | |||
a7101e7bfb | |||
beb65056cf | |||
c2d4330f27 | |||
077645476c | |||
e9e35b011e | |||
86a4d47215 | |||
4a33d57143 | |||
34a4109946 | |||
7e728fe1a1 | |||
96a883a454 | |||
9ab6bdce01 | |||
681f779a3c | |||
ac3143c093 | |||
d41bab4028 | |||
3da88b8917 | |||
9cfa27f9c5 | |||
c39f3026a8 | |||
222bb2b88d | |||
b8538f5dcd | |||
c4fdcb04be | |||
0823511262 | |||
738ae4a77f | |||
47ac6a1a2e | |||
3d2c4dc034 | |||
082fcc53cc | |||
074295245b | |||
cb14bbdbc9 | |||
841c3478fd | |||
6294509cc6 | |||
1481125042 | |||
10d27998b3 | |||
a9a7c297ae | |||
023cf21848 | |||
cb305b9fc0 | |||
a0cc570f86 | |||
903569d533 | |||
d77546773b | |||
de13abdfdf | |||
2566bdfbc3 | |||
143a9d7ee6 | |||
6e1f421a6d | |||
fd37eeddd6 | |||
6b48233f25 | |||
3ec4813ba2 | |||
e8dbaf62d3 | |||
705fee709f | |||
71f4fbfbde | |||
16e9b32c2f | |||
3b6840e099 | |||
67a61cce1b | |||
d9d47b7b88 | |||
181e701cc5 | |||
a421879bb5 | |||
3472910177 | |||
088ee7618d | |||
a405b89555 | |||
88760141da | |||
b174c27d4d | |||
bfd0689d64 | |||
0ac20a8fdb | |||
d16332be72 | |||
6a8cc1dcd4 | |||
c923dee8de | |||
633aea92fb | |||
e1733a6271 | |||
114744cee1 | |||
dfe3eb12d0 | |||
d3605b81f3 | |||
4daea88516 | |||
810ab095e6 | |||
5fb71bd530 | |||
dd385eb5ac | |||
b4e8de3a31 |
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,13 +1,16 @@
|
||||
*.5
|
||||
*.7
|
||||
*.8
|
||||
*.a
|
||||
*.d
|
||||
*.o
|
||||
*.orig
|
||||
*.pc
|
||||
*.pot
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*.swp
|
||||
*.sw*
|
||||
*~
|
||||
|
||||
.export.sym
|
||||
@ -17,11 +20,11 @@
|
||||
Makefile
|
||||
make.tmpl
|
||||
|
||||
configure.h
|
||||
version.h
|
||||
|
||||
/autom4te.cache/
|
||||
/autoscan.log
|
||||
/config.log
|
||||
/config.status
|
||||
/configure.scan
|
||||
/cscope.out
|
||||
/tags
|
||||
/tmp/
|
||||
|
17
Makefile.in
17
Makefile.in
@ -95,7 +95,7 @@ endif
|
||||
DISTCLEAN_TARGETS += cscope.out
|
||||
CLEAN_DIRS += autom4te.cache
|
||||
|
||||
check check_system check_cluster check_local check_lvmetad unit: all
|
||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate: tools
|
||||
@ -131,6 +131,9 @@ rpm: dist
|
||||
generate: conf.generate
|
||||
$(MAKE) -C conf generate
|
||||
|
||||
all_man:
|
||||
$(MAKE) -C man all_man
|
||||
|
||||
install_system_dirs:
|
||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||
@ -150,6 +153,9 @@ install_systemd_generators:
|
||||
install_systemd_units:
|
||||
$(MAKE) -C scripts install_systemd_units
|
||||
|
||||
install_all_man:
|
||||
$(MAKE) -C man install_all_man
|
||||
|
||||
ifeq ("@PYTHON_BINDINGS@", "yes")
|
||||
install_python_bindings:
|
||||
$(MAKE) -C liblvm/python install_python_bindings
|
||||
@ -223,3 +229,12 @@ memcheck: test-programs
|
||||
ruby-test:
|
||||
$(RUBY) report-generators/test/ts.rb
|
||||
endif
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
tags:
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
|
||||
CLEAN_TARGETS += tags
|
||||
endif
|
||||
|
@ -1 +1 @@
|
||||
1.02.101-git (2015-07-03)
|
||||
1.02.111-git (2015-10-30)
|
||||
|
125
WHATS_NEW
125
WHATS_NEW
@ -1,3 +1,128 @@
|
||||
Version 2.02.134 -
|
||||
====================================
|
||||
|
||||
Version 2.02.133 - 30th October 2015
|
||||
====================================
|
||||
Support repeated -o|--options for reporting commands.
|
||||
Support -o- and -o# for reporting commands to remove and compact fields.
|
||||
Fix missing PVs from pvs output if vgremove is run concurrently.
|
||||
Remove unwanted error message when running pvs/vgs/lvs and vgremove at once.
|
||||
Check newly created VG's metadata do not overlap in metadata ring buffer.
|
||||
Check metadata area size is at least the minimum size defined for the format.
|
||||
Thin pool targets uses low_water_mark from profile.
|
||||
Dropping 'yet' from error of unsupported thick snapshot of snapshots.
|
||||
Do not support unpartitioned DASD devices with CDL formatted with pvcreate.
|
||||
For thins use flush for suspend only when volume size is reduced.
|
||||
Enable code which detects the need of flush during suspend.
|
||||
Ensure --use-policy will resize volume to fit below threshold.
|
||||
Correct percentage evaluation when checking thin-pool over threshold.
|
||||
Fix lvmcache to move PV from VG to orphans if VG is removed and lvmetad used.
|
||||
Fix lvmcache to not cache even invalid info about PV which got removed.
|
||||
Support checking of memlock daemon counter.
|
||||
Allow all log levels to be used with the lvmetad -l option.
|
||||
Add optional shutdown when idle support for lvmetad.
|
||||
Fix missing in-sync progress info while lvconvert used with lvmpolld.
|
||||
Add report/compact_output_cols to lvm.conf to define report cols to compact.
|
||||
Do not change logging in lvm2 library when it's already set.
|
||||
Check for enough space in thin-pool in command before creating new thin.
|
||||
Make libblkid detect all copies of the same signature if use_blkid_wiping=1.
|
||||
Fix vgimportclone with -n to not add number unnecessarily to base VG name.
|
||||
Cleanup vgimportclone script and remove dependency on awk, grep, cut and tr.
|
||||
Add vg_missing_pv_count report field to report number of missing PVs in a VG.
|
||||
Properly identify internal LV holding sanlock locks within lv_role field.
|
||||
Add metadata_devices and seg_metadata_le_ranges report fields for raid vols.
|
||||
Fix lvm2-{activation,clvmd,cmirrord,monitor} service to exec before mounting.
|
||||
|
||||
Version 2.02.132 - 22nd September 2015
|
||||
======================================
|
||||
Fix lvmconf to set locking_type=2 if external locking library is requested.
|
||||
Remove verbose message when rescanning an unchanged device. (2.02.119)
|
||||
Add origin_uuid, mirror_log_uuid, move_pv_uuid, convert_lv_uuid report fields.
|
||||
Add pool_lv_uuid, metadata_lv_uuid, data_lv_uuid reporting fields.
|
||||
Fix PV label processing failure after pvcreate in lvm shell with lvmetad.
|
||||
|
||||
Version 2.02.131 - 15th September 2015
|
||||
======================================
|
||||
Rename 'make install_full_man' to install_all_man and add all_man target.
|
||||
Fix vgimportclone cache_dir path name (2.02.115).
|
||||
Swapping of LV identifiers handles more complex LVs.
|
||||
Use passed list of PVS when allocating space in lvconvert --thinpool.
|
||||
Disallow usage of --stripe and --stripesize when creating cache pool.
|
||||
Warn user when caching raid or thin pool data LV.
|
||||
When layering LV, move LV flags with segments.
|
||||
Ignore persistent cache if configuration changed. (2.02.127)
|
||||
Fix devices/filter to be applied before disk-accessing filters. (2.02.112)
|
||||
Make tags only when requested via 'make tags'.
|
||||
Configure supports --disable-dependency-tracking for one-time builds.
|
||||
Fix usage of configure.h when building in srcdir != builddir.
|
||||
|
||||
Version 2.02.130 - 5th September 2015
|
||||
=====================================
|
||||
Fix use of uninitialized device status if reading outdated .cache record.
|
||||
Restore support for --monitor option in lvcreate (2.02.112).
|
||||
Read thin-pool data and metadata percent without flush.
|
||||
Detect blocked thin-pool and avoid scanning their thin volumes.
|
||||
Check if dm device is usable before checking its size (2.02.116).
|
||||
Extend parsing of cache_check version in configure.
|
||||
Make lvpoll error messages visible in lvmpolld's stderr and in syslog.
|
||||
Add 'make install_full_man' to install all man pages regardless of config.
|
||||
|
||||
Version 2.02.129 - 26th August 2015
|
||||
===================================
|
||||
Drop error message when vgdisplay encounters an exported VG. (2.02.27)
|
||||
Fix shared library generation to stop exporting internal functions.(2.02.120)
|
||||
Accept --cachemode with lvconvert.
|
||||
Fix and improve reporting properties of cache-pool.
|
||||
Enable usage of --cachepolicy and --cachesetting with lvconvert.
|
||||
Don't allow to reduce size of thin-pool metadata.
|
||||
Fix debug buffer overflows in cmirrord logging.
|
||||
Add --foreground and --help to cmirrord.
|
||||
|
||||
Version 2.02.128 - 17th August 2015
|
||||
===================================
|
||||
Allocation setting cache_pool_cachemode is replaced by cache_mode.
|
||||
Don't attempt to close config file that couldn't be opened.
|
||||
Check for valid cache mode in validation of cache segment.
|
||||
Change internal interface handling cache mode and policy.
|
||||
When no cache policy specified, prefer smq (if available) over mq.
|
||||
Add demo cache-mq and cache-smq profiles.
|
||||
Add cmd profilable allocation/cache_policy,cache_settings,cache_mode.
|
||||
Require cache_check 0.5.4 for use of --clear-needs-check-flag.
|
||||
Fix lvmetad udev rules to not override SYSTEMD_WANTS, add the service instead.
|
||||
|
||||
Version 2.02.127 - 10th August 2015
|
||||
===================================
|
||||
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
|
||||
Order fields in struct cmd_context more logically.
|
||||
Add lock_type to lvmcache VG summary and info structs.
|
||||
Fix regression in cache causing some PVs to bypass filters (2.02.105).
|
||||
Make configure --enable-realtime the default now.
|
||||
Update .gitignore and configure.in files to reflect usage of current tree.
|
||||
|
||||
Version 2.02.126 - 24th July 2015
|
||||
=================================
|
||||
Fix long option hyphen removal. (2.02.122)
|
||||
Fix clvmd freeze if client disappears without first releasing its locks.
|
||||
Fix lvconvert segfaults while performing snapshots merge.
|
||||
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
|
||||
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
|
||||
Fix alloc segfault when extending LV with fewer stripes than in first seg.
|
||||
Fix handling of cache policy name.
|
||||
Set cache policy before with the first lvm2 cache pool metadata commit.
|
||||
Fix detection of thin-pool overprovisioning (2.02.124).
|
||||
Fix lvmpolld segfaults on 32 bit architectures.
|
||||
Add lvmlockd lock_args validation to vg_validate.
|
||||
Fix ignored --startstopservices option if running lvmconf with systemd.
|
||||
Hide sanlock LVs when processing LVs in VG unless named or --all used.
|
||||
|
||||
Version 2.02.125 - 7th July 2015
|
||||
================================
|
||||
Fix getline memory usage in lvmpolld.
|
||||
Add support --clear-needs-check-flag for cache_check of cache pool metadata.
|
||||
Add lvmetactl for developer use only.
|
||||
Rename global/lock_retries to lvmlockd_retries.
|
||||
Replace --enable-lvmlockd by --enable-lockd-sanlock and --enable-lockd-dlm.
|
||||
|
||||
Version 2.02.124 - 3rd July 2015
|
||||
================================
|
||||
Move sending thin pool messages from resume to suspend phase.
|
||||
|
116
WHATS_NEW_DM
116
WHATS_NEW_DM
@ -1,3 +1,119 @@
|
||||
Version 1.02.111 -
|
||||
====================================
|
||||
|
||||
Version 1.02.110 - 30th October 2015
|
||||
====================================
|
||||
Disable thin monitoring plugin when it fails too often (>10 times).
|
||||
Fix/restore parsing of empty field '-' when processing dmeventd event.
|
||||
Enhance dm_tree_node_size_changed() to recognize size reduction.
|
||||
Support exit on idle for dmenventd (1 hour).
|
||||
Add support to allow unmonitor device from plugin itself.
|
||||
New design for thread co-operation in dmeventd.
|
||||
Dmeventd read device status with 'noflush'.
|
||||
Dmeventd closes control device when no device is monitored.
|
||||
Thin plugin for dmeventd improved percentage usage.
|
||||
Snapshot plugin for dmeventd improved percentage usage.
|
||||
Add dm_hold_control_dev to allow holding of control device open.
|
||||
Add dm_report_compact_given_fields to remove given empty fields from report.
|
||||
Use libdm status parsing and local mem raid dmeventd plugin.
|
||||
Use local mem pool and lock only lvm2 execution for mirror dmeventd plugin.
|
||||
Lock protect only lvm2 execution for snapshot and thin dmeventd plugin.
|
||||
Use local mempool for raid and mirror plugins.
|
||||
Reworked thread initialization for dmeventd plugins.
|
||||
Dmeventd handles snapshot overflow for now equally as invalid.
|
||||
Convert dmeventd to use common logging macro system from libdm.
|
||||
Return -ENOMEM when device registration fails instead of 0 (=success).
|
||||
Enforce writethrough mode for cleaner policy.
|
||||
Add support for recognition and deactivation of MD devices to blkdeactivate.
|
||||
Move target status functions out of libdm-deptree.
|
||||
Correct use of max_write_behind parameter when generating raid target line.
|
||||
Fix dm-event systemd service to make sure it is executed before mounting.
|
||||
|
||||
Version 1.02.109 - 22nd September 2016
|
||||
======================================
|
||||
Update man pages for dmsetup and dmstats.
|
||||
Improve help text for dmsetup.
|
||||
Use --noflush and --nolockfs when removing device with --force.
|
||||
Parse new Overflow status string for snapshot target.
|
||||
Check dir path components are valid if using dm_create_dir, error out if not.
|
||||
Fix /dev/mapper handling to remove dangling entries if symlinks are found.
|
||||
Make it possible to use blank value as selection for string list report field.
|
||||
|
||||
Version 1.02.108 - 15th September 2015
|
||||
======================================
|
||||
Do not check for full thin pool when activating without messages (1.02.107).
|
||||
|
||||
Version 1.02.107 - 5th September 2015
|
||||
=====================================
|
||||
Parse thin-pool status with one single routine internally.
|
||||
Add --histogram to select default histogram fields for list and report.
|
||||
Add report fields for displaying latency histogram configuration and data.
|
||||
Add dmstats --bounds to specify histogram boundaries for a new region.
|
||||
Add dm_histogram_to_string() to format histogram data in string form.
|
||||
Add public methods to libdm to access numerical histogram config and data.
|
||||
Parse and store histogram data in dm_stats_list() and dm_stats_populate().
|
||||
Add an argument to specify histogram bounds to dm_stats_create_region().
|
||||
Add dm_histogram_bounds_from_{string,uint64_t}() to parse histogram bounds.
|
||||
Add dm_histogram handle type to represent a latency histogram and its bounds.
|
||||
Fix devmapper.pc pkgconfig file to not reference non-existent rt.pc file.
|
||||
Reinstate dm_task_get_info@Base to libdevmapper exports. (1.02.106)
|
||||
|
||||
Version 1.02.106 - 26th August 2015
|
||||
===================================
|
||||
Add 'precise' column to statistics reports.
|
||||
Add --precise switch to 'dmstats create' to request nanosecond counters.
|
||||
Add precise argument to dm_stats_create_region().
|
||||
Add support to libdm-stats for precise_timestamps
|
||||
|
||||
Version 1.02.105 - 17th August 2015
|
||||
===================================
|
||||
Fix 'dmstats list -o all' segfault.
|
||||
Separate dmstats statistics fields from region information fields.
|
||||
Add interval and interval_ns fields to dmstats reports.
|
||||
Do not include internal glibc headers in libdm-timestamp.c (1.02.104)
|
||||
Exit immediately if no device is supplied to dmsetup wipe_table.
|
||||
Suppress dmsetup report headings when no data is output. (1.02.104)
|
||||
Adjust dmsetup usage/help output selection to match command invoked.
|
||||
Fix dmsetup -o all to select correct fields in splitname report.
|
||||
Restructure internal dmsetup argument handling across all commands.
|
||||
Add dm_report_is_empty() to indicate there is no data awaiting output.
|
||||
Add more arg validation for dm_tree_node_add_cache_target().
|
||||
Add --alldevices switch to replace use of --force for stats create / delete.
|
||||
|
||||
Version 1.02.104 - 10th August 2015
|
||||
===================================
|
||||
Add dmstats.8 man page
|
||||
Add dmstats --segments switch to create one region per device segment.
|
||||
Add dmstats --regionid, --allregions to specify a single / all stats regions.
|
||||
Add dmstats --allprograms for stats commands that filter by program ID.
|
||||
Add dmstats --auxdata and --programid args to specify aux data and program ID.
|
||||
Add report stats sub-command to provide repeating stats reports.
|
||||
Add clear, delete, list, and print stats sub-commands.
|
||||
Add create stats sub-command and --start, --length, --areas and --areasize.
|
||||
Recognize 'dmstats' as an alias for 'dmsetup stats' when run with this name.
|
||||
Add a 'stats' command to dmsetup to configure, manage and report stats data.
|
||||
Add statistics fields to dmsetup -o.
|
||||
Add libdm-stats library to allow management of device-mapper statistics.
|
||||
Add --nosuffix to suppress dmsetup unit suffixes in report output.
|
||||
Add --units to control dmsetup report field output units.
|
||||
Add support to redisplay column headings for repeating column reports.
|
||||
Fix report header and row resource leaks.
|
||||
Report timestamps of ioctls with dmsetup -vvv.
|
||||
Recognize report field name variants without any underscores too.
|
||||
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
||||
Add dm_timestamp functions to libdevmapper.
|
||||
Recognise vg/lv name format in dmsetup.
|
||||
Move size display code to libdevmapper as dm_size_to_string.
|
||||
|
||||
Version 1.02.103 - 24th July 2015
|
||||
=================================
|
||||
Introduce libdevmapper wrappers for all malloc-related functions.
|
||||
|
||||
Version 1.02.102 - 7th July 2015
|
||||
================================
|
||||
Include tool.h for default non-library use.
|
||||
Introduce format macros with embedded % such as FMTu64.
|
||||
|
||||
Version 1.02.101 - 3rd July 2015
|
||||
================================
|
||||
Add experimental support to passing messages in suspend tree.
|
||||
|
2
aclocal.m4
vendored
2
aclocal.m4
vendored
@ -15,7 +15,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
# Copyright (c) 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
6
conf/.gitignore
vendored
Normal file
6
conf/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
command_profile_template.profile
|
||||
example.conf
|
||||
lvmlocal.conf
|
||||
metadata_profile_template.profile
|
||||
configure.h
|
||||
lvm-version.h
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@ -20,7 +20,11 @@ CONFDEST=lvm.conf
|
||||
CONFLOCAL=lvmlocal.conf
|
||||
|
||||
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) \
|
||||
$(srcdir)/cache-mq.profile \
|
||||
$(srcdir)/cache-smq.profile \
|
||||
$(srcdir)/thin-generic.profile \
|
||||
$(srcdir)/thin-performance.profile
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
|
20
conf/cache-mq.profile
Normal file
20
conf/cache-mq.profile
Normal file
@ -0,0 +1,20 @@
|
||||
# Demo configuration 'mq' cache policy
|
||||
#
|
||||
# Note: This policy has been deprecated in favor of the smq policy
|
||||
# keyword "default" means, setting is left with kernel defaults.
|
||||
#
|
||||
|
||||
allocation {
|
||||
cache_pool_chunk_size = 64
|
||||
cache_mode = "writethrough"
|
||||
cache_policy = "mq"
|
||||
cache_settings {
|
||||
mq {
|
||||
sequential_threshold = "default" # #nr_sequential_ios
|
||||
random_threshold = "default" # #nr_random_ios
|
||||
read_promote_adjustment = "default"
|
||||
write_promote_adjustment = "default"
|
||||
discard_promote_adjustment = "default"
|
||||
}
|
||||
}
|
||||
}
|
14
conf/cache-smq.profile
Normal file
14
conf/cache-smq.profile
Normal file
@ -0,0 +1,14 @@
|
||||
# Demo configuration 'smq' cache policy
|
||||
#
|
||||
# The stochastic multi-queue (smq) policy addresses some of the problems
|
||||
# with the multiqueue (mq) policy and uses less memory.
|
||||
#
|
||||
|
||||
allocation {
|
||||
cache_pool_chunk_size = 64
|
||||
cache_mode = "writethrough"
|
||||
cache_policy = "smq"
|
||||
cache_settings {
|
||||
# currently no settins for "smq" policy
|
||||
}
|
||||
}
|
1729
conf/example.conf.in
1729
conf/example.conf.in
File diff suppressed because it is too large
Load Diff
@ -24,28 +24,33 @@ local {
|
||||
|
||||
# Configuration option local/system_id.
|
||||
# Defines the local system ID for lvmlocal mode.
|
||||
# This is used when global/system_id_source is set
|
||||
# to 'lvmlocal' in the main configuration file,
|
||||
# e.g. lvm.conf.
|
||||
# When used, it must be set to a unique value
|
||||
# among all hosts sharing access to the storage,
|
||||
# This is used when global/system_id_source is set to 'lvmlocal' in the
|
||||
# main configuration file, e.g. lvm.conf. When used, it must be set to
|
||||
# a unique value among all hosts sharing access to the storage,
|
||||
# e.g. a host name.
|
||||
# Example:
|
||||
# Set no system ID.
|
||||
#
|
||||
# Example
|
||||
# Set no system ID:
|
||||
# system_id = ""
|
||||
# Example:
|
||||
# Set the system_id to the string 'host1'.
|
||||
# Set the system_id to a specific name:
|
||||
# system_id = "host1"
|
||||
#
|
||||
# This configuration option has an automatic default value.
|
||||
# system_id = ""
|
||||
|
||||
# Configuration option local/extra_system_ids.
|
||||
# A list of extra VG system IDs the local host can access.
|
||||
# VGs with the system IDs listed here (in addition
|
||||
# to the host's own system ID) can be fully accessed
|
||||
# by the local host. (These are system IDs that the
|
||||
# host sees in VGs, not system IDs that identify the
|
||||
# local host, which is determined by system_id_source.)
|
||||
# Use this only after consulting 'man lvmsystemid'
|
||||
# to be certain of correct usage and possible dangers.
|
||||
# VGs with the system IDs listed here (in addition to the host's own
|
||||
# system ID) can be fully accessed by the local host. (These are
|
||||
# system IDs that the host sees in VGs, not system IDs that identify
|
||||
# the local host, which is determined by system_id_source.)
|
||||
# Use this only after consulting 'man lvmsystemid' to be certain of
|
||||
# correct usage and possible dangers.
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option local/host_id.
|
||||
# The lvmlockd sanlock host_id.
|
||||
# This must be unique among all hosts, and must be between 1 and 2000.
|
||||
# This configuration option has an automatic default value.
|
||||
# host_id = 0
|
||||
}
|
||||
|
287
configure.in
287
configure.in
@ -16,7 +16,7 @@ AC_PREREQ(2.61)
|
||||
dnl -- Process this file with autoconf to produce a configure script.
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
|
||||
AC_CONFIG_HEADERS([lib/misc/configure.h])
|
||||
AC_CONFIG_HEADERS([include/configure.h])
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the directory where autoconf has auxilary files
|
||||
@ -40,6 +40,8 @@ case "$host_os" in
|
||||
LVMETAD=no
|
||||
LVMPOLLD=no
|
||||
LVMLOCKD=no
|
||||
LOCKDSANLOCK=no
|
||||
LOCKDDLM=no
|
||||
ODIRECT=yes
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
@ -89,14 +91,19 @@ AC_PATH_TOOL(CSCOPE_CMD, cscope)
|
||||
dnl -- Check for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_MAJOR
|
||||
AC_HEADER_STDBOOL
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_HEADERS([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
|
||||
langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
|
||||
sys/wait.h time.h], ,
|
||||
[AC_MSG_ERROR(bailing out)])
|
||||
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
|
||||
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
|
||||
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
|
||||
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
|
||||
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||
unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||
|
||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h)
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
@ -105,16 +112,13 @@ case "$host_os" in
|
||||
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||
esac
|
||||
|
||||
AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
|
||||
stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
|
||||
sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_CHECK_TYPES([ptrdiff_t])
|
||||
AC_STRUCT_TM
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIGNAL
|
||||
@ -130,15 +134,13 @@ AC_TYPE_UINT8_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_STRUCT_TM
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for functions
|
||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize \
|
||||
gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
|
||||
strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
|
||||
strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
|
||||
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
|
||||
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
|
||||
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_FUNC_ALLOCA
|
||||
AC_FUNC_CLOSEDIR_VOID
|
||||
AC_FUNC_CHOWN
|
||||
@ -146,12 +148,22 @@ AC_FUNC_FORK
|
||||
AC_FUNC_LSTAT
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_MKTIME
|
||||
AC_FUNC_MMAP
|
||||
AC_FUNC_REALLOC
|
||||
AC_FUNC_STAT
|
||||
AC_FUNC_STRTOD
|
||||
AC_FUNC_VPRINTF
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable dependency tracking
|
||||
AC_MSG_CHECKING(whether to enable dependency tracking)
|
||||
AC_ARG_ENABLE(dependency-tracking,
|
||||
AC_HELP_STRING([--disable-dependency-tracking],
|
||||
[speeds up one-time build.]),
|
||||
USE_TRACKING=$enableval, USE_TRACKING=yes)
|
||||
AC_MSG_RESULT($USE_TRACKING)
|
||||
|
||||
################################################################################
|
||||
dnl -- Enables statically-linked tools
|
||||
AC_MSG_CHECKING(whether to use static linking)
|
||||
@ -172,6 +184,9 @@ AC_SUBST(HAVE_FULL_RELRO)
|
||||
################################################################################
|
||||
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||
AC_PREFIX_DEFAULT(/usr)
|
||||
if test "$prefix" = NONE; then
|
||||
datarootdir=${ac_default_prefix}/share
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the ownership of the files
|
||||
@ -558,6 +573,12 @@ case "$CACHE" in
|
||||
*) AC_MSG_ERROR([--with-cache parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
dnl -- cache_check needs-check flag
|
||||
AC_ARG_ENABLE(cache_check_needs_check,
|
||||
AC_HELP_STRING([--disable-cache_check_needs_check],
|
||||
[required if cache_check version is < 0.5]),
|
||||
CACHE_CHECK_NEEDS_CHECK=$enableval, CACHE_CHECK_NEEDS_CHECK=yes)
|
||||
|
||||
# Test if necessary cache tools are available
|
||||
# if not - use plain defaults and warn user
|
||||
case "$CACHE" in
|
||||
@ -571,6 +592,28 @@ case "$CACHE" in
|
||||
CACHE_CONFIGURE_WARN=y
|
||||
fi
|
||||
fi
|
||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||
$CACHE_CHECK_CMD -V 2>/dev/null >conftest.tmp
|
||||
read -r CACHE_CHECK_VSN < conftest.tmp
|
||||
IFS=.- read -r CACHE_CHECK_VSN_MAJOR CACHE_CHECK_VSN_MINOR CACHE_CHECK_VSN_PATCH LEFTOVER < conftest.tmp
|
||||
rm -f conftest.tmp
|
||||
|
||||
# Require version >= 0.5.4 for --clear-needs-check-flag
|
||||
if test -z "$CACHE_CHECK_VSN_MAJOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_MINOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_PATCH"; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 ; then
|
||||
if test "$CACHE_CHECK_VSN_MINOR" -lt 5 \
|
||||
|| test "$CACHE_CHECK_VSN_MINOR" -eq 5 -a "$CACHE_CHECK_VSN_PATCH" -lt 4; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Empty means a config way to ignore cache dumping
|
||||
if test "$CACHE_DUMP_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
|
||||
@ -598,6 +641,12 @@ case "$CACHE" in
|
||||
CACHE_CONFIGURE_WARN=y
|
||||
}
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether cache_check supports the needs-check flag])
|
||||
AC_MSG_RESULT([$CACHE_CHECK_NEEDS_CHECK])
|
||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||
AC_DEFINE([CACHE_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'cache_check' tool requires the --clear-needs-check-flag option])
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -626,8 +675,8 @@ AC_MSG_RESULT($READLINE)
|
||||
dnl -- Disable realtime clock support
|
||||
AC_MSG_CHECKING(whether to enable realtime support)
|
||||
AC_ARG_ENABLE(realtime,
|
||||
AC_HELP_STRING([--enable-realtime], [enable realtime clock support]),
|
||||
REALTIME=$enableval)
|
||||
AC_HELP_STRING([--disable-realtime], [disable realtime clock support]),
|
||||
REALTIME=$enableval, REALTIME=yes)
|
||||
AC_MSG_RESULT($REALTIME)
|
||||
|
||||
################################################################################
|
||||
@ -1032,6 +1081,13 @@ if test "$TESTING" = yes; then
|
||||
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Set LVM2 testsuite data
|
||||
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
|
||||
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
|
||||
AC_DEFINE_UNQUOTED(TESTSUITE_DATA, ["$(eval echo $(eval echo $TESTSUITE_DATA))"], [Path to testsuite data])
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable valgrind awareness of memory pools
|
||||
AC_MSG_CHECKING(whether to enable valgrind awareness of pools)
|
||||
@ -1077,6 +1133,96 @@ AC_MSG_RESULT($LVMETAD)
|
||||
|
||||
BUILD_LVMETAD=$LVMETAD
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmpolld
|
||||
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||
AC_ARG_ENABLE(lvmpolld,
|
||||
AC_HELP_STRING([--enable-lvmpolld],
|
||||
[enable the LVM Polling Daemon]),
|
||||
LVMPOLLD=$enableval)
|
||||
AC_MSG_RESULT($LVMPOLLD)
|
||||
|
||||
BUILD_LVMPOLLD=$LVMPOLLD
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lockdsanlock
|
||||
AC_MSG_CHECKING(whether to build lockdsanlock)
|
||||
AC_ARG_ENABLE(lockd-sanlock,
|
||||
AC_HELP_STRING([--enable-lockd-sanlock],
|
||||
[enable the LVM lock daemon using sanlock]),
|
||||
LOCKDSANLOCK=$enableval)
|
||||
AC_MSG_RESULT($LOCKDSANLOCK)
|
||||
|
||||
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
|
||||
|
||||
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Look for sanlock libraries
|
||||
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
|
||||
BUILD_LVMLOCKD=yes
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lockddlm
|
||||
AC_MSG_CHECKING(whether to build lockddlm)
|
||||
AC_ARG_ENABLE(lockd-dlm,
|
||||
AC_HELP_STRING([--enable-lockd-dlm],
|
||||
[enable the LVM lock daemon using dlm]),
|
||||
LOCKDDLM=$enableval)
|
||||
AC_MSG_RESULT($LOCKDDLM)
|
||||
|
||||
BUILD_LOCKDDLM=$LOCKDDLM
|
||||
|
||||
if test "$BUILD_LOCKDDLM" = yes; then
|
||||
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Look for dlm libraries
|
||||
if test "$BUILD_LOCKDDLM" = yes; then
|
||||
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
|
||||
BUILD_LVMLOCKD=yes
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmlockd
|
||||
|
||||
AC_MSG_CHECKING(whether to build lvmlockd)
|
||||
AC_MSG_RESULT($BUILD_LVMLOCKD)
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
|
||||
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
|
||||
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||
AC_ARG_ENABLE(use_lvmlockd,
|
||||
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||
[disable usage of LVM lock daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMLOCKD=1 ;;
|
||||
*) DEFAULT_USE_LVMLOCKD=0 ;;
|
||||
esac], DEFAULT_USE_LVMLOCKD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMLOCKD)
|
||||
AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.])
|
||||
|
||||
AC_ARG_WITH(lvmlockd-pidfile,
|
||||
AC_HELP_STRING([--with-lvmlockd-pidfile=PATH],
|
||||
[lvmlockd pidfile [PID_DIR/lvmlockd.pid]]),
|
||||
LVMLOCKD_PIDFILE=$withval,
|
||||
LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"],
|
||||
[Path to lvmlockd pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMLOCKD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
|
||||
[Use lvmlockd by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check lvmetad
|
||||
if test "$BUILD_LVMETAD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmetad])
|
||||
AC_ARG_ENABLE(use_lvmetad,
|
||||
@ -1103,16 +1249,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
|
||||
[Use lvmetad by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmpolld
|
||||
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||
AC_ARG_ENABLE(lvmpolld,
|
||||
AC_HELP_STRING([--enable-lvmpolld],
|
||||
[enable the LVM Polling Daemon]),
|
||||
LVMPOLLD=$enableval)
|
||||
AC_MSG_RESULT($LVMPOLLD)
|
||||
|
||||
BUILD_LVMPOLLD=$LVMPOLLD
|
||||
|
||||
dnl -- Check lvmpolld
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmpolld])
|
||||
AC_ARG_ENABLE(use_lvmpolld,
|
||||
@ -1138,49 +1275,6 @@ fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
|
||||
[Use lvmpolld by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmlockd
|
||||
AC_MSG_CHECKING(whether to build lvmlockd)
|
||||
AC_ARG_ENABLE(lvmlockd,
|
||||
AC_HELP_STRING([--enable-lvmlockd],
|
||||
[enable the LVM lock daemon]),
|
||||
LVMLOCKD=$enableval)
|
||||
AC_MSG_RESULT($LVMLOCKD)
|
||||
|
||||
BUILD_LVMLOCKD=$LVMLOCKD
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||
AC_ARG_ENABLE(use_lvmlockd,
|
||||
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||
[disable usage of LVM lock daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMLOCKD=1 ;;
|
||||
*) DEFAULT_USE_LVMLOCKD=0 ;;
|
||||
esac], DEFAULT_USE_LVMLOCKD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMLOCKD)
|
||||
AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.])
|
||||
|
||||
AC_ARG_WITH(lvmlockd-pidfile,
|
||||
AC_HELP_STRING([--with-lvmlockd-pidfile=PATH],
|
||||
[lvmlockd pidfile [PID_DIR/lvmlockd.pid]]),
|
||||
LVMLOCKD_PIDFILE=$withval,
|
||||
LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"],
|
||||
[Path to lvmlockd pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMLOCKD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
|
||||
[Use lvmlockd by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Look for sanlock and dlm libraries
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
|
||||
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
||||
dnl -- Enable blkid wiping functionality
|
||||
@ -1452,6 +1546,10 @@ if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
AC_CHECK_LIB(m, log10,
|
||||
[M_LIBS="-lm"], hard_bailout)
|
||||
|
||||
################################################################################
|
||||
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
|
||||
[PTHREAD_LIBS="-lpthread"], hard_bailout)
|
||||
@ -1492,6 +1590,7 @@ if test "$REALTIME" = yes; then
|
||||
if test "$HAVE_REALTIME" = yes; then
|
||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||
LIBS="-lrt $LIBS"
|
||||
RT_LIB="-lrt"
|
||||
else
|
||||
AC_MSG_WARN(Disabling realtime clock)
|
||||
fi
|
||||
@ -1642,6 +1741,19 @@ if test "$READLINE" = yes; then
|
||||
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_CHECK_FUNCS(atexit,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_CHECK_FUNCS(strpbrk,,hard_bailout)
|
||||
AC_FUNC_STRERROR_R
|
||||
fi
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
||||
@ -1684,12 +1796,10 @@ test "$lvm_exec_prefix" = NONE && lvm_exec_prefix=$ac_default_prefix
|
||||
LVM_PATH="$lvm_exec_prefix/sbin/lvm"
|
||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
fi
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
|
||||
################################################################################
|
||||
dnl -- dmeventd pidfile and executable path
|
||||
@ -1778,14 +1888,14 @@ test "$interface" != ioctl && AC_MSG_ERROR([--with-interface=ioctl required. fs
|
||||
AC_MSG_RESULT($interface)
|
||||
|
||||
################################################################################
|
||||
DM_LIB_VERSION="\"`cat "$srcdir"/VERSION_DM 2>/dev/null || echo Unknown`\""
|
||||
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, $DM_LIB_VERSION, [Library version])
|
||||
read DM_LIB_VERSION < "$srcdir"/VERSION_DM 2>/dev/null || DM_LIB_VERSION=Unknown
|
||||
AC_DEFINE_UNQUOTED(DM_LIB_VERSION, "$DM_LIB_VERSION", [Library version])
|
||||
|
||||
DM_LIB_PATCHLEVEL=`cat "$srcdir"/VERSION_DM | $AWK -F '[[-. ]]' '{printf "%s.%s.%s",$1,$2,$3}'`
|
||||
|
||||
LVM_VERSION="\"`cat "$srcdir"/VERSION 2>/dev/null || echo Unknown`\""
|
||||
read VER < "$srcdir"/VERSION 2>/dev/null || VER=Unknown
|
||||
|
||||
VER=`cat "$srcdir"/VERSION`
|
||||
LVM_VERSION=\"$VER\"
|
||||
LVM_RELEASE_DATE="\"`echo $VER | $SED 's/.* (//;s/).*//'`\""
|
||||
VER=`echo "$VER" | $AWK '{print $1}'`
|
||||
LVM_RELEASE="\"`echo "$VER" | $AWK -F '-' '{print $2}'`\""
|
||||
@ -1804,6 +1914,8 @@ AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMETAD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
AC_SUBST(BUILD_LVMLOCKD)
|
||||
AC_SUBST(BUILD_LOCKDSANLOCK)
|
||||
AC_SUBST(BUILD_LOCKDDLM)
|
||||
AC_SUBST(CACHE)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CFLOW_CMD)
|
||||
@ -1851,7 +1963,6 @@ AC_SUBST(DLM_LIBS)
|
||||
AC_SUBST(DL_LIBS)
|
||||
AC_SUBST(DMEVENTD)
|
||||
AC_SUBST(DMEVENTD_PATH)
|
||||
AC_SUBST(DM_LIB_VERSION)
|
||||
AC_SUBST(DM_LIB_PATCHLEVEL)
|
||||
AC_SUBST(ELDFLAGS)
|
||||
AC_SUBST(FSADM)
|
||||
@ -1882,6 +1993,7 @@ AC_SUBST(OCF)
|
||||
AC_SUBST(OCFDIR)
|
||||
AC_SUBST(PKGCONFIG)
|
||||
AC_SUBST(POOL)
|
||||
AC_SUBST(M_LIBS)
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PYTHON)
|
||||
AC_SUBST(PYTHON_BINDINGS)
|
||||
@ -1890,6 +2002,7 @@ AC_SUBST(PYTHON_LIBDIRS)
|
||||
AC_SUBST(QUORUM_CFLAGS)
|
||||
AC_SUBST(QUORUM_LIBS)
|
||||
AC_SUBST(RAID)
|
||||
AC_SUBST(RT_LIB)
|
||||
AC_SUBST(READLINE_LIBS)
|
||||
AC_SUBST(REPLICATORS)
|
||||
AC_SUBST(SACKPT_CFLAGS)
|
||||
@ -1902,6 +2015,7 @@ AC_SUBST(SNAPSHOTS)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(TESTING)
|
||||
AC_SUBST(TESTSUITE_DATA)
|
||||
AC_SUBST(THIN)
|
||||
AC_SUBST(THIN_CHECK_CMD)
|
||||
AC_SUBST(THIN_DUMP_CMD)
|
||||
@ -1917,6 +2031,7 @@ AC_SUBST(UDEV_SYNC)
|
||||
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(USE_TRACKING)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
@ -1971,7 +2086,7 @@ lib/format_pool/Makefile
|
||||
lib/locking/Makefile
|
||||
lib/mirror/Makefile
|
||||
lib/replicator/Makefile
|
||||
lib/misc/lvm-version.h
|
||||
include/lvm-version.h
|
||||
lib/raid/Makefile
|
||||
lib/snapshot/Makefile
|
||||
lib/thin/Makefile
|
||||
@ -2033,9 +2148,3 @@ AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
|
||||
|
||||
AS_IF([test "$ODIRECT" != yes],
|
||||
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
|
||||
|
||||
AS_IF([test "$BUILD_LVMLOCKD" == yes && test "$BUILD_LVMPOLLD" == no],
|
||||
[AC_MSG_WARN([lvmlockd requires lvmpolld])])
|
||||
|
||||
AS_IF([test "$BUILD_LVMLOCKD" == yes && test "$BUILD_LVMETAD" == no],
|
||||
[AC_MSG_WARN([lvmlockd requires lvmetad])])
|
||||
|
1
daemons/clvmd/.gitignore
vendored
Normal file
1
daemons/clvmd/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
clvmd
|
@ -323,6 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
|
||||
int lkid;
|
||||
char *lockname;
|
||||
|
||||
DEBUGLOG("Client thread cleanup (%p)\n", client);
|
||||
if (!client->bits.localsock.private)
|
||||
return;
|
||||
|
||||
@ -331,7 +332,7 @@ void cmd_client_cleanup(struct local_client *client)
|
||||
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("cleanup: Unlocking lock %s %x\n", lockname, lkid);
|
||||
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
|
||||
(void) sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
@ -339,7 +340,6 @@ void cmd_client_cleanup(struct local_client *client)
|
||||
client->bits.localsock.private = NULL;
|
||||
}
|
||||
|
||||
|
||||
static int restart_clvmd(void)
|
||||
{
|
||||
const char **argv;
|
||||
|
@ -18,15 +18,10 @@
|
||||
#ifndef _LVM_CLVMD_COMMON_H
|
||||
#define _LVM_CLVMD_COMMON_H
|
||||
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvm-logging.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#endif
|
||||
|
@ -243,7 +243,7 @@ static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
||||
"%" PRIsize_t " left, %" PRIsize_t " members\n",
|
||||
FMTsize_t " left, %" PRIsize_t " members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
|
@ -154,7 +154,7 @@ static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage: %s [options]\n"
|
||||
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
||||
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||
" -d[<n>] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||
" -E<uuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -h Show this help information\n"
|
||||
@ -223,6 +223,7 @@ void debuglog(const char *fmt, ...)
|
||||
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
break;
|
||||
case DEBUG_SYSLOG:
|
||||
if (!syslog_init) {
|
||||
@ -598,7 +599,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* This needs to be started after cluster initialisation
|
||||
as it may need to take out locks */
|
||||
DEBUGLOG("starting LVM thread\n");
|
||||
DEBUGLOG("Starting LVM thread\n");
|
||||
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
|
||||
local_client_head.fd, &local_client_head, newfd->fd, newfd);
|
||||
|
||||
/* Don't let anyone else to do work until we are started */
|
||||
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
|
||||
@ -698,7 +701,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
newfd->type = LOCAL_SOCK;
|
||||
newfd->callback = local_sock_callback;
|
||||
newfd->bits.localsock.all_success = 1;
|
||||
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
|
||||
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
|
||||
*new_client = newfd;
|
||||
}
|
||||
return 1;
|
||||
@ -850,18 +853,48 @@ static void main_loop(int cmd_timeout)
|
||||
struct local_client *thisfd;
|
||||
struct timeval tv = { cmd_timeout, 0 };
|
||||
int quorate = clops->is_quorate();
|
||||
int client_count = 0;
|
||||
int max_fd = 0;
|
||||
struct local_client *lastfd = &local_client_head;
|
||||
struct local_client *nextfd = local_client_head.next;
|
||||
|
||||
/* Wait on the cluster FD and all local sockets/pipes */
|
||||
local_client_head.fd = clops->get_main_cluster_fd();
|
||||
FD_ZERO(&in);
|
||||
|
||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||
client_count++;
|
||||
max_fd = max(max_fd, thisfd->fd);
|
||||
}
|
||||
|
||||
if (max_fd > FD_SETSIZE - 32) {
|
||||
fprintf(stderr, "WARNING: There are too many connections to clvmd. Investigate and take action now!\n");
|
||||
fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
|
||||
}
|
||||
|
||||
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
|
||||
|
||||
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
|
||||
struct local_client *free_fd = thisfd;
|
||||
lastfd->next = nextfd;
|
||||
DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
lastfd = thisfd;
|
||||
|
||||
if (thisfd->removeme)
|
||||
continue;
|
||||
|
||||
/* if the cluster is not quorate then don't listen for new requests */
|
||||
if ((thisfd->type != LOCAL_RENDEZVOUS &&
|
||||
thisfd->type != LOCAL_SOCK) || quorate)
|
||||
FD_SET(thisfd->fd, &in);
|
||||
if (thisfd->fd < FD_SETSIZE)
|
||||
FD_SET(thisfd->fd, &in);
|
||||
}
|
||||
|
||||
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
|
||||
@ -877,31 +910,20 @@ static void main_loop(int cmd_timeout)
|
||||
}
|
||||
|
||||
if (select_status > 0) {
|
||||
struct local_client *lastfd = NULL;
|
||||
char csid[MAX_CSID_LEN];
|
||||
char buf[max_cluster_message];
|
||||
|
||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
|
||||
struct local_client *free_fd = thisfd;
|
||||
lastfd->next = thisfd->next;
|
||||
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(thisfd->fd, &in)) {
|
||||
if (thisfd->fd < FD_SETSIZE && FD_ISSET(thisfd->fd, &in)) {
|
||||
struct local_client *newfd = NULL;
|
||||
int ret;
|
||||
|
||||
/* FIXME Remove from main thread in case it blocks! */
|
||||
/* Do callback */
|
||||
ret = thisfd->callback(thisfd, buf, sizeof(buf),
|
||||
csid, &newfd);
|
||||
/* Ignore EAGAIN */
|
||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
|
||||
lastfd = thisfd;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -917,17 +939,16 @@ static void main_loop(int cmd_timeout)
|
||||
DEBUGLOG("ret == %d, errno = %d. removing client\n",
|
||||
ret, errno);
|
||||
thisfd->removeme = 1;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* New client...simply add it to the list */
|
||||
if (newfd) {
|
||||
newfd->next = thisfd->next;
|
||||
thisfd->next = newfd;
|
||||
break;
|
||||
thisfd = newfd;
|
||||
}
|
||||
}
|
||||
lastfd = thisfd;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1420,7 +1441,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
thisfd->bits.localsock.in_progress = TRUE;
|
||||
thisfd->bits.localsock.state = PRE_COMMAND;
|
||||
thisfd->bits.localsock.cleanup_needed = 1;
|
||||
DEBUGLOG("Creating pre&post thread\n");
|
||||
DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
|
||||
status = pthread_create(&thisfd->bits.localsock.threadid,
|
||||
&stack_attr, pre_and_post_thread, thisfd);
|
||||
DEBUGLOG("Created pre&post thread, state = %d\n", status);
|
||||
@ -1674,7 +1695,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
sigset_t ss;
|
||||
int pipe_fd = client->bits.localsock.pipe;
|
||||
|
||||
DEBUGLOG("Pre&post thread (%p), pipe %d\n", client, pipe_fd);
|
||||
DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
|
||||
pthread_mutex_lock(&client->bits.localsock.mutex);
|
||||
|
||||
/* Ignore SIGUSR1 (handled by master process) but enable
|
||||
@ -1694,7 +1715,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
if ((status = do_pre_command(client)))
|
||||
client->bits.localsock.all_success = 0;
|
||||
|
||||
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe %d\n",
|
||||
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
|
||||
client, status, pipe_fd);
|
||||
|
||||
/* Tell the parent process we have finished this bit */
|
||||
@ -1976,7 +1997,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
{
|
||||
/* If msg is NULL then this is a cleanup request */
|
||||
if (cmd->msg == NULL) {
|
||||
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
|
||||
DEBUGLOG("process_work_item: free %p\n", cmd->client);
|
||||
cmd_client_cleanup(cmd->client);
|
||||
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
|
||||
pthread_cond_destroy(&cmd->client->bits.localsock.cond);
|
||||
|
@ -510,7 +510,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
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->config_initialized || config_files_changed(cmd)) {
|
||||
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.");
|
||||
@ -899,7 +899,7 @@ int init_clvm(struct dm_hash_table *excl_uuid)
|
||||
if (!get_initial_state(excl_uuid))
|
||||
log_error("Cannot load initial lock states.");
|
||||
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1))) {
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
1
daemons/cmirrord/.gitignore
vendored
Normal file
1
daemons/cmirrord/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
cmirrord
|
@ -15,6 +15,7 @@
|
||||
#include "link_mon.h"
|
||||
#include "local.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
@ -32,14 +33,49 @@ static void daemonize(void);
|
||||
static void init_all(void);
|
||||
static void cleanup_all(void);
|
||||
|
||||
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
|
||||
static void usage (FILE *dest)
|
||||
{
|
||||
daemonize();
|
||||
fprintf (dest, "Usage: cmirrord [options]\n"
|
||||
" -f, --foreground stay in the foreground, log to the terminal\n"
|
||||
" -h, --help print this help\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int foreground_mode = 0;
|
||||
struct option longopts[] = {
|
||||
{ "foreground", no_argument, NULL, 'f' },
|
||||
{ "help" , no_argument, NULL, 'h' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
foreground_mode = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage (stdout);
|
||||
exit (0);
|
||||
default:
|
||||
usage (stderr);
|
||||
exit (2);
|
||||
}
|
||||
}
|
||||
if (optind < argc) {
|
||||
usage (stderr);
|
||||
exit (2);
|
||||
}
|
||||
|
||||
if (!foreground_mode)
|
||||
daemonize();
|
||||
|
||||
init_all();
|
||||
|
||||
/* Parent can now exit, we're ready to handle requests */
|
||||
kill(getppid(), SIGTERM);
|
||||
if (!foreground_mode)
|
||||
kill(getppid(), SIGTERM);
|
||||
|
||||
LOG_PRINT("Starting cmirrord:");
|
||||
LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
|
||||
@ -209,6 +245,16 @@ static void daemonize(void)
|
||||
}
|
||||
|
||||
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
|
||||
}
|
||||
|
||||
/*
|
||||
* init_all
|
||||
*
|
||||
* Initialize modules. Exit on failure.
|
||||
*/
|
||||
static void init_all(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
|
||||
if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
|
||||
@ -227,16 +273,6 @@ static void daemonize(void)
|
||||
signal(SIGUSR2, &sig_handler);
|
||||
sigemptyset(&signal_mask);
|
||||
signal_received = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* init_all
|
||||
*
|
||||
* Initialize modules. Exit on failure.
|
||||
*/
|
||||
static void init_all(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = init_local()) ||
|
||||
(r = init_cluster())) {
|
||||
|
@ -104,10 +104,11 @@ static SaVersionT version = { 'B', 1, 1 };
|
||||
#endif
|
||||
|
||||
#define DEBUGGING_HISTORY 100
|
||||
#define DEBUGGING_BUFLEN 128
|
||||
#define LOG_SPRINT(cc, f, arg...) do { \
|
||||
cc->idx++; \
|
||||
cc->idx = cc->idx % DEBUGGING_HISTORY; \
|
||||
sprintf(cc->debugging[cc->idx], f, ## arg); \
|
||||
snprintf(cc->debugging[cc->idx], DEBUGGING_BUFLEN, f, ## arg); \
|
||||
} while (0)
|
||||
|
||||
static int log_resp_rec = 0;
|
||||
@ -150,7 +151,7 @@ struct clog_cpg {
|
||||
uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS];
|
||||
struct checkpoint_data *checkpoint_list;
|
||||
int idx;
|
||||
char debugging[DEBUGGING_HISTORY][128];
|
||||
char debugging[DEBUGGING_HISTORY][DEBUGGING_BUFLEN];
|
||||
};
|
||||
|
||||
static struct dm_list clog_cpg_list;
|
||||
@ -1294,7 +1295,9 @@ static void cpg_join_callback(struct clog_cpg *match,
|
||||
uint32_t my_pid = (uint32_t)getpid();
|
||||
uint32_t lowest = match->lowest_id;
|
||||
struct clog_request *rq;
|
||||
char dbuf[32] = { 0 };
|
||||
char dbuf[64] = { 0 };
|
||||
char *dbuf_p = dbuf;
|
||||
size_t dbuf_rem = sizeof dbuf;
|
||||
|
||||
/* Assign my_cluster_id */
|
||||
if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
|
||||
@ -1310,9 +1313,17 @@ static void cpg_join_callback(struct clog_cpg *match,
|
||||
if (joined->nodeid == my_cluster_id)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < member_list_entries - 1; i++)
|
||||
sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid);
|
||||
sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid);
|
||||
for (i = 0; i < member_list_entries - 1; i++) {
|
||||
int written = snprintf(dbuf_p, dbuf_rem, "%u-", member_list[i].nodeid);
|
||||
if (written < 0) continue; /* impossible */
|
||||
if ((unsigned)written >= dbuf_rem) {
|
||||
dbuf_rem = 0;
|
||||
break;
|
||||
}
|
||||
dbuf_rem -= written;
|
||||
dbuf_p += written;
|
||||
}
|
||||
snprintf(dbuf_p, dbuf_rem, "(%u)", joined->nodeid);
|
||||
LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]",
|
||||
SHORT_UUID(match->name.value), joined->nodeid, dbuf);
|
||||
|
||||
|
@ -32,12 +32,13 @@
|
||||
#define LOG_OFFSET 2
|
||||
|
||||
#define RESYNC_HISTORY 50
|
||||
#define RESYNC_BUFLEN 128
|
||||
//static char resync_history[RESYNC_HISTORY][128];
|
||||
//static int idx = 0;
|
||||
#define LOG_SPRINT(_lc, f, arg...) do { \
|
||||
lc->idx++; \
|
||||
lc->idx = lc->idx % RESYNC_HISTORY; \
|
||||
sprintf(lc->resync_history[lc->idx], f, ## arg); \
|
||||
snprintf(lc->resync_history[lc->idx], RESYNC_BUFLEN, f, ## arg); \
|
||||
} while (0)
|
||||
|
||||
struct log_header {
|
||||
@ -88,7 +89,7 @@ struct log_c {
|
||||
size_t disk_size; /* size of disk_buffer in bytes */
|
||||
void *disk_buffer; /* aligned memory for O_DIRECT */
|
||||
int idx;
|
||||
char resync_history[RESYNC_HISTORY][128];
|
||||
char resync_history[RESYNC_HISTORY][RESYNC_BUFLEN];
|
||||
};
|
||||
|
||||
struct mark_entry {
|
||||
@ -1444,7 +1445,7 @@ static int disk_status_info(struct log_c *lc, struct dm_ulog_request *rq)
|
||||
char *data = (char *)rq->data;
|
||||
struct stat statbuf;
|
||||
|
||||
if(fstat(lc->disk_fd, &statbuf)) {
|
||||
if (fstat(lc->disk_fd, &statbuf)) {
|
||||
rq->error = -errno;
|
||||
return -errno;
|
||||
}
|
||||
@ -1507,7 +1508,7 @@ static int disk_status_table(struct log_c *lc, struct dm_ulog_request *rq)
|
||||
char *data = (char *)rq->data;
|
||||
struct stat statbuf;
|
||||
|
||||
if(fstat(lc->disk_fd, &statbuf)) {
|
||||
if (fstat(lc->disk_fd, &statbuf)) {
|
||||
rq->error = -errno;
|
||||
return -errno;
|
||||
}
|
||||
|
1
daemons/dmeventd/.gitignore
vendored
Normal file
1
daemons/dmeventd/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
dmeventd
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@ -12,23 +12,22 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
#include "dmlib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
//#include "libmultilog.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
|
||||
static int _debug_level = 0;
|
||||
static int _use_syslog = 0;
|
||||
static int _sequence_nr = 0;
|
||||
|
||||
struct dm_event_handler {
|
||||
@ -199,7 +198,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg)
|
||||
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
||||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
||||
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
||||
"Expected %d:%d but received %s", getpid(),
|
||||
"Expected %d:%d but received %s.", getpid(),
|
||||
_sequence_nr, msg->data);
|
||||
return 0;
|
||||
}
|
||||
@ -234,7 +233,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
FD_SET(fifos->server, &fds);
|
||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
log_error("Unable to read from event server");
|
||||
log_error("Unable to read from event server.");
|
||||
return 0;
|
||||
}
|
||||
if ((ret == 0) && (i > 4) && !bytes) {
|
||||
@ -300,7 +299,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
@ -309,7 +308,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -321,7 +320,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
FD_SET(fifos->client, &fds);
|
||||
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
||||
if ((ret < 0) && (errno != EINTR)) {
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
} while (ret < 1);
|
||||
@ -331,7 +330,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -361,7 +360,7 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
||||
getpid(), _sequence_nr,
|
||||
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
||||
< 0) {
|
||||
log_error("_daemon_talk: message allocation failed");
|
||||
log_error("_daemon_talk: message allocation failed.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->cmd = cmd;
|
||||
@ -449,11 +448,11 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
||||
|
||||
else if (!pid) {
|
||||
execvp(args[0], args);
|
||||
log_error("Unable to exec dmeventd: %s", strerror(errno));
|
||||
log_error("Unable to exec dmeventd: %s.", strerror(errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
log_error("Unable to start dmeventd: %s",
|
||||
log_error("Unable to start dmeventd: %s.",
|
||||
strerror(errno));
|
||||
else if (WEXITSTATUS(status))
|
||||
log_error("Unable to start dmeventd.");
|
||||
@ -526,7 +525,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
struct dm_info info;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||
log_error("_get_device_info: dm_task creation for info failed");
|
||||
log_error("_get_device_info: dm_task creation for info failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -544,17 +543,17 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
|
||||
/* FIXME Add name or uuid or devno to messages */
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("_get_device_info: dm_task_run() failed");
|
||||
log_error("_get_device_info: dm_task_run() failed.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info)) {
|
||||
log_error("_get_device_info: failed to get info for device");
|
||||
log_error("_get_device_info: failed to get info for device.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!info.exists) {
|
||||
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found",
|
||||
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.",
|
||||
dmevh->uuid ? : "",
|
||||
(!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
|
||||
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
||||
@ -623,12 +622,12 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
||||
log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso);
|
||||
log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso);
|
||||
|
||||
|
||||
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||
log_error("%s: event registration failed: %s",
|
||||
log_error("%s: event registration failed: %s.",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
@ -655,7 +654,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
|
||||
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||
log_error("%s: event deregistration failed: %s",
|
||||
log_error("%s: event deregistration failed: %s.",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
@ -828,6 +827,79 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_event_log_set(int debug_level, int use_syslog)
|
||||
{
|
||||
_debug_level = debug_level;
|
||||
_use_syslog = use_syslog;
|
||||
}
|
||||
|
||||
void dm_event_log(const char *subsys, int level, const char *file,
|
||||
int line, int dm_errno_or_class,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static time_t start = 0;
|
||||
const char *indent = "";
|
||||
FILE *stream = stdout;
|
||||
int prio = -1;
|
||||
time_t now;
|
||||
|
||||
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
|
||||
case _LOG_DEBUG:
|
||||
if (_debug_level < 3)
|
||||
return;
|
||||
prio = LOG_DEBUG;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_INFO:
|
||||
if (_debug_level < 2)
|
||||
return;
|
||||
prio = LOG_INFO;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (_debug_level < 1)
|
||||
return;
|
||||
prio = LOG_NOTICE;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_WARN:
|
||||
prio = LOG_WARNING;
|
||||
break;
|
||||
case _LOG_ERR:
|
||||
prio = LOG_ERR;
|
||||
stream = stderr;
|
||||
break;
|
||||
default:
|
||||
prio = LOG_CRIT;
|
||||
}
|
||||
|
||||
/* Serialize to keep lines readable */
|
||||
pthread_mutex_lock(&_log_mutex);
|
||||
|
||||
if (_use_syslog) {
|
||||
vsyslog(prio, format, ap);
|
||||
} else {
|
||||
now = time(NULL);
|
||||
if (!start)
|
||||
start = now;
|
||||
now -= start;
|
||||
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||
(int)now / 60, (int)now % 60,
|
||||
// TODO: Maybe use shorter ID
|
||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||
(int)pthread_self(), subsys,
|
||||
(_debug_level > 3) ? "" : indent);
|
||||
if (_debug_level > 3)
|
||||
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||
vfprintf(stream, _(format), ap);
|
||||
fputc('\n', stream);
|
||||
fflush(stream);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_log_mutex);
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
static char *_skip_string(char *src, const int delimiter)
|
||||
@ -861,7 +933,7 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
0, 0))) {
|
||||
char *p = _skip_string(msg.data, ' ');
|
||||
if (!p) {
|
||||
log_error("malformed reply from dmeventd '%s'\n",
|
||||
log_error("Malformed reply from dmeventd '%s'.",
|
||||
msg.data);
|
||||
dm_free(msg.data);
|
||||
return -EIO;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@ -105,6 +105,25 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
|
||||
void dm_event_log_set(int debug_level, int use_syslog);
|
||||
|
||||
/* Log messages acroding to current debug level */
|
||||
__attribute__((format(printf, 6, 0)))
|
||||
void dm_event_log(const char *subsys, int level, const char *file,
|
||||
int line, int dm_errno_or_class,
|
||||
const char *format, va_list ap);
|
||||
/* Macro to route print_log do dm_event_log() */
|
||||
#define DM_EVENT_LOG_FN(subsys) \
|
||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,\
|
||||
const char *format, ...)\
|
||||
{\
|
||||
va_list ap;\
|
||||
va_start(ap, format);\
|
||||
dm_event_log(subsys, level, file, line, dm_errno_or_class, format, ap);\
|
||||
va_end(ap);\
|
||||
}
|
||||
|
||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||
detailed descriptions. */
|
||||
// FIXME misuse of bitmask as enum
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -13,15 +13,11 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "lvm2cmd.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
|
||||
extern int dmeventd_debug;
|
||||
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
@ -36,48 +32,19 @@ static int _register_count = 0;
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
DM_EVENT_LOG_FN("lvm")
|
||||
|
||||
static void _lvm2_print_log(int level, const char *file, int line,
|
||||
int dm_errno_or_class, const char *msg)
|
||||
{
|
||||
print_log(level, file, line, dm_errno_or_class, "%s", msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently only one event can be processed at a time.
|
||||
*/
|
||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* FIXME Do not pass things directly to syslog, rather use the existing logging
|
||||
* facilities to sort logging ... however that mechanism needs to be somehow
|
||||
* configurable and we don't have that option yet
|
||||
*/
|
||||
static void _temporary_log_fn(int level,
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)),
|
||||
int dm_errno __attribute__((unused)),
|
||||
const char *message)
|
||||
{
|
||||
level &= ~(_LOG_STDERR | _LOG_ONCE);
|
||||
|
||||
switch (level) {
|
||||
case _LOG_DEBUG:
|
||||
if (dmeventd_debug >= 3)
|
||||
syslog(LOG_DEBUG, "%s", message);
|
||||
break;
|
||||
case _LOG_INFO:
|
||||
if (dmeventd_debug >= 2)
|
||||
syslog(LOG_INFO, "%s", message);
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (dmeventd_debug >= 1)
|
||||
syslog(LOG_NOTICE, "%s", message);
|
||||
break;
|
||||
case _LOG_WARN:
|
||||
syslog(LOG_WARNING, "%s", message);
|
||||
break;
|
||||
case _LOG_ERR:
|
||||
syslog(LOG_ERR, "%s", message);
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_CRIT, "%s", message);
|
||||
}
|
||||
}
|
||||
|
||||
void dmeventd_lvm2_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
@ -94,24 +61,26 @@ int dmeventd_lvm2_init(void)
|
||||
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
/*
|
||||
* Need some space for allocations. 1024 should be more
|
||||
* than enough for what we need (device mapper name splitting)
|
||||
*/
|
||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
||||
goto out;
|
||||
|
||||
if (!_lvm_handle) {
|
||||
if (!getenv("LVM_LOG_FILE_EPOCH"))
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_log_fn(_lvm2_print_log);
|
||||
|
||||
if (!(_lvm_handle = lvm2_init()))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Need some space for allocations. 1024 should be more
|
||||
* than enough for what we need (device mapper name splitting)
|
||||
*/
|
||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024))) {
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
log_debug("lvm plugin initilized.");
|
||||
}
|
||||
|
||||
_register_count++;
|
||||
@ -127,11 +96,13 @@ void dmeventd_lvm2_exit(void)
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
if (!--_register_count) {
|
||||
log_debug("lvm plugin shuting down.");
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
log_debug("lvm plugin exited.");
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
@ -154,8 +125,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
int r;
|
||||
|
||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
|
||||
device);
|
||||
log_error("Unable to determine VG name from %s.",
|
||||
device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -169,7 +140,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
dm_pool_free(mem, vg);
|
||||
|
||||
if (r < 0) {
|
||||
syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
|
||||
log_error("Unable to form LVM command. (too long).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -39,4 +39,36 @@ struct dm_pool *dmeventd_lvm2_pool(void);
|
||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
const char *cmd, const char *device);
|
||||
|
||||
#define dmeventd_lvm2_run_with_lock(cmdline) \
|
||||
({\
|
||||
int rc;\
|
||||
dmeventd_lvm2_lock();\
|
||||
rc = dmeventd_lvm2_run(cmdline);\
|
||||
dmeventd_lvm2_unlock();\
|
||||
rc;\
|
||||
})
|
||||
|
||||
#define dmeventd_lvm2_init_with_pool(name, st) \
|
||||
({\
|
||||
struct dm_pool *mem;\
|
||||
st = NULL;\
|
||||
if (dmeventd_lvm2_init()) {\
|
||||
if ((mem = dm_pool_create(name, 2048)) &&\
|
||||
(st = dm_pool_zalloc(mem, sizeof(*st))))\
|
||||
st->mem = mem;\
|
||||
else {\
|
||||
if (mem)\
|
||||
dm_pool_destroy(mem);\
|
||||
dmeventd_lvm2_exit();\
|
||||
}\
|
||||
}\
|
||||
st;\
|
||||
})
|
||||
|
||||
#define dmeventd_lvm2_exit_with_pool(pool) \
|
||||
do {\
|
||||
dm_pool_destroy(pool->mem);\
|
||||
dmeventd_lvm2_exit();\
|
||||
} while(0)
|
||||
|
||||
#endif /* _DMEVENTD_LVMWRAP_H */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -13,20 +13,24 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
||||
/* FIXME Reformat to 80 char lines. */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
char cmd_lvscan[512];
|
||||
char cmd_lvconvert[512];
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("mirr")
|
||||
|
||||
static int _process_status_code(const char status_code, const char *dev_name,
|
||||
const char *dev_type, int r)
|
||||
{
|
||||
@ -39,18 +43,15 @@ static int _process_status_code(const char status_code, const char *dev_name,
|
||||
* U => Unclassified failure (bug)
|
||||
*/
|
||||
if (status_code == 'F') {
|
||||
syslog(LOG_ERR, "%s device %s flush failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s flush failed.", dev_type, dev_name);
|
||||
r = ME_FAILURE;
|
||||
} else if (status_code == 'S')
|
||||
syslog(LOG_ERR, "%s device %s sync failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s sync failed.", dev_type, dev_name);
|
||||
else if (status_code == 'R')
|
||||
syslog(LOG_ERR, "%s device %s read failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s read failed.", dev_type, dev_name);
|
||||
else if (status_code != 'A') {
|
||||
syslog(LOG_ERR, "%s device %s has failed (%c).",
|
||||
dev_type, dev_name, status_code);
|
||||
log_error("%s device %s has failed (%c).",
|
||||
dev_type, dev_name, status_code);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
@ -125,62 +126,49 @@ out:
|
||||
|
||||
out_parse:
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
log_error("Unable to parse mirror status string.");
|
||||
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
|
||||
{
|
||||
int r;
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvscan --cache", device))
|
||||
return -1;
|
||||
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Re-scan of mirror device %s failed.", device);
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device))
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
||||
log_info("Re-scan of mirrored device failed.");
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
||||
|
||||
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
||||
(r) ? "finished successfully" : "failed");
|
||||
log_info("Repair of mirrored device %s.",
|
||||
(r) ? "finished successfully" : "failed");
|
||||
|
||||
return (r) ? 0 : -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||
log_info("%s mapping lost.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.", device);
|
||||
log_info("%s has unmirrored portion.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -190,54 +178,75 @@ void process_event(struct dm_task *dmt,
|
||||
_part_ of the device is in sync
|
||||
Also, this is not an error
|
||||
*/
|
||||
syslog(LOG_NOTICE, "%s is now in-sync.", device);
|
||||
log_notice("%s is now in-sync.", device);
|
||||
break;
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s.", device);
|
||||
if (_remove_failed_devices(device))
|
||||
log_error("Device failure in %s.", device);
|
||||
if (!_remove_failed_devices(state->cmd_lvscan,
|
||||
state->cmd_lvconvert))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
log_error("Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
else
|
||||
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
||||
device);
|
||||
log_notice("%s is now a linear device.",
|
||||
device);
|
||||
*/
|
||||
break;
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.");
|
||||
log_info("Unknown event received.");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
if (!dmeventd_lvm2_init())
|
||||
return 0;
|
||||
struct dso_state *state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
|
||||
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
||||
"lvscan --cache", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
||||
"lvconvert --repair --use-policies", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
*user = state;
|
||||
|
||||
log_info("Monitoring mirror device %s for events.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
log_error("Failed to monitor mirror %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
|
||||
device);
|
||||
dmeventd_lvm2_exit();
|
||||
struct dso_state *state = *user;
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring mirror device %s for events.",
|
||||
device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -13,168 +13,133 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
char cmd_lvscan[512];
|
||||
char cmd_lvconvert[512];
|
||||
int failed;
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("raid")
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
||||
/* FIXME Reformat to 80 char lines. */
|
||||
|
||||
/*
|
||||
* run_repair is a close copy to
|
||||
* plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
|
||||
*/
|
||||
static int run_repair(const char *device)
|
||||
static int _process_raid_event(struct dso_state *state, char *params, const char *device)
|
||||
{
|
||||
int r;
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
struct dm_status_raid *status;
|
||||
const char *d;
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvscan --cache", device))
|
||||
return -1;
|
||||
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Re-scan of RAID device %s failed.", device);
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device))
|
||||
return -1;
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Repair of RAID device %s failed.", device);
|
||||
|
||||
return (r) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int _process_raid_event(char *params, const char *device)
|
||||
{
|
||||
int i, n, failure = 0;
|
||||
char *p, *a[4];
|
||||
char *raid_type;
|
||||
char *num_devices;
|
||||
char *health_chars;
|
||||
char *resync_ratio;
|
||||
|
||||
/*
|
||||
* RAID parms: <raid_type> <#raid_disks> \
|
||||
* <health chars> <resync ratio>
|
||||
*/
|
||||
if (!dm_split_words(params, 4, 0, a)) {
|
||||
syslog(LOG_ERR, "Failed to process status line for %s\n",
|
||||
device);
|
||||
return -EINVAL;
|
||||
}
|
||||
raid_type = a[0];
|
||||
num_devices = a[1];
|
||||
health_chars = a[2];
|
||||
resync_ratio = a[3];
|
||||
|
||||
if (!(n = atoi(num_devices))) {
|
||||
syslog(LOG_ERR, "Failed to parse number of devices for %s: %s",
|
||||
device, num_devices);
|
||||
return -EINVAL;
|
||||
if (!dm_get_status_raid(state->mem, params, &status)) {
|
||||
log_error("Failed to process status line for %s.", device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (health_chars[i]) {
|
||||
case 'A':
|
||||
/* Device is 'A'live and well */
|
||||
case 'a':
|
||||
/* Device is 'a'live, but not yet in-sync */
|
||||
break;
|
||||
case 'D':
|
||||
syslog(LOG_ERR,
|
||||
"Device #%d of %s array, %s, has failed.",
|
||||
i, raid_type, device);
|
||||
failure++;
|
||||
break;
|
||||
default:
|
||||
/* Unhandled character returned from kernel */
|
||||
break;
|
||||
if ((d = strchr(status->dev_health, 'D'))) {
|
||||
if (state->failed)
|
||||
goto out; /* already reported */
|
||||
|
||||
log_error("Device #%d of %s array, %s, has failed.",
|
||||
(int)(d - status->dev_health),
|
||||
status->raid_type, device);
|
||||
|
||||
state->failed = 1;
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
|
||||
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
||||
log_info("Repair of RAID device %s failed.", device);
|
||||
dm_pool_free(state->mem, status);
|
||||
return 0;
|
||||
}
|
||||
if (failure)
|
||||
return run_repair(device);
|
||||
} else {
|
||||
state->failed = 0;
|
||||
log_info("%s array, %s, is %s in-sync.",
|
||||
status->raid_type, device,
|
||||
(status->insync_regions == status->total_regions) ? "now" : "not");
|
||||
}
|
||||
out:
|
||||
dm_pool_free(state->mem, status);
|
||||
|
||||
p = strstr(resync_ratio, "/");
|
||||
if (!p) {
|
||||
syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s",
|
||||
device, resync_ratio);
|
||||
return -EINVAL;
|
||||
}
|
||||
p[0] = '\0';
|
||||
syslog(LOG_INFO, "%s array, %s, is %s in-sync.",
|
||||
raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now");
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||
log_info("%s mapping lost.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "raid")) {
|
||||
syslog(LOG_INFO, "%s has non-raid portion.", device);
|
||||
log_info("%s has non-raid portion.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_process_raid_event(params, device))
|
||||
syslog(LOG_ERR, "Failed to process event for %s",
|
||||
device);
|
||||
if (!_process_raid_event(state, params, device))
|
||||
log_error("Failed to process event for %s.",
|
||||
device);
|
||||
} while (next);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
if (!dmeventd_lvm2_init())
|
||||
return 0;
|
||||
struct dso_state *state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
|
||||
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
||||
"lvscan --cache", device) ||
|
||||
!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
*user = state;
|
||||
|
||||
log_info("Monitoring RAID device %s for events.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
log_error("Failed to monitor RAID %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
|
||||
device);
|
||||
dmeventd_lvm2_exit();
|
||||
struct dso_state *state = *user;
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring RAID device %s for events.",
|
||||
device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -13,31 +13,31 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
#include <stdarg.h>
|
||||
/* FIXME Missing openlog? */
|
||||
#include <pthread.h>
|
||||
|
||||
/* First warning when snapshot is 80% full. */
|
||||
#define WARNING_THRESH 80
|
||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP 5
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking snapshots less than 50% full. */
|
||||
#define CHECK_MINIMUM 50
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define UMOUNT_COMMAND "/bin/umount"
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
int percent_check;
|
||||
dm_percent_t percent_check;
|
||||
uint64_t known_size;
|
||||
char cmd_str[1024];
|
||||
char cmd_lvextend[512];
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("snap")
|
||||
|
||||
static int _run(const char *cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@ -62,7 +62,7 @@ static int _run(const char *cmd, ...)
|
||||
va_end(ap);
|
||||
|
||||
execvp(cmd, (char **)argv);
|
||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||
log_sys_error("exec", cmd);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
@ -81,18 +81,56 @@ static int _run(const char *cmd, ...)
|
||||
|
||||
static int _extend(const char *cmd)
|
||||
{
|
||||
return dmeventd_lvm2_run(cmd);
|
||||
log_debug("Extending snapshot via %s.", cmd);
|
||||
return dmeventd_lvm2_run_with_lock(cmd);
|
||||
}
|
||||
|
||||
#ifdef SNAPSHOT_REMOVE
|
||||
/* Remove invalid snapshot from dm-table */
|
||||
/* Experimental for now and not used by default */
|
||||
static int _remove(const char *uuid)
|
||||
{
|
||||
int r = 1;
|
||||
uint32_t cookie = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_uuid(dmt, uuid)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
dm_task_retry_remove(dmt);
|
||||
|
||||
if (!dm_task_set_cookie(dmt, &cookie, 0)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* SNAPSHOT_REMOVE */
|
||||
|
||||
static void _umount(const char *device, int major, int minor)
|
||||
{
|
||||
FILE *mounts;
|
||||
char buffer[4096];
|
||||
char *words[3];
|
||||
struct stat st;
|
||||
const char procmounts[] = "/proc/mounts";
|
||||
|
||||
if (!(mounts = fopen("/proc/mounts", "r"))) {
|
||||
syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device);
|
||||
if (!(mounts = fopen(procmounts, "r"))) {
|
||||
log_sys_error("fopen", procmounts);
|
||||
log_error("Not umounting %s.", device);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -112,21 +150,22 @@ static void _umount(const char *device, int major, int minor)
|
||||
if (S_ISBLK(st.st_mode) &&
|
||||
major(st.st_rdev) == major &&
|
||||
minor(st.st_rdev) == minor) {
|
||||
syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||
syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
|
||||
device, words[1], strerror(errno));
|
||||
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||
log_error("Failed to umount snapshot %s from %s: %s.",
|
||||
device, words[1], strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(mounts))
|
||||
syslog(LOG_ERR, "Failed to close /proc/mounts.\n");
|
||||
log_sys_error("close", procmounts);
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
@ -134,28 +173,47 @@ void process_event(struct dm_task *dmt,
|
||||
struct dm_status_snapshot *status = NULL;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dso_state *state = *private;
|
||||
struct dm_info info;
|
||||
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->percent_check)
|
||||
return;
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!target_type)
|
||||
goto out;
|
||||
if (!target_type || strcmp(target_type, "snapshot")) {
|
||||
log_error("Target %s is not snapshot.", target_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dm_get_status_snapshot(state->mem, params, &status))
|
||||
goto out;
|
||||
if (!dm_get_status_snapshot(state->mem, params, &status)) {
|
||||
log_error("Cannot parse snapshot %s state: %s.", device, params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status->invalid) {
|
||||
struct dm_info info;
|
||||
if (dm_task_get_info(dmt, &info)) {
|
||||
dmeventd_lvm2_unlock();
|
||||
/*
|
||||
* If the snapshot has been invalidated or we failed to parse
|
||||
* the status string. Report the full status string to syslog.
|
||||
*/
|
||||
if (status->invalid || status->overflow || !status->total_sectors) {
|
||||
log_warn("WARNING: Snapshot %s changed state to: %s and should be removed.",
|
||||
device, params);
|
||||
state->percent_check = 0;
|
||||
if (dm_task_get_info(dmt, &info))
|
||||
_umount(device, info.major, info.minor);
|
||||
return;
|
||||
} /* else; too bad, but this is best-effort thing... */
|
||||
#ifdef SNAPSHOT_REMOVE
|
||||
/* Maybe configurable ? */
|
||||
_remove(dm_task_get_uuid(dmt));
|
||||
#endif
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (length <= (status->used_sectors - status->metadata_sectors)) {
|
||||
/* TODO eventually recognize earlier when room is enough */
|
||||
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
||||
device);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Snapshot size had changed. Clear the threshold. */
|
||||
@ -164,69 +222,50 @@ void process_event(struct dm_task *dmt,
|
||||
state->known_size = status->total_sectors;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the snapshot has been invalidated or we failed to parse
|
||||
* the status string. Report the full status string to syslog.
|
||||
*/
|
||||
if (status->invalid || !status->total_sectors) {
|
||||
syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
|
||||
state->percent_check = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
percent = (int) (100 * status->used_sectors / status->total_sectors);
|
||||
percent = dm_make_percent(status->used_sectors, status->total_sectors);
|
||||
if (percent >= state->percent_check) {
|
||||
/* Usage has raised more than CHECK_STEP since the last
|
||||
time. Run actions. */
|
||||
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
|
||||
/* Try to extend the snapshot, in accord with user-set policies */
|
||||
if (!_extend(state->cmd_str))
|
||||
syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
|
||||
}
|
||||
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
|
||||
/* Try to extend the snapshot, in accord with user-set policies */
|
||||
if (!_extend(state->cmd_lvextend))
|
||||
log_error("Failed to extend snapshot %s.", device);
|
||||
}
|
||||
out:
|
||||
if (status)
|
||||
dm_pool_free(state->mem, status);
|
||||
dmeventd_lvm2_unlock();
|
||||
dm_pool_free(state->mem, status);
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dm_pool *statemem = NULL;
|
||||
struct dso_state *state;
|
||||
|
||||
if (!dmeventd_lvm2_init())
|
||||
goto out;
|
||||
if (!dmeventd_lvm2_init_with_pool("snapshot_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!(statemem = dm_pool_create("snapshot_state", 512)) ||
|
||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))))
|
||||
goto bad;
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
|
||||
sizeof(state->cmd_lvextend),
|
||||
"lvextend --use-policies", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||
sizeof(state->cmd_str),
|
||||
"lvextend --use-policies", device))
|
||||
goto bad;
|
||||
|
||||
state->mem = statemem;
|
||||
state->percent_check = CHECK_MINIMUM;
|
||||
*private = state;
|
||||
*user = state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
|
||||
log_info("Monitoring snapshot %s.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
if (statemem)
|
||||
dm_pool_destroy(statemem);
|
||||
dmeventd_lvm2_exit();
|
||||
out:
|
||||
syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
|
||||
log_error("Failed to monitor snapshot %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -235,13 +274,12 @@ int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
|
||||
dm_pool_destroy(state->mem);
|
||||
dmeventd_lvm2_exit();
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring snapshot %s.", device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -12,25 +12,33 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib.h" /* using here lvm log */
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
#include <stdarg.h>
|
||||
/* FIXME Missing openlog? */
|
||||
#include <pthread.h>
|
||||
|
||||
/* First warning when thin is 80% full. */
|
||||
#define WARNING_THRESH 80
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
#endif
|
||||
|
||||
/* First warning when thin data or metadata is 80% full. */
|
||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP 5
|
||||
/* Do not bother checking thins less than 50% full. */
|
||||
#define CHECK_MINIMUM 50
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking thin data or metadata is less than 50% full. */
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define UMOUNT_COMMAND "/bin/umount"
|
||||
|
||||
#define MAX_FAILS (10)
|
||||
|
||||
#define THIN_DEBUG 0
|
||||
|
||||
struct dso_state {
|
||||
@ -39,18 +47,11 @@ struct dso_state {
|
||||
int data_percent_check;
|
||||
uint64_t known_metadata_size;
|
||||
uint64_t known_data_size;
|
||||
unsigned fails;
|
||||
char cmd_str[1024];
|
||||
};
|
||||
|
||||
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
# define MKDEV(x,y) makedev((x),(y))
|
||||
#endif
|
||||
DM_EVENT_LOG_FN("thin")
|
||||
|
||||
/* Get dependencies for device, and try to find matching device */
|
||||
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
|
||||
@ -93,8 +94,8 @@ static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_mino
|
||||
{
|
||||
char dev_name[PATH_MAX];
|
||||
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
||||
syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
|
||||
name, major, *dev_minor, dev_name);
|
||||
log_debug("Found %s (%u:%u) depends on %s.",
|
||||
name, major, *dev_minor, dev_name);
|
||||
}
|
||||
#endif
|
||||
r = 1;
|
||||
@ -141,14 +142,6 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _extend(struct dso_state *state)
|
||||
{
|
||||
#if THIN_DEBUG
|
||||
syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str);
|
||||
#endif
|
||||
return dmeventd_lvm2_run(state->cmd_str);
|
||||
}
|
||||
|
||||
static int _run(const char *cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@ -168,12 +161,12 @@ static int _run(const char *cmd, ...)
|
||||
argv = alloca(sizeof(const char *) * (argc + 1));
|
||||
|
||||
argv[0] = cmd;
|
||||
va_start(ap, cmd);
|
||||
va_start(ap, cmd);
|
||||
while ((argv[++i] = va_arg(ap, const char *)));
|
||||
va_end(ap);
|
||||
|
||||
execvp(cmd, (char **)argv);
|
||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||
log_sys_error("exec", cmd);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
@ -191,9 +184,9 @@ static int _run(const char *cmd, ...)
|
||||
}
|
||||
|
||||
struct mountinfo_s {
|
||||
const char *device;
|
||||
struct dm_info info;
|
||||
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
||||
const char *device;
|
||||
};
|
||||
|
||||
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
@ -202,11 +195,11 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
struct mountinfo_s *data = cb_data;
|
||||
|
||||
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
||||
syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
|
||||
data->device, target);
|
||||
log_info("Unmounting thin volume %s from %s.",
|
||||
data->device, target);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
||||
syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
|
||||
data->device, target, strerror(errno));
|
||||
log_error("Failed to umount thin %s from %s: %s.",
|
||||
data->device, target, strerror(errno));
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -216,78 +209,94 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
* Find all thin pool users and try to umount them.
|
||||
* TODO: work with read-only thin pool support
|
||||
*/
|
||||
static void _umount(struct dm_task *dmt, const char *device)
|
||||
static void _umount(struct dm_task *dmt)
|
||||
{
|
||||
/* TODO: Convert to use hash to reduce memory usage */
|
||||
static const size_t MINORS = (1U << 20); /* 20 bit */
|
||||
struct mountinfo_s data = {
|
||||
.device = device,
|
||||
};
|
||||
struct mountinfo_s data = { NULL };
|
||||
|
||||
if (!dm_task_get_info(dmt, &data.info))
|
||||
return;
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
data.device = dm_task_get_name(dmt);
|
||||
|
||||
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
||||
syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
|
||||
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
||||
syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
|
||||
log_error("Failed to detect mounted volumes for %s.", data.device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_mountinfo_read(_umount_device, &data)) {
|
||||
syslog(LOG_ERR, "Could not parse mountinfo file.\n");
|
||||
log_error("Could not parse mountinfo file.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (data.minors)
|
||||
dm_bitset_destroy(data.minors);
|
||||
dmeventd_lvm2_lock();
|
||||
}
|
||||
|
||||
static void _use_policy(struct dm_task *dmt, struct dso_state *state)
|
||||
{
|
||||
#if THIN_DEBUG
|
||||
log_info("dmeventd executes: %s.", state->cmd_str);
|
||||
#endif
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
||||
log_error("Failed to extend thin pool %s.",
|
||||
dm_task_get_name(dmt));
|
||||
_umount(dmt);
|
||||
state->fails++;
|
||||
} else
|
||||
state->fails = 0;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
struct dm_status_thin_pool *tps = NULL;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
int needs_policy = 0;
|
||||
|
||||
#if 0
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->meta_percent_check && !state->data_percent_check)
|
||||
return;
|
||||
#endif
|
||||
dmeventd_lvm2_lock();
|
||||
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||
/* Error -> no need to check and do instant resize */
|
||||
_use_policy(dmt, state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
|
||||
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
||||
syslog(LOG_ERR, "Invalid target type.\n");
|
||||
log_error("Invalid target type.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
||||
syslog(LOG_ERR, "Failed to parse status.\n");
|
||||
_umount(dmt, device);
|
||||
log_error("Failed to parse status.");
|
||||
_umount(dmt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if THIN_DEBUG
|
||||
syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
|
||||
" %" PRIu64 " / %" PRIu64 ".\n", state,
|
||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||
tps->used_data_blocks, tps->total_data_blocks);
|
||||
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
|
||||
FMTu64 "/" FMTu64 ".",
|
||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||
tps->used_data_blocks, tps->total_data_blocks);
|
||||
#endif
|
||||
|
||||
/* Thin pool size had changed. Clear the threshold. */
|
||||
@ -301,7 +310,7 @@ void process_event(struct dm_task *dmt,
|
||||
state->known_data_size = tps->total_data_blocks;
|
||||
}
|
||||
|
||||
percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
|
||||
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
||||
if (percent >= state->metadata_percent_check) {
|
||||
/*
|
||||
* Usage has raised more than CHECK_STEP since the last
|
||||
@ -311,18 +320,12 @@ void process_event(struct dm_task *dmt,
|
||||
|
||||
/* FIXME: extension of metadata needs to be written! */
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
|
||||
device, percent);
|
||||
/* Try to extend the metadata, in accord with user-set policies */
|
||||
if (!_extend(state)) {
|
||||
syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
|
||||
device);
|
||||
_umount(dmt, device);
|
||||
}
|
||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
needs_policy = 1;
|
||||
}
|
||||
|
||||
percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
|
||||
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
|
||||
if (percent >= state->data_percent_check) {
|
||||
/*
|
||||
* Usage has raised more than CHECK_STEP since
|
||||
@ -331,56 +334,53 @@ void process_event(struct dm_task *dmt,
|
||||
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
|
||||
/* Try to extend the thin data, in accord with user-set policies */
|
||||
if (!_extend(state)) {
|
||||
syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
|
||||
state->data_percent_check = 0;
|
||||
_umount(dmt, device);
|
||||
}
|
||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
needs_policy = 1;
|
||||
}
|
||||
|
||||
if (needs_policy)
|
||||
_use_policy(dmt, state);
|
||||
out:
|
||||
if (tps)
|
||||
dm_pool_free(state->mem, tps);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
if (state->fails >= MAX_FAILS) {
|
||||
log_warn("WARNING: Dropping monitoring of %s. "
|
||||
"lvm2 command fails too often (%u times in raw).",
|
||||
device, state->fails);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
}
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dm_pool *statemem = NULL;
|
||||
struct dso_state *state;
|
||||
|
||||
if (!dmeventd_lvm2_init())
|
||||
goto bad;
|
||||
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
|
||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
|
||||
!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
|
||||
sizeof(state->cmd_str),
|
||||
"lvextend --use-policies",
|
||||
device)) {
|
||||
if (statemem)
|
||||
dm_pool_destroy(statemem);
|
||||
dmeventd_lvm2_exit();
|
||||
goto bad;
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
state->mem = statemem;
|
||||
state->metadata_percent_check = CHECK_MINIMUM;
|
||||
state->data_percent_check = CHECK_MINIMUM;
|
||||
*private = state;
|
||||
*user = state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring thin %s.\n", device);
|
||||
log_info("Monitoring thin %s.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
|
||||
log_error("Failed to monitor thin %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -389,13 +389,12 @@ int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
|
||||
dm_pool_destroy(state->mem);
|
||||
dmeventd_lvm2_exit();
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring thin %s.", device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
2
daemons/lvmetad/.gitignore
vendored
Normal file
2
daemons/lvmetad/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
lvmetad
|
||||
lvmetactl
|
@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
SOURCES = lvmetad-core.c
|
||||
SOURCES2 = testclient.c
|
||||
|
||||
TARGETS = lvmetad
|
||||
TARGETS = lvmetad lvmetactl
|
||||
|
||||
.PHONY: install_lvmetad
|
||||
|
||||
@ -41,6 +41,12 @@ lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||
|
||||
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
|
||||
|
||||
CLEAN_TARGETS += lvmetactl.o
|
||||
|
||||
# TODO: No idea. No idea how to test either.
|
||||
#ifneq ("$(CFLOW_CMD)", "")
|
||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
|
208
daemons/lvmetad/lvmetactl.c
Normal file
208
daemons/lvmetad/lvmetactl.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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 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 get_global_invalid\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",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_list")) {
|
||||
reply = daemon_send_simple(h, "pv_list",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_list")) {
|
||||
reply = daemon_send_simple(h, "vg_list",
|
||||
"token = %s", "skip",
|
||||
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 = %d", val,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "get_global_invalid")) {
|
||||
reply = daemon_send_simple(h, "get_global_info",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} 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 = %d", ver,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
} else if (uuid) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"uuid = %s", uuid,
|
||||
"version = %d", ver,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
} else if (name) {
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"name = %s", name,
|
||||
"version = %d", ver,
|
||||
"token = %s", "skip",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else {
|
||||
printf("unknown command\n");
|
||||
goto out_close;
|
||||
}
|
||||
out:
|
||||
daemon_reply_destroy(reply);
|
||||
out_close:
|
||||
daemon_close(h);
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -14,17 +14,18 @@
|
||||
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
|
||||
#include "configure.h"
|
||||
#define _REENTRANT
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include "daemon-io.h"
|
||||
#include "config-util.h"
|
||||
#include "daemon-server.h"
|
||||
#include "daemon-log.h"
|
||||
#include "lvm-version.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||
|
||||
@ -123,6 +124,7 @@ struct vg_info {
|
||||
#define VGFL_INVALID 0x00000001
|
||||
|
||||
typedef struct {
|
||||
daemon_idle *idle;
|
||||
log_state *log; /* convenience */
|
||||
const char *log_config;
|
||||
|
||||
@ -578,7 +580,7 @@ static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvi
|
||||
!(cft_vgid = make_text_node(outdated_pvs, "vgid", dm_pool_strdup(outdated_pvs->mem, vgid),
|
||||
outdated_pvs->root, NULL)))
|
||||
abort();
|
||||
if(!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
|
||||
if (!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
|
||||
abort();
|
||||
DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
|
||||
}
|
||||
@ -999,7 +1001,8 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
|
||||
DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
|
||||
|
||||
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
|
||||
if (!(pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid)))
|
||||
return reply_unknown("PVID does not exist");
|
||||
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
|
||||
|
||||
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
|
||||
@ -1021,9 +1024,6 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
dm_free(vgid);
|
||||
}
|
||||
|
||||
if (!pvmeta)
|
||||
return reply_unknown("PVID does not exist");
|
||||
|
||||
if (!alt_device)
|
||||
dm_config_destroy(pvmeta);
|
||||
|
||||
@ -1312,20 +1312,29 @@ static response set_vg_info(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_tree *vg;
|
||||
struct vg_info *info;
|
||||
const char *uuid = daemon_request_str(r, "uuid", NULL);
|
||||
const char *name;
|
||||
const char *uuid;
|
||||
const int64_t new_version = daemon_request_int(r, "version", -1);
|
||||
int64_t cache_version;
|
||||
|
||||
if (!uuid)
|
||||
goto out;
|
||||
|
||||
if (new_version == -1)
|
||||
goto out;
|
||||
|
||||
vg = dm_hash_lookup(s->vgid_to_metadata, uuid);
|
||||
if (!vg)
|
||||
if (!(uuid = daemon_request_str(r, "uuid", NULL)))
|
||||
goto use_name;
|
||||
|
||||
if ((vg = dm_hash_lookup(s->vgid_to_metadata, uuid)))
|
||||
goto vers;
|
||||
use_name:
|
||||
if (!(name = daemon_request_str(r, "name", NULL)))
|
||||
goto out;
|
||||
|
||||
if (!(uuid = dm_hash_lookup(s->vgname_to_vgid, name)))
|
||||
goto out;
|
||||
|
||||
if (!(vg = dm_hash_lookup(s->vgid_to_metadata, uuid)))
|
||||
goto out;
|
||||
vers:
|
||||
if (!new_version)
|
||||
goto inval;
|
||||
|
||||
@ -1340,7 +1349,8 @@ inval:
|
||||
if (!info)
|
||||
goto bad;
|
||||
memset(info, 0, sizeof(struct vg_info));
|
||||
dm_hash_insert(s->vgid_to_info, uuid, (void*)info);
|
||||
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
info->external_version = new_version;
|
||||
@ -1584,6 +1594,9 @@ static int init(daemon_state *s)
|
||||
/* if (ls->initial_registrations)
|
||||
_process_initial_registrations(ds->initial_registrations); */
|
||||
|
||||
if (ls->idle)
|
||||
ls->idle->is_idle = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1606,21 +1619,39 @@ static int fini(daemon_state *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(str, &endptr, 10);
|
||||
if (errno || *endptr || l >= UINT_MAX)
|
||||
return 0;
|
||||
|
||||
*max_timeouts = (unsigned) l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage:\n"
|
||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
|
||||
"%s [-V] [-h] [-f] [-l level[,level ...]] [-s path] [-t secs]\n\n"
|
||||
" -V Show version of lvmetad\n"
|
||||
" -h Show this help information\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -l Logging message level (-l {all|wire|debug})\n"
|
||||
" -l Logging message levels (all,fatal,error,warn,info,wire,debug)\n"
|
||||
" -p Set path to the pidfile\n"
|
||||
" -s Set path to the socket to listen on\n\n", prog);
|
||||
" -s Set path to the socket to listen on\n"
|
||||
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
signed char opt;
|
||||
struct timeval timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
lvmetad_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
.daemon_fini = fini,
|
||||
@ -1635,7 +1666,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
|
||||
// use getopt_long
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:t:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@ -1655,6 +1686,15 @@ int main(int argc, char *argv[])
|
||||
case 's': // --socket
|
||||
s.socket_path = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||
fprintf(stderr, "Invalid value of timeout parameter.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* 0 equals to wait indefinitely */
|
||||
if (di.max_timeouts)
|
||||
s.idle = ls.idle = &di;
|
||||
break;
|
||||
case 'V':
|
||||
printf("lvmetad version: " LVM_VERSION "\n");
|
||||
exit(1);
|
||||
|
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
#include "label.h"
|
||||
#include "lvmcache.h"
|
||||
@ -109,7 +124,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (argc > 1) {
|
||||
int i;
|
||||
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0);
|
||||
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]);
|
||||
|
2
daemons/lvmlockd/.gitignore
vendored
Normal file
2
daemons/lvmlockd/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
lvmlockctl
|
||||
lvmlockd
|
@ -15,10 +15,15 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = \
|
||||
lvmlockd-core.c \
|
||||
lvmlockd-sanlock.c \
|
||||
lvmlockd-dlm.c
|
||||
SOURCES = lvmlockd-core.c
|
||||
|
||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||
SOURCES += lvmlockd-sanlock.c
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||
SOURCES += lvmlockd-dlm.c
|
||||
endif
|
||||
|
||||
TARGETS = lvmlockd lvmlockctl
|
||||
|
||||
@ -29,7 +34,15 @@ include $(top_builddir)/make.tmpl
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
|
||||
|
||||
LIBS += $(PTHREAD_LIBS) -ldlm_lt -lsanlock_client -lrt
|
||||
LIBS += $(PTHREAD_LIBS)
|
||||
|
||||
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
|
||||
LIBS += -lsanlock_client
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LOCKDDLM@", "yes")
|
||||
LIBS += -ldlm_lt
|
||||
endif
|
||||
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server
|
||||
CLDFLAGS += -L$(top_builddir)/libdaemon/server
|
||||
|
@ -8,49 +8,41 @@
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "configure.h"
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmlockd-client.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
static int quit;
|
||||
static int info;
|
||||
static int dump;
|
||||
static int wait_opt;
|
||||
static int force_opt;
|
||||
static int gl_enable;
|
||||
static int gl_disable;
|
||||
static int stop_lockspaces;
|
||||
static char *able_vg_name;
|
||||
static int quit = 0;
|
||||
static int info = 0;
|
||||
static int dump = 0;
|
||||
static int wait_opt = 0;
|
||||
static int force_opt = 0;
|
||||
static int kill_vg = 0;
|
||||
static int drop_vg = 0;
|
||||
static int gl_enable = 0;
|
||||
static int gl_disable = 0;
|
||||
static int stop_lockspaces = 0;
|
||||
static char *arg_vg_name = NULL;
|
||||
|
||||
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
|
||||
#define DUMP_BUF_SIZE (1024 * 1024)
|
||||
static char dump_buf[DUMP_BUF_SIZE];
|
||||
static char dump_buf[DUMP_BUF_SIZE+1];
|
||||
static int dump_len;
|
||||
static struct sockaddr_un dump_addr;
|
||||
static socklen_t dump_addrlen;
|
||||
|
||||
daemon_handle _lvmlockd;
|
||||
|
||||
#define log_debug(fmt, args...) \
|
||||
do { \
|
||||
printf(fmt "\n", ##args); \
|
||||
} while (0)
|
||||
|
||||
#define log_error(fmt, args...) \
|
||||
do { \
|
||||
printf(fmt "\n", ##args); \
|
||||
@ -108,6 +100,8 @@ static void find_client_info(uint32_t client_id, uint32_t *pid, char *cl_name)
|
||||
}
|
||||
}
|
||||
|
||||
static int first_ls = 1;
|
||||
|
||||
static void format_info_ls(char *line)
|
||||
{
|
||||
char ls_name[MAX_NAME+1] = { 0 };
|
||||
@ -120,7 +114,9 @@ static void format_info_ls(char *line)
|
||||
sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
|
||||
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
|
||||
|
||||
printf("\n");
|
||||
if (!first_ls)
|
||||
printf("\n");
|
||||
first_ls = 0;
|
||||
|
||||
printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
|
||||
|
||||
@ -141,7 +137,7 @@ static void format_info_ls_action(char *line)
|
||||
|
||||
find_client_info(client_id, &pid, cl_name);
|
||||
|
||||
printf("OP %s pid %u (%s)", op, pid, cl_name);
|
||||
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
|
||||
}
|
||||
|
||||
static void format_info_r(char *line, char *r_name_out, char *r_type_out)
|
||||
@ -155,21 +151,20 @@ static void format_info_r(char *line, char *r_name_out, char *r_type_out)
|
||||
sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
|
||||
r_name, r_type, mode, sh_count, &ver);
|
||||
|
||||
/* when mode is not un, wait and print each lk line */
|
||||
strcpy(r_name_out, r_name);
|
||||
strcpy(r_type_out, r_type);
|
||||
|
||||
if (strcmp(mode, "un")) {
|
||||
strcpy(r_name_out, r_name);
|
||||
strcpy(r_type_out, r_type);
|
||||
/* when mode is not un, wait and print each lk line */
|
||||
if (strcmp(mode, "un"))
|
||||
return;
|
||||
}
|
||||
|
||||
/* when mode is un, there will be no lk lines, so print now */
|
||||
|
||||
if (!strcmp(r_type, "gl")) {
|
||||
printf("LK GL un ver %4u\n", ver);
|
||||
printf("LK GL un ver %u\n", ver);
|
||||
|
||||
} else if (!strcmp(r_type, "vg")) {
|
||||
printf("LK VG un ver %4u\n", ver);
|
||||
printf("LK VG un ver %u\n", ver);
|
||||
|
||||
} else if (!strcmp(r_type, "lv")) {
|
||||
printf("LK LV un %s\n", r_name);
|
||||
@ -197,10 +192,10 @@ static void format_info_lk(char *line, char *r_name, char *r_type)
|
||||
find_client_info(client_id, &pid, cl_name);
|
||||
|
||||
if (!strcmp(r_type, "gl")) {
|
||||
printf("LK GL %s ver %4u pid %u (%s)\n", mode, ver, pid, cl_name);
|
||||
printf("LK GL %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
|
||||
|
||||
} else if (!strcmp(r_type, "vg")) {
|
||||
printf("LK VG %s ver %4u pid %u (%s)\n", mode, ver, pid, cl_name);
|
||||
printf("LK VG %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
|
||||
|
||||
} else if (!strcmp(r_type, "lv")) {
|
||||
printf("LK LV %s %s\n", mode, r_name);
|
||||
@ -233,28 +228,25 @@ static void format_info_r_action(char *line, char *r_name, char *r_type)
|
||||
find_client_info(client_id, &pid, cl_name);
|
||||
|
||||
if (strcmp(op, "lock")) {
|
||||
printf("OP %s pid %u (%s)", op, pid, cl_name);
|
||||
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(r_type, "gl")) {
|
||||
printf("LW GL %s ver %4u pid %u (%s)\n", mode, 0, pid, cl_name);
|
||||
printf("LW GL %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
|
||||
|
||||
} else if (!strcmp(r_type, "vg")) {
|
||||
printf("LW VG %s ver %4u pid %u (%s)\n", mode, 0, pid, cl_name);
|
||||
printf("LW VG %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
|
||||
|
||||
} else if (!strcmp(r_type, "lv")) {
|
||||
printf("LW LV %s %s\n", mode, r_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void format_info_line(char *line)
|
||||
static void format_info_line(char *line, char *r_name, char *r_type)
|
||||
{
|
||||
char r_name[MAX_NAME+1];
|
||||
char r_type[MAX_NAME+1];
|
||||
|
||||
if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
|
||||
printf("%s\n", line);
|
||||
/* only print this in the raw info dump */
|
||||
|
||||
} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
|
||||
save_client_info(line);
|
||||
@ -266,8 +258,13 @@ static void format_info_line(char *line)
|
||||
format_info_ls_action(line);
|
||||
|
||||
} else if (!strncmp(line, "info=r ", strlen("info=r "))) {
|
||||
memset(r_name, 0, sizeof(r_name));
|
||||
memset(r_type, 0, sizeof(r_type));
|
||||
/*
|
||||
* r_name/r_type are reset when a new resource is found.
|
||||
* They are reused for the lock and action lines that
|
||||
* follow a resource line.
|
||||
*/
|
||||
memset(r_name, 0, MAX_NAME+1);
|
||||
memset(r_type, 0, MAX_NAME+1);
|
||||
format_info_r(line, r_name, r_type);
|
||||
|
||||
} else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
|
||||
@ -285,6 +282,8 @@ static void format_info_line(char *line)
|
||||
static void format_info(void)
|
||||
{
|
||||
char line[MAX_LINE];
|
||||
char r_name[MAX_NAME+1];
|
||||
char r_type[MAX_NAME+1];
|
||||
int i, j;
|
||||
|
||||
j = 0;
|
||||
@ -294,7 +293,7 @@ static void format_info(void)
|
||||
line[j++] = dump_buf[i];
|
||||
|
||||
if ((line[j-1] == '\n') || (line[j-1] == '\0')) {
|
||||
format_info_line(line);
|
||||
format_info_line(line, r_name, r_type);
|
||||
j = 0;
|
||||
memset(line, 0, sizeof(line));
|
||||
}
|
||||
@ -327,8 +326,6 @@ static daemon_reply _lvmlockd_send(const char *req_name, ...)
|
||||
static int _lvmlockd_result(daemon_reply reply, int *result)
|
||||
{
|
||||
int reply_result;
|
||||
const char *reply_flags;
|
||||
const char *lock_type;
|
||||
|
||||
if (reply.error) {
|
||||
log_error("lvmlockd_result reply error %d", reply.error);
|
||||
@ -346,14 +343,8 @@ static int _lvmlockd_result(daemon_reply reply, int *result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The lock_type that lvmlockd used for locking. */
|
||||
lock_type = daemon_reply_str(reply, "lock_type", "none");
|
||||
|
||||
*result = reply_result;
|
||||
|
||||
reply_flags = daemon_reply_str(reply, "result_flags", NULL);
|
||||
|
||||
log_debug("lvmlockd_result %d %s lm %s", reply_result, reply_flags, lock_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -387,8 +378,12 @@ static int setup_dump_socket(void)
|
||||
dump_addrlen = sizeof(sa_family_t) + strlen(dump_addr.sun_path+1) + 1;
|
||||
|
||||
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
|
||||
if (rv < 0)
|
||||
if (rv < 0) {
|
||||
rv = -errno;
|
||||
if (!close(s))
|
||||
log_error("failed to close dump socket");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -398,6 +393,7 @@ static int do_dump(const char *req_name)
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
int fd, rv = 0;
|
||||
int count = 0;
|
||||
|
||||
fd = setup_dump_socket();
|
||||
if (fd < 0) {
|
||||
@ -428,13 +424,18 @@ static int do_dump(const char *req_name)
|
||||
|
||||
memset(dump_buf, 0, sizeof(dump_buf));
|
||||
|
||||
rv = recvfrom(fd, dump_buf, dump_len, MSG_WAITALL,
|
||||
retry:
|
||||
rv = recvfrom(fd, dump_buf + count, dump_len - count, MSG_WAITALL,
|
||||
(struct sockaddr *)&dump_addr, &dump_addrlen);
|
||||
if (rv < 0) {
|
||||
log_error("recvfrom error %d %d", rv, errno);
|
||||
rv = -errno;
|
||||
goto out;
|
||||
}
|
||||
count += rv;
|
||||
|
||||
if (count < dump_len)
|
||||
goto retry;
|
||||
|
||||
rv = 0;
|
||||
if ((info && dump) || !strcmp(req_name, "dump"))
|
||||
@ -442,7 +443,8 @@ static int do_dump(const char *req_name)
|
||||
else
|
||||
format_info();
|
||||
out:
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_error("failed to close dump socket %d", fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -453,9 +455,9 @@ static int do_able(const char *req_name)
|
||||
int rv;
|
||||
|
||||
reply = _lvmlockd_send(req_name,
|
||||
"cmd = %s", "lvmlock",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", able_vg_name,
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
@ -484,7 +486,7 @@ static int do_stop_lockspaces(void)
|
||||
strcat(opts, "force ");
|
||||
|
||||
reply = _lvmlockd_send("stop_all",
|
||||
"cmd = %s", "lvmlock",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = %d", getpid(),
|
||||
"opts = %s", opts[0] ? opts : "none",
|
||||
NULL);
|
||||
@ -500,6 +502,87 @@ static int do_stop_lockspaces(void)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int do_kill(void)
|
||||
{
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
reply = _lvmlockd_send("kill_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
|
||||
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)
|
||||
{
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
|
||||
|
||||
/*
|
||||
* Check for misuse by looking for any active LVs in the VG
|
||||
* and refusing this operation if found? One possible way
|
||||
* to kill LVs (e.g. if fs cannot be unmounted) is to suspend
|
||||
* them, or replace them with the error target. In that
|
||||
* case the LV will still appear to be active, but it is
|
||||
* safe to release the lock.
|
||||
*/
|
||||
|
||||
reply = _lvmlockd_send("drop_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
log_error("lvmlockd result %d", result);
|
||||
rv = result;
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
printf("lvmlockctl options\n");
|
||||
@ -516,12 +599,16 @@ static void print_usage(void)
|
||||
printf(" Wait option for other commands.\n");
|
||||
printf("--force | -f 0|1>\n");
|
||||
printf(" Force option for other commands.\n");
|
||||
printf("--kill | -k <vgname>\n");
|
||||
printf(" Kill access to the VG when sanlock cannot renew lease.\n");
|
||||
printf("--drop | -r <vgname>\n");
|
||||
printf(" Clear locks for the VG when it is unused after kill (-k).\n");
|
||||
printf("--gl-enable | -E <vgname>\n");
|
||||
printf(" Tell lvmlockd to enable the global lock in a sanlock VG.\n");
|
||||
printf("--gl-disable | -D <vgname>\n");
|
||||
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
|
||||
printf("--stop-lockspaces | -S\n");
|
||||
printf(" Stop all lockspaces.\n");
|
||||
printf("--gl-enable <vg_name>\n");
|
||||
printf(" Tell lvmlockd to enable the global lock in a sanlock vg.\n");
|
||||
printf("--gl-disable <vg_name>\n");
|
||||
printf(" Tell lvmlockd to disable the global lock in a sanlock vg.\n");
|
||||
}
|
||||
|
||||
static int read_options(int argc, char *argv[])
|
||||
@ -536,6 +623,8 @@ static int read_options(int argc, char *argv[])
|
||||
{"dump", no_argument, 0, 'd' },
|
||||
{"wait", required_argument, 0, 'w' },
|
||||
{"force", required_argument, 0, 'f' },
|
||||
{"kill", required_argument, 0, 'k' },
|
||||
{"drop", required_argument, 0, 'r' },
|
||||
{"gl-enable", required_argument, 0, 'E' },
|
||||
{"gl-disable", required_argument, 0, 'D' },
|
||||
{"stop-lockspaces", no_argument, 0, 'S' },
|
||||
@ -548,7 +637,7 @@ static int read_options(int argc, char *argv[])
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "hqidE:D:w:S", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
@ -572,13 +661,21 @@ static int read_options(int argc, char *argv[])
|
||||
case 'w':
|
||||
wait_opt = atoi(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
kill_vg = 1;
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
drop_vg = 1;
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
gl_enable = 1;
|
||||
able_vg_name = strdup(optarg);
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
gl_disable = 1;
|
||||
able_vg_name = strdup(optarg);
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stop_lockspaces = 1;
|
||||
@ -604,7 +701,7 @@ int main(int argc, char **argv)
|
||||
_lvmlockd = lvmlockd_open(NULL);
|
||||
|
||||
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
|
||||
log_error("lvmlockd open error %d", _lvmlockd.error);
|
||||
log_error("Cannot connect to lvmlockd.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -623,12 +720,24 @@ int main(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kill_vg) {
|
||||
rv = do_kill();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (drop_vg) {
|
||||
rv = do_drop();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gl_enable) {
|
||||
syslog(LOG_INFO, "Enabling global lock in VG %s.", arg_vg_name);
|
||||
rv = do_able("enable_gl");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gl_disable) {
|
||||
syslog(LOG_INFO, "Disabling global lock in VG %s.", arg_vg_name);
|
||||
rv = do_able("disable_gl");
|
||||
goto out;
|
||||
}
|
||||
|
@ -45,5 +45,8 @@ static inline void lvmlockd_close(daemon_handle h)
|
||||
#define EMANAGER 214
|
||||
#define EPREPARE 215
|
||||
#define ELOCKD 216
|
||||
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
|
||||
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
|
||||
#define EREMOVED 219
|
||||
|
||||
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,28 +10,9 @@
|
||||
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <byteswap.h>
|
||||
#include <syslog.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include "tool.h"
|
||||
|
||||
#include "configure.h"
|
||||
#include "daemon-server.h"
|
||||
#include "daemon-log.h"
|
||||
#include "xlate.h"
|
||||
@ -45,6 +26,17 @@
|
||||
*/
|
||||
#include "libdlm.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <byteswap.h>
|
||||
#include <syslog.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
struct lm_dlm {
|
||||
dlm_lshandle_t *dh;
|
||||
};
|
||||
@ -75,6 +67,8 @@ int lm_data_size_dlm(void)
|
||||
#define VG_LOCK_ARGS_MINOR 0
|
||||
#define VG_LOCK_ARGS_PATCH 0
|
||||
|
||||
static int dlm_has_lvb_bug;
|
||||
|
||||
static int cluster_name_from_args(char *vg_args, char *clustername)
|
||||
{
|
||||
return last_string_from_args(vg_args, clustername);
|
||||
@ -104,6 +98,7 @@ static int check_args_version(char *vg_args)
|
||||
|
||||
static int read_cluster_name(char *clustername)
|
||||
{
|
||||
static const char close_error_msg[] = "read_cluster_name: close_error %d";
|
||||
char *n;
|
||||
int fd;
|
||||
int rv;
|
||||
@ -119,24 +114,26 @@ static int read_cluster_name(char *clustername)
|
||||
return fd;
|
||||
}
|
||||
|
||||
rv = read(fd, clustername, MAX_ARGS - 1);
|
||||
rv = read(fd, clustername, MAX_ARGS);
|
||||
if (rv < 0) {
|
||||
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_error(close_error_msg, fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
n = strstr(clustername, "\n");
|
||||
if (n)
|
||||
*n = '\0';
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_error(close_error_msg, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
{
|
||||
char clustername[MAX_ARGS];
|
||||
char lock_args_version[MAX_ARGS];
|
||||
char clustername[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_ARGS+1];
|
||||
int rv;
|
||||
|
||||
memset(clustername, 0, sizeof(clustername));
|
||||
@ -163,8 +160,9 @@ int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
|
||||
int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||
{
|
||||
char sys_clustername[MAX_ARGS];
|
||||
char arg_clustername[MAX_ARGS];
|
||||
char sys_clustername[MAX_ARGS+1];
|
||||
char arg_clustername[MAX_ARGS+1];
|
||||
uint32_t major = 0, minor = 0, patch = 0;
|
||||
struct lm_dlm *lmd;
|
||||
int rv;
|
||||
|
||||
@ -175,6 +173,17 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||
if (rv < 0)
|
||||
return -EMANAGER;
|
||||
|
||||
rv = dlm_kernel_version(&major, &minor, &patch);
|
||||
if (rv < 0) {
|
||||
log_error("prepare_lockspace_dlm kernel_version not detected %d", rv);
|
||||
dlm_has_lvb_bug = 1;
|
||||
}
|
||||
|
||||
if ((major == 6) && (minor == 0) && (patch == 1)) {
|
||||
log_debug("dlm kernel version %u.%u.%u has lvb bug", major, minor, patch);
|
||||
dlm_has_lvb_bug = 1;
|
||||
}
|
||||
|
||||
if (!ls->vg_args[0]) {
|
||||
/* global lockspace has no vg args */
|
||||
goto skip_args;
|
||||
@ -251,12 +260,6 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||
out:
|
||||
free(lmd);
|
||||
ls->lm_data = NULL;
|
||||
|
||||
if (!strcmp(ls->name, gl_lsname_dlm)) {
|
||||
gl_running_dlm = 0;
|
||||
gl_auto_dlm = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -340,7 +343,7 @@ static int to_dlm_mode(int ld_mode)
|
||||
}
|
||||
|
||||
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version)
|
||||
struct val_blk *vb_out)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||
@ -349,7 +352,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
int mode;
|
||||
int rv;
|
||||
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
|
||||
if (!r->lm_init) {
|
||||
rv = lm_add_resource_dlm(ls, r, 0);
|
||||
@ -391,7 +394,7 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
(void *)1, (void *)1, (void *)1,
|
||||
NULL, NULL);
|
||||
|
||||
if (rv == -EAGAIN) {
|
||||
if (rv == -1 && errno == -EAGAIN) {
|
||||
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
|
||||
ls->name, r->name, ld_mode);
|
||||
rv = -EUCLEAN;
|
||||
@ -428,14 +431,13 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
*/
|
||||
|
||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int adopt)
|
||||
struct val_blk *vb_out, int adopt)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||
struct dlm_lksb *lksb;
|
||||
struct val_blk vb;
|
||||
uint32_t flags = 0;
|
||||
uint16_t vb_version;
|
||||
int mode;
|
||||
int rv;
|
||||
|
||||
@ -443,7 +445,7 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
/* When adopting, we don't follow the normal method
|
||||
of acquiring a NL lock then converting it to the
|
||||
desired mode. */
|
||||
return lm_adopt_dlm(ls, r, ld_mode, r_version);
|
||||
return lm_adopt_dlm(ls, r, ld_mode, vb_out);
|
||||
}
|
||||
|
||||
if (!r->lm_init) {
|
||||
@ -471,19 +473,37 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
log_debug("S %s R %s lock_dlm", ls->name, r->name);
|
||||
|
||||
if (daemon_test) {
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The dlm lvb bug means that converting NL->EX will not return
|
||||
* the latest lvb, so we have to convert NL->PR->EX to reread it.
|
||||
*/
|
||||
if (dlm_has_lvb_bug && (ld_mode == LD_LK_EX)) {
|
||||
rv = dlm_ls_lock_wait(lmd->dh, LKM_PRMODE, lksb, flags,
|
||||
r->name, strlen(r->name),
|
||||
0, NULL, NULL, NULL);
|
||||
if (rv == -1) {
|
||||
log_debug("S %s R %s lock_dlm acquire mode PR for %d rv %d",
|
||||
ls->name, r->name, mode, rv);
|
||||
goto lockrv;
|
||||
}
|
||||
|
||||
/* Fall through to request EX. */
|
||||
}
|
||||
|
||||
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
||||
r->name, strlen(r->name),
|
||||
0, NULL, NULL, NULL);
|
||||
if (rv == -EAGAIN) {
|
||||
log_error("S %s R %s lock_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||
lockrv:
|
||||
if (rv == -1 && errno == EAGAIN) {
|
||||
log_debug("S %s R %s lock_dlm acquire mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_dlm error %d", ls->name, r->name, rv);
|
||||
log_error("S %s R %s lock_dlm acquire error %d errno %d", ls->name, r->name, rv, errno);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -491,28 +511,22 @@ int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
|
||||
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
|
||||
memset(rdd->vb, 0, sizeof(struct val_blk));
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'vb' contains disk endian values, not host endian.
|
||||
* It is copied directly to rdd->vb which is also kept
|
||||
* in disk endian form.
|
||||
* vb_out is returned to the caller in host endian form.
|
||||
*/
|
||||
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
|
||||
vb_version = le16_to_cpu(vb.version);
|
||||
memcpy(rdd->vb, &vb, sizeof(vb));
|
||||
|
||||
if (vb_version && ((vb_version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
||||
log_error("S %s R %s lock_dlm ignore vb_version %x",
|
||||
ls->name, r->name, vb_version);
|
||||
*r_version = 0;
|
||||
free(rdd->vb);
|
||||
rdd->vb = NULL;
|
||||
lksb->sb_lvbptr = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*r_version = le32_to_cpu(vb.r_version);
|
||||
memcpy(rdd->vb, &vb, sizeof(vb)); /* rdd->vb saved as le */
|
||||
|
||||
log_debug("S %s R %s lock_dlm get r_version %u",
|
||||
ls->name, r->name, *r_version);
|
||||
vb_out->version = le16_to_cpu(vb.version);
|
||||
vb_out->flags = le16_to_cpu(vb.flags);
|
||||
vb_out->r_version = le32_to_cpu(vb.r_version);
|
||||
}
|
||||
out:
|
||||
return 0;
|
||||
@ -556,7 +570,7 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
|
||||
r->name, strlen(r->name),
|
||||
0, NULL, NULL, NULL);
|
||||
if (rv == -EAGAIN) {
|
||||
if (rv == -1 && errno == EAGAIN) {
|
||||
/* FIXME: When does this happen? Should something different be done? */
|
||||
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
|
||||
return -EAGAIN;
|
||||
@ -568,17 +582,17 @@ int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmuf_flags)
|
||||
uint32_t r_version, uint32_t lmu_flags)
|
||||
{
|
||||
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
|
||||
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
|
||||
struct dlm_lksb *lksb = &rdd->lksb;
|
||||
struct val_blk vb_prev;
|
||||
struct val_blk vb_next;
|
||||
uint32_t flags = 0;
|
||||
int new_vb = 0;
|
||||
int rv;
|
||||
|
||||
log_debug("S %s R %s unlock_dlm r_version %u flags %x",
|
||||
ls->name, r->name, r_version, lmuf_flags);
|
||||
|
||||
/*
|
||||
* Do not set PERSISTENT, because we don't need an orphan
|
||||
* NL lock to protect anything.
|
||||
@ -586,19 +600,46 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
|
||||
flags |= LKF_CONVERT;
|
||||
|
||||
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
|
||||
if (!rdd->vb->version) {
|
||||
/* first time vb has been written */
|
||||
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
|
||||
}
|
||||
if (r_version)
|
||||
rdd->vb->r_version = cpu_to_le32(r_version);
|
||||
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
|
||||
if (rdd->vb && (r->mode == LD_LK_EX)) {
|
||||
|
||||
log_debug("S %s R %s unlock_dlm set r_version %u",
|
||||
ls->name, r->name, r_version);
|
||||
/* vb_prev and vb_next are in disk endian form */
|
||||
memcpy(&vb_prev, rdd->vb, sizeof(struct val_blk));
|
||||
memcpy(&vb_next, rdd->vb, sizeof(struct val_blk));
|
||||
|
||||
if (!vb_prev.version) {
|
||||
vb_next.version = cpu_to_le16(VAL_BLK_VERSION);
|
||||
new_vb = 1;
|
||||
}
|
||||
|
||||
if ((lmu_flags & LMUF_FREE_VG) && (r->type == LD_RT_VG)) {
|
||||
vb_next.flags = cpu_to_le16(VBF_REMOVED);
|
||||
new_vb = 1;
|
||||
}
|
||||
|
||||
if (r_version) {
|
||||
vb_next.r_version = cpu_to_le32(r_version);
|
||||
new_vb = 1;
|
||||
}
|
||||
|
||||
if (new_vb) {
|
||||
memcpy(rdd->vb, &vb_next, sizeof(struct val_blk));
|
||||
memcpy(lksb->sb_lvbptr, &vb_next, sizeof(struct val_blk));
|
||||
|
||||
log_debug("S %s R %s unlock_dlm vb old %x %x %u new %x %x %u",
|
||||
ls->name, r->name,
|
||||
le16_to_cpu(vb_prev.version),
|
||||
le16_to_cpu(vb_prev.flags),
|
||||
le32_to_cpu(vb_prev.r_version),
|
||||
le16_to_cpu(vb_next.version),
|
||||
le16_to_cpu(vb_next.flags),
|
||||
le32_to_cpu(vb_next.r_version));
|
||||
} else {
|
||||
log_debug("S %s R %s unlock_dlm vb unchanged", ls->name, r->name);
|
||||
}
|
||||
|
||||
flags |= LKF_VALBLK;
|
||||
} else {
|
||||
log_debug("S %s R %s unlock_dlm", ls->name, r->name);
|
||||
}
|
||||
|
||||
if (daemon_test)
|
||||
@ -621,8 +662,65 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
|
||||
#define DLM_LOCKSPACES_PATH "/sys/kernel/config/dlm/cluster/spaces"
|
||||
|
||||
/*
|
||||
* FIXME: this should be implemented differently.
|
||||
* It's not nice to use an aspect of the dlm clustering
|
||||
* implementation, which could change. It would be
|
||||
* better to do something like use a special lock in the
|
||||
* lockspace that was held PR by all nodes, and then an
|
||||
* EX request on it could check if it's started (and
|
||||
* possibly also notify others to stop it automatically).
|
||||
* Or, possibly an enhancement to libdlm that would give
|
||||
* info about lockspace members.
|
||||
*
|
||||
* (We could let the VG be removed while others still
|
||||
* have the lockspace running, which largely works, but
|
||||
* introduces problems if another VG with the same name is
|
||||
* recreated while others still have the lockspace running
|
||||
* for the previous VG. We'd also want a way to clean up
|
||||
* the stale lockspaces on the others eventually.)
|
||||
*/
|
||||
|
||||
int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||
{
|
||||
static const char closedir_err_msg[] = "lm_hosts_dlm: closedir failed";
|
||||
char ls_nodes_path[PATH_MAX];
|
||||
struct dirent *de;
|
||||
DIR *ls_dir;
|
||||
int count = 0;
|
||||
|
||||
memset(ls_nodes_path, 0, sizeof(ls_nodes_path));
|
||||
snprintf(ls_nodes_path, PATH_MAX-1, "%s/%s/nodes",
|
||||
DLM_LOCKSPACES_PATH, ls->name);
|
||||
|
||||
if (!(ls_dir = opendir(ls_nodes_path)))
|
||||
return -ECONNREFUSED;
|
||||
|
||||
while ((de = readdir(ls_dir))) {
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (closedir(ls_dir))
|
||||
log_error(closedir_err_msg);
|
||||
|
||||
if (!count) {
|
||||
log_error("lm_hosts_dlm found no nodes in %s", ls_nodes_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assume that a count of one node represents ourself,
|
||||
* and any value over one represents other nodes.
|
||||
*/
|
||||
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
{
|
||||
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||
struct lockspace *ls;
|
||||
struct dirent *de;
|
||||
DIR *ls_dir;
|
||||
@ -638,7 +736,8 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
continue;
|
||||
|
||||
if (!(ls = alloc_lockspace())) {
|
||||
closedir(ls_dir);
|
||||
if (closedir(ls_dir))
|
||||
log_error(closedir_err_msg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -648,13 +747,14 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
list_add_tail(&ls->list, ls_rejoin);
|
||||
}
|
||||
|
||||
closedir(ls_dir);
|
||||
if (closedir(ls_dir))
|
||||
log_error(closedir_err_msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lm_is_running_dlm(void)
|
||||
{
|
||||
char sys_clustername[MAX_ARGS];
|
||||
char sys_clustername[MAX_ARGS+1];
|
||||
int rv;
|
||||
|
||||
memset(sys_clustername, 0, sizeof(sys_clustername));
|
||||
@ -664,3 +764,4 @@ int lm_is_running_dlm(void)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,9 @@ enum {
|
||||
LD_OP_RENAME_FINAL,
|
||||
LD_OP_RUNNING_LM,
|
||||
LD_OP_FIND_FREE_LOCK,
|
||||
LD_OP_FORGET_VG_NAME,
|
||||
LD_OP_KILL_VG,
|
||||
LD_OP_DROP_VG,
|
||||
LD_OP_BUSY,
|
||||
};
|
||||
|
||||
/* resource types */
|
||||
@ -83,11 +85,12 @@ struct client {
|
||||
unsigned int recv : 1;
|
||||
unsigned int dead : 1;
|
||||
unsigned int poll_ignore : 1;
|
||||
unsigned int lock_ops : 1;
|
||||
char name[MAX_NAME+1];
|
||||
};
|
||||
|
||||
#define LD_AF_PERSISTENT 0x00000001
|
||||
#define LD_AF_UNUSED 0x00000002 /* use me */
|
||||
#define LD_AF_NO_CLIENT 0x00000002
|
||||
#define LD_AF_UNLOCK_CANCEL 0x00000004
|
||||
#define LD_AF_NEXT_VERSION 0x00000008
|
||||
#define LD_AF_WAIT 0x00000010
|
||||
@ -98,9 +101,10 @@ struct client {
|
||||
#define LD_AF_SEARCH_LS 0x00000200
|
||||
#define LD_AF_WAIT_STARTING 0x00001000
|
||||
#define LD_AF_DUP_GL_LS 0x00002000
|
||||
#define LD_AF_INACTIVE_LS 0x00004000
|
||||
#define LD_AF_ADD_LS_ERROR 0x00008000
|
||||
#define LD_AF_ADOPT 0x00010000
|
||||
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||
#define LD_AF_LV_LOCK 0x00040000
|
||||
#define LD_AF_LV_UNLOCK 0x00080000
|
||||
|
||||
/*
|
||||
* Number of times to repeat a lock request after
|
||||
@ -127,8 +131,8 @@ struct action {
|
||||
char vg_name[MAX_NAME+1];
|
||||
char lv_name[MAX_NAME+1];
|
||||
char lv_uuid[MAX_NAME+1];
|
||||
char vg_args[MAX_ARGS];
|
||||
char lv_args[MAX_ARGS];
|
||||
char vg_args[MAX_ARGS+1];
|
||||
char lv_args[MAX_ARGS+1];
|
||||
char vg_sysid[MAX_NAME+1];
|
||||
};
|
||||
|
||||
@ -139,13 +143,14 @@ struct resource {
|
||||
int8_t mode;
|
||||
unsigned int sh_count; /* number of sh locks on locks list */
|
||||
uint32_t version;
|
||||
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
||||
unsigned int lm_init : 1; /* lm_data is initialized */
|
||||
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
||||
unsigned int version_zero_valid : 1;
|
||||
unsigned int use_vb : 1;
|
||||
struct list_head locks;
|
||||
struct list_head actions;
|
||||
struct val_blk *vb;
|
||||
char lv_args[MAX_ARGS];
|
||||
char lv_args[MAX_ARGS+1];
|
||||
char lm_data[0]; /* lock manager specific data */
|
||||
};
|
||||
|
||||
@ -164,7 +169,7 @@ struct lockspace {
|
||||
char name[MAX_NAME+1];
|
||||
char vg_name[MAX_NAME+1];
|
||||
char vg_uuid[64];
|
||||
char vg_args[MAX_ARGS]; /* lock manager specific args */
|
||||
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
|
||||
char vg_sysid[MAX_NAME+1];
|
||||
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
|
||||
void *lm_data;
|
||||
@ -182,13 +187,20 @@ struct lockspace {
|
||||
unsigned int thread_done : 1;
|
||||
unsigned int sanlock_gl_enabled: 1;
|
||||
unsigned int sanlock_gl_dup: 1;
|
||||
unsigned int free_vg: 1;
|
||||
unsigned int kill_vg: 1;
|
||||
unsigned int drop_vg: 1;
|
||||
|
||||
struct list_head actions; /* new client actions */
|
||||
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
||||
};
|
||||
|
||||
/* val_blk version */
|
||||
#define VAL_BLK_VERSION 0x0101
|
||||
|
||||
/* val_blk flags */
|
||||
#define VBF_REMOVED 0x0001
|
||||
|
||||
struct val_blk {
|
||||
uint16_t version;
|
||||
uint16_t flags;
|
||||
@ -198,49 +210,6 @@ struct val_blk {
|
||||
/* lm_unlock flags */
|
||||
#define LMUF_FREE_VG 0x00000001
|
||||
|
||||
struct lockspace *alloc_lockspace(void);
|
||||
int lockspaces_empty(void);
|
||||
int last_string_from_args(char *args_in, char *last);
|
||||
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
||||
|
||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int adopt);
|
||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags);
|
||||
int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r);
|
||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
||||
int lm_data_size_dlm(void);
|
||||
int lm_is_running_dlm(void);
|
||||
|
||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
|
||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
||||
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int *retry, int adopt);
|
||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags);
|
||||
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
|
||||
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
|
||||
int lm_hosts_sanlock(struct lockspace *ls, int notify);
|
||||
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
|
||||
int lm_gl_is_enabled(struct lockspace *ls);
|
||||
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
||||
int lm_data_size_sanlock(void);
|
||||
int lm_is_running_sanlock(void);
|
||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
@ -351,13 +320,9 @@ static inline int list_empty(const struct list_head *head)
|
||||
EXTERN int gl_type_static;
|
||||
EXTERN int gl_use_dlm;
|
||||
EXTERN int gl_use_sanlock;
|
||||
EXTERN pthread_mutex_t gl_type_mutex;
|
||||
|
||||
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||
|
||||
EXTERN int gl_running_dlm;
|
||||
EXTERN int gl_auto_dlm;
|
||||
EXTERN int global_dlm_lockspace_exists;
|
||||
|
||||
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||
EXTERN int daemon_debug;
|
||||
@ -365,9 +330,258 @@ EXTERN int daemon_host_id;
|
||||
EXTERN const char *daemon_host_id_file;
|
||||
EXTERN int sanlock_io_timeout;
|
||||
|
||||
/*
|
||||
* This flag is set to 1 if we see multiple vgs with the global
|
||||
* lock enabled. While this is set, we return a special flag
|
||||
* with the vg lock result indicating to the lvm command that
|
||||
* there is a duplicate gl in the vg which should be resolved.
|
||||
* While this is set, find_lockspace_name has the side job of
|
||||
* counting the number of lockspaces with enabled gl's so that
|
||||
* this can be set back to zero when the duplicates are disabled.
|
||||
*/
|
||||
EXTERN int sanlock_gl_dup;
|
||||
|
||||
void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
|
||||
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
|
||||
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
|
||||
|
||||
struct lockspace *alloc_lockspace(void);
|
||||
int lockspaces_empty(void);
|
||||
int last_string_from_args(char *args_in, char *last);
|
||||
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
|
||||
|
||||
|
||||
#ifdef LOCKDDLM_SUPPORT
|
||||
|
||||
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_dlm(struct lockspace *ls);
|
||||
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, int adopt);
|
||||
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags);
|
||||
int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r);
|
||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
|
||||
int lm_data_size_dlm(void);
|
||||
int lm_is_running_dlm(void);
|
||||
int lm_hosts_dlm(struct lockspace *ls, int notify);
|
||||
|
||||
static inline int lm_support_dlm(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_data_size_dlm(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_is_running_dlm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_support_dlm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_hosts_dlm(struct lockspace *ls, int notify)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* dlm support */
|
||||
|
||||
#ifdef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
|
||||
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
|
||||
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
|
||||
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
|
||||
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
|
||||
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
|
||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, int *retry, int adopt);
|
||||
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version);
|
||||
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags);
|
||||
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
|
||||
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
|
||||
int lm_hosts_sanlock(struct lockspace *ls, int notify);
|
||||
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
|
||||
int lm_gl_is_enabled(struct lockspace *ls);
|
||||
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
|
||||
int lm_data_size_sanlock(void);
|
||||
int lm_is_running_sanlock(void);
|
||||
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
|
||||
|
||||
static inline int lm_support_sanlock(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
struct val_blk *vb_out, int *retry, int adopt)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
|
||||
int ld_mode, uint32_t r_version)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version, uint32_t lmu_flags)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_gl_is_enabled(struct lockspace *ls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_data_size_sanlock(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_is_running_sanlock(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int lm_support_sanlock(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* sanlock support */
|
||||
|
||||
#endif /* _LVM_LVMLOCKD_INTERNAL_H */
|
||||
|
@ -10,23 +10,9 @@
|
||||
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
#define _ISOC99_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include "tool.h"
|
||||
|
||||
#include "configure.h"
|
||||
#include "daemon-server.h"
|
||||
#include "daemon-log.h"
|
||||
#include "xlate.h"
|
||||
@ -39,53 +25,109 @@
|
||||
#include "sanlock_admin.h"
|
||||
#include "sanlock_resource.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/*
|
||||
* If access to the pv containing the vg's leases is lost, sanlock cannot renew
|
||||
* the leases we have acquired for locked LVs. This means that we could soon
|
||||
* loose the lease to another host which could activate our LV exclusively. We
|
||||
* do not want to get to the point of two hosts having the same LV active
|
||||
* exclusively (it obviously violates the purpose of LV locks.)
|
||||
*
|
||||
* The default method of preventing this problem is for lvmlockd to do nothing,
|
||||
* which produces a safe but potentially inconvenient result. Doing nothing
|
||||
* leads to our LV leases not being released, which leads to sanlock using the
|
||||
* local watchdog to reset us before another host can acquire our lock. It
|
||||
* would often be preferrable to avoid the abrupt hard reset from the watchdog.
|
||||
*
|
||||
* There are other options to avoid being reset by our watchdog. If we can
|
||||
* quickly stop using the LVs in question and release the locks for them, then
|
||||
* we could avoid a reset (there's a certain grace period of about 40 seconds
|
||||
* in which we can attempt this.) To do this, we can tell sanlock to run a
|
||||
* specific program when it has lost access to our leases. We could use this
|
||||
* program to:
|
||||
*
|
||||
* 1. Deactivate all lvs in the effected vg. If all the leases are
|
||||
* deactivated, then our LV locks would be released and sanlock would no longer
|
||||
* use the watchdog to reset us. If file systems are mounted on the active
|
||||
* lvs, then deactivating them would fail, so this option would be of limited
|
||||
* usefulness.
|
||||
*
|
||||
* 2. Option 1 could be extended to kill pids using the fs on the lv, unmount
|
||||
* the fs, and deactivate the lv. This is probably out of scope for lvm
|
||||
* directly, and would likely need the help of another system service.
|
||||
*
|
||||
* 3. Use dmsetup suspend to block access to lvs in the effected vg. If this
|
||||
* was successful, the local host could no longer write to the lvs, we could
|
||||
* safely release the LV locks, and sanlock would no longer reset us. At this
|
||||
* point, with suspended lvs, the host would be in a fairly hobbled state, and
|
||||
* would almost certainly need a manual, forcible reset.
|
||||
*
|
||||
* 4. Option 3 could be extended to monitor the lost storage, and if it is
|
||||
* reconnected, the leases could be reacquired, and the suspended lvs resumed
|
||||
* (reacquiring leases will fail if another host has acquired them since they
|
||||
* were released.) This complexity of this option, combined with the fact that
|
||||
* the error conditions are often not as simple as storage being lost and then
|
||||
* later connecting, will result in this option being too unreliable.
|
||||
*
|
||||
* Add a config option that we could use to select a different behavior than
|
||||
* the default. Then implement one of the simpler options as a proof of
|
||||
* concept, which could be extended if needed.
|
||||
*/
|
||||
-------------------------------------------------------------------------------
|
||||
For each VG, lvmlockd creates a sanlock lockspace that holds the leases for
|
||||
that VG. There's a lease for the VG lock, and there's a lease for each active
|
||||
LV. sanlock maintains (reads/writes) these leases, which exist on storage.
|
||||
That storage is a hidden LV within the VG: /dev/vg/lvmlock. lvmlockd gives the
|
||||
path of this internal LV to sanlock, which then reads/writes the leases on it.
|
||||
|
||||
# lvs -a cc -o+uuid
|
||||
LV VG Attr LSize LV UUID
|
||||
lv1 cc -wi-a----- 2.00g 7xoDtu-yvNM-iwQx-C94t-BbYs-UzBl-o8hAIa
|
||||
lv2 cc -wi-a----- 100.00g exxNPX-wZdO-uCNy-yiGa-aJGT-JKVl-arfcYT
|
||||
[lvmlock] cc -wi-ao---- 256.00m iLpDel-hR0T-hJ3u-rnVo-PcDh-mcjt-sF9egM
|
||||
|
||||
# sanlock status
|
||||
s lvm_cc:1:/dev/mapper/cc-lvmlock:0
|
||||
r lvm_cc:exxNPX-wZdO-uCNy-yiGa-aJGT-JKVl-arfcYT:/dev/mapper/cc-lvmlock:71303168:13 p 26099
|
||||
r lvm_cc:7xoDtu-yvNM-iwQx-C94t-BbYs-UzBl-o8hAIa:/dev/mapper/cc-lvmlock:70254592:3 p 26099
|
||||
|
||||
This shows that sanlock is maintaining leases on /dev/mapper/cc-lvmlock.
|
||||
|
||||
sanlock acquires a lockspace lease when the lockspace is joined, i.e. when the
|
||||
VG is started by 'vgchange --lock-start cc'. This lockspace lease exists at
|
||||
/dev/mapper/cc-lvmlock offset 0, and sanlock regularly writes to it to maintain
|
||||
ownership of it. Joining the lockspace (by acquiring the lockspace lease in
|
||||
it) then allows standard resource leases to be acquired in the lockspace for
|
||||
whatever the application wants. lvmlockd uses resource leases for the VG lock
|
||||
and LV locks.
|
||||
|
||||
sanlock acquires a resource lease for each actual lock that lvm commands use.
|
||||
Above, there are two LV locks that are held because the two LVs are active.
|
||||
These are on /dev/mapper/cc-lvmlock at offsets 71303168 and 70254592. sanlock
|
||||
does not write to these resource leases except when acquiring and releasing
|
||||
them (e.g. lvchange -ay/-an). The renewal of the lockspace lease maintains
|
||||
ownership of all the resource leases in the lockspace.
|
||||
|
||||
If the host loses access to the disk that the sanlock lv lives on, then sanlock
|
||||
can no longer renew its lockspace lease. The lockspace lease will eventually
|
||||
expire, at which point the host will lose ownership of it, and of all resource
|
||||
leases it holds in the lockspace. Eventually, other hosts will be able to
|
||||
acquire those leases. sanlock ensures that another host will not be able to
|
||||
acquire one of the expired leases until the current host has quit using it.
|
||||
|
||||
It is important that the host "quit using" the leases it is holding if the
|
||||
sanlock storage is lost and they begin expiring. If the host cannot quit using
|
||||
the leases and release them within a limited time, then sanlock will use the
|
||||
local watchdog to forcibly reset the host before any other host can acquire
|
||||
them. This is severe, but preferable to possibly corrupting the data protected
|
||||
by the lease. It ensures that two nodes will not be using the same lease at
|
||||
once. For LV leases, that means that another host will not be able to activate
|
||||
the LV while another host still has it active.
|
||||
|
||||
sanlock notifies the application that it cannot renew the lockspace lease. The
|
||||
application needs to quit using all leases in the lockspace and release them as
|
||||
quickly as possible. In the initial version, lvmlockd ignored this
|
||||
notification, so sanlock would eventually reach the point where it would use
|
||||
the local watchdog to reset the host. However, it's better to attempt a
|
||||
response. If that response succeeds, the host can avoid being reset. If the
|
||||
response fails, then sanlock will eventually reset the host as the last resort.
|
||||
sanlock gives the application about 40 seconds to complete its response and
|
||||
release its leases before resetting the host.
|
||||
|
||||
An application can specify the path and args of a program that sanlock should
|
||||
run to notify it if the lockspace lease cannot be renewed. This program should
|
||||
carry out the application's response to the expiring leases: attempt to quit
|
||||
using the leases and then release them. lvmlockd gives this command to sanlock
|
||||
for each VG when that VG is started: 'lvmlockctl --kill vg_name'
|
||||
|
||||
If sanlock loses access to lease storage in that VG, it runs lvmlockctl --kill,
|
||||
which:
|
||||
|
||||
1. Uses syslog to explain what is happening.
|
||||
|
||||
2. Notifies lvmlockd that the VG is being killed, so lvmlockd can
|
||||
immediatley return an error for this condition if any new lock
|
||||
requests are made. (This step would not be strictly necessary.)
|
||||
|
||||
3. Attempts to quit using the VG. This is not yet implemented, but
|
||||
will eventually use blkdeactivate on the VG (or a more forceful
|
||||
equivalent.)
|
||||
|
||||
4. If step 3 was successful at terminating all use of the VG, then
|
||||
lvmlockd is told to release all the leases for the VG. If this
|
||||
is all done without about 40 seconds, the host can avoid being
|
||||
reset.
|
||||
|
||||
Until steps 3 and 4 are fully implemented, manual steps can be substituted.
|
||||
This is primarily for testing since the problem needs to be noticed and
|
||||
responded to in a very short time. The manual alternative to step 3 is to kill
|
||||
any processes using file systems on LV's in the VG, unmount all file systems on
|
||||
the LVs, and deactivate all the LVs. Once this is done, the manual alternative
|
||||
to step 4 is to run 'lvmlockctl --drop vg_name', which tells lvmlockd to
|
||||
release all the leases for the VG.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Each lockspace thread has its own sanlock daemon connection.
|
||||
@ -174,7 +216,7 @@ static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
|
||||
|
||||
static int lock_lv_offset_from_args(char *lv_args, uint64_t *lock_lv_offset)
|
||||
{
|
||||
char offset_str[MAX_ARGS];
|
||||
char offset_str[MAX_ARGS+1];
|
||||
int rv;
|
||||
|
||||
memset(offset_str, 0, sizeof(offset_str));
|
||||
@ -243,7 +285,8 @@ static int read_host_id_file(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
if (fclose(file))
|
||||
log_error("failed to close host id file %s", daemon_host_id_file);
|
||||
out:
|
||||
log_debug("host_id %d from %s", host_id, daemon_host_id_file);
|
||||
return host_id;
|
||||
@ -262,8 +305,8 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
struct sanlk_lockspace ss;
|
||||
struct sanlk_resourced rd;
|
||||
struct sanlk_disk disk;
|
||||
char lock_lv_name[MAX_ARGS];
|
||||
char lock_args_version[MAX_ARGS];
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_ARGS+1];
|
||||
const char *gl_name = NULL;
|
||||
uint32_t daemon_version;
|
||||
uint32_t daemon_proto;
|
||||
@ -291,7 +334,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
|
||||
if (strlen(lock_lv_name) + strlen(lock_args_version) + 2 > MAX_ARGS)
|
||||
return -EARGS;
|
||||
|
||||
snprintf(disk.path, SANLK_PATH_LEN, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
snprintf(disk.path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
|
||||
log_debug("S %s init_vg_san path %s", ls_name, disk.path);
|
||||
|
||||
@ -429,8 +472,8 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
char *vg_args, char *lv_args, uint64_t free_offset)
|
||||
{
|
||||
struct sanlk_resourced rd;
|
||||
char lock_lv_name[MAX_ARGS];
|
||||
char lock_args_version[MAX_ARGS];
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
char lock_args_version[MAX_ARGS+1];
|
||||
uint64_t offset;
|
||||
int align_size;
|
||||
int rv;
|
||||
@ -451,7 +494,7 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name,
|
||||
|
||||
strncpy(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN);
|
||||
rd.rs.num_disks = 1;
|
||||
snprintf(rd.rs.disks[0].path, SANLK_PATH_LEN, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
snprintf(rd.rs.disks[0].path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
|
||||
align_size = sanlock_align(&rd.rs.disks[0]);
|
||||
if (align_size <= 0) {
|
||||
@ -535,7 +578,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
struct sanlk_lockspace ss;
|
||||
struct sanlk_resourced rd;
|
||||
struct sanlk_disk disk;
|
||||
char lock_lv_name[MAX_ARGS];
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
uint64_t offset;
|
||||
uint32_t io_timeout;
|
||||
int align_size;
|
||||
@ -556,7 +599,7 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
|
||||
return rv;
|
||||
}
|
||||
|
||||
snprintf(disk.path, SANLK_PATH_LEN, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
snprintf(disk.path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s", vg_name, lock_lv_name);
|
||||
|
||||
log_debug("S %s rename_vg_san path %s", ls_name, disk.path);
|
||||
|
||||
@ -736,7 +779,7 @@ int lm_ex_disable_gl_sanlock(struct lockspace *ls)
|
||||
strncpy(rd2.rs.name, R_NAME_GL_DISABLED, SANLK_NAME_LEN);
|
||||
|
||||
rd1.rs.num_disks = 1;
|
||||
strncpy(rd1.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
||||
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;
|
||||
|
||||
rv = sanlock_acquire(lms->sock, -1, 0, 1, &rs1, NULL);
|
||||
@ -794,7 +837,7 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
||||
strncpy(rd.rs.name, gl_name, SANLK_NAME_LEN);
|
||||
|
||||
rd.rs.num_disks = 1;
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
||||
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;
|
||||
|
||||
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
|
||||
@ -807,8 +850,6 @@ int lm_able_gl_sanlock(struct lockspace *ls, int enable)
|
||||
log_debug("S %s able_gl %s", ls->name, gl_name);
|
||||
|
||||
ls->sanlock_gl_enabled = enable;
|
||||
if (ls->sanlock_gl_dup && !enable)
|
||||
ls->sanlock_gl_dup = 0;
|
||||
|
||||
if (enable)
|
||||
strncpy(gl_lsname_sanlock, ls->name, MAX_NAME);
|
||||
@ -833,7 +874,7 @@ static int gl_is_enabled(struct lockspace *ls, struct lm_sanlock *lms)
|
||||
/* leave rs.name empty, it is what we're checking */
|
||||
|
||||
rd.rs.num_disks = 1;
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
|
||||
offset = lms->align_size * GL_LOCK_BEGIN;
|
||||
rd.rs.disks[0].offset = offset;
|
||||
@ -891,7 +932,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
|
||||
|
||||
strncpy(rd.rs.lockspace_name, ls->name, SANLK_NAME_LEN);
|
||||
rd.rs.num_disks = 1;
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN);
|
||||
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
|
||||
|
||||
offset = lms->align_size * LV_LOCK_BEGIN;
|
||||
|
||||
@ -966,15 +1007,27 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
{
|
||||
struct stat st;
|
||||
struct lm_sanlock *lms = NULL;
|
||||
char lock_lv_name[MAX_ARGS];
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
char lsname[SANLK_NAME_LEN + 1];
|
||||
char disk_path[SANLK_PATH_LEN];
|
||||
char killpath[SANLK_PATH_LEN];
|
||||
char killargs[SANLK_PATH_LEN];
|
||||
int gl_found;
|
||||
int ret, rv;
|
||||
|
||||
memset(disk_path, 0, sizeof(disk_path));
|
||||
memset(lock_lv_name, 0, sizeof(lock_lv_name));
|
||||
|
||||
/*
|
||||
* Construct the path to lvmlockctl by using the path to the lvm binary
|
||||
* and appending "lockctl" to get /path/to/lvmlockctl.
|
||||
*/
|
||||
memset(killpath, 0, sizeof(killpath));
|
||||
snprintf(killpath, SANLK_PATH_LEN - 1, "%slockctl", LVM_PATH);
|
||||
|
||||
memset(killargs, 0, sizeof(killargs));
|
||||
snprintf(killargs, SANLK_PATH_LEN - 1, "--kill %s", ls->vg_name);
|
||||
|
||||
rv = check_args_version(ls->vg_args, VG_LOCK_ARGS_MAJOR);
|
||||
if (rv < 0) {
|
||||
ret = -EARGS;
|
||||
@ -989,7 +1042,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
snprintf(disk_path, SANLK_PATH_LEN, "/dev/mapper/%s-%s",
|
||||
snprintf(disk_path, SANLK_PATH_LEN-1, "/dev/mapper/%s-%s",
|
||||
ls->vg_name, lock_lv_name);
|
||||
|
||||
/*
|
||||
@ -1041,7 +1094,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
memcpy(lms->ss.name, lsname, SANLK_NAME_LEN);
|
||||
lms->ss.host_id_disk.offset = 0;
|
||||
lms->ss.host_id = ls->host_id;
|
||||
strncpy(lms->ss.host_id_disk.path, disk_path, SANLK_PATH_LEN);
|
||||
strncpy(lms->ss.host_id_disk.path, disk_path, SANLK_PATH_LEN-1);
|
||||
|
||||
if (daemon_test) {
|
||||
if (!gl_lsname_sanlock[0]) {
|
||||
@ -1059,6 +1112,15 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
log_debug("set killpath to %s %s", killpath, killargs);
|
||||
|
||||
rv = sanlock_killpath(lms->sock, 0, killpath, killargs);
|
||||
if (rv < 0) {
|
||||
log_error("S %s killpath error %d", lsname, rv);
|
||||
ret = -EMANAGER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = sanlock_restrict(lms->sock, SANLK_RESTRICT_SIGKILL);
|
||||
if (rv < 0) {
|
||||
log_error("S %s restrict error %d", lsname, rv);
|
||||
@ -1145,7 +1207,8 @@ out:
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
close(lms->sock);
|
||||
if (close(lms->sock))
|
||||
log_error("failed to close sanlock daemon socket connection");
|
||||
free(lms);
|
||||
ls->lm_data = NULL;
|
||||
return rv;
|
||||
@ -1181,7 +1244,8 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
|
||||
}
|
||||
}
|
||||
out:
|
||||
close(lms->sock);
|
||||
if (close(lms->sock))
|
||||
log_error("failed to close sanlock daemon socket connection");
|
||||
|
||||
free(lms);
|
||||
ls->lm_data = NULL;
|
||||
@ -1236,7 +1300,7 @@ int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
|
||||
}
|
||||
|
||||
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint32_t *r_version, int *retry, int adopt)
|
||||
struct val_blk *vb_out, int *retry, int adopt)
|
||||
{
|
||||
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
|
||||
struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data;
|
||||
@ -1244,7 +1308,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
uint64_t lock_lv_offset;
|
||||
uint32_t flags = 0;
|
||||
struct val_blk vb;
|
||||
uint16_t vb_version;
|
||||
int added = 0;
|
||||
int rv;
|
||||
|
||||
@ -1258,6 +1321,14 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
|
||||
rs = &rds->rs;
|
||||
|
||||
/*
|
||||
* While there are duplicate global locks, keep checking
|
||||
* to see if any have been disabled.
|
||||
*/
|
||||
if (sanlock_gl_dup && ls->sanlock_gl_enabled &&
|
||||
(r->type == LD_RT_GL || r->type == LD_RT_VG))
|
||||
ls->sanlock_gl_enabled = gl_is_enabled(ls, ls->lm_data);
|
||||
|
||||
if (r->type == LD_RT_LV) {
|
||||
/*
|
||||
* The lv may have been removed and recreated with a new lease
|
||||
@ -1312,7 +1383,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
(unsigned long long)rs->disks[0].offset);
|
||||
|
||||
if (daemon_test) {
|
||||
*r_version = 0;
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1321,6 +1392,15 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
if (adopt)
|
||||
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
|
||||
|
||||
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
|
||||
/*
|
||||
* Don't block waiting for a failed lease to expire since it causes
|
||||
* sanlock_acquire to block for a long time, which would prevent this
|
||||
* thread from processing other lock requests.
|
||||
*/
|
||||
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
|
||||
#endif
|
||||
|
||||
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, NULL);
|
||||
|
||||
if (rv == -EAGAIN) {
|
||||
@ -1391,15 +1471,30 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
|
||||
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
|
||||
/*
|
||||
* The lock is held by a failed host, and will eventually
|
||||
* expire. If we retry we'll eventually acquire the lock
|
||||
* (or find someone else has acquired it). The EAGAIN retry
|
||||
* attempts for SH locks above would not be sufficient for
|
||||
* the length of expiration time. We could add a longer
|
||||
* retry time here to cover the full expiration time and block
|
||||
* the activation command for that long. For now just return
|
||||
* the standard error indicating that another host still owns
|
||||
* the lease. FIXME: return a different error number so the
|
||||
* command can print an different error indicating that the
|
||||
* owner of the lease is in the process of expiring?
|
||||
*/
|
||||
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
|
||||
*retry = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
#endif
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_san acquire error %d",
|
||||
ls->name, r->name, rv);
|
||||
|
||||
if (added) {
|
||||
lm_rem_resource_sanlock(ls, r);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* if the gl has been disabled, remove and free the gl resource */
|
||||
if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) {
|
||||
if (!lm_gl_is_enabled(ls)) {
|
||||
@ -1411,6 +1506,22 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
lm_rem_resource_sanlock(ls, r);
|
||||
|
||||
/* sanlock gets i/o errors trying to read/write the leases. */
|
||||
if (rv == -EIO)
|
||||
rv = -ELOCKIO;
|
||||
|
||||
/*
|
||||
* The sanlock lockspace can disappear if the lease storage fails,
|
||||
* the delta lease renewals fail, the lockspace enters recovery,
|
||||
* lvmlockd holds no leases in the lockspace, so sanlock can
|
||||
* stop and free the lockspace.
|
||||
*/
|
||||
if (rv == -ENOSPC)
|
||||
rv = -ELOCKIO;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1418,26 +1529,23 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
rv = sanlock_get_lvb(0, rs, (char *)&vb, sizeof(vb));
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_san get_lvb error %d", ls->name, r->name, rv);
|
||||
*r_version = 0;
|
||||
memset(rds->vb, 0, sizeof(struct val_blk));
|
||||
memset(vb_out, 0, sizeof(struct val_blk));
|
||||
goto out;
|
||||
}
|
||||
|
||||
vb_version = le16_to_cpu(vb.version);
|
||||
/*
|
||||
* 'vb' contains disk endian values, not host endian.
|
||||
* It is copied directly to rrs->vb which is also kept
|
||||
* in disk endian form.
|
||||
* vb_out is returned to the caller in host endian form.
|
||||
*/
|
||||
|
||||
if (vb_version && ((vb_version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
|
||||
log_error("S %s R %s lock_san ignore vb_version %x",
|
||||
ls->name, r->name, vb_version);
|
||||
*r_version = 0;
|
||||
free(rds->vb);
|
||||
rds->vb = NULL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(rds->vb, &vb, sizeof(vb));
|
||||
|
||||
*r_version = le32_to_cpu(vb.r_version);
|
||||
memcpy(rds->vb, &vb, sizeof(vb)); /* rds->vb saved as le */
|
||||
|
||||
log_debug("S %s R %s lock_san get r_version %u",
|
||||
ls->name, r->name, *r_version);
|
||||
vb_out->version = le16_to_cpu(vb.version);
|
||||
vb_out->flags = le16_to_cpu(vb.flags);
|
||||
vb_out->r_version = le32_to_cpu(vb.r_version);
|
||||
}
|
||||
out:
|
||||
return rv;
|
||||
@ -1592,9 +1700,11 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
rv = sanlock_release(lms->sock, -1, 0, 1, &rs);
|
||||
if (rv < 0) {
|
||||
if (rv < 0)
|
||||
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
|
||||
}
|
||||
|
||||
if (rv == -EIO)
|
||||
rv = -ELOCKIO;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
1
daemons/lvmpolld/.gitignore
vendored
Normal file
1
daemons/lvmpolld/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
lvmpolld
|
@ -18,19 +18,14 @@
|
||||
#ifndef _LVM_LVMPOLLD_COMMON_H
|
||||
#define _LVM_LVMPOLLD_COMMON_H
|
||||
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmpolld-cmd-utils.h"
|
||||
#include "lvmpolld-protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif /* _LVM_LVMPOLLD_COMMON_H */
|
||||
|
@ -83,6 +83,12 @@ static int _init(struct daemon_state *s)
|
||||
struct lvmpolld_state *ls = s->private;
|
||||
ls->log = s->log;
|
||||
|
||||
/*
|
||||
* log warnings to stderr by default. Otherwise we would miss any lvpoll
|
||||
* error messages in default configuration
|
||||
*/
|
||||
daemon_log_enable(ls->log, DAEMON_LOG_OUTLET_STDERR, DAEMON_LOG_WARN, 1);
|
||||
|
||||
if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1))
|
||||
return 0;
|
||||
|
||||
@ -284,7 +290,7 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
||||
"caught input data in STDERR");
|
||||
|
||||
assert(read_single_line(data, 1)); /* may block indef. anyway */
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||
WARN(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||
pdlv->cmd_pid, "STDERR", data->line);
|
||||
} else if (fds[1].revents) {
|
||||
if (fds[1].revents & POLLHUP)
|
||||
@ -327,15 +333,19 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
|
||||
if (fds[1].fd >= 0)
|
||||
while (read_single_line(data, 1)) {
|
||||
assert(r > 0);
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDERR", data->line);
|
||||
WARN(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDERR", data->line);
|
||||
}
|
||||
|
||||
if (WIFEXITED(ch_stat)) {
|
||||
INFO(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
|
||||
"lvm2 cmd", pdlv->cmd_pid, "exited with", WEXITSTATUS(ch_stat));
|
||||
cmd_state.retcode = WEXITSTATUS(ch_stat);
|
||||
if (cmd_state.retcode)
|
||||
ERROR(pdlv->ls, "%s: %s (PID %d) %s (retcode: %d)", PD_LOG_PREFIX,
|
||||
"lvm2 cmd", pdlv->cmd_pid, "failed", cmd_state.retcode);
|
||||
else
|
||||
INFO(pdlv->ls, "%s: %s (PID %d) %s", PD_LOG_PREFIX,
|
||||
"lvm2 cmd", pdlv->cmd_pid, "finished successfully");
|
||||
} else if (WIFSIGNALED(ch_stat)) {
|
||||
WARN(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
|
||||
ERROR(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
|
||||
"lvm2 cmd", pdlv->cmd_pid, "got terminated by signal",
|
||||
WTERMSIG(ch_stat));
|
||||
cmd_state.signal = WTERMSIG(ch_stat);
|
||||
@ -529,7 +539,7 @@ static response progress_info(client_handle h, struct lvmpolld_state *ls, reques
|
||||
if (st.polling_finished)
|
||||
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
|
||||
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
|
||||
LVMPD_PARM_VALUE " = %d", st.cmd_state.signal ?: st.cmd_state.retcode,
|
||||
LVMPD_PARM_VALUE " = %d", (int64_t)(st.cmd_state.signal ?: st.cmd_state.retcode),
|
||||
NULL);
|
||||
else
|
||||
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
|
||||
@ -566,6 +576,8 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
|
||||
cmdenvp = cmdenvp_ctr(pdlv);
|
||||
if (!cmdenvp) {
|
||||
pdlv_destroy(pdlv);
|
||||
@ -573,7 +585,6 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
pdlv->cmdenvp = cmdenvp;
|
||||
|
||||
return pdlv;
|
||||
@ -584,12 +595,16 @@ static int spawn_detached_thread(struct lvmpolld_lv *pdlv)
|
||||
int r;
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (pthread_attr_init(&attr) != 0)
|
||||
return 0;
|
||||
|
||||
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
|
||||
return 0;
|
||||
|
||||
r = pthread_create(&pdlv->tid, &attr, fork_and_poll, (void *)pdlv);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
if (pthread_attr_destroy(&attr) != 0)
|
||||
return 0;
|
||||
|
||||
return !r;
|
||||
}
|
||||
|
@ -325,6 +325,7 @@ struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv
|
||||
|
||||
data->pdlv = NULL;
|
||||
data->line = NULL;
|
||||
data->line_size = 0;
|
||||
data->fout = data->ferr = NULL;
|
||||
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
|
||||
|
||||
@ -365,7 +366,8 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
pdst_unlock(data->pdlv->pdst);
|
||||
}
|
||||
|
||||
dm_free(data->line);
|
||||
/* may get reallocated in getline(). dm_free must not be used */
|
||||
free(data->line);
|
||||
|
||||
if (data->fout && !fclose(data->fout))
|
||||
data->outpipe[0] = -1;
|
||||
@ -374,16 +376,16 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
data->errpipe[0] = -1;
|
||||
|
||||
if (data->outpipe[0] >= 0)
|
||||
close(data->outpipe[0]);
|
||||
(void) close(data->outpipe[0]);
|
||||
|
||||
if (data->outpipe[1] >= 0)
|
||||
close(data->outpipe[1]);
|
||||
(void) close(data->outpipe[1]);
|
||||
|
||||
if (data->errpipe[0] >= 0)
|
||||
close(data->errpipe[0]);
|
||||
(void) close(data->errpipe[0]);
|
||||
|
||||
if (data->errpipe[1] >= 0)
|
||||
close(data->errpipe[1]);
|
||||
(void) close(data->errpipe[1]);
|
||||
|
||||
dm_free(data);
|
||||
}
|
||||
|
@ -45,7 +45,6 @@
|
||||
@top_srcdir@/lib/metadata/vg.h
|
||||
@top_srcdir@/lib/mm/memlock.h
|
||||
@top_srcdir@/lib/mm/xlate.h
|
||||
@top_builddir@/lib/misc/configure.h
|
||||
@top_srcdir@/lib/misc/crc.h
|
||||
@top_srcdir@/lib/misc/intl.h
|
||||
@top_srcdir@/lib/misc/last-path-component.h
|
||||
@ -56,7 +55,6 @@
|
||||
@top_srcdir@/lib/misc/lvm-globals.h
|
||||
@top_srcdir@/lib/misc/lvm-signal.h
|
||||
@top_srcdir@/lib/misc/lvm-string.h
|
||||
@top_builddir@/lib/misc/lvm-version.h
|
||||
@top_srcdir@/lib/misc/lvm-percent.h
|
||||
@top_srcdir@/lib/misc/lvm-wrappers.h
|
||||
@top_srcdir@/lib/misc/sharedlib.h
|
||||
@ -76,3 +74,4 @@
|
||||
@top_srcdir@/libdm/misc/kdev_t.h
|
||||
@top_srcdir@/po/pogen.h
|
||||
@top_srcdir@/tools/lvm2cmd.h
|
||||
@top_srcdir@/tools/tool.h
|
||||
|
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@ -35,5 +35,5 @@ device-mapper: all
|
||||
|
||||
cflow: all
|
||||
|
||||
DISTCLEAN_TARGETS += .symlinks
|
||||
DISTCLEAN_TARGETS += .symlinks configure.h lvm-version.h
|
||||
CLEAN_TARGETS += $(LINKS) .include_symlinks .symlinks_created
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* lib/misc/configure.h.in. Generated from configure.in by autoheader. */
|
||||
/* include/configure.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 to use libblkid detection of signatures when wiping. */
|
||||
#undef BLKID_WIPING_SUPPORT
|
||||
@ -6,6 +6,10 @@
|
||||
/* The path to 'cache_check', if available. */
|
||||
#undef CACHE_CHECK_CMD
|
||||
|
||||
/* Define to 1 if the external 'cache_check' tool requires the
|
||||
--clear-needs-check-flag option */
|
||||
#undef CACHE_CHECK_NEEDS_CHECK
|
||||
|
||||
/* The path to 'cache_dump', if available. */
|
||||
#undef CACHE_DUMP_CMD
|
||||
|
||||
@ -141,6 +145,9 @@
|
||||
/* Library version */
|
||||
#undef DM_LIB_VERSION
|
||||
|
||||
/* Define to 1 if you have the `alarm' function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
@ -157,12 +164,18 @@
|
||||
/* Define to 1 if you have the <assert.h> header file. */
|
||||
#undef HAVE_ASSERT_H
|
||||
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#undef HAVE_ATEXIT
|
||||
|
||||
/* Define to 1 if canonicalize_file_name is available. */
|
||||
#undef HAVE_CANONICALIZE_FILE_NAME
|
||||
|
||||
/* Define to 1 if your system has a working `chown' function. */
|
||||
#undef HAVE_CHOWN
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* Define to 1 if you have the <corosync/cmap.h> header file. */
|
||||
#undef HAVE_COROSYNC_CMAP_H
|
||||
|
||||
@ -172,6 +185,10 @@
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
@ -190,6 +207,9 @@
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <float.h> header file. */
|
||||
#undef HAVE_FLOAT_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
@ -247,6 +267,9 @@
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define to 1 if you have the `localtime_r' function. */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if `lstat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_LSTAT_EMPTY_STRING_BUG
|
||||
@ -261,6 +284,9 @@
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the `memchr' function. */
|
||||
#undef HAVE_MEMCHR
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
@ -297,9 +323,15 @@
|
||||
/* Define to 1 if you have the `nl_langinfo' function. */
|
||||
#undef HAVE_NL_LANGINFO
|
||||
|
||||
/* Define to 1 if you have the <paths.h> header file. */
|
||||
#undef HAVE_PATHS_H
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#undef HAVE_PTHREAD_H
|
||||
|
||||
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||
#undef HAVE_PTRDIFF_T
|
||||
|
||||
/* Define to 1 if you have the <readline/history.h> header file. */
|
||||
#undef HAVE_READLINE_HISTORY_H
|
||||
|
||||
@ -310,6 +342,9 @@
|
||||
and to 0 otherwise. */
|
||||
#undef HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
/* Define to 1 to include support for realtime clock. */
|
||||
#undef HAVE_REALTIME
|
||||
|
||||
@ -359,6 +394,9 @@
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
@ -386,6 +424,9 @@
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#undef HAVE_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
@ -395,6 +436,12 @@
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#undef HAVE_STRNCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strndup' function. */
|
||||
#undef HAVE_STRNDUP
|
||||
|
||||
/* Define to 1 if you have the `strpbrk' function. */
|
||||
#undef HAVE_STRPBRK
|
||||
|
||||
/* Define to 1 if you have the `strrchr' function. */
|
||||
#undef HAVE_STRRCHR
|
||||
|
||||
@ -410,6 +457,9 @@
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
|
||||
/* Define to 1 if you have the `strtoull' function. */
|
||||
#undef HAVE_STRTOULL
|
||||
|
||||
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_RDEV
|
||||
|
||||
@ -463,6 +513,9 @@
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/timerfd.h> header file. */
|
||||
#undef HAVE_SYS_TIMERFD_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
@ -514,12 +567,21 @@
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Internalization package */
|
||||
#undef INTL_PACKAGE
|
||||
|
||||
/* Locale-dependent data */
|
||||
#undef LOCALEDIR
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd dlm option. */
|
||||
#undef LOCKDDLM_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd sanlock option. */
|
||||
#undef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
@ -625,6 +687,12 @@
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if strerror_r returns char *. */
|
||||
#undef STRERROR_R_CHAR_P
|
||||
|
||||
/* Path to testsuite data */
|
||||
#undef TESTSUITE_DATA
|
||||
|
||||
/* The path to 'thin_check', if available. */
|
||||
#undef THIN_CHECK_CMD
|
||||
|
@ -62,6 +62,7 @@ SOURCES =\
|
||||
device/dev-swap.c \
|
||||
device/dev-type.c \
|
||||
device/dev-luks.c \
|
||||
device/dev-dasd.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
unknown/unknown.c \
|
||||
@ -122,11 +123,6 @@ SOURCES =\
|
||||
uuid/uuid.c \
|
||||
zero/zero.c
|
||||
|
||||
ifeq ("@HAVE_REALTIME@", "yes")
|
||||
SOURCES +=\
|
||||
misc/timestamp.c
|
||||
endif
|
||||
|
||||
ifeq ("@LVM1@", "internal")
|
||||
SOURCES +=\
|
||||
format1/disk-rep.c \
|
||||
@ -235,4 +231,4 @@ CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
||||
DISTCLEAN_TARGETS += misc/configure.h misc/lvm-version.h
|
||||
CLEAN_TARGETS += misc/configure.h misc/lvm-version.h
|
||||
|
@ -180,7 +180,7 @@ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_vol
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
|
||||
if (!(cn = find_config_tree_array(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
|
||||
log_verbose("activation/auto_activation_volume_list configuration setting "
|
||||
"not defined: All logical volumes will be auto-activated.");
|
||||
return 1;
|
||||
@ -467,7 +467,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, activation_volume_list_CFG, NULL))) {
|
||||
if (!(cn = find_config_tree_array(cmd, activation_volume_list_CFG, NULL))) {
|
||||
log_verbose("activation/volume_list configuration setting "
|
||||
"not defined: Checking only host tags for %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
@ -496,7 +496,7 @@ static int _passes_readonly_filter(struct cmd_context *cmd,
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||
return 0;
|
||||
|
||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
|
||||
|
@ -143,23 +143,23 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(segtype->name, "cache")) {
|
||||
if (segtype_is_cache(segtype)) {
|
||||
if (!dm_get_status_cache(seg_status->mem, params, &(seg_status->cache)))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_CACHE;
|
||||
} else if (!strcmp(segtype->name, "raid")) {
|
||||
} else if (segtype_is_raid(segtype)) {
|
||||
if (!dm_get_status_raid(seg_status->mem, params, &seg_status->raid))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_RAID;
|
||||
} else if (!strcmp(segtype->name, "thin")) {
|
||||
} else if (segtype_is_thin_volume(segtype)) {
|
||||
if (!dm_get_status_thin(seg_status->mem, params, &seg_status->thin))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN;
|
||||
} else if (!strcmp(segtype->name, "thin-pool")) {
|
||||
} else if (segtype_is_thin_pool(segtype)) {
|
||||
if (!dm_get_status_thin_pool(seg_status->mem, params, &seg_status->thin_pool))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN_POOL;
|
||||
} else if (!strcmp(segtype->name, "snapshot")) {
|
||||
} else if (segtype_is_snapshot(segtype)) {
|
||||
if (!dm_get_status_snapshot(seg_status->mem, params, &seg_status->snapshot))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_SNAPSHOT;
|
||||
@ -518,6 +518,73 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _ignore_unusable_thins(struct device *dev)
|
||||
{
|
||||
/* TODO make function for thin testing */
|
||||
struct dm_pool *mem;
|
||||
struct dm_status_thin_pool *status;
|
||||
struct dm_task *dmt = NULL;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
int minor, major;
|
||||
int r = 0;
|
||||
|
||||
if (!(mem = dm_pool_create("unusable_thins", 128)))
|
||||
return_0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
|
||||
goto_out;
|
||||
if (!dm_task_no_open_count(dmt))
|
||||
goto_out;
|
||||
if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
|
||||
goto_out;
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("Failed to get state of mapped device.");
|
||||
goto out;
|
||||
}
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (sscanf(params, "%d:%d", &minor, &major) != 2) {
|
||||
log_error("Failed to get thin-pool major:minor for thin device %d:%d.",
|
||||
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
goto out;
|
||||
}
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
|
||||
goto_out;
|
||||
if (!dm_task_no_flush(dmt))
|
||||
log_warn("Can't set no_flush.");
|
||||
if (!dm_task_no_open_count(dmt))
|
||||
goto_out;
|
||||
if (!dm_task_set_major_minor(dmt, minor, major, 1))
|
||||
goto_out;
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("Failed to get state of mapped device.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!dm_get_status_thin_pool(mem, params, &status))
|
||||
return_0;
|
||||
|
||||
if (status->read_only || status->out_of_data_space) {
|
||||
log_warn("WARNING: %s: Thin's thin-pool needs inspection.",
|
||||
dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
dm_pool_destroy(mem);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_is_usable
|
||||
* @dev
|
||||
@ -646,6 +713,13 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* TODO: extend check struct ? */
|
||||
if (target_type && !strcmp(target_type, "thin") &&
|
||||
!_ignore_unusable_thins(dev)) {
|
||||
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target_type && strcmp(target_type, "error"))
|
||||
only_error_target = 0;
|
||||
} while (next);
|
||||
@ -971,6 +1045,11 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
||||
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
/* No freeze on overfilled thin-pool, read existing slightly outdated data */
|
||||
if (lv && lv_is_thin_pool(lv) &&
|
||||
!dm_task_no_flush(dmt))
|
||||
log_warn("Can't set no_flush flag."); /* Non fatal */
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto_out;
|
||||
|
||||
@ -1038,7 +1117,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_debug_activation("LV percent: %f", dm_percent_to_float(*overall_percent));
|
||||
log_debug_activation("LV percent: %.2f", dm_percent_to_float(*overall_percent));
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@ -1918,7 +1997,6 @@ struct pool_cb_data {
|
||||
int skip_zero; /* to skip zeroed device header (check first 64B) */
|
||||
int exec; /* which binary to call */
|
||||
int opts;
|
||||
const char *defaults;
|
||||
const char *global;
|
||||
};
|
||||
|
||||
@ -1926,7 +2004,6 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
dm_node_callback_t type, void *cb_data)
|
||||
{
|
||||
int ret, status, fd;
|
||||
char *split;
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const struct pool_cb_data *data = cb_data;
|
||||
@ -1941,23 +2018,19 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
if (!*argv[0])
|
||||
return 1; /* Checking disabled */
|
||||
|
||||
if ((cn = find_config_tree_node(mlv->vg->cmd, data->opts, NULL))) {
|
||||
for (cv = cn->v; cv && args < 16; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"global/%s_check_options",
|
||||
data->global);
|
||||
return 0;
|
||||
}
|
||||
argv[++args] = cv->v.str;
|
||||
}
|
||||
} else {
|
||||
/* Use default options (no support for options with spaces) */
|
||||
if (!(split = dm_pool_strdup(data->dm->mem, data->defaults))) {
|
||||
log_error("Failed to duplicate defaults.");
|
||||
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv && args < 16; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"global/%s_check_options",
|
||||
data->global);
|
||||
return 0;
|
||||
}
|
||||
args = dm_split_words(split, 16, 0, (char**) argv + 1);
|
||||
argv[++args] = cv->v.str;
|
||||
}
|
||||
|
||||
if (args == 16) {
|
||||
@ -2048,14 +2121,12 @@ static int _pool_register_callback(struct dev_manager *dm,
|
||||
data->skip_zero = 1;
|
||||
data->exec = global_thin_check_executable_CFG;
|
||||
data->opts = global_thin_check_options_CFG;
|
||||
data->defaults = DEFAULT_THIN_CHECK_OPTION1 " " DEFAULT_THIN_CHECK_OPTION2;
|
||||
data->global = "thin";
|
||||
} else if (lv_is_cache(lv)) { /* cache pool */
|
||||
data->pool_lv = first_seg(lv)->pool_lv;
|
||||
data->skip_zero = dm->activation;
|
||||
data->exec = global_cache_check_executable_CFG;
|
||||
data->opts = global_cache_check_options_CFG;
|
||||
data->defaults = DEFAULT_CACHE_CHECK_OPTION1;
|
||||
data->global = "cache";
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
|
||||
@ -3206,7 +3277,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
break;
|
||||
case SUSPEND:
|
||||
dm_tree_skip_lockfs(root);
|
||||
if (!dm->flush_required && lv_is_mirror(lv) && !lv_is_pvmove(lv))
|
||||
if (!dm->flush_required && !lv_is_pvmove(lv))
|
||||
dm_tree_use_no_flush_suspend(root);
|
||||
/* Fall through */
|
||||
case SUSPEND_WITH_LOCKFS:
|
||||
@ -3225,7 +3296,14 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
|
||||
goto_out;
|
||||
|
||||
if (dm_tree_node_size_changed(root))
|
||||
if ((dm_tree_node_size_changed(root) < 0))
|
||||
dm->flush_required = 1;
|
||||
|
||||
/* Currently keep the code require flush for any
|
||||
* non 'thin pool/volume, mirror' or with any size change */
|
||||
if (!lv_is_thin_volume(lv) &&
|
||||
!lv_is_thin_pool(lv) &&
|
||||
(!lv_is_mirror(lv) || dm_tree_node_size_changed(root)))
|
||||
dm->flush_required = 1;
|
||||
|
||||
if (action == ACTIVATE) {
|
||||
|
85
lib/cache/lvmcache.c
vendored
85
lib/cache/lvmcache.c
vendored
@ -56,6 +56,7 @@ struct lvmcache_vginfo {
|
||||
char _padding[7];
|
||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||
char *creation_host;
|
||||
char *lock_type;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
size_t vgmetadata_size;
|
||||
@ -1447,7 +1448,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
|
||||
const char *creation_host)
|
||||
const char *creation_host, const char *lock_type)
|
||||
{
|
||||
if (!info || !info->vginfo)
|
||||
return 1;
|
||||
@ -1460,11 +1461,11 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
||||
info->vginfo->status = vgstatus;
|
||||
|
||||
if (!creation_host)
|
||||
return 1;
|
||||
goto set_lock_type;
|
||||
|
||||
if (info->vginfo->creation_host && !strcmp(creation_host,
|
||||
info->vginfo->creation_host))
|
||||
return 1;
|
||||
goto set_lock_type;
|
||||
|
||||
if (info->vginfo->creation_host)
|
||||
dm_free(info->vginfo->creation_host);
|
||||
@ -1478,6 +1479,24 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
||||
log_debug_cache("lvmcache: %s: VG %s: Set creation host to %s.",
|
||||
dev_name(info->dev), info->vginfo->vgname, creation_host);
|
||||
|
||||
set_lock_type:
|
||||
|
||||
if (!lock_type)
|
||||
goto out;
|
||||
|
||||
if (info->vginfo->lock_type && !strcmp(lock_type, info->vginfo->lock_type))
|
||||
goto out;
|
||||
|
||||
if (info->vginfo->lock_type)
|
||||
dm_free(info->vginfo->lock_type);
|
||||
|
||||
if (!(info->vginfo->lock_type = dm_strdup(lock_type))) {
|
||||
log_error("cache creation host alloc failed for %s",
|
||||
lock_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1523,10 +1542,6 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
|
||||
vgid = vgname;
|
||||
}
|
||||
|
||||
/* When using lvmetad, the PV could not have become orphaned. */
|
||||
if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo)
|
||||
return 1;
|
||||
|
||||
/* If PV without mdas is already in a real VG, don't make it orphan */
|
||||
if (is_orphan_vg(vgname) && info->vginfo &&
|
||||
mdas_empty_or_ignored(&info->mdas) &&
|
||||
@ -1546,7 +1561,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
|
||||
vgsummary->creation_host, info->fmt) ||
|
||||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
|
||||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host) ||
|
||||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type) ||
|
||||
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
|
||||
return_0;
|
||||
|
||||
@ -1561,7 +1576,8 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
struct lvmcache_vgsummary vgsummary = {
|
||||
.vgname = vg->name,
|
||||
.vgstatus = vg->status,
|
||||
.vgid = vg->id
|
||||
.vgid = vg->id,
|
||||
.lock_type = vg->lock_type
|
||||
};
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
@ -1851,19 +1867,17 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
* device already exists? Things don't seem to work
|
||||
* if we do that for some reason.
|
||||
*/
|
||||
log_verbose("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
log_debug_cache("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: when could this ever happen?
|
||||
* If this does happen, identify when/why here, and
|
||||
* if not, remove this code.
|
||||
* This happens when running pvcreate on an existing PV.
|
||||
*/
|
||||
if (strcmp(pvid_s, existing->dev->pvid)) {
|
||||
log_warn("Replacing dev %s pvid %s with dev %s pvid %s",
|
||||
dev_name(existing->dev), existing->dev->pvid,
|
||||
dev_name(dev), pvid_s);
|
||||
log_verbose("Replacing dev %s pvid %s with dev %s pvid %s",
|
||||
dev_name(existing->dev), existing->dev->pvid,
|
||||
dev_name(dev), pvid_s);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2327,3 +2341,40 @@ int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
if (vginfo->lock_type && !strcmp(vginfo->lock_type, "sanlock"))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||
unsigned *pv_max_name_len,
|
||||
unsigned *vg_max_name_len)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
unsigned len;
|
||||
|
||||
*vg_max_name_len = 0;
|
||||
*pv_max_name_len = 0;
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
len = strlen(vginfo->vgname);
|
||||
if (*vg_max_name_len < len)
|
||||
*vg_max_name_len = len;
|
||||
|
||||
dm_list_iterate_items(info, &vginfo->infos) {
|
||||
len = strlen(dev_name(info->dev));
|
||||
if (*pv_max_name_len < len)
|
||||
*pv_max_name_len = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
18
lib/cache/lvmcache.h
vendored
18
lib/cache/lvmcache.h
vendored
@ -39,11 +39,23 @@ struct disk_locn;
|
||||
|
||||
struct lvmcache_vginfo;
|
||||
|
||||
/*
|
||||
* vgsummary represents a summary of the VG that is read
|
||||
* without a lock. The info does not come through vg_read(),
|
||||
* but through reading mdas. It provides information about
|
||||
* the VG that is needed to lock the VG and then read it fully
|
||||
* with vg_read(), after which the VG summary should be checked
|
||||
* against the full VG metadata to verify it was correct (since
|
||||
* it was read without a lock.)
|
||||
*
|
||||
* Once read, vgsummary information is saved in lvmcache_vginfo.
|
||||
*/
|
||||
struct lvmcache_vgsummary {
|
||||
const char *vgname;
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
char *creation_host;
|
||||
const char *lock_type;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
};
|
||||
@ -176,4 +188,10 @@ int lvmcache_found_duplicate_pvs(void);
|
||||
|
||||
void lvmcache_set_preferred_duplicates(const char *vgid);
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
|
||||
|
||||
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||
unsigned *pv_max_name_len, unsigned *vg_max_name_len);
|
||||
|
||||
|
||||
#endif
|
||||
|
213
lib/cache/lvmetad.c
vendored
213
lib/cache/lvmetad.c
vendored
@ -37,6 +37,70 @@ static struct cmd_context *_lvmetad_cmd = NULL;
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
static int _log_debug_inequality(const char *name, struct dm_config_node *a, struct dm_config_node *b)
|
||||
{
|
||||
int result = 0;
|
||||
int final_result = 0;
|
||||
|
||||
if (a->v && b->v) {
|
||||
result = compare_value(a->v, b->v);
|
||||
if (result) {
|
||||
struct dm_config_value *av = a->v;
|
||||
struct dm_config_value *bv = b->v;
|
||||
|
||||
if (!strcmp(a->key, b->key)) {
|
||||
if (a->v->type == DM_CFG_STRING && b->v->type == DM_CFG_STRING)
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: %s / %s",
|
||||
name, a->key, b->key, av->v.str, bv->v.str);
|
||||
else if (a->v->type == DM_CFG_INT && b->v->type == DM_CFG_INT)
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTi64 " / " FMTi64,
|
||||
name, a->key, b->key, av->v.i, bv->v.i);
|
||||
else
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: type %d / type %d",
|
||||
name, a->key, b->key, av->type, bv->type);
|
||||
} else {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
}
|
||||
final_result = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->v && !b->v) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = 1;
|
||||
}
|
||||
|
||||
if (!a->v && b->v) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = -1;
|
||||
}
|
||||
|
||||
if (a->child && b->child) {
|
||||
result = _log_debug_inequality(name, a->child, b->child);
|
||||
if (result)
|
||||
final_result = result;
|
||||
}
|
||||
|
||||
if (a->sib && b->sib) {
|
||||
result = _log_debug_inequality(name, a->sib, b->sib);
|
||||
if (result)
|
||||
final_result = result;
|
||||
}
|
||||
|
||||
|
||||
if (a->sib && !b->sib) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = 1;
|
||||
}
|
||||
|
||||
if (!a->sib && b->sib) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = -1;
|
||||
}
|
||||
|
||||
return final_result;
|
||||
}
|
||||
|
||||
void lvmetad_disconnect(void)
|
||||
{
|
||||
if (_lvmetad_connected)
|
||||
@ -148,7 +212,7 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
|
||||
static daemon_reply _lvmetad_send(const char *id, ...)
|
||||
{
|
||||
va_list ap;
|
||||
daemon_reply repl;
|
||||
daemon_reply repl = { 0 };
|
||||
daemon_request req;
|
||||
unsigned num_rescans = 0;
|
||||
unsigned total_usecs_waited = 0;
|
||||
@ -158,8 +222,10 @@ static daemon_reply _lvmetad_send(const char *id, ...)
|
||||
retry:
|
||||
req = daemon_request_make(id);
|
||||
|
||||
if (_lvmetad_token)
|
||||
daemon_request_extend(req, "token = %s", _lvmetad_token, NULL);
|
||||
if (_lvmetad_token && !daemon_request_extend(req, "token = %s", _lvmetad_token, NULL)) {
|
||||
repl.error = ENOMEM;
|
||||
return repl;
|
||||
}
|
||||
|
||||
va_start(ap, id);
|
||||
daemon_request_extend_v(req, ap);
|
||||
@ -432,6 +498,7 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
struct format_type *fmt;
|
||||
struct dm_config_node *pvcn;
|
||||
struct pv_list *pvl;
|
||||
int rescan = 0;
|
||||
|
||||
if (!lvmetad_active())
|
||||
return NULL;
|
||||
@ -490,16 +557,56 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
if (!(vg = import_vg_from_lvmetad_config_tree(reply.cft, fid)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Read the VG from disk, ignoring the lvmetad copy in these
|
||||
* cases:
|
||||
*
|
||||
* 1. The host is not using lvmlockd, but is reading lockd VGs
|
||||
* using the --shared option. The shared option is meant to
|
||||
* let hosts not running lvmlockd look at lockd VGs, like the
|
||||
* foreign option allows hosts to look at foreign VGs. When
|
||||
* --foreign is used, the code forces a rescan since the local
|
||||
* lvmetad cache of foreign VGs is likely stale. Similarly,
|
||||
* for --shared, have the code reading the shared VGs below
|
||||
* not use the cached copy from lvmetad but to rescan the VG.
|
||||
*
|
||||
* 2. The host failed to acquire the VG lock from lvmlockd for
|
||||
* the lockd VG. In this case, the usual mechanisms for
|
||||
* updating the lvmetad copy of the VG have been missed. Since
|
||||
* we don't know if the cached copy is valid, assume it's not.
|
||||
*
|
||||
* 3. lvmetad has returned the "vg_invalid" flag, which is the
|
||||
* usual mechanism used by lvmlockd/lvmetad to cause a host to
|
||||
* reread a VG from disk that has been modified from another
|
||||
* host.
|
||||
*/
|
||||
|
||||
if (is_lockd_type(vg->lock_type) && cmd->include_shared_vgs) {
|
||||
log_debug_lvmetad("Rescan VG %s because including shared", vgname);
|
||||
rescan = 1;
|
||||
} else if (is_lockd_type(vg->lock_type) && cmd->lockd_vg_rescan) {
|
||||
log_debug_lvmetad("Rescan VG %s because no lvmlockd lock is held", vgname);
|
||||
rescan = 1;
|
||||
} else if (dm_config_find_node(reply.cft->root, "vg_invalid")) {
|
||||
log_debug_lvmetad("Rescan VG %s because lvmetad returned invalid", vgname);
|
||||
rescan = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* locking may have detected a newer vg version and
|
||||
* invalidated the cached vg.
|
||||
*/
|
||||
if (dm_config_find_node(reply.cft->root, "vg_invalid")) {
|
||||
if (rescan) {
|
||||
log_debug_lvmetad("Update invalid lvmetad cache for VG %s", vgname);
|
||||
vg2 = lvmetad_pvscan_vg(cmd, vg);
|
||||
release_vg(vg);
|
||||
vg = vg2;
|
||||
fid = vg->fid;
|
||||
if (!vg) {
|
||||
log_debug_lvmetad("VG %s from lvmetad not found during rescan.", vgname);
|
||||
fid = NULL;
|
||||
goto out;
|
||||
} else
|
||||
fid = vg->fid;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
@ -950,6 +1057,51 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
|
||||
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
|
||||
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
|
||||
|
||||
/*
|
||||
* pvscan --cache does not perform any lvmlockd locking, and
|
||||
* pvscan --cache -aay skips autoactivation in lockd VGs.
|
||||
*
|
||||
* pvscan --cache populates lvmetad with VG metadata from disk.
|
||||
* No lvmlockd locking is needed. It is expected that lockd VG
|
||||
* metadata that is read by pvscan and populated in lvmetad may
|
||||
* be immediately stale due to changes to the VG from other hosts
|
||||
* during or after this pvscan. This is normal and not a problem.
|
||||
* When a subsequent lvm command uses the VG, it will lock the VG
|
||||
* with lvmlockd, read the VG from lvmetad, and update the cached
|
||||
* copy from disk if necessary.
|
||||
*
|
||||
* pvscan --cache -aay does not activate LVs in lockd VGs because
|
||||
* activation requires locking, and a lock-start operation is needed
|
||||
* on a lockd VG before any locking can be performed in it.
|
||||
*
|
||||
* An equivalent of pvscan --cache -aay for lockd VGs is:
|
||||
* 1. pvscan --cache
|
||||
* 2. vgchange --lock-start
|
||||
* 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
|
||||
*
|
||||
* [We could eventually add support for autoactivating lockd VGs
|
||||
* using pvscan by incorporating the lock start step (which can
|
||||
* take a long time), but there may be a better option than
|
||||
* continuing to overload pvscan.]
|
||||
*
|
||||
* Stages of starting a lockd VG:
|
||||
*
|
||||
* . pvscan --cache populates lockd VGs in lvmetad without locks,
|
||||
* and this initial cached copy may quickly become stale.
|
||||
*
|
||||
* . vgchange --lock-start VG reads the VG without the VG lock
|
||||
* because no locks are available until the locking is started.
|
||||
* It only uses the VG name and lock_type from the VG metadata,
|
||||
* and then only uses it to start the VG lockspace in lvmlockd.
|
||||
*
|
||||
* . Further lvm commands, e.g. activation, can then lock the VG
|
||||
* with lvmlockd and use current VG metdata.
|
||||
*/
|
||||
if (handler && vg && is_lockd_type(vg->lock_type)) {
|
||||
log_debug_lvmetad("Skip pvscan activation for lockd type VG %s", vg->name);
|
||||
handler = NULL;
|
||||
}
|
||||
|
||||
if (result && handler) {
|
||||
status = daemon_reply_str(reply, "status", "<missing>");
|
||||
vgname = daemon_reply_str(reply, "vgname", "<missing>");
|
||||
@ -1017,7 +1169,8 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
struct _lvmetad_pvscan_baton *b = baton;
|
||||
struct volume_group *this;
|
||||
|
||||
this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1);
|
||||
if (!(this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
|
||||
return 1;
|
||||
|
||||
/* FIXME Also ensure contents match etc. */
|
||||
if (!b->vg || this->seqno > b->vg->seqno)
|
||||
@ -1033,6 +1186,8 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
* due to something like an lvcreate from another host.
|
||||
* This is limited to changes that only affect the vg (not global state like
|
||||
* orphan PVs), so we only need to reread mdas on the vg's existing pvs.
|
||||
* But, a previous PV in the VG may have been removed since we last read
|
||||
* the VG, and that PV may have been reused for another VG.
|
||||
*/
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
@ -1045,13 +1200,17 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
struct device *save_dev = NULL;
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
/* missing pv */
|
||||
if (!pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0);
|
||||
if (!(info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
|
||||
log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
baton.vg = NULL;
|
||||
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
@ -1068,9 +1227,25 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG by another host
|
||||
* since we last read the VG.
|
||||
*/
|
||||
if (!baton.vg) {
|
||||
log_debug_lvmetad("Did not find VG %s in scan of PV %s", vg->name, dev_name(pvl->pv->dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
return NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG and used for a
|
||||
* different VG since we last read the VG.
|
||||
*/
|
||||
if (strcmp(baton.vg->name, vg->name)) {
|
||||
log_debug_lvmetad("Did not find VG %s in scan of PV %s which is now VG %s",
|
||||
vg->name, dev_name(pvl->pv->dev), baton.vg->name);
|
||||
release_vg(baton.vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
@ -1081,9 +1256,12 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
|
||||
if (!vgmeta_ret) {
|
||||
vgmeta_ret = vgmeta;
|
||||
save_dev = pvl->pv->dev;
|
||||
} else {
|
||||
if (!compare_config(vgmeta_ret->root, vgmeta->root)) {
|
||||
log_error("VG metadata comparison failed");
|
||||
if (compare_config(vgmeta_ret->root, vgmeta->root)) {
|
||||
log_error("VG %s metadata comparison failed for device %s vs %s",
|
||||
vg->name, dev_name(pvl->pv->dev), save_dev ? dev_name(save_dev) : "none");
|
||||
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
|
||||
dm_config_destroy(vgmeta);
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
release_vg(baton.vg);
|
||||
@ -1153,7 +1331,7 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
log_warn("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
else
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
log_error("Ignoring obsolete format of metadata (%s) on device %s when using lvmetad.",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
|
||||
@ -1350,7 +1528,8 @@ static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *p
|
||||
/*
|
||||
* Opening the device RDWR should trigger a udev db update.
|
||||
* FIXME: is there a better way to update the udev db than
|
||||
* doing an open/close of the device?
|
||||
* doing an open/close of the device? - For example writing
|
||||
* "change" to /sys/block/<device>/uevent?
|
||||
*/
|
||||
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
{
|
||||
@ -1364,9 +1543,13 @@ static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_open(dev))
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return;
|
||||
dev_close(dev);
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1500,7 +1683,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lvmetad_used())
|
||||
if (!lvmetad_active())
|
||||
return;
|
||||
|
||||
log_debug_lvmetad("Validating global lvmetad cache");
|
||||
|
@ -25,6 +25,11 @@
|
||||
#include "lv_alloc.h"
|
||||
#include "defaults.h"
|
||||
|
||||
static const char _cache_module[] = "cache";
|
||||
|
||||
/* TODO: using static field here, maybe should be a part of segment_type */
|
||||
static unsigned _feature_mask;
|
||||
|
||||
#define SEG_LOG_ERROR(t, p...) \
|
||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||
@ -66,20 +71,16 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
if (dm_config_has_node(sn, "cache_mode")) {
|
||||
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
|
||||
return SEG_LOG_ERROR("cache_mode must be a string in");
|
||||
if (!set_cache_pool_feature(&seg->feature_flags, str))
|
||||
if (!cache_set_mode(seg, str))
|
||||
return SEG_LOG_ERROR("Unknown cache_mode in");
|
||||
} else
|
||||
/* When missed in metadata, it's an old stuff - use writethrough */
|
||||
seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "policy")) {
|
||||
if (!(str = dm_config_find_str(sn, "policy", NULL)))
|
||||
return SEG_LOG_ERROR("policy must be a string in");
|
||||
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
|
||||
return SEG_LOG_ERROR("Failed to duplicate policy in");
|
||||
} else
|
||||
/* Cannot use 'just' default, so pick one */
|
||||
seg->policy_name = DEFAULT_CACHE_POOL_POLICY; /* FIXME make configurable */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in policy args:
|
||||
@ -99,6 +100,9 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
* If the policy is not present, default policy is used.
|
||||
*/
|
||||
if ((sn = dm_config_find_node(sn, "policy_settings"))) {
|
||||
if (!seg->policy_name)
|
||||
return SEG_LOG_ERROR("policy_settings must have a policy_name in");
|
||||
|
||||
if (sn->v)
|
||||
return SEG_LOG_ERROR("policy_settings must be a section in");
|
||||
|
||||
@ -127,24 +131,33 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
|
||||
{
|
||||
const char *cache_mode;
|
||||
|
||||
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
|
||||
return_0;
|
||||
|
||||
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
|
||||
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
|
||||
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
|
||||
if (seg->policy_name)
|
||||
/*
|
||||
* Cache pool used by a cache LV holds data. Not ideal,
|
||||
* but not worth to break backward compatibility, by shifting
|
||||
* content to cache segment
|
||||
*/
|
||||
if (cache_mode_is_set(seg)) {
|
||||
if (!(cache_mode = get_cache_mode_name(seg)))
|
||||
return_0;
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
}
|
||||
|
||||
if (seg->policy_name) {
|
||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
}
|
||||
if (seg->policy_settings->child)
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -157,12 +170,29 @@ static void _destroy(struct segment_type *segtype)
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _target_present(struct cmd_context *cmd,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
{
|
||||
uint32_t maj, min, patchlevel;
|
||||
/* List of features with their kernel target version */
|
||||
static const struct feature {
|
||||
uint32_t maj;
|
||||
uint32_t min;
|
||||
unsigned cache_feature;
|
||||
const char feature[12];
|
||||
const char module[12]; /* check dm-%s */
|
||||
} _features[] = {
|
||||
{ 1, 3, CACHE_FEATURE_POLICY_MQ, "policy_mq", "cache-mq" },
|
||||
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, "policy_smq", "cache-smq" },
|
||||
};
|
||||
static const char _lvmconf[] = "global/cache_disabled_features";
|
||||
static unsigned _attrs = 0;
|
||||
static int _cache_checked = 0;
|
||||
static int _cache_present = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
unsigned i;
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
|
||||
if (!_cache_checked) {
|
||||
_cache_present = target_present(cmd, "cache", 1);
|
||||
@ -176,11 +206,53 @@ static int _target_present(struct cmd_context *cmd,
|
||||
|
||||
if ((maj < 1) ||
|
||||
((maj == 1) && (min < 3))) {
|
||||
log_error("The cache kernel module is version %u.%u.%u."
|
||||
" Version 1.3.0+ is required.",
|
||||
_cache_present = 0;
|
||||
log_error("The cache kernel module is version %u.%u.%u. "
|
||||
"Version 1.3.0+ is required.",
|
||||
maj, min, patchlevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) {
|
||||
if (((maj > _features[i].maj) ||
|
||||
(maj == _features[i].maj && min >= _features[i].min)) &&
|
||||
(!_features[i].module[0] || module_present(cmd, _features[i].module)))
|
||||
_attrs |= _features[i].cache_feature;
|
||||
else
|
||||
log_very_verbose("Target %s does not support %s.",
|
||||
_cache_module, _features[i].feature);
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes) {
|
||||
if (!_feature_mask) {
|
||||
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
|
||||
if ((cn = find_config_tree_array(cmd, global_cache_disabled_features_CFG, NULL))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Ignoring invalid string in config file %s.",
|
||||
_lvmconf);
|
||||
continue;
|
||||
}
|
||||
str = cv->v.str;
|
||||
if (!*str)
|
||||
continue;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||
if (strcasecmp(str, _features[i].feature) == 0)
|
||||
_feature_mask |= _features[i].cache_feature;
|
||||
}
|
||||
}
|
||||
|
||||
_feature_mask = ~_feature_mask;
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||
if ((_attrs & _features[i].cache_feature) &&
|
||||
!(_feature_mask & _features[i].cache_feature))
|
||||
log_very_verbose("Target %s %s support disabled by %s",
|
||||
_cache_module, _features[i].feature, _lvmconf);
|
||||
}
|
||||
*attributes = _attrs & _feature_mask;
|
||||
}
|
||||
|
||||
return _cache_present;
|
||||
@ -306,7 +378,9 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
metadata_uuid,
|
||||
data_uuid,
|
||||
origin_uuid,
|
||||
seg->cleaner_policy ? "cleaner" : cache_pool_seg->policy_name,
|
||||
seg->cleaner_policy ? "cleaner" :
|
||||
/* undefined policy name -> likely an old "mq" */
|
||||
cache_pool_seg->policy_name ? : "mq",
|
||||
seg->cleaner_policy ? NULL : cache_pool_seg->policy_settings,
|
||||
cache_pool_seg->chunk_size))
|
||||
return_0;
|
||||
@ -346,7 +420,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = "cache-pool";
|
||||
segtype->name = SEG_TYPE_NAME_CACHE_POOL;
|
||||
segtype->flags = SEG_CACHE_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->ops = &_cache_pool_ops;
|
||||
|
||||
@ -360,7 +434,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = "cache";
|
||||
segtype->name = SEG_TYPE_NAME_CACHE;
|
||||
segtype->flags = SEG_CACHE | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->ops = &_cache_ops;
|
||||
|
||||
@ -368,5 +442,8 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return_0;
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
/* Reset mask for recalc */
|
||||
_feature_mask = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -245,8 +245,10 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
||||
const struct dm_config_value *cv;
|
||||
int debug_classes = 0;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, log_debug_classes_CFG, NULL)))
|
||||
return DEFAULT_LOGGED_DEBUG_CLASSES;
|
||||
if (!(cn = find_config_tree_array(cmd, log_debug_classes_CFG, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for log/debug_classes.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
@ -360,7 +362,8 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
|
||||
/* Tell device-mapper about our logging */
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
dm_log_with_errno_init(print_log);
|
||||
if (!dm_log_is_non_default())
|
||||
dm_log_with_errno_init(print_log);
|
||||
#endif
|
||||
reset_log_duplicated();
|
||||
reset_lvm_errno(1);
|
||||
@ -530,8 +533,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
int64_t pv_min_kb;
|
||||
const char *lvmetad_socket;
|
||||
const char *lvmpolld_socket;
|
||||
int udev_disabled = 0;
|
||||
char sysfs_dir[PATH_MAX];
|
||||
|
||||
@ -652,7 +653,7 @@ static int _process_config(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if ((cn = find_config_tree_node(cmd, activation_mlock_filter_CFG, NULL)))
|
||||
if ((cn = find_config_tree_array(cmd, activation_mlock_filter_CFG, NULL)))
|
||||
for (cv = cn->v; cv; cv = cv->next)
|
||||
if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
|
||||
log_error("Ignoring invalid activation/mlock_filter entry in config file");
|
||||
@ -674,41 +675,9 @@ static int _process_config(struct cmd_context *cmd)
|
||||
init_detect_internal_vg_cache_corruption
|
||||
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
|
||||
|
||||
lvmetad_disconnect();
|
||||
lvmpolld_disconnect();
|
||||
|
||||
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
|
||||
if (!lvmetad_socket)
|
||||
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
|
||||
|
||||
/* TODO?
|
||||
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
|
||||
DEFAULT_RUN_DIR "/lvmetad.socket");
|
||||
*/
|
||||
lvmetad_set_socket(lvmetad_socket);
|
||||
cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL);
|
||||
lvmetad_set_token(cn ? cn->v : NULL);
|
||||
|
||||
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
|
||||
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
|
||||
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
|
||||
"Clustered environment not supported by lvmetad yet.");
|
||||
lvmetad_set_active(NULL, 0);
|
||||
} else
|
||||
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
||||
|
||||
lvmetad_init(cmd);
|
||||
|
||||
if (!_init_system_id(cmd))
|
||||
return_0;
|
||||
|
||||
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
|
||||
if (!lvmpolld_socket)
|
||||
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
|
||||
lvmpolld_set_socket(lvmpolld_socket);
|
||||
|
||||
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1015,15 +984,9 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
|
||||
init_obtain_device_list_from_udev(device_list_from_udev);
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, devices_scan_CFG, NULL))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
log_error("Failed to add /dev to internal "
|
||||
"device cache");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("device/scan not in config file: "
|
||||
"Defaulting to /dev");
|
||||
return 1;
|
||||
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
|
||||
return_0;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@ -1061,7 +1024,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, devices_loopfiles_CFG, NULL)))
|
||||
if (!(cn = find_config_tree_array(cmd, devices_loopfiles_CFG, NULL)))
|
||||
return 1;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@ -1107,7 +1070,7 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* regex filter. Optional. */
|
||||
/* global regex filter. Optional. */
|
||||
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create global regex device filter");
|
||||
@ -1116,6 +1079,17 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* regex filter. Optional. */
|
||||
if (!lvmetad_used()) {
|
||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filters[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create regex device filter");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* device type filter. Required. */
|
||||
if (!(filters[nr_filt] = lvm_type_filter_create(cmd->dev_types))) {
|
||||
log_error("Failed to create lvm type filter");
|
||||
@ -1183,30 +1157,33 @@ bad:
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
* - cmd->filter - the filter chain used for lvmetad responses:
|
||||
* persistent filter -> usable device filter(FILTER_MODE_POST_LVMETAD) ->
|
||||
* regex filter
|
||||
* persistent filter -> regex_filter -> usable device filter(FILTER_MODE_POST_LVMETAD)
|
||||
*
|
||||
* - cmd->full_filter - the filter chain used for all the remaining situations:
|
||||
* lvmetad_filter -> filter
|
||||
* cmd->lvmetad_filter -> cmd->filter
|
||||
*
|
||||
* If lvmetad isnot used, there's just one filter chain:
|
||||
* If lvmetad is not used, there's just one filter chain:
|
||||
*
|
||||
* - cmd->filter == cmd->full_filter:
|
||||
* persistent filter -> regex filter -> sysfs filter ->
|
||||
* global regex filter -> type filter ->
|
||||
* usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter ->
|
||||
* md component filter -> fw raid filter
|
||||
* persistent filter -> sysfs filter -> global regex filter ->
|
||||
* regex_filter -> type filter -> usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter -> md component filter -> fw raid filter
|
||||
*
|
||||
*/
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
||||
int nr_filt;
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
struct timespec ts, cts;
|
||||
|
||||
if (!cmd->initialized.connections) {
|
||||
log_error(INTERNAL_ERROR "connections must be initialized before filters");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
cmd->lvmetad_filter = _init_lvmetad_filter_chain(cmd);
|
||||
@ -1226,26 +1203,26 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
*/
|
||||
/* filter component 0 */
|
||||
if (lvmetad_used()) {
|
||||
if (!(filter_components[0] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
||||
nr_filt = 0;
|
||||
if ((cn = find_config_tree_array(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filter_components[nr_filt] = regex_filter_create(cn->v))) {
|
||||
log_verbose("Failed to create regex device filter.");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
}
|
||||
if (!(filter_components[nr_filt] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
||||
log_verbose("Failed to create usable device filter.");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
if (!(filter = composite_filter_create(nr_filt, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
filter = cmd->lvmetad_filter;
|
||||
cmd->lvmetad_filter = NULL;
|
||||
}
|
||||
|
||||
/* filter component 1 */
|
||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filter_components[1] = regex_filter_create(cn->v)))
|
||||
goto_bad;
|
||||
/* we have two filter components - create composite filter */
|
||||
if (!(filter = composite_filter_create(2, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
/* we have only one filter component - no need to create composite filter */
|
||||
filter = filter_components[0];
|
||||
|
||||
if (!(dev_cache = find_config_tree_str(cmd, devices_cache_CFG, NULL)))
|
||||
goto_bad;
|
||||
|
||||
@ -1257,9 +1234,12 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
cmd->filter = filter;
|
||||
|
||||
if (lvmetad_used()) {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
filter_components[1] = cmd->filter;
|
||||
if (!(cmd->full_filter = composite_filter_create(2, 0, filter_components)))
|
||||
nr_filt = 0;
|
||||
filter_components[nr_filt] = cmd->lvmetad_filter;
|
||||
nr_filt++;
|
||||
filter_components[nr_filt] = cmd->filter;
|
||||
nr_filt++;
|
||||
if (!(cmd->full_filter = composite_filter_create(nr_filt, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
cmd->full_filter = filter;
|
||||
@ -1287,6 +1267,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
dev_cache);
|
||||
}
|
||||
|
||||
cmd->initialized.filters = 1;
|
||||
return 1;
|
||||
bad:
|
||||
if (!filter) {
|
||||
@ -1310,6 +1291,7 @@ bad:
|
||||
if (cmd->lvmetad_filter)
|
||||
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
|
||||
|
||||
cmd->initialized.filters = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1353,7 +1335,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs if not static */
|
||||
if (!is_static() &&
|
||||
(cn = find_config_tree_node(cmd, global_format_libraries_CFG, NULL))) {
|
||||
(cn = find_config_tree_array(cmd, global_format_libraries_CFG, NULL))) {
|
||||
|
||||
const struct dm_config_value *cv;
|
||||
struct format_type *(*init_format_fn) (struct cmd_context *);
|
||||
@ -1519,7 +1501,7 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs unless static */
|
||||
if (!is_static() &&
|
||||
(cn = find_config_tree_node(cmd, global_segment_libraries_CFG, NULL))) {
|
||||
(cn = find_config_tree_array(cmd, global_segment_libraries_CFG, NULL))) {
|
||||
|
||||
const struct dm_config_value *cv;
|
||||
int (*init_multiple_segtypes_fn) (struct cmd_context *,
|
||||
@ -1683,11 +1665,80 @@ static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *na
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_lvmetad(struct cmd_context *cmd)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
const char *lvmetad_socket;
|
||||
|
||||
lvmetad_disconnect();
|
||||
|
||||
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
|
||||
if (!lvmetad_socket)
|
||||
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
|
||||
|
||||
/* TODO?
|
||||
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
|
||||
DEFAULT_RUN_DIR "/lvmetad.socket");
|
||||
*/
|
||||
|
||||
lvmetad_set_socket(lvmetad_socket);
|
||||
cn = find_config_tree_array(cmd, devices_global_filter_CFG, NULL);
|
||||
lvmetad_set_token(cn ? cn->v : NULL);
|
||||
|
||||
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
|
||||
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
|
||||
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
|
||||
"Clustered environment not supported by lvmetad yet.");
|
||||
lvmetad_set_active(NULL, 0);
|
||||
} else
|
||||
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
||||
|
||||
lvmetad_init(cmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_lvmpolld(struct cmd_context *cmd)
|
||||
{
|
||||
const char *lvmpolld_socket;
|
||||
|
||||
lvmpolld_disconnect();
|
||||
|
||||
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
|
||||
if (!lvmpolld_socket)
|
||||
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
|
||||
lvmpolld_set_socket(lvmpolld_socket);
|
||||
|
||||
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_connections(struct cmd_context *cmd)
|
||||
{
|
||||
|
||||
if (!_init_lvmetad(cmd)) {
|
||||
log_error("Failed to initialize lvmetad connection.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_init_lvmpolld(cmd)) {
|
||||
log_error("Failed to initialize lvmpolld connection.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
cmd->initialized.connections = 1;
|
||||
return 1;
|
||||
bad:
|
||||
cmd->initialized.connections = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
const char *system_dir,
|
||||
unsigned set_buffering,
|
||||
unsigned threaded)
|
||||
unsigned threaded,
|
||||
unsigned set_connections,
|
||||
unsigned set_filters)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
FILE *new_stream;
|
||||
@ -1825,15 +1876,12 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
goto_out;
|
||||
|
||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||
find_config_tree_node(cmd, devices_types_CFG, NULL))))
|
||||
find_config_tree_array(cmd, devices_types_CFG, NULL))))
|
||||
goto_out;
|
||||
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto_out;
|
||||
|
||||
if (!_init_filters(cmd, 1))
|
||||
goto_out;
|
||||
|
||||
memlock_init(cmd);
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
@ -1852,12 +1900,18 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
|
||||
_init_globals(cmd);
|
||||
|
||||
if (set_connections && !init_connections(cmd))
|
||||
return_0;
|
||||
|
||||
if (set_filters && !init_filters(cmd, 1))
|
||||
goto_out;
|
||||
|
||||
cmd->default_settings.cache_vgmetadata = 1;
|
||||
cmd->current_settings = cmd->default_settings;
|
||||
|
||||
cmd->config_initialized = 1;
|
||||
cmd->initialized.config = 1;
|
||||
out:
|
||||
if (!cmd->config_initialized) {
|
||||
if (!cmd->initialized.config) {
|
||||
destroy_toolcontext(cmd);
|
||||
cmd = NULL;
|
||||
}
|
||||
@ -1929,14 +1983,19 @@ static void _destroy_filters(struct cmd_context *cmd)
|
||||
cmd->full_filter->destroy(cmd->full_filter);
|
||||
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
|
||||
}
|
||||
cmd->initialized.filters = 0;
|
||||
}
|
||||
|
||||
int refresh_filters(struct cmd_context *cmd)
|
||||
{
|
||||
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
|
||||
|
||||
if (!cmd->initialized.filters)
|
||||
/* if filters not initialized, there's nothing to refresh */
|
||||
return 1;
|
||||
|
||||
_destroy_filters(cmd);
|
||||
if (!(r = _init_filters(cmd, 0)))
|
||||
if (!(r = init_filters(cmd, 0)))
|
||||
stack;
|
||||
|
||||
/*
|
||||
@ -1965,7 +2024,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
_destroy_filters(cmd);
|
||||
|
||||
if (!dev_cache_exit())
|
||||
stack;
|
||||
@ -1983,7 +2041,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
|
||||
_destroy_config(cmd);
|
||||
|
||||
cmd->config_initialized = 0;
|
||||
cmd->initialized.config = 0;
|
||||
|
||||
cmd->hosttags = 0;
|
||||
|
||||
@ -2040,15 +2098,12 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
return_0;
|
||||
|
||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||
find_config_tree_node(cmd, devices_types_CFG, NULL))))
|
||||
find_config_tree_array(cmd, devices_types_CFG, NULL))))
|
||||
return_0;
|
||||
|
||||
if (!_init_dev_cache(cmd))
|
||||
return_0;
|
||||
|
||||
if (!_init_filters(cmd, 0))
|
||||
return_0;
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
return_0;
|
||||
|
||||
@ -2061,7 +2116,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_backup(cmd))
|
||||
return_0;
|
||||
|
||||
cmd->config_initialized = 1;
|
||||
cmd->initialized.config = 1;
|
||||
|
||||
if (cmd->initialized.connections && !init_connections(cmd))
|
||||
return_0;
|
||||
|
||||
if (!refresh_filters(cmd))
|
||||
return_0;
|
||||
|
||||
reset_lvm_errno(1);
|
||||
return 1;
|
||||
|
@ -60,29 +60,59 @@ struct config_tree_list {
|
||||
struct dm_config_tree *cft;
|
||||
};
|
||||
|
||||
struct cmd_context_initialized_parts {
|
||||
unsigned config:1; /* used to reinitialize config if previous init was not successful */
|
||||
unsigned filters:1;
|
||||
unsigned connections:1;
|
||||
};
|
||||
|
||||
/* FIXME Split into tool & library contexts */
|
||||
/* command-instance-related variables needed by library */
|
||||
struct cmd_context {
|
||||
struct dm_pool *libmem; /* For permanent config data */
|
||||
struct dm_pool *mem; /* Transient: Cleared between each command */
|
||||
/*
|
||||
* Memory handlers.
|
||||
*/
|
||||
struct dm_pool *libmem; /* for permanent config data */
|
||||
struct dm_pool *mem; /* transient: cleared between each command */
|
||||
|
||||
const struct format_type *fmt; /* Current format to use by default */
|
||||
struct format_type *fmt_backup; /* Format to use for backups */
|
||||
|
||||
struct dm_list formats; /* Available formats */
|
||||
struct dm_list segtypes; /* Available segment types */
|
||||
const char *system_id;
|
||||
const char *hostname;
|
||||
const char *kernel_vsn;
|
||||
|
||||
unsigned rand_seed;
|
||||
char *linebuffer;
|
||||
/*
|
||||
* Command line and arguments.
|
||||
*/
|
||||
const char *cmd_line;
|
||||
struct command *command;
|
||||
char **argv;
|
||||
struct arg_values *arg_values;
|
||||
struct dm_list arg_value_groups;
|
||||
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
|
||||
|
||||
/*
|
||||
* Format handlers.
|
||||
*/
|
||||
const struct format_type *fmt; /* current format to use by default */
|
||||
struct format_type *fmt_backup; /* format to use for backups */
|
||||
struct dm_list formats; /* available formats */
|
||||
struct dm_list segtypes; /* available segment types */
|
||||
|
||||
/*
|
||||
* Machine and system identification.
|
||||
*/
|
||||
const char *system_id;
|
||||
const char *hostname;
|
||||
const char *kernel_vsn;
|
||||
|
||||
/*
|
||||
* Device identification.
|
||||
*/
|
||||
struct dev_types *dev_types; /* recognized extra device types. */
|
||||
|
||||
/*
|
||||
* Initialization state.
|
||||
*/
|
||||
struct cmd_context_initialized_parts initialized;
|
||||
|
||||
/*
|
||||
* Switches.
|
||||
*/
|
||||
unsigned is_long_lived:1; /* optimises persistent_filter handling */
|
||||
unsigned handles_missing_pvs:1;
|
||||
unsigned handles_unknown_segments:1;
|
||||
unsigned use_linear_target:1;
|
||||
@ -93,73 +123,73 @@ struct cmd_context {
|
||||
unsigned report_binary_values_as_numeric:1;
|
||||
unsigned metadata_read_only:1;
|
||||
unsigned ignore_clustered_vgs:1;
|
||||
unsigned threaded:1; /* Set if running within a thread e.g. clvmd */
|
||||
|
||||
const char *time_format;
|
||||
|
||||
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
|
||||
unsigned threaded:1; /* set if running within a thread e.g. clvmd */
|
||||
unsigned independent_metadata_areas:1; /* active formats have MDAs outside PVs */
|
||||
unsigned unknown_system_id:1;
|
||||
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
|
||||
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
|
||||
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
|
||||
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
|
||||
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
|
||||
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
|
||||
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
|
||||
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
|
||||
unsigned lockd_gl_disable:1;
|
||||
unsigned lockd_vg_disable:1;
|
||||
unsigned lockd_lv_disable:1;
|
||||
unsigned lockd_gl_removed:1;
|
||||
unsigned lockd_vg_rescan:1;
|
||||
unsigned lockd_vg_default_sh:1;
|
||||
|
||||
struct dev_types *dev_types;
|
||||
unsigned lockd_vg_enforce_sh:1;
|
||||
|
||||
/*
|
||||
* Use of filters depends on whether lvmetad is used or not:
|
||||
*
|
||||
* - if lvmetad is used:
|
||||
* - cmd->lvmetad_filter used when scanning devices for lvmetad
|
||||
* - cmd->filter used when processing lvmetad responses
|
||||
* - cmd->full_filter used for remaining situations
|
||||
*
|
||||
* - if lvmetad is not used:
|
||||
* - cmd->lvmetad_filter is NULL
|
||||
* - cmd->filter == cmd->full_filter used for all situations
|
||||
*
|
||||
* Filtering.
|
||||
*/
|
||||
struct dev_filter *lvmetad_filter;
|
||||
struct dev_filter *filter;
|
||||
struct dev_filter *full_filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
struct dev_filter *lvmetad_filter; /* pre-lvmetad filter chain */
|
||||
struct dev_filter *filter; /* post-lvmetad filter chain */
|
||||
struct dev_filter *full_filter; /* lvmetad_filter + filter */
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
|
||||
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
||||
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
|
||||
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
int config_initialized; /* used to reinitialize config if previous init was not successful */
|
||||
|
||||
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
|
||||
|
||||
/* selected settings with original default/configured value which can be changed during cmd processing */
|
||||
struct config_info default_settings;
|
||||
/* may contain changed values compared to default_settings */
|
||||
struct config_info current_settings;
|
||||
/*
|
||||
* Configuration.
|
||||
*/
|
||||
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
||||
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
|
||||
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
|
||||
struct config_info default_settings; /* selected settings with original default/configured value which can be changed during cmd processing */
|
||||
struct config_info current_settings; /* may contain changed values compared to default_settings */
|
||||
|
||||
/*
|
||||
* Archives and backups.
|
||||
*/
|
||||
struct archive_params *archive_params;
|
||||
struct backup_params *backup_params;
|
||||
const char *stripe_filler;
|
||||
|
||||
/* List of defined tags */
|
||||
struct dm_list tags;
|
||||
const char *report_list_item_separator;
|
||||
/*
|
||||
* Host tags.
|
||||
*/
|
||||
struct dm_list tags; /* list of defined tags */
|
||||
int hosttags;
|
||||
|
||||
/* Locking */
|
||||
const char *lock_gl_mode; /* gl mode, from --lock-gl */
|
||||
const char *lock_vg_mode; /* vg mode, from --lock-vg */
|
||||
const char *lock_lv_mode; /* lv mode, from --lock-lv */
|
||||
|
||||
const char *lib_dir; /* Cache value global/library_dir */
|
||||
/*
|
||||
* Paths.
|
||||
*/
|
||||
const char *lib_dir; /* cache value global/library_dir */
|
||||
char system_dir[PATH_MAX];
|
||||
char dev_dir[PATH_MAX];
|
||||
char proc_dir[PATH_MAX];
|
||||
char display_buffer[NAME_LEN * 10]; /* Ring buffer for upto 10 longest vg/lv names */
|
||||
unsigned display_lvname_idx; /* Index to ring buffer */
|
||||
|
||||
/*
|
||||
* Buffers.
|
||||
*/
|
||||
char display_buffer[NAME_LEN * 10]; /* ring buffer for upto 10 longest vg/lv names */
|
||||
unsigned display_lvname_idx; /* index to ring buffer */
|
||||
char *linebuffer;
|
||||
|
||||
/*
|
||||
* Others - unsorted.
|
||||
*/
|
||||
const char *report_list_item_separator;
|
||||
const char *time_format;
|
||||
unsigned rand_seed;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -169,13 +199,17 @@ struct cmd_context {
|
||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
const char *system_dir,
|
||||
unsigned set_buffering,
|
||||
unsigned threaded);
|
||||
unsigned threaded,
|
||||
unsigned set_connections,
|
||||
unsigned set_filters);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_filters(struct cmd_context *cmd);
|
||||
int process_profilable_config(struct cmd_context *cmd);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
int init_lvmcache_orphans(struct cmd_context *cmd);
|
||||
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
|
||||
int init_connections(struct cmd_context *cmd);
|
||||
|
||||
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);
|
||||
|
||||
|
@ -581,8 +581,11 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_open_readonly_buffered(cf->dev))
|
||||
if (!dev_open_readonly_buffered(cf->dev)) {
|
||||
dev_destroy_file(cf->dev);
|
||||
cf->dev = NULL;
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
|
||||
@ -666,14 +669,18 @@ static void _log_type_error(const char *path, cfg_def_type_t actual,
|
||||
actual_type_name, expected_type_name);
|
||||
}
|
||||
|
||||
static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
||||
static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
|
||||
struct dm_config_tree *cft,
|
||||
const cfg_def_item_t *def,
|
||||
uint32_t format_flags)
|
||||
{
|
||||
const char *def_enc_value;
|
||||
char *enc_value, *token, *p, *r;
|
||||
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
|
||||
|
||||
if (!def->default_value.v_CFG_TYPE_STRING) {
|
||||
def_enc_value = cfg_def_get_default_value(cmd, def, CFG_TYPE_ARRAY, NULL);
|
||||
|
||||
if (!def_enc_value) {
|
||||
if (!(array = dm_config_create_value(cft))) {
|
||||
log_error("Failed to create default empty array for %s.", def->name);
|
||||
return NULL;
|
||||
@ -683,7 +690,7 @@ static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
||||
return array;
|
||||
}
|
||||
|
||||
if (!(p = token = enc_value = dm_strdup(def->default_value.v_CFG_TYPE_STRING))) {
|
||||
if (!(p = token = enc_value = dm_strdup(def_enc_value))) {
|
||||
log_error("_get_def_array_values: dm_strdup failed");
|
||||
return NULL;
|
||||
}
|
||||
@ -844,7 +851,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
|
||||
}
|
||||
|
||||
if (!v_def && (def->type & CFG_TYPE_ARRAY)) {
|
||||
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cft, def, 0)))
|
||||
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cmd, handle->cft, def, 0)))
|
||||
return_0;
|
||||
do {
|
||||
/* iterate over each element of the array and check its value */
|
||||
@ -1036,9 +1043,14 @@ static int _config_def_check_tree(struct cft_check_handle *handle,
|
||||
size_t buf_size, struct dm_config_node *root)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
cfg_def_item_t *def;
|
||||
int valid, r = 1;
|
||||
size_t len;
|
||||
|
||||
def = cfg_def_get_item_p(root->id);
|
||||
if (def->flags & CFG_SECTION_NO_CHECK)
|
||||
return 1;
|
||||
|
||||
for (cn = root->child; cn; cn = cn->sib) {
|
||||
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
|
||||
buf_size, cn)) && !cn->v) {
|
||||
@ -1360,6 +1372,106 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct dm_config_node *_get_array_def_node(struct cmd_context *cmd,
|
||||
cfg_def_item_t *def,
|
||||
struct profile *profile)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
|
||||
if (def->flags & CFG_DEFAULT_UNDEFINED)
|
||||
return NULL;
|
||||
|
||||
if (!(cn = dm_config_create_node(cmd->cft, def->name))) {
|
||||
log_error("Failed to create default array node for %s.", def->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(cn->v = _get_def_array_values(cmd, cmd->cft, def, 0))) {
|
||||
dm_pool_free(cmd->cft->mem, cn);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
struct _config_array_out_handle {
|
||||
struct dm_pool *mem;
|
||||
char *str;
|
||||
};
|
||||
|
||||
static int _config_array_line(const struct dm_config_node *cn, const char *line, void *baton)
|
||||
{
|
||||
struct _config_array_out_handle *handle = (struct _config_array_out_handle *) baton;
|
||||
|
||||
if (!(handle->str = dm_pool_strdup(handle->mem, line))) {
|
||||
log_error("_config_array_line: dm_pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _log_array_value_used(struct dm_pool *mem, const struct dm_config_node *cn,
|
||||
const char *path, int default_used)
|
||||
{
|
||||
struct _config_array_out_handle out_handle = { 0 };
|
||||
struct dm_config_node_out_spec out_spec = { 0 };
|
||||
uint32_t old_format_flags;
|
||||
|
||||
out_handle.mem = mem;
|
||||
out_spec.line_fn = _config_array_line;
|
||||
|
||||
old_format_flags = dm_config_value_get_format_flags(cn->v);
|
||||
dm_config_value_set_format_flags(cn->v,
|
||||
DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES |
|
||||
DM_CONFIG_VALUE_FMT_COMMON_ARRAY);
|
||||
|
||||
if (!dm_config_write_one_node_out(cn, &out_spec, &out_handle)) {
|
||||
log_error("_log_array_value_used: failed to write node value");
|
||||
out_handle.mem = NULL;
|
||||
}
|
||||
|
||||
if (default_used)
|
||||
log_very_verbose("%s not found in config: defaulting to %s",
|
||||
path, out_handle.mem ? out_handle.str : "<unknown>");
|
||||
else
|
||||
log_very_verbose("Setting %s to %s",
|
||||
path, out_handle.mem ? out_handle.str : "<unknown>");
|
||||
|
||||
if (out_handle.mem)
|
||||
dm_pool_free(out_handle.mem, out_handle.str);
|
||||
dm_config_value_set_format_flags(cn->v, old_format_flags);
|
||||
}
|
||||
|
||||
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
int profile_applied;
|
||||
const struct dm_config_node *cn = NULL, *cn_def = NULL;
|
||||
profile_applied = _apply_local_profile(cmd, profile);
|
||||
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||
|
||||
if (!(item->type & CFG_TYPE_ARRAY))
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as array.", path);
|
||||
|
||||
if (_config_disabled(cmd, item, path) ||
|
||||
!(cn = find_config_tree_node(cmd, id, profile)))
|
||||
cn_def = _get_array_def_node(cmd, item, profile);
|
||||
|
||||
if (cn)
|
||||
_log_array_value_used(cmd->cft->mem, cn, path, 0);
|
||||
else if (cn_def) {
|
||||
_log_array_value_used(cmd->cft->mem, cn_def, path, 1);
|
||||
cn = cn_def;
|
||||
}
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
/* Insert cn2 after cn1 */
|
||||
static void _insert_config_node(struct dm_config_node **cn1,
|
||||
struct dm_config_node *cn2)
|
||||
@ -1558,14 +1670,9 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
char commentline[MAX_COMMENT_LINE+1];
|
||||
|
||||
if (cn->id < 0)
|
||||
if (cn->id <= 0)
|
||||
return 1;
|
||||
|
||||
if (!cn->id) {
|
||||
log_error(INTERNAL_ERROR "Configuration node %s has invalid id.", cn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
|
||||
return 1;
|
||||
|
||||
@ -1587,6 +1694,11 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
if (cfg_def->comment) {
|
||||
int pos = 0;
|
||||
while (_copy_one_line(cfg_def->comment, commentline, &pos, strlen(cfg_def->comment))) {
|
||||
if ((commentline[0] == '#') && (strlen(commentline) == 1)) {
|
||||
if (!out->tree_spec->withspaces)
|
||||
continue;
|
||||
commentline[0] = '\0';
|
||||
}
|
||||
fprintf(out->fp, "%s# %s\n", line, commentline);
|
||||
/* withsummary prints only the first comment line. */
|
||||
if (!out->tree_spec->withcomments)
|
||||
@ -1609,6 +1721,9 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
if (cfg_def->flags & CFG_DEFAULT_UNDEFINED)
|
||||
fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name);
|
||||
|
||||
if (cfg_def->flags & CFG_DEFAULT_COMMENTED)
|
||||
fprintf(out->fp, "%s# This configuration %s has an automatic default value.\n", line, node_type_name);
|
||||
|
||||
if ((out->tree_spec->type == CFG_DEF_TREE_FULL) &&
|
||||
(out->tree_spec->check_status[cn->id] & CFG_USED))
|
||||
fprintf(out->fp, "%s# Value defined in existing configuration has been used for this setting.\n", line);
|
||||
@ -1826,7 +1941,7 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
if (spec->withspaces)
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_ARRAY;
|
||||
cn->v = _get_def_array_values(cft, def, format_flags);
|
||||
cn->v = _get_def_array_values(spec->cmd, cft, def, format_flags);
|
||||
}
|
||||
|
||||
cn->child = NULL;
|
||||
|
@ -50,7 +50,7 @@ struct profile_params {
|
||||
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
||||
};
|
||||
|
||||
#define CFG_PATH_MAX_LEN 64
|
||||
#define CFG_PATH_MAX_LEN 128
|
||||
|
||||
/*
|
||||
* Structures used for definition of a configuration tree.
|
||||
@ -121,6 +121,8 @@ typedef union {
|
||||
#define CFG_DISABLED 0x200
|
||||
/* whether to print integers in octal form (prefixed by "0") */
|
||||
#define CFG_FORMAT_INT_OCTAL 0x400
|
||||
/* whether to disable checks for the whole config section subtree */
|
||||
#define CFG_SECTION_NO_CHECK 0x800
|
||||
|
||||
/* configuration definition item structure */
|
||||
typedef struct cfg_def_item {
|
||||
@ -272,6 +274,7 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
|
||||
int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
|
||||
/*
|
||||
* Functions for configuration settings for which the default
|
||||
@ -293,5 +296,7 @@ int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, str
|
||||
#define get_default_unconfigured_allocation_thin_pool_chunk_size_CFG NULL
|
||||
int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
|
||||
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_policy_CFG NULL
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@
|
||||
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
||||
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
||||
#define DEFAULT_WAIT_FOR_LOCKS 1
|
||||
#define DEFAULT_LOCK_RETRIES 3
|
||||
#define DEFAULT_LVMLOCKD_LOCK_RETRIES 3
|
||||
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
|
||||
#define DEFAULT_USE_MLOCKALL 0
|
||||
#define DEFAULT_METADATA_READ_ONLY 0
|
||||
@ -63,6 +63,8 @@
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
#define DEFAULT_RAID_MAX_IMAGES 8
|
||||
|
||||
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
||||
|
||||
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
|
||||
@ -88,8 +90,8 @@
|
||||
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1
|
||||
#endif
|
||||
|
||||
#define DEFAULT_THIN_REPAIR_OPTIONS ""
|
||||
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG NULL
|
||||
#define DEFAULT_THIN_REPAIR_OPTION1 ""
|
||||
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
|
||||
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||
@ -101,16 +103,24 @@
|
||||
#define DEFAULT_THIN_POOL_ZERO 1
|
||||
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
||||
|
||||
#define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
#define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG NULL
|
||||
#ifdef CACHE_CHECK_NEEDS_CHECK
|
||||
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_CACHE_CHECK_OPTION2 "--clear-needs-check-flag"
|
||||
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1 "#S" DEFAULT_CACHE_CHECK_OPTION2
|
||||
#else
|
||||
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_CACHE_CHECK_OPTION2 ""
|
||||
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1
|
||||
#endif
|
||||
|
||||
#define DEFAULT_CACHE_REPAIR_OPTION1 ""
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
|
||||
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||
#define DEFAULT_CACHE_POOL_CACHEMODE "writethrough"
|
||||
#define DEFAULT_CACHE_POOL_POLICY "mq"
|
||||
#define DEFAULT_CACHE_POLICY "mq"
|
||||
#define DEFAULT_CACHE_MODE "writethrough"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
@ -144,11 +154,6 @@
|
||||
# define DEFAULT_LOG_FACILITY LOG_USER
|
||||
#endif
|
||||
|
||||
#define DEFAULT_LOGGED_DEBUG_CLASSES (LOG_CLASS_MEM | LOG_CLASS_DEVS | \
|
||||
LOG_CLASS_ACTIVATION | LOG_CLASS_ALLOC | LOG_CLASS_LVMETAD | \
|
||||
LOG_CLASS_METADATA | LOG_CLASS_CACHE | LOG_CLASS_LOCKING | \
|
||||
LOG_CLASS_LVMPOLLD)
|
||||
|
||||
#define DEFAULT_SYSLOG 1
|
||||
#define DEFAULT_VERBOSE 0
|
||||
#define DEFAULT_SILENT 0
|
||||
@ -196,6 +201,8 @@
|
||||
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
|
||||
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
|
||||
|
||||
#define DEFAULT_COMPACT_OUTPUT_COLS ""
|
||||
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
|
@ -16,11 +16,14 @@
|
||||
#include "lib.h"
|
||||
#include "str_list.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
struct dm_list *str_list_create(struct dm_pool *mem)
|
||||
{
|
||||
struct dm_list *sl;
|
||||
|
||||
if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) {
|
||||
if (!(sl = mem ? dm_pool_alloc(mem, sizeof(struct dm_list))
|
||||
: dm_malloc(sizeof(struct dm_list)))) {
|
||||
log_errno(ENOMEM, "str_list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@ -37,7 +40,8 @@ static int _str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll,
|
||||
if (!str)
|
||||
return_0;
|
||||
|
||||
if (!(sln = dm_pool_alloc(mem, sizeof(*sln))))
|
||||
if (!(sln = mem ? dm_pool_alloc(mem, sizeof(*sln))
|
||||
: dm_malloc(sizeof(*sln))))
|
||||
return_0;
|
||||
|
||||
sln->str = str;
|
||||
@ -158,3 +162,101 @@ int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list,
|
||||
const char *delim)
|
||||
{
|
||||
size_t delim_len = strlen(delim);
|
||||
unsigned list_size = dm_list_size(list);
|
||||
struct dm_str_list *sl;
|
||||
char *str, *p;
|
||||
size_t len = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
dm_list_iterate_items(sl, list)
|
||||
len += strlen(sl->str);
|
||||
if (list_size > 1)
|
||||
len += ((list_size - 1) * delim_len);
|
||||
|
||||
str = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||
if (!str) {
|
||||
log_error("str_list_to_str: string allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
str[len] = '\0';
|
||||
p = str;
|
||||
|
||||
dm_list_iterate_items(sl, list) {
|
||||
len = strlen(sl->str);
|
||||
memcpy(p, sl->str, len);
|
||||
p += len;
|
||||
|
||||
if (++i != list_size) {
|
||||
memcpy(p, delim, delim_len);
|
||||
p += delim_len;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str,
|
||||
const char *delim, int ignore_multiple_delim)
|
||||
{
|
||||
size_t delim_len = strlen(delim);
|
||||
struct dm_list *list;
|
||||
const char *p1, *p2, *next;
|
||||
char *str_item;
|
||||
size_t len;
|
||||
|
||||
if (!(list = str_list_create(mem))) {
|
||||
log_error("str_to_str_list: string list allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p1 = p2 = str;
|
||||
while (*p1) {
|
||||
if (!(p2 = strstr(p1, delim)))
|
||||
next = p2 = str + strlen(str);
|
||||
else
|
||||
next = p2 + delim_len;
|
||||
|
||||
len = p2 - p1;
|
||||
str_item = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||
if (!str_item) {
|
||||
log_error("str_to_str_list: string list item allocation failed.");
|
||||
goto bad;
|
||||
}
|
||||
memcpy(str_item, p1, len);
|
||||
str_item[len] = '\0';
|
||||
|
||||
if (!str_list_add_no_dup_check(mem, list, str_item))
|
||||
goto_bad;
|
||||
|
||||
if (ignore_multiple_delim) {
|
||||
while (!strncmp(next, delim, delim_len))
|
||||
next += delim_len;
|
||||
}
|
||||
|
||||
p1 = next;
|
||||
}
|
||||
|
||||
return list;
|
||||
bad:
|
||||
if (mem)
|
||||
dm_pool_free(mem, list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void str_list_destroy(struct dm_list *list, int deallocate_strings)
|
||||
{
|
||||
struct dm_str_list *sl, *tmp_sl;
|
||||
|
||||
dm_list_iterate_items_safe(sl, tmp_sl, list) {
|
||||
dm_list_del(&sl->list);
|
||||
if (deallocate_strings)
|
||||
dm_free((char *)sl->str);
|
||||
dm_free(sl);
|
||||
}
|
||||
dm_free(list);
|
||||
}
|
||||
|
@ -30,5 +30,9 @@ int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, c
|
||||
int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2);
|
||||
int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew,
|
||||
const struct dm_list *sllold);
|
||||
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list, const char *delim);
|
||||
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str, const char *delim, int ignore_multiple_delim);
|
||||
/* Only for lists which were *not* allocated from the mem pool! */
|
||||
void str_list_destroy(struct dm_list *list, int deallocate_strings);
|
||||
|
||||
#endif
|
||||
|
@ -71,6 +71,16 @@ static void _dev_init(struct device *dev, int max_error_count)
|
||||
dm_list_init(&dev->open_list);
|
||||
}
|
||||
|
||||
void dev_destroy_file(struct device *dev)
|
||||
{
|
||||
if (!(dev->flags & DEV_ALLOCED))
|
||||
return;
|
||||
|
||||
dm_free((void *) dm_list_item(dev->aliases.n, struct dm_str_list)->str);
|
||||
dm_free(dev->aliases.n);
|
||||
dm_free(dev);
|
||||
}
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct dm_str_list *alias, int use_malloc)
|
||||
{
|
||||
@ -331,11 +341,13 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
if (!dm_list_empty(&dev->aliases)) {
|
||||
oldpath = dm_list_item(dev->aliases.n, struct dm_str_list)->str;
|
||||
prefer_old = _compare_paths(path, oldpath);
|
||||
log_debug_devs("%s: Aliased to %s in device cache%s",
|
||||
path, oldpath, prefer_old ? "" : " (preferred name)");
|
||||
log_debug_devs("%s: Aliased to %s in device cache%s (%d:%d)",
|
||||
path, oldpath, prefer_old ? "" : " (preferred name)",
|
||||
(int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
||||
|
||||
} else
|
||||
log_debug_devs("%s: Added to device cache", path);
|
||||
log_debug_devs("%s: Added to device cache (%d:%d)", path,
|
||||
(int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
||||
|
||||
if (prefer_old)
|
||||
dm_list_add(&dev->aliases, &sl->list);
|
||||
@ -681,10 +693,12 @@ static int _init_preferred_names(struct cmd_context *cmd)
|
||||
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, devices_preferred_names_CFG, NULL)) ||
|
||||
if (!(cn = find_config_tree_array(cmd, devices_preferred_names_CFG, NULL)) ||
|
||||
cn->v->type == DM_CFG_EMPTY_ARRAY) {
|
||||
log_very_verbose("devices/preferred_names not found in config file: "
|
||||
"using built-in preferences");
|
||||
log_very_verbose("devices/preferred_names %s: "
|
||||
"using built-in preferences",
|
||||
cn && cn->v->type == DM_CFG_EMPTY_ARRAY ? "is empty"
|
||||
: "not found in config");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -934,6 +948,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
{
|
||||
struct stat buf;
|
||||
struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
int info_available = 0;
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
@ -943,8 +958,9 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
if (d)
|
||||
dm_hash_remove(_cache.names, name);
|
||||
log_sys_very_verbose("stat", name);
|
||||
return NULL;
|
||||
}
|
||||
d = NULL;
|
||||
} else
|
||||
info_available = 1;
|
||||
|
||||
if (d && (buf.st_rdev != d->dev)) {
|
||||
dm_hash_remove(_cache.names, name);
|
||||
@ -952,7 +968,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
}
|
||||
|
||||
if (!d) {
|
||||
_insert(name, &buf, 0, obtain_device_list_from_udev());
|
||||
_insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev());
|
||||
d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
if (!d) {
|
||||
_full_scan(0);
|
||||
|
111
lib/device/dev-dasd.c
Normal file
111
lib/device/dev-dasd.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "dev-type.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/*
|
||||
* Interface taken from kernel header arch/s390/include/uapi/asm/dasd.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Copyright IBM Corp. 1999, 2000
|
||||
* EMC Symmetrix ioctl Copyright EMC Corporation, 2008
|
||||
* Author.........: Nigel Hislop <hislop_nigel@emc.com>
|
||||
*/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
#define DASD_API_VERSION 6
|
||||
|
||||
/*
|
||||
* struct dasd_information2_t
|
||||
* represents any data about the device, which is visible to userspace.
|
||||
* including foramt and featueres.
|
||||
*/
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64]; /* from read_device_characteristics */
|
||||
char configuration_data[256]; /* from read_configuration_data */
|
||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
||||
unsigned int features; /* dasd features like 'ro',... */
|
||||
unsigned int reserved0; /* reserved for further use ,... */
|
||||
unsigned int reserved1; /* reserved for further use ,... */
|
||||
unsigned int reserved2; /* reserved for further use ,... */
|
||||
unsigned int reserved3; /* reserved for further use ,... */
|
||||
unsigned int reserved4; /* reserved for further use ,... */
|
||||
unsigned int reserved5; /* reserved for further use ,... */
|
||||
unsigned int reserved6; /* reserved for further use ,... */
|
||||
unsigned int reserved7; /* reserved for further use ,... */
|
||||
} dasd_information2_t;
|
||||
|
||||
#define DASD_FORMAT_CDL 2
|
||||
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
|
||||
|
||||
/*
|
||||
* End of included interface.
|
||||
*/
|
||||
|
||||
int dasd_is_cdl_formatted(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
dasd_information2_t dasd_info2;
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
|
||||
if (ioctl(dev->fd, BIODASDINFO2, &dasd_info2)) {
|
||||
log_sys_error("ioctl BIODASDINFO2", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dasd_info2.format == DASD_FORMAT_CDL)
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int dasd_is_cdl_formatted(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -586,12 +586,8 @@ static void _close(struct device *dev)
|
||||
|
||||
log_debug_devs("Closed %s", dev_name(dev));
|
||||
|
||||
if (dev->flags & DEV_ALLOCED) {
|
||||
dm_free((void *) dm_list_item(dev->aliases.n, struct dm_str_list)->
|
||||
str);
|
||||
dm_free(dev->aliases.n);
|
||||
dm_free(dev);
|
||||
}
|
||||
if (dev->flags & DEV_ALLOCED)
|
||||
dev_destroy_file(dev);
|
||||
}
|
||||
|
||||
static int _dev_close(struct device *dev, int immediate)
|
||||
|
@ -363,7 +363,7 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
return 0;
|
||||
|
||||
/* Unpartitioned DASD devices are not supported. */
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
|
||||
return 1;
|
||||
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
@ -528,12 +528,14 @@ static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
|
||||
((flag_list & TYPE_DM_SNAPSHOT_COW) && !strcmp(type, "DM_snapshot_cow")));
|
||||
}
|
||||
|
||||
#define MSG_FAILED_SIG_OFFSET "Failed to get offset of the %s signature on %s."
|
||||
#define MSG_FAILED_SIG_LENGTH "Failed to get length of the %s signature on %s."
|
||||
#define MSG_WIPING_SKIPPED " Wiping skipped."
|
||||
|
||||
static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude, uint32_t types_no_prompt,
|
||||
int yes, force_t force)
|
||||
{
|
||||
static const char _msg_failed_offset[] = "Failed to get offset of the %s signature on %s.";
|
||||
static const char _msg_failed_length[] = "Failed to get length of the %s signature on %s.";
|
||||
static const char _msg_wiping[] = "Wiping %s signature on %s.";
|
||||
const char *offset = NULL, *type = NULL, *magic = NULL,
|
||||
*usage = NULL, *label = NULL, *uuid = NULL;
|
||||
@ -544,21 +546,41 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
if (_type_in_flag_list(type, types_to_exclude))
|
||||
return 2;
|
||||
if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) {
|
||||
log_error(_msg_failed_offset, type, name);
|
||||
return 0;
|
||||
if (force < DONT_PROMPT) {
|
||||
log_error(MSG_FAILED_SIG_OFFSET, type, name);
|
||||
return 0;
|
||||
} else {
|
||||
log_error("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (blkid_probe_lookup_value(probe, "SBMAGIC", &magic, &len)) {
|
||||
log_error(_msg_failed_length, type, name);
|
||||
return 0;
|
||||
if (force < DONT_PROMPT) {
|
||||
log_error(MSG_FAILED_SIG_LENGTH, type, name);
|
||||
return 0;
|
||||
} else {
|
||||
log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
} else if (!blkid_probe_lookup_value(probe, "PTTYPE", &type, NULL)) {
|
||||
if (blkid_probe_lookup_value(probe, "PTMAGIC_OFFSET", &offset, NULL)) {
|
||||
log_error(_msg_failed_offset, type, name);
|
||||
return 0;
|
||||
if (force < DONT_PROMPT) {
|
||||
log_error(MSG_FAILED_SIG_OFFSET, type, name);
|
||||
return 0;
|
||||
} else {
|
||||
log_warn("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (blkid_probe_lookup_value(probe, "PTMAGIC", &magic, &len)) {
|
||||
log_error(_msg_failed_length, type, name);
|
||||
return 0;
|
||||
if (force < DONT_PROMPT) {
|
||||
log_error(MSG_FAILED_SIG_LENGTH, type, name);
|
||||
return 0;
|
||||
} else {
|
||||
log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
usage = "partition table";
|
||||
} else
|
||||
@ -629,8 +651,13 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
|
||||
while (!blkid_do_probe(probe)) {
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1)
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1) {
|
||||
(*wiped)++;
|
||||
if (blkid_probe_step_back(probe)) {
|
||||
log_error("Failed to step back blkid probe to check just wiped signature.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* do not count excluded types */
|
||||
if (r_wipe != 2)
|
||||
found++;
|
||||
@ -712,13 +739,20 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
|
||||
uint32_t types_no_prompt, int yes, force_t force,
|
||||
int *wiped)
|
||||
{
|
||||
int blkid_wiping_enabled = find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL);
|
||||
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
if (find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL))
|
||||
if (blkid_wiping_enabled)
|
||||
return _wipe_known_signatures_with_blkid(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force, wiped);
|
||||
#endif
|
||||
if (blkid_wiping_enabled) {
|
||||
log_warn("allocation/use_blkid_wiping=1 configuration setting is set "
|
||||
"while LVM is not compiled with blkid wiping support.");
|
||||
log_warn("Falling back to native LVM signature detection.");
|
||||
}
|
||||
return _wipe_known_signatures_with_lvm(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
|
@ -59,6 +59,7 @@ int major_is_scsi_device(struct dev_types *dt, int major);
|
||||
int dev_is_md(struct device *dev, uint64_t *sb);
|
||||
int dev_is_swap(struct device *dev, uint64_t *signature);
|
||||
int dev_is_luks(struct device *dev, uint64_t *signature);
|
||||
int dasd_is_cdl_formatted(struct device *dev);
|
||||
|
||||
/* Signature wiping. */
|
||||
#define TYPE_LVM1_MEMBER 0x001
|
||||
|
@ -123,6 +123,7 @@ void dev_flush(struct device *dev);
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct dm_str_list *alias, int use_malloc);
|
||||
void dev_destroy_file(struct device *dev);
|
||||
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||
|
@ -24,10 +24,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
||||
|
||||
static const struct {
|
||||
alloc_policy_t alloc;
|
||||
const char str[14]; /* must be changed when size extends 13 chars */
|
||||
@ -146,164 +142,30 @@ const char *display_lvname(const struct logical_volume *lv)
|
||||
return name;
|
||||
}
|
||||
|
||||
#define BASE_UNKNOWN 0
|
||||
#define BASE_SHARED 1
|
||||
#define BASE_1024 8
|
||||
#define BASE_1000 15
|
||||
#define BASE_SPECIAL 21
|
||||
#define NUM_UNIT_PREFIXES 6
|
||||
#define NUM_SPECIAL 3
|
||||
|
||||
/* Size supplied in sectors */
|
||||
static const char *_display_size(const struct cmd_context *cmd,
|
||||
uint64_t size, size_len_t sl)
|
||||
uint64_t size, dm_size_suffix_t suffix_type)
|
||||
{
|
||||
unsigned base = BASE_UNKNOWN;
|
||||
unsigned s;
|
||||
int suffix, precision;
|
||||
uint64_t byte = UINT64_C(0);
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
const char * const size_str[][3] = {
|
||||
/* BASE_UNKNOWN */
|
||||
{" ", " ", " "}, /* [0] */
|
||||
|
||||
/* BASE_SHARED - Used if cmd->si_unit_consistency = 0 */
|
||||
{" Exabyte", " EB", "E"}, /* [1] */
|
||||
{" Petabyte", " PB", "P"}, /* [2] */
|
||||
{" Terabyte", " TB", "T"}, /* [3] */
|
||||
{" Gigabyte", " GB", "G"}, /* [4] */
|
||||
{" Megabyte", " MB", "M"}, /* [5] */
|
||||
{" Kilobyte", " KB", "K"}, /* [6] */
|
||||
{" Byte ", " B", "B"}, /* [7] */
|
||||
|
||||
/* BASE_1024 - Used if cmd->si_unit_consistency = 1 */
|
||||
{" Exbibyte", " EiB", "e"}, /* [8] */
|
||||
{" Pebibyte", " PiB", "p"}, /* [9] */
|
||||
{" Tebibyte", " TiB", "t"}, /* [10] */
|
||||
{" Gibibyte", " GiB", "g"}, /* [11] */
|
||||
{" Mebibyte", " MiB", "m"}, /* [12] */
|
||||
{" Kibibyte", " KiB", "k"}, /* [13] */
|
||||
{" Byte ", " B", "b"}, /* [14] */
|
||||
|
||||
/* BASE_1000 - Used if cmd->si_unit_consistency = 1 */
|
||||
{" Exabyte", " EB", "E"}, /* [15] */
|
||||
{" Petabyte", " PB", "P"}, /* [16] */
|
||||
{" Terabyte", " TB", "T"}, /* [17] */
|
||||
{" Gigabyte", " GB", "G"}, /* [18] */
|
||||
{" Megabyte", " MB", "M"}, /* [19] */
|
||||
{" Kilobyte", " kB", "K"}, /* [20] */
|
||||
|
||||
/* BASE_SPECIAL */
|
||||
{" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */
|
||||
{" Units ", " Un", "U"}, /* [22] */
|
||||
{" Sectors ", " Se", "S"}, /* [23] */
|
||||
};
|
||||
|
||||
if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) {
|
||||
log_error("no memory for size display buffer");
|
||||
return "";
|
||||
}
|
||||
|
||||
suffix = cmd->current_settings.suffix;
|
||||
|
||||
if (!cmd->si_unit_consistency) {
|
||||
/* Case-independent match */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[BASE_SHARED + s][2]) {
|
||||
base = BASE_SHARED;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Case-dependent match for powers of 1000 */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (cmd->current_settings.unit_type ==
|
||||
*size_str[BASE_1000 + s][2]) {
|
||||
base = BASE_1000;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Case-dependent match for powers of 1024 */
|
||||
if (base == BASE_UNKNOWN)
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (cmd->current_settings.unit_type ==
|
||||
*size_str[BASE_1024 + s][2]) {
|
||||
base = BASE_1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (base == BASE_UNKNOWN)
|
||||
/* Check for special units - s, b or u */
|
||||
for (s = 0; s < NUM_SPECIAL; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[BASE_SPECIAL + s][2]) {
|
||||
base = BASE_SPECIAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == UINT64_C(0)) {
|
||||
if (base == BASE_UNKNOWN)
|
||||
s = 0;
|
||||
sprintf(size_buf, "0%s", suffix ? size_str[base + s][sl] : "");
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
size *= UINT64_C(512);
|
||||
|
||||
if (base != BASE_UNKNOWN)
|
||||
byte = cmd->current_settings.unit_factor;
|
||||
else {
|
||||
/* Human-readable style */
|
||||
if (cmd->current_settings.unit_type == 'H') {
|
||||
units = UINT64_C(1000);
|
||||
base = BASE_1000;
|
||||
} else {
|
||||
units = UINT64_C(1024);
|
||||
base = BASE_1024;
|
||||
}
|
||||
|
||||
if (!cmd->si_unit_consistency)
|
||||
base = BASE_SHARED;
|
||||
|
||||
byte = units * units * units * units * units * units;
|
||||
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
|
||||
byte /= units;
|
||||
|
||||
suffix = 1;
|
||||
}
|
||||
|
||||
/* FIXME Make precision configurable */
|
||||
switch (toupper(*size_str[base + s][SIZE_UNIT])) {
|
||||
case 'B':
|
||||
case 'S':
|
||||
precision = 0;
|
||||
break;
|
||||
default:
|
||||
precision = 2;
|
||||
}
|
||||
|
||||
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
|
||||
(double) size / byte, suffix ? size_str[base + s][sl] : "");
|
||||
|
||||
return size_buf;
|
||||
return dm_size_to_string(cmd->mem, size, cmd->current_settings.unit_type,
|
||||
cmd->si_unit_consistency,
|
||||
cmd->current_settings.unit_factor,
|
||||
cmd->current_settings.suffix,
|
||||
suffix_type);
|
||||
}
|
||||
|
||||
const char *display_size_long(const struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_LONG);
|
||||
return _display_size(cmd, size, DM_SIZE_LONG);
|
||||
}
|
||||
|
||||
const char *display_size_units(const struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_UNIT);
|
||||
return _display_size(cmd, size, DM_SIZE_UNIT);
|
||||
}
|
||||
|
||||
const char *display_size(const struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_SHORT);
|
||||
return _display_size(cmd, size, DM_SIZE_SHORT);
|
||||
}
|
||||
|
||||
void pvdisplay_colons(const struct physical_volume *pv)
|
||||
|
@ -95,7 +95,7 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_error_ops;
|
||||
segtype->name = "error";
|
||||
segtype->name = SEG_TYPE_NAME_ERROR;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
@ -61,6 +61,8 @@ static int _dev_is_fwraid(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping firmware RAID component device"
|
||||
|
||||
static int _ignore_fwraid(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
@ -72,8 +74,11 @@ static int _ignore_fwraid(struct dev_filter *f __attribute__((unused)),
|
||||
ret = _dev_is_fwraid(dev);
|
||||
|
||||
if (ret == 1) {
|
||||
log_debug_devs("%s: Skipping firmware RAID component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping md component device"
|
||||
|
||||
static int _ignore_md(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
@ -29,8 +31,11 @@ static int _ignore_md(struct dev_filter *f __attribute__((unused)),
|
||||
ret = dev_is_md(dev, NULL);
|
||||
|
||||
if (ret == 1) {
|
||||
log_debug_devs("%s: Skipping md component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -244,11 +244,16 @@ static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping mpath component device"
|
||||
|
||||
static int _ignore_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
if (_dev_is_mpath(f, dev) == 1) {
|
||||
log_debug_devs("%s: Skipping mpath component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -16,13 +16,18 @@
|
||||
#include "lib.h"
|
||||
#include "filter.h"
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping: Partition table signature found"
|
||||
|
||||
static int _passes_partitioned_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
|
||||
if (dev_is_partitioned(dt, dev)) {
|
||||
log_debug_devs("%s: Skipping: Partition table signature found [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -29,22 +29,19 @@ static int _native_check_pv_min_size(struct device *dev)
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: Skipping: open failed [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
log_debug_devs("%s: Skipping: open failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's not too small */
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg,
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
log_debug_devs("%s: Skipping: %s", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -115,26 +112,11 @@ static int _passes_usable_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
filter_mode_t mode = *((filter_mode_t *) f->private);
|
||||
struct dev_usable_check_params ucp = {0};
|
||||
int r;
|
||||
|
||||
/* check if the device is not too small to hold a PV */
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
/* fall through */
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
if (!_check_pv_min_size(dev))
|
||||
return 0;
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
}
|
||||
int r = 1;
|
||||
|
||||
/* further checks are done on dm devices only */
|
||||
if (!dm_is_dm_major(MAJOR(dev->dev)))
|
||||
return 1;
|
||||
|
||||
switch (mode) {
|
||||
if (dm_is_dm_major(MAJOR(dev->dev))) {
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
ucp.check_empty = 1;
|
||||
ucp.check_blocked = 1;
|
||||
@ -163,10 +145,25 @@ static int _passes_usable_filter(struct dev_filter *f, struct device *dev)
|
||||
ucp.check_error_target = 0;
|
||||
ucp.check_reserved = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(r = device_is_usable(dev, ucp)))
|
||||
log_debug_devs("%s: Skipping unusable device.", dev_name(dev));
|
||||
}
|
||||
|
||||
if (!(r = device_is_usable(dev, ucp)))
|
||||
log_debug_devs("%s: Skipping unusable device", dev_name(dev));
|
||||
if (r) {
|
||||
/* check if the device is not too small to hold a PV */
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
/* fall through */
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
r = _check_pv_min_size(dev);
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && vg_is_exported(vg)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!*vg->lvm1_system_id ||
|
||||
if (!vg->lvm1_system_id || !*vg->lvm1_system_id ||
|
||||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
|
@ -219,7 +219,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
@ -281,7 +281,7 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
|
||||
total_area_len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
while (first_area_le < total_area_len) {
|
||||
|
@ -188,8 +188,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
|
||||
|
||||
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
|
||||
@ -226,7 +225,7 @@ static int _add_linear_seg(struct dm_pool *mem,
|
||||
unsigned j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
|
@ -453,8 +453,9 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
"not match expected name %s.", vgname);
|
||||
|
||||
bad:
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)) &&
|
||||
!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
|
||||
stack;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -653,7 +654,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if ((new_wrap && old_wrap) ||
|
||||
(rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) ||
|
||||
(mdac->rlocn.size >= mdah->size)) {
|
||||
(MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)) {
|
||||
log_error("VG %s metadata too large for circular buffer",
|
||||
vg->name);
|
||||
goto out;
|
||||
@ -1338,6 +1339,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
|
||||
label = lvmcache_get_label(info);
|
||||
label->sector = pv->label_sector;
|
||||
label->dev = pv->dev;
|
||||
|
||||
lvmcache_update_pv(info, pv, fmt);
|
||||
|
||||
@ -2144,7 +2146,6 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
goto bad;
|
||||
}
|
||||
/* Otherwise, give up and take any usable space. */
|
||||
/* FIXME: We should probably check for some minimum MDA size here. */
|
||||
else
|
||||
mda_size = limit - mda_start;
|
||||
|
||||
@ -2237,10 +2238,16 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
if (limit_applied)
|
||||
log_very_verbose("Using limited metadata area size on %s "
|
||||
"with value %" PRIu64 " (limited by %s of "
|
||||
"%" PRIu64 ").", pv_dev_name(pv),
|
||||
FMTu64 ").", pv_dev_name(pv),
|
||||
mda_size, limit_name, limit);
|
||||
|
||||
if (mda_size) {
|
||||
if (mda_size < MDA_SIZE_MIN) {
|
||||
log_error("Metadata area size too small: %" PRIu64" bytes. "
|
||||
"It must be at least %u bytes.", mda_size, MDA_SIZE_MIN);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Wipe metadata area with zeroes. */
|
||||
if (!dev_set((struct device *) pv->dev, mda_start,
|
||||
(size_t) ((mda_size > wipe_size) ?
|
||||
@ -2491,7 +2498,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if ((cn = find_config_tree_node(cmd, metadata_dirs_CFG, NULL))) {
|
||||
if ((cn = find_config_tree_array(cmd, metadata_dirs_CFG, NULL))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
|
@ -375,7 +375,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype_str = "striped";
|
||||
segtype_str = SEG_TYPE_NAME_STRIPED;
|
||||
|
||||
if (!dm_config_get_str(sn_child, "type", &segtype_str)) {
|
||||
log_error("Segment type must be a string.");
|
||||
@ -600,6 +600,25 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The LV lock_args string is generated in lvmlockd, and the content
|
||||
* depends on the lock_type.
|
||||
*
|
||||
* lock_type dlm does not use LV lock_args, so the LV lock_args field
|
||||
* is just set to "dlm".
|
||||
*
|
||||
* lock_type sanlock uses the LV lock_args field to save the
|
||||
* location on disk of that LV's sanlock lock. The disk name is
|
||||
* specified in the VG lock_args. The lock_args string begins
|
||||
* with a version number, e.g. 1.0.0, followed by a colon, followed
|
||||
* by a number. The number is the offset on disk where sanlock is
|
||||
* told to find the LV's lock.
|
||||
* e.g. lock_args = 1.0.0:70254592
|
||||
* means that the lock is located at offset 70254592.
|
||||
*
|
||||
* The lvmlockd code for each specific lock manager also validates
|
||||
* the lock_args before using it to access the lock manager.
|
||||
*/
|
||||
if (dm_config_get_str(lvn, "lock_args", &str)) {
|
||||
if (!(lv->lock_args = dm_pool_strdup(mem, str)))
|
||||
return_0;
|
||||
@ -828,6 +847,27 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* The VG lock_args string is generated in lvmlockd, and the content
|
||||
* depends on the lock_type. lvmlockd begins the lock_args string
|
||||
* with a version number, e.g. 1.0.0, followed by a colon, followed
|
||||
* by a string that depends on the lock manager. The string after
|
||||
* the colon is information needed to use the lock manager for the VG.
|
||||
*
|
||||
* For sanlock, the string is the name of the internal LV used to store
|
||||
* sanlock locks. lvmlockd needs to know where the locks are located
|
||||
* so it can pass that location to sanlock which needs to access the locks.
|
||||
* e.g. lock_args = 1.0.0:lvmlock
|
||||
* means that the locks are located on the the LV "lvmlock".
|
||||
*
|
||||
* For dlm, the string is the dlm cluster name. lvmlockd needs to use
|
||||
* a dlm lockspace in this cluster to use the VG.
|
||||
* e.g. lock_args = 1.0.0:foo
|
||||
* means that the host needs to be a member of the cluster "foo".
|
||||
*
|
||||
* The lvmlockd code for each specific lock manager also validates
|
||||
* the lock_args before using it to access the lock manager.
|
||||
*/
|
||||
if (dm_config_get_str(vgn, "lock_args", &str)) {
|
||||
if (!(vg->lock_args = dm_pool_strdup(vg->vgmem, str)))
|
||||
goto bad;
|
||||
@ -991,6 +1031,11 @@ static void _read_desc(struct dm_pool *mem,
|
||||
*when = u;
|
||||
}
|
||||
|
||||
/*
|
||||
* It would be more accurate to call this _read_vgsummary().
|
||||
* It is used to read vgsummary information about a VG
|
||||
* before locking and reading the VG via vg_read().
|
||||
*/
|
||||
static int _read_vgname(const struct format_type *fmt, const struct dm_config_tree *cft,
|
||||
struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
@ -1027,6 +1072,8 @@ static int _read_vgname(const struct format_type *fmt, const struct dm_config_tr
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_config_get_str(vgn, "lock_type", &vgsummary->lock_type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct segment_type *init_free_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_freeseg_ops;
|
||||
segtype->name = "free";
|
||||
segtype->name = SEG_TYPE_NAME_FREE;
|
||||
segtype->flags = SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
@ -105,7 +105,8 @@ static void _update_lvmcache_orphan(struct lvmcache_info *info)
|
||||
|
||||
memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
|
||||
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
if (!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
|
||||
stack;
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
|
@ -119,8 +119,9 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cmd, suppress_messages);
|
||||
log_warn("WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
log_warn_suppress(suppress_messages,
|
||||
"WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
return 1;
|
||||
|
||||
case 1:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,8 +17,7 @@
|
||||
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
|
||||
|
||||
/* lockd_gl flags */
|
||||
#define LDGL_SKIP_CACHE_VALIDATE 0x00000001
|
||||
#define LDGL_UPDATE_NAMES 0x00000002
|
||||
#define LDGL_UPDATE_NAMES 0x00000001
|
||||
|
||||
/* lockd_lv flags */
|
||||
#define LDLV_MODE_NO_SH 0x00000001
|
||||
@ -27,10 +26,8 @@
|
||||
/* lvmlockd result flags */
|
||||
#define LD_RF_NO_LOCKSPACES 0x00000001
|
||||
#define LD_RF_NO_GL_LS 0x00000002
|
||||
#define LD_RF_LOCAL_LS 0x00000004
|
||||
#define LD_RF_WARN_GL_REMOVED 0x00000004
|
||||
#define LD_RF_DUP_GL_LS 0x00000008
|
||||
#define LD_RF_INACTIVE_LS 0x00000010
|
||||
#define LD_RF_ADD_LS_ERROR 0x00000020
|
||||
|
||||
/* lockd_state flags */
|
||||
#define LDST_EX 0x00000001
|
||||
@ -54,8 +51,8 @@ void lvmlockd_disconnect(void);
|
||||
|
||||
/* vgcreate/vgremove use init/free */
|
||||
|
||||
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type);
|
||||
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count);
|
||||
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg, int changing);
|
||||
void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
/* vgrename */
|
||||
@ -65,7 +62,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
|
||||
|
||||
/* start and stop the lockspace for a vg */
|
||||
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int start_init);
|
||||
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_start_wait(struct cmd_context *cmd);
|
||||
|
||||
@ -92,7 +89,7 @@ int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
|
||||
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id, const char *lock_args);
|
||||
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd);
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple);
|
||||
|
||||
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
@ -125,12 +122,12 @@ static inline int lvmlockd_use(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type)
|
||||
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static inline int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg, int changing)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -150,7 +147,7 @@ static inline int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_g
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int start_init)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -167,6 +164,14 @@ static inline int lockd_start_wait(struct cmd_context *cmd)
|
||||
|
||||
static inline int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type)
|
||||
{
|
||||
/*
|
||||
* When lvm is built without lvmlockd support, creating a VG with
|
||||
* a shared lock type should fail.
|
||||
*/
|
||||
if (is_lockd_type(vg_lock_type)) {
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -218,8 +223,9 @@ static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple)
|
||||
{
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* No locking
|
||||
*/
|
||||
|
@ -36,7 +36,7 @@ static int _indent = 1;
|
||||
static int _log_suppress = 0;
|
||||
static char _msg_prefix[30] = " ";
|
||||
static int _already_logging = 0;
|
||||
static int _abort_on_internal_errors = 0;
|
||||
static int _abort_on_internal_errors_config = 0;
|
||||
|
||||
static lvm2_log_fn_t _lvm2_log_fn = NULL;
|
||||
|
||||
@ -49,10 +49,7 @@ static size_t _lvm_errmsg_len = 0;
|
||||
|
||||
void init_log_fn(lvm2_log_fn_t log_fn)
|
||||
{
|
||||
if (log_fn)
|
||||
_lvm2_log_fn = log_fn;
|
||||
else
|
||||
_lvm2_log_fn = NULL;
|
||||
_lvm2_log_fn = log_fn;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -69,7 +66,7 @@ void init_log_file(const char *log_file, int append)
|
||||
static const char statfile[] = "/proc/self/stat";
|
||||
const char *env;
|
||||
int pid;
|
||||
long long starttime;
|
||||
unsigned long long starttime;
|
||||
FILE *st;
|
||||
int i = 0;
|
||||
|
||||
@ -92,9 +89,6 @@ void init_log_file(const char *log_file, int append)
|
||||
"%llu", &pid, &starttime) != 2) {
|
||||
log_warn("WARNING: Cannot parse content of %s.", statfile);
|
||||
} else {
|
||||
if (fclose(st))
|
||||
log_sys_debug("fclose", statfile);
|
||||
|
||||
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
|
||||
"%s_%s_%d_%lld", log_file, env, pid, starttime) < 0) {
|
||||
log_warn("WARNING: Debug log file path is too long for epoch.");
|
||||
@ -104,7 +98,11 @@ void init_log_file(const char *log_file, int append)
|
||||
append = 1; /* force */
|
||||
}
|
||||
}
|
||||
|
||||
if (st && fclose(st))
|
||||
log_sys_debug("fclose", statfile);
|
||||
}
|
||||
|
||||
no_epoch:
|
||||
if (!(_log_file = fopen(log_file, append ? "a" : "w"))) {
|
||||
log_sys_error("fopen", log_file);
|
||||
@ -217,9 +215,10 @@ void init_indent(int indent)
|
||||
_indent = indent;
|
||||
}
|
||||
|
||||
/* If present, environment setting will override this. */
|
||||
void init_abort_on_internal_errors(int fatal)
|
||||
{
|
||||
_abort_on_internal_errors = fatal;
|
||||
_abort_on_internal_errors_config = fatal;
|
||||
}
|
||||
|
||||
void reset_lvm_errno(int store_errmsg)
|
||||
@ -276,10 +275,24 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
size_t msglen;
|
||||
const char *indent_spaces = "";
|
||||
FILE *stream;
|
||||
static int _abort_on_internal_errors_env_present = -1;
|
||||
static int _abort_on_internal_errors_env = 0;
|
||||
char *env_str;
|
||||
|
||||
level &= ~(_LOG_STDERR|_LOG_ONCE);
|
||||
|
||||
if (_abort_on_internal_errors &&
|
||||
if (_abort_on_internal_errors_env_present < 0) {
|
||||
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
|
||||
_abort_on_internal_errors_env_present = 1;
|
||||
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
|
||||
_abort_on_internal_errors_env = strcmp(env_str, "0");
|
||||
} else
|
||||
_abort_on_internal_errors_env_present = 0;
|
||||
}
|
||||
|
||||
/* Use value from environment if present, otherwise use value from config. */
|
||||
if (((_abort_on_internal_errors_env_present && _abort_on_internal_errors_env) ||
|
||||
(!_abort_on_internal_errors_env_present && _abort_on_internal_errors_config)) &&
|
||||
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1)) {
|
||||
fatal_internal_error = 1;
|
||||
/* Internal errors triggering abort cannot be suppressed. */
|
||||
|
@ -37,8 +37,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* FILE */
|
||||
#include <string.h> /* strerror() */
|
||||
#include <errno.h>
|
||||
|
||||
#define EUNCLASSIFIED -1 /* Generic error code */
|
||||
|
@ -16,9 +16,9 @@
|
||||
#ifndef _LVM_LOGGING_H
|
||||
#define _LVM_LOGGING_H
|
||||
|
||||
__attribute__ ((format(printf, 5, 6)))
|
||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
const char *format, ...)
|
||||
__attribute__ ((format(printf, 5, 6)));
|
||||
const char *format, ...);
|
||||
|
||||
#define LOG_LINE(l, x...) \
|
||||
print_log(l, __FILE__, __LINE__ , 0, ## x)
|
||||
|
@ -106,6 +106,7 @@ static void _explain_error_codes(int retcode)
|
||||
/* lvmpolld specific return codes */
|
||||
case LVMPD_RET_DUP_FAILED:
|
||||
log_error("lvmpolld failed to duplicate file descriptors.");
|
||||
/* fall through */
|
||||
case LVMPD_RET_EXC_FAILED:
|
||||
log_error("lvmpolld failed to exec() lvm binary.");
|
||||
break;
|
||||
@ -146,7 +147,7 @@ static struct progress_info _request_progress_info(const char *uuid, unsigned ab
|
||||
}
|
||||
|
||||
if (abort_polling &&
|
||||
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", abort_polling, NULL)) {
|
||||
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)abort_polling, NULL)) {
|
||||
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
|
||||
goto out_req;
|
||||
}
|
||||
@ -227,14 +228,14 @@ static int _process_poll_init(const struct cmd_context *cmd, const char *poll_ty
|
||||
}
|
||||
|
||||
if (parms->aborting &&
|
||||
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", parms->aborting, NULL))) {
|
||||
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)(parms->aborting), NULL))) {
|
||||
log_error("Failed to create %s request." , poll_type);
|
||||
goto out_req;
|
||||
}
|
||||
|
||||
if (cmd->handles_missing_pvs &&
|
||||
!(daemon_request_extend(req, LVMPD_PARM_HANDLE_MISSING_PVS " = %d",
|
||||
cmd->handles_missing_pvs, NULL))) {
|
||||
(int64_t)(cmd->handles_missing_pvs), NULL))) {
|
||||
log_error("Failed to create %s request." , poll_type);
|
||||
goto out_req;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -29,7 +29,17 @@
|
||||
#define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
|
||||
#define DM_MAX_HINT_WIDTH (4+16) /* bytes. FIXME Configurable? */
|
||||
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
int cache_mode_is_set(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
return (seg->feature_flags & (DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH)) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *get_cache_mode_name(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
|
||||
return "writeback";
|
||||
@ -46,22 +56,68 @@ const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str)
|
||||
int cache_set_mode(struct lv_segment *seg, const char *str)
|
||||
{
|
||||
struct cmd_context *cmd = seg->lv->vg->cmd;
|
||||
int id;
|
||||
uint64_t mode;
|
||||
|
||||
if (!str && !seg_is_cache(seg))
|
||||
return 1; /* Defaults only for cache */
|
||||
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (!str) {
|
||||
if (cache_mode_is_set(seg))
|
||||
return 1; /* Default already set in cache pool */
|
||||
|
||||
id = allocation_cache_mode_CFG;
|
||||
|
||||
/* If present, check backward compatible settings */
|
||||
if (!find_config_node(cmd, cmd->cft, id) &&
|
||||
find_config_node(cmd, cmd->cft, allocation_cache_pool_cachemode_CFG))
|
||||
id = allocation_cache_pool_cachemode_CFG;
|
||||
|
||||
str = find_config_tree_str(cmd, id, NULL);
|
||||
}
|
||||
|
||||
if (!strcmp(str, "writeback"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
mode = DM_CACHE_FEATURE_WRITEBACK;
|
||||
else if (!strcmp(str, "writethrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passhrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
mode = DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passthrough"))
|
||||
mode = DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
else {
|
||||
log_error("Cache pool feature \"%s\" is unknown.", str);
|
||||
log_error("Cannot set unknown cache mode \"%s\".", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->feature_flags &= ~(DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH);
|
||||
seg->feature_flags |= mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* At least warn a user if certain cache stacks may present some problems
|
||||
*/
|
||||
void cache_check_for_warns(const struct lv_segment *seg)
|
||||
{
|
||||
struct logical_volume *origin_lv = seg_lv(seg, 0);
|
||||
|
||||
if (lv_is_raid(origin_lv) &&
|
||||
first_seg(seg->pool_lv)->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
|
||||
log_warn("WARNING: Data redundancy is lost with writeback "
|
||||
"caching of raid logical volume!");
|
||||
|
||||
if (lv_is_thin_pool_data(seg->lv))
|
||||
log_warn("WARNING: Cached thin pool's data cannot be currently "
|
||||
"resized and require manual uncache before resize!");
|
||||
}
|
||||
|
||||
int update_cache_pool_params(const struct segment_type *segtype,
|
||||
struct volume_group *vg, unsigned attr,
|
||||
int passed_args, uint32_t pool_data_extents,
|
||||
@ -205,7 +261,7 @@ struct logical_volume *lv_cache_create(struct logical_volume *pool_lv,
|
||||
if (lv_is_thin_pool(cache_lv))
|
||||
cache_lv = seg_lv(first_seg(cache_lv), 0); /* cache _tdata */
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "cache")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE)))
|
||||
return_NULL;
|
||||
|
||||
if (!insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig"))
|
||||
@ -322,7 +378,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
|
||||
dirty_blocks = status->cache->dirty_blocks;
|
||||
dm_pool_destroy(status->mem);
|
||||
if (dirty_blocks) {
|
||||
log_print_unless_silent("%" PRIu64 " blocks must still be flushed.",
|
||||
log_print_unless_silent(FMTu64 " blocks must still be flushed.",
|
||||
dirty_blocks);
|
||||
sleep(1);
|
||||
}
|
||||
@ -351,7 +407,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
|
||||
|
||||
/* Replace 'error' with 'cache' segtype */
|
||||
cache_seg = first_seg(corigin_lv);
|
||||
if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, "cache")))
|
||||
if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, SEG_TYPE_NAME_CACHE)))
|
||||
return_0;
|
||||
|
||||
if (!(cache_seg->areas = dm_pool_zalloc(cache_lv->vg->vgmem, sizeof(*cache_seg->areas))))
|
||||
@ -395,36 +451,104 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
|
||||
}
|
||||
|
||||
int lv_cache_setpolicy(struct logical_volume *lv, struct dm_config_tree *policy)
|
||||
static const char *_get_default_cache_policy(struct cmd_context *cmd)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
const char *name;
|
||||
struct dm_config_node *cn;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE);
|
||||
unsigned attr = ~0;
|
||||
const char *def = NULL;
|
||||
|
||||
if (lv_is_cache(lv))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = policy->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = policy = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
if (!segtype ||
|
||||
!segtype->ops->target_present ||
|
||||
!segtype->ops->target_present(cmd, NULL, &attr)) {
|
||||
log_warn("WARNING: Cannot detect default cache policy, using \""
|
||||
DEFAULT_CACHE_POLICY "\".");
|
||||
return DEFAULT_CACHE_POLICY;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node(policy->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
if (attr & CACHE_FEATURE_POLICY_SMQ)
|
||||
def = "smq";
|
||||
else if (attr & CACHE_FEATURE_POLICY_MQ)
|
||||
def = "mq";
|
||||
else {
|
||||
log_error("Default cache policy is not available.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((name = dm_config_find_str(policy->root, "policy", NULL)) &&
|
||||
!(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name)))
|
||||
goto_out;
|
||||
log_debug_metadata("Detected default cache_policy \"%s\".", def);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
int cache_set_policy(struct lv_segment *seg, const char *name,
|
||||
const struct dm_config_tree *settings)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
const struct dm_config_node *cns;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
const int passed_seg_is_cache = seg_is_cache(seg);
|
||||
|
||||
if (passed_seg_is_cache)
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (name) {
|
||||
if (!(seg->policy_name = dm_pool_strdup(seg->lv->vg->vgmem, name))) {
|
||||
log_error("Failed to duplicate policy name.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!seg->policy_name && passed_seg_is_cache) {
|
||||
if (!(seg->policy_name = find_config_tree_str(seg->lv->vg->cmd, allocation_cache_policy_CFG, NULL)) &&
|
||||
!(seg->policy_name = _get_default_cache_policy(seg->lv->vg->cmd)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (settings) {
|
||||
if (!seg->policy_name) {
|
||||
log_error(INTERNAL_ERROR "Can't set policy settings without policy name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = settings->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
} else if (passed_seg_is_cache && /* Look for command's profile cache_policies */
|
||||
(cns = find_config_tree_node(seg->lv->vg->cmd, allocation_cache_settings_CFG_SECTION, NULL))) {
|
||||
/* Try to find our section for given policy */
|
||||
for (cn = cns->child; cn; cn = cn->sib) {
|
||||
/* Only matching section names */
|
||||
if (cn->v || strcmp(cn->key, seg->policy_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!cn->child)
|
||||
break;
|
||||
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
|
||||
if (!(new->root = dm_config_clone_node_with_mem(new->mem,
|
||||
cn->child, 1)))
|
||||
goto_out;
|
||||
|
||||
if (!(seg->policy_settings = dm_config_create_node(new, "policy_settings")))
|
||||
goto_out;
|
||||
|
||||
seg->policy_settings->child = new->root;
|
||||
|
||||
break; /* Only first match counts */
|
||||
}
|
||||
}
|
||||
|
||||
restart: /* remove any 'default" nodes */
|
||||
cn = seg->policy_settings ? seg->policy_settings->child : NULL;
|
||||
@ -439,12 +563,13 @@ restart: /* remove any 'default" nodes */
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (old)
|
||||
dm_config_destroy(old);
|
||||
if (new)
|
||||
dm_config_destroy(new);
|
||||
if (tmp)
|
||||
dm_config_destroy(tmp);
|
||||
if (new)
|
||||
dm_config_destroy(new);
|
||||
if (old)
|
||||
dm_config_destroy(old);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user