mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-01 00:23:49 +03:00
Compare commits
409 Commits
old-v1_02_
...
v2_02_24
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
154e9a2c47 | ||
|
|
84574a1257 | ||
|
|
bf83527b64 | ||
|
|
12c53622a0 | ||
|
|
d8f54cf891 | ||
|
|
625a671189 | ||
|
|
6ebdad3102 | ||
|
|
9a8f21aa03 | ||
|
|
291dd8edc2 | ||
|
|
de4c1daf29 | ||
|
|
0b55d7d0d8 | ||
|
|
5d86fd8fdb | ||
|
|
1b76eb1f59 | ||
|
|
b05678d8bf | ||
|
|
781f4971c6 | ||
|
|
d02ac7b99a | ||
|
|
b1b6c97f7c | ||
|
|
baee28ab5c | ||
|
|
83edf68ff9 | ||
|
|
c7588f91dd | ||
|
|
30b432adc5 | ||
|
|
7c9733eb5d | ||
|
|
a223c3fea3 | ||
|
|
d5250f4901 | ||
|
|
25f29f4712 | ||
|
|
382af5563d | ||
|
|
8cf3d165d3 | ||
|
|
0fd6ce546f | ||
|
|
b881c372bc | ||
|
|
94c5e7deb0 | ||
|
|
c344766f3c | ||
|
|
67895de0bc | ||
|
|
ff00cb6990 | ||
|
|
2cc75c11ed | ||
|
|
cd79e58eda | ||
|
|
6fa801f3d8 | ||
|
|
684eecba1d | ||
|
|
da9cf7e5de | ||
|
|
f57e7445fd | ||
|
|
fba1388719 | ||
|
|
80ed029c17 | ||
|
|
34a74e81e3 | ||
|
|
cb120ddb15 | ||
|
|
f9ee4395b0 | ||
|
|
71f06d51ed | ||
|
|
217f70952f | ||
|
|
f813d41a76 | ||
|
|
d851289d8a | ||
|
|
b115b8a2ea | ||
|
|
d0f7067471 | ||
|
|
be5b4c38a7 | ||
|
|
d6d597e3dd | ||
|
|
84e348fade | ||
|
|
910054657e | ||
|
|
8357a11249 | ||
|
|
9b021ba057 | ||
|
|
317e588efd | ||
|
|
b1d32a03c7 | ||
|
|
ee6e6529ee | ||
|
|
9d944d6cf9 | ||
|
|
13635d281a | ||
|
|
2493c46970 | ||
|
|
63e4217271 | ||
|
|
f4bd12e8e9 | ||
|
|
df15f46900 | ||
|
|
fb3a732361 | ||
|
|
2d74110feb | ||
|
|
19d102082d | ||
|
|
d2af2c9487 | ||
|
|
82980149fa | ||
|
|
a19bb7b909 | ||
|
|
9d98c3278d | ||
|
|
26376ac1c9 | ||
|
|
8459f99341 | ||
|
|
e5bdb0e0b5 | ||
|
|
1106b7775a | ||
|
|
ae2852156d | ||
|
|
44c6c36c43 | ||
|
|
a81926503d | ||
|
|
af13ccddda | ||
|
|
392e1bc2e8 | ||
|
|
9268d92c70 | ||
|
|
bb3366c07d | ||
|
|
d24d563ebc | ||
|
|
954bd9257b | ||
|
|
5d51a56c02 | ||
|
|
f48648552e | ||
|
|
edb9c3cc9f | ||
|
|
01dc83b936 | ||
|
|
3a8dff3a62 | ||
|
|
13b234ccba | ||
|
|
e451e93664 | ||
|
|
b4f9531475 | ||
|
|
3184ff75c4 | ||
|
|
43243f4d30 | ||
|
|
c975a100b1 | ||
|
|
02bf389425 | ||
|
|
bcb9a3dd04 | ||
|
|
cce3baa275 | ||
|
|
2b48fad426 | ||
|
|
d554b2bc94 | ||
|
|
f66943de43 | ||
|
|
9d1e9bc2fb | ||
|
|
2d6a014920 | ||
|
|
c1952bf257 | ||
|
|
a10227eb03 | ||
|
|
475ae29b85 | ||
|
|
0b9cfc278b | ||
|
|
b57b6b4fba | ||
|
|
7d948f7bc5 | ||
|
|
459023d171 | ||
|
|
fd6570720a | ||
|
|
7831665417 | ||
|
|
7c9920d982 | ||
|
|
cbdccf0a9c | ||
|
|
64fa83ec3f | ||
|
|
faff865cfd | ||
|
|
742ab55a9a | ||
|
|
66e623fb2a | ||
|
|
4ab17ee965 | ||
|
|
7f48ca5132 | ||
|
|
da983848b4 | ||
|
|
bc03f7bad3 | ||
|
|
a1c8bd3846 | ||
|
|
404bc284e0 | ||
|
|
9dee30ff0e | ||
|
|
f91aadbea8 | ||
|
|
aa15a10c91 | ||
|
|
5b03e36351 | ||
|
|
b9ba9ffad2 | ||
|
|
642be5d16c | ||
|
|
ee68d715bf | ||
|
|
224084f056 | ||
|
|
1cd8c849b8 | ||
|
|
169f68bfcd | ||
|
|
d2b7cfa2d1 | ||
|
|
a40c7dff5d | ||
|
|
e8e00630d3 | ||
|
|
e33720c854 | ||
|
|
bd8a4e0d17 | ||
|
|
586a2aef76 | ||
|
|
ce1d8f6754 | ||
|
|
7b0f401065 | ||
|
|
8387016eef | ||
|
|
4e1342b641 | ||
|
|
e45a184d90 | ||
|
|
979e1012d2 | ||
|
|
fe10a50e23 | ||
|
|
8ab6d72519 | ||
|
|
3aada6dd1d | ||
|
|
0933036366 | ||
|
|
05f5abdc06 | ||
|
|
fb875e0709 | ||
|
|
9acdc2f6bf | ||
|
|
028ce4bff6 | ||
|
|
3f245ad6db | ||
|
|
23115f4116 | ||
|
|
cf5f48e6cc | ||
|
|
997fa756ad | ||
|
|
e23f75b1cc | ||
|
|
6531e88761 | ||
|
|
e76a9c2618 | ||
|
|
45be8a836b | ||
|
|
954b6032e7 | ||
|
|
bd95416f27 | ||
|
|
df2577ace2 | ||
|
|
720e6558c9 | ||
|
|
c239f15d8a | ||
|
|
dfa1f80a57 | ||
|
|
15dfb93b17 | ||
|
|
0ec8488c2b | ||
|
|
94b2e29cb1 | ||
|
|
fefa8e9b4d | ||
|
|
32c4c44812 | ||
|
|
05195e2b1d | ||
|
|
4c2ff675b8 | ||
|
|
e5692a4721 | ||
|
|
312e6a0d31 | ||
|
|
5bb8efa41f | ||
|
|
949a835f4a | ||
|
|
85e6042941 | ||
|
|
3cd2f28975 | ||
|
|
2179a72c3a | ||
|
|
a5f282f156 | ||
|
|
40e8631f63 | ||
|
|
9ded05bb97 | ||
|
|
ec8efa35a1 | ||
|
|
f72bf20482 | ||
|
|
ebde2002e8 | ||
|
|
352a66f46f | ||
|
|
d84c5391f7 | ||
|
|
f4c582472b | ||
|
|
1485586f7e | ||
|
|
d5c9024335 | ||
|
|
860cf80703 | ||
|
|
897ff3161f | ||
|
|
b356b2e501 | ||
|
|
1d2733c893 | ||
|
|
32d9126094 | ||
|
|
db43314e50 | ||
|
|
68d2baeb65 | ||
|
|
1fd5f562d3 | ||
|
|
48e02f2086 | ||
|
|
eab7b2b581 | ||
|
|
45abade7fc | ||
|
|
5372fc4b43 | ||
|
|
4e2f240c98 | ||
|
|
bb3605518d | ||
|
|
3ef6d37f27 | ||
|
|
88e9f2f7f4 | ||
|
|
704a447df9 | ||
|
|
a5fcb26a33 | ||
|
|
2491a61481 | ||
|
|
91831d51ed | ||
|
|
174f0c19f7 | ||
|
|
de6fadfb4f | ||
|
|
f946db3e00 | ||
|
|
8d05e5bc31 | ||
|
|
cfb46820e4 | ||
|
|
081f1cbcc2 | ||
|
|
7bc6da326f | ||
|
|
cd95a0df7b | ||
|
|
82fa497c16 | ||
|
|
44fd345206 | ||
|
|
088e1c9db4 | ||
|
|
d4f16e666e | ||
|
|
8233cfd371 | ||
|
|
ff05e2e30d | ||
|
|
a8ea7dd3fb | ||
|
|
96f70a5303 | ||
|
|
f1604c3e69 | ||
|
|
c42c8c5192 | ||
|
|
5facb53a41 | ||
|
|
d039ce89af | ||
|
|
bc7605103f | ||
|
|
d305d655d4 | ||
|
|
4ef1220b16 | ||
|
|
a4fef143cd | ||
|
|
74ecb724a9 | ||
|
|
af235897ab | ||
|
|
5ec4e458b5 | ||
|
|
2dae63ce21 | ||
|
|
be748fe33b | ||
|
|
7408340b6a | ||
|
|
29eb92446e | ||
|
|
ae6918742e | ||
|
|
863484bb65 | ||
|
|
1cd7ebce4c | ||
|
|
eef8c7862e | ||
|
|
b52375d446 | ||
|
|
6e2babc2ce | ||
|
|
08e253bed1 | ||
|
|
c6661477a2 | ||
|
|
415cfd99a0 | ||
|
|
8c2e37381a | ||
|
|
45df79feba | ||
|
|
5824f992b7 | ||
|
|
b0b60fafd5 | ||
|
|
8d98b02ba2 | ||
|
|
a93fe79bc4 | ||
|
|
4aebd7be37 | ||
|
|
3170a5db32 | ||
|
|
3605b9eef6 | ||
|
|
a945f1fde2 | ||
|
|
461a997b5b | ||
|
|
a80afd7b4e | ||
|
|
aad2b51d85 | ||
|
|
36a9a81ff1 | ||
|
|
42c88546ae | ||
|
|
0f0e86ef9b | ||
|
|
98efd9a857 | ||
|
|
a0c27d95b7 | ||
|
|
984651d99d | ||
|
|
c6f7370b30 | ||
|
|
3e4b8e8985 | ||
|
|
73f08b98d2 | ||
|
|
8607a74206 | ||
|
|
8339f3ceb3 | ||
|
|
c0c9f3cc19 | ||
|
|
81f4813c29 | ||
|
|
94f57745b9 | ||
|
|
54fb2ebbe0 | ||
|
|
02d122b65b | ||
|
|
df0a5561a1 | ||
|
|
f7c55da7d0 | ||
|
|
b385f701ce | ||
|
|
05dd42f443 | ||
|
|
36d816d5cb | ||
|
|
92a6746e70 | ||
|
|
1728848a39 | ||
|
|
f9eb4e7487 | ||
|
|
d0b9f33aeb | ||
|
|
718583b241 | ||
|
|
6737127e9a | ||
|
|
19a7b4479b | ||
|
|
c340647502 | ||
|
|
0f987d2982 | ||
|
|
52bcaed169 | ||
|
|
177bd565ac | ||
|
|
c801c32fc5 | ||
|
|
d090cf3058 | ||
|
|
1e4b82cc94 | ||
|
|
3426f31184 | ||
|
|
b4fb7af1df | ||
|
|
b36647598b | ||
|
|
fd6b94f20e | ||
|
|
296dc0ed8a | ||
|
|
4f869e14d6 | ||
|
|
5704270e9d | ||
|
|
505b381e85 | ||
|
|
da6cb15393 | ||
|
|
16843f6cc8 | ||
|
|
64f3ad1fd4 | ||
|
|
ff4c4f99b3 | ||
|
|
f5d2e09569 | ||
|
|
f2bdbe0d4d | ||
|
|
c51a13caa6 | ||
|
|
7840c78a23 | ||
|
|
c706f3246b | ||
|
|
608eedf88d | ||
|
|
a564ca82be | ||
|
|
c868b1fee2 | ||
|
|
22374f718f | ||
|
|
abe3cfcf41 | ||
|
|
59db4b50cd | ||
|
|
bdae38765d | ||
|
|
66d3ceeb61 | ||
|
|
445dd17db3 | ||
|
|
cff78a2577 | ||
|
|
6a09e64195 | ||
|
|
22eabe5eab | ||
|
|
b69ba36c2d | ||
|
|
5240aad22b | ||
|
|
2897eb3cb3 | ||
|
|
d3f2f00c25 | ||
|
|
bacfb913a0 | ||
|
|
c99d0236a0 | ||
|
|
aac2b655f7 | ||
|
|
126c41e73a | ||
|
|
359ee54f0d | ||
|
|
28ab560907 | ||
|
|
ead252fee4 | ||
|
|
abf67914c4 | ||
|
|
127884e9dd | ||
|
|
654f5049eb | ||
|
|
979ca34259 | ||
|
|
4dd1086805 | ||
|
|
3503d4b72c | ||
|
|
b8d32a0d33 | ||
|
|
45dca55fc8 | ||
|
|
445d8ecd9f | ||
|
|
c980add503 | ||
|
|
133842392a | ||
|
|
8baf2ef155 | ||
|
|
20b71340bc | ||
|
|
61d8baf8b1 | ||
|
|
56a9645aa5 | ||
|
|
85877000a6 | ||
|
|
2f7d2477b6 | ||
|
|
21ea3f05f4 | ||
|
|
79d3492e90 | ||
|
|
5972777abe | ||
|
|
8e373ff868 | ||
|
|
a4db92da3a | ||
|
|
9b777eb281 | ||
|
|
bd3c652184 | ||
|
|
800f747570 | ||
|
|
2b8423437e | ||
|
|
8b4b6945f8 | ||
|
|
e5ecfec5c4 | ||
|
|
f95dbff71f | ||
|
|
098f6830a6 | ||
|
|
d1ecebdb52 | ||
|
|
590b654251 | ||
|
|
3bf190c8ab | ||
|
|
dcca7638e0 | ||
|
|
70e45ad37b | ||
|
|
db88210289 | ||
|
|
d2e0d96cc3 | ||
|
|
3feba82ccc | ||
|
|
db924da231 | ||
|
|
fc55ae7e6d | ||
|
|
86e757a6ad | ||
|
|
4790715cd3 | ||
|
|
e7e9c60042 | ||
|
|
1c3bc52cc4 | ||
|
|
5227dff0e1 | ||
|
|
33f0b5b7c2 | ||
|
|
0a02968303 | ||
|
|
f7bf658c07 | ||
|
|
8d16a0abad | ||
|
|
c974b97ca3 | ||
|
|
b8025bfebd | ||
|
|
30323b253f | ||
|
|
535c3ede96 | ||
|
|
89fed8ca33 | ||
|
|
f43c77aaed | ||
|
|
96c676b371 | ||
|
|
113047e1a2 | ||
|
|
abed57cb53 | ||
|
|
c01a800a6b | ||
|
|
d648832a2d | ||
|
|
f06833fbd2 | ||
|
|
c561addc94 | ||
|
|
702f5f1f4c | ||
|
|
1273f179e8 | ||
|
|
5d02f60bde | ||
|
|
4cf7a108e8 | ||
|
|
42635c3938 |
13
Makefile.in
13
Makefile.in
@@ -16,7 +16,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SUBDIRS = doc include man
|
||||
SUBDIRS = doc include man scripts
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
SUBDIRS += po
|
||||
@@ -38,6 +38,7 @@ ifeq ($(MAKECMDGOALS),distclean)
|
||||
lib/snapshot \
|
||||
po \
|
||||
test/mm test/device test/format1 test/regex test/filters
|
||||
DISTCLEAN_TARGETS += lib/misc/configure.h
|
||||
endif
|
||||
|
||||
include make.tmpl
|
||||
@@ -57,3 +58,13 @@ po.pofile: tools.pofile daemons.pofile dmeventd.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
ifneq ("@CFLOW_CMD@", "")
|
||||
tools.cflow: lib.cflow
|
||||
cflow: tools.cflow
|
||||
endif
|
||||
|
||||
ifneq ("@CSCOPE_CMD@", "")
|
||||
cscope.out: tools
|
||||
@CSCOPE_CMD@ -b -R
|
||||
all: cscope.out
|
||||
endif
|
||||
|
||||
314
WHATS_NEW
314
WHATS_NEW
@@ -1,6 +1,318 @@
|
||||
Version 2.02.03 -
|
||||
Version 2.02.24 - 19th March 2007
|
||||
=================================
|
||||
Fix processing of exit status in init scripts
|
||||
Fix vgremove to require at least one vg argument.
|
||||
Fix reading of striped LVs in LVM1 format.
|
||||
Flag nolocking as clustered so clvmd startup sees clustered LVs. (2.02.10)
|
||||
Add a few missing pieces of vgname command line validation.
|
||||
Support the /dev/mapper prefix on most command lines.
|
||||
|
||||
Version 2.02.23 - 8th March 2007
|
||||
================================
|
||||
Fix vgrename active LV check to ignore differing vgids.
|
||||
Remove no-longer-used uuid_out parameter from activation info functions.
|
||||
Fix two more segfaults if an empty config file section encountered.
|
||||
Move .cache file into a new /etc/lvm/cache directory by default.
|
||||
Add devices/cache_dir & devices/cache_file_prefix, deprecating devices/cache.
|
||||
Create directory in fcntl_lock_file() if required.
|
||||
Exclude readline support from lvm.static.
|
||||
Fix a leak in a reporting error path (2.02.19).
|
||||
|
||||
Version 2.02.22 - 13th February 2007
|
||||
====================================
|
||||
Correct -b and -P on a couple of man pages.
|
||||
Add global/units to example.conf.
|
||||
Fix loading of segment_libraries.
|
||||
If a PV reappears after it was removed from its VG, make it an orphan.
|
||||
Don't update metadata automatically if VGIDs don't match.
|
||||
Fix some vgreduce --removemissing command line validation.
|
||||
|
||||
Version 2.02.21 - 30th January 2007
|
||||
===================================
|
||||
Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring.
|
||||
Fix vgsplit to handle mirrors.
|
||||
Reorder fields in reporting field definitions.
|
||||
Fix vgs to treat args as VGs even when PV fields are displayed.
|
||||
Fix md signature check to handle both endiannesses.
|
||||
|
||||
Version 2.02.20 - 25th January 2007
|
||||
===================================
|
||||
dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors.
|
||||
Add devices/ignore_suspended_devices to ignore suspended dm devices.
|
||||
Add some missing close() and fclose() return code checks.
|
||||
Fix exit statuses of reporting tools (2.02.19).
|
||||
Add init script for dmeventd monitoring.
|
||||
lvm.static no longer interacts with dmeventd unless explicitly asked to.
|
||||
Add field definitions to report help text.
|
||||
Remove unnecessary cmd arg from target_*monitor_events().
|
||||
Add private variable to dmeventd shared library interface.
|
||||
Long-lived processes write out persistent dev cache in refresh_toolcontext().
|
||||
Fix refresh_toolcontext() always to wipe persistent device filter cache.
|
||||
Add is_long_lived to toolcontext.
|
||||
Add --clustered to man pages.
|
||||
Streamline dm_report_field_* interface.
|
||||
Change remaining dmeventd terminology 'register' to 'monitor'.
|
||||
Update reporting man pages.
|
||||
No longer necessary to specify alignment type for report fields.
|
||||
|
||||
Version 2.02.19 - 17th January 2007
|
||||
===================================
|
||||
Fix a segfault if an empty config file section encountered.
|
||||
Move basic reporting functions into libdevmapper.
|
||||
Fix partition table processing after sparc changes (2.02.16).
|
||||
Fix cmdline PE range processing segfault (2.02.13).
|
||||
Some libdevmapper-event interface changes.
|
||||
Report dmeventd mirror monitoring status.
|
||||
Fix dmeventd mirror status line processing.
|
||||
|
||||
Version 2.02.18 - 11th January 2007
|
||||
===================================
|
||||
Revised libdevmapper-event interface for dmeventd.
|
||||
Remove dmeventd mirror status line word limit.
|
||||
Use CFLAGS when linking so mixed sparc builds can supply -m64.
|
||||
Prevent permission changes on active mirrors.
|
||||
Print warning instead of error message if lvconvert cannot zero volume.
|
||||
Add snapshot options to lvconvert man page.
|
||||
dumpconfig accepts a list of configuration variables to display.
|
||||
Change dumpconfig to use --file to redirect output to a file.
|
||||
Avoid vgreduce error when mirror code removes the log LV.
|
||||
Remove 3 redundant AC_MSG_RESULTs from configure.in.
|
||||
Free memory in _raw_read_mda_header() error paths.
|
||||
Fix ambiguous vgsplit error message for split LV.
|
||||
Fix lvextend man page typo.
|
||||
Add configure --with-dmdir to compile against a device-mapper source tree.
|
||||
Use no flush suspending for mirrors.
|
||||
Add dmeventd_mirror register_mutex, tidy initialisation & add memlock.
|
||||
Fix create mirror with name longer than 22 chars.
|
||||
Fix some activate.c prototypes when compiled without devmapper.
|
||||
Fix dmeventd mirror to cope if monitored device disappears.
|
||||
|
||||
Version 2.02.17 - 14th December 2006
|
||||
====================================
|
||||
Add missing pvremove error message when device doesn't exist.
|
||||
When lvconvert allocates a mirror log, respect parallel area constraints.
|
||||
Use loop to iterate through the now-ordered policy list in _allocate().
|
||||
Check for failure to allocate just the mirror log.
|
||||
Introduce calc_area_multiple().
|
||||
Support mirror log allocation when there is only one PV: area_count now 0.
|
||||
Fix detection of smallest area in _alloc_parallel_area() for cling policy.
|
||||
Add manpage entry for clvmd -T
|
||||
Fix gulm operation of clvmd, including a hang when doing lvchange -aey
|
||||
Fix hang in clvmd if a pre-command failed.
|
||||
|
||||
Version 2.02.16 - 1st December 2006
|
||||
===================================
|
||||
Fix VG clustered read locks to use PR not CR.
|
||||
Adjust some alignments for ia64/sparc.
|
||||
Fix mirror segment removal to use temporary error segment.
|
||||
Always compile debug logging into clvmd.
|
||||
Add startup timeout to RHEL4 clvmd startup script.
|
||||
Add -T (startup timeout) switch to clvmd.
|
||||
Improve lvm_dump.sh robustness.
|
||||
Update lvm2create_initrd to support gentoo.
|
||||
|
||||
Version 2.02.15 - 21st November 2006
|
||||
====================================
|
||||
Fix clvmd_init_rhel4 line truncation (2.02.14).
|
||||
Install lvmdump by default.
|
||||
Fix check for snapshot module when activating snapshot.
|
||||
Fix pvremove error path for case when PV is in use.
|
||||
Warn if certain duplicate config file entries are seen.
|
||||
Enhance lvm_dump.sh for sysreport integration and add man page.
|
||||
Fix --autobackup argument which could never disable backups.
|
||||
Fix a label_verify error path.
|
||||
|
||||
Version 2.02.14 - 10th November 2006
|
||||
====================================
|
||||
Fix adjusted_mirror_region_size() to handle 64-bit size.
|
||||
Add some missing bounds checks on 32-bit extent counters.
|
||||
Add Petabyte and Exabyte support.
|
||||
Fix lvcreate error message when 0 extents requested.
|
||||
lvremove man page: volumes must be cluster inactive before being removed.
|
||||
Protect .cache manipulations with fcntl locking.
|
||||
Change .cache timestamp comparisons to use ctime.
|
||||
Fix mirror log LV writing to set all bits in whole LV.
|
||||
Fix clustered VG detection and default runlevels in clvmd_init_rhel4.
|
||||
Fix high-level free space check for partial allocations.
|
||||
|
||||
Version 2.02.13 - 27th October 2006
|
||||
===================================
|
||||
Add couple of missing files to tools/Makefile CLEAN_TARGETS.
|
||||
When adding snapshot leave cow LV mapped device active after zeroing.
|
||||
Fix a clvmd debug message.
|
||||
Add dev_flush() to set_lv().
|
||||
Add lvchange --resync.
|
||||
Perform high-level free space check before each allocation attempt.
|
||||
Don't allow a node to remove an LV that's exclusively active on anther node.
|
||||
Cope if same PV is included more than once in cmdline PE range list.
|
||||
Set PV size to current device size if it is found to be zero.
|
||||
Add segment parameter to target_present functions.
|
||||
|
||||
Version 2.02.12 - 16th October 2006
|
||||
===================================
|
||||
Fix pvdisplay to use vg_read() for non-orphans.
|
||||
Fall back to internal locking if external locking lib is missing or fails.
|
||||
Retain activation state after changing LV minor number with --force.
|
||||
Propagate clustered flag in vgsplit and require resizeable flag.
|
||||
|
||||
Version 2.02.11 - 12th October 2006
|
||||
===================================
|
||||
Add clvmd function to return the cluster name. not used by LVM yet.
|
||||
Add cling allocation policy.
|
||||
Change _check_contiguous() to use _for_each_pv().
|
||||
Extend _for_each_pv() to allow termination without error.
|
||||
Abstract _is_contiguous().
|
||||
Remove duplicated pv arg from _check_contiguous().
|
||||
Accept regionsize with lvconvert.
|
||||
Add report columns with underscore before field names ending 'size'.
|
||||
Correct regionsize default on lvcreate man page (MB).
|
||||
Fix clvmd bug that could cause it to die when a node with a long name crashed.
|
||||
Add device size to text metadata.
|
||||
Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
|
||||
Fix _for_each_pv() for mirror with core log.
|
||||
Add lvm_dump.sh script to create a tarball of debugging info from a system.
|
||||
Capture error messages in clvmd and pass them back to the user.
|
||||
Remove unused #defines from filter-md.c.
|
||||
Make clvmd restart init script wait until clvmd has died before starting it.
|
||||
Add -R to clvmd which tells running clvmds to reload their device cache.
|
||||
Add LV column to reports listing kernel modules needed for activation.
|
||||
Show available fields if report given invalid field. (e.g. lvs -o list)
|
||||
Add timestamp functions with --disable-realtime configure option.
|
||||
Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
|
||||
Fix two potential NULL pointer derefs in error cases in vg_read().
|
||||
Separate --enable-cluster from locking lib options in lvmconf.sh.
|
||||
Add a missing comma in lvcreate man page.
|
||||
|
||||
Version 2.02.10 - 19th September 2006
|
||||
=====================================
|
||||
Fix lvconvert mirror change case detection logic.
|
||||
Fix mirror log detachment so it correctly becomes a standalone LV.
|
||||
Extend _check_contiguous() to detect single-area LVs.
|
||||
Include mirror log (untested) in _for_each_pv() processing.
|
||||
Use MIRROR_LOG_SIZE constant.
|
||||
Remove struct seg_pvs from _for_each_pv() to generalise.
|
||||
Avoid adding duplicates to list of parallel PVs to avoid.
|
||||
Fix several incorrect comparisons in parallel area avoidance code.
|
||||
Fix segment lengths when flattening existing parallel areas.
|
||||
Log existing parallel areas prior to allocation.
|
||||
Fix mirror log creation when activation disabled.
|
||||
Don't attempt automatic recovery without proper locking.
|
||||
When using local file locking, skip clustered VGs.
|
||||
Add fallback_to_clustered_locking and fallback_to_local_locking parameters.
|
||||
lvm.static uses built-in cluster locking instead of external locking.
|
||||
Don't attempt to load shared libraries if built statically.
|
||||
Change default locking_lib to liblvm2clusterlock.so.
|
||||
Add skip_dev_dir() to process command line VGs.
|
||||
Stop clvmd complaining about nodes that have left the cluster.
|
||||
Move lvm_snprintf(), split_words() and split_dm_name() into libdevmapper.
|
||||
Add lvconvert man page.
|
||||
Add mirror options to man pages.
|
||||
Prevent mirror renames.
|
||||
Move CMDLIB code into separate file and record whether static build.
|
||||
|
||||
Version 2.02.09 - 17th August 2006
|
||||
==================================
|
||||
Fix PE_ALIGN for pagesize over 32KB.
|
||||
Separate out LVM1_PE_ALIGN and pe_align().
|
||||
Add lvm_getpagesize wrapper.
|
||||
Add --maxphysicalvolumes to vgchange.
|
||||
|
||||
Version 2.02.08 - 15th August 2006
|
||||
==================================
|
||||
Add checks for duplicate LV name, lvid and PV id before writing metadata.
|
||||
Report all sanity check failures, not just the first.
|
||||
Fix missing lockfs on first snapshot creation.
|
||||
Add unreliable --trustcache option to reporting commands.
|
||||
Fix locking for mimage removal.
|
||||
Fix clvmd_init_rhel4 'status' exit code.
|
||||
|
||||
Version 2.02.07 - 17th July 2006
|
||||
================================
|
||||
Fix activation logic in lvchange --persistent.
|
||||
Don't ignore persistent minor numbers when activating.
|
||||
Use RTLD_GLOBAL when loading shared libraries.
|
||||
Add some forgotten memlock checks to _vg_read to protect against full scans.
|
||||
Add mutex to dmeventd_mirror to avoid concurrent execution.
|
||||
Fix vgreduce --removemissing to return success if VG is already consistent.
|
||||
Fix return code if VG specified on command line is not found.
|
||||
Fix PV tools to include orphaned PVs in default output again.
|
||||
Fixed unaligned access when using clvm.
|
||||
Fix an extra dev_close in a label_read error path.
|
||||
Append patches to commit emails.
|
||||
Fix target_register_events args.
|
||||
Prevent snapshots of mirrors.
|
||||
Add DISTCLEAN_TARGETS to make template for configure.h.
|
||||
More fixes to error paths.
|
||||
Fix lvcreate corelog validation.
|
||||
Add --config for overriding most config file settings from cmdline.
|
||||
Quote arguments when printing command line.
|
||||
Remove linefeed from 'initialising logging' message.
|
||||
Add 'Completed' debug message.
|
||||
Don't attempt library exit after reloading config files.
|
||||
Always compile with libdevmapper, even if device-mapper is disabled.
|
||||
|
||||
Version 2.02.06 - 12th May 2006
|
||||
===============================
|
||||
Propagate --monitor around cluster.
|
||||
Add --monitor to vgcreate and lvcreate to control dmeventd registration.
|
||||
Filter LCK_NONBLOCK in clvmd lock_vg.
|
||||
Add --nosync to lvcreate with LV flag NOTSYNCED.
|
||||
Use mirror's uuid for a core log.
|
||||
Add mirror log fault-handling policy.
|
||||
Improve mirror warning messages and tidy dmeventd syslog output.
|
||||
Propagate nosync flag around cluster.
|
||||
Allow vgreduce to handle mirror log failures.
|
||||
Add --corelog to lvcreate and lvconvert.
|
||||
Create a log header for replacement in-sync mirror log.
|
||||
Use set_lv() and dev_set() to wipe sections of devices.
|
||||
Add mirror_in_sync() flag to avoid unnecessary resync on activation.
|
||||
Add mirror_library description to example.conf.
|
||||
Fix uuid_from_num() buffer overrun.
|
||||
Make SIZE_SHORT the default for display_size().
|
||||
Fix some memory leaks in error paths found by coverity.
|
||||
Use C99 struct initialisers.
|
||||
Move DEFS into configure.h.
|
||||
Clean-ups to remove miscellaneous compiler warnings.
|
||||
Improve stripe size validation.
|
||||
Increase maximum stripe size limit to physical extent size for lvm2 metadata.
|
||||
Fix activation code to check for pre-existing mirror logs.
|
||||
Tighten region size validation.
|
||||
Ignore empty strings in config files.
|
||||
Require non-zero regionsize and document parameter on lvcreate man page.
|
||||
Invalidate cache if composition of VG changed externally.
|
||||
|
||||
Version 2.02.05 - 21st April 2006
|
||||
=================================
|
||||
Fix vgid string termination in recent cache code.
|
||||
|
||||
Version 2.02.04 - 19th April 2006
|
||||
=================================
|
||||
Check for libsepol.
|
||||
Add some cflow & scope support.
|
||||
Separate out DEFS from CFLAGS.
|
||||
Remove inlines and use unique function names.
|
||||
|
||||
Version 2.02.03 - 14th April 2006
|
||||
=================================
|
||||
vgrename accepts vgid and exported VG.
|
||||
Add --partial to pvs.
|
||||
When choosing between identically-named VGs, also consider creation_host.
|
||||
Provide total log suppression with 2.
|
||||
Fix vgexport/vgimport to set/reset PV exported flag so pv_attr is correct.
|
||||
Add vgid to struct physical_volume and pass with vg_name to some functions.
|
||||
If two or more VGs are found with the same name, use one that is not exported.
|
||||
Whenever vgname is captured, also capture vgid and whether exported.
|
||||
Remove an incorrect unlock_vg() from process_each_lv().
|
||||
Update extent size information in vgchange and vgcreate man pages.
|
||||
Introduce origin_from_cow() and lv_is_visible().
|
||||
pvremove without -f now fails if there's no PV label.
|
||||
Support lvconvert -s.
|
||||
Suppress locking library load failure message if --ignorelockingfailure.
|
||||
Propagate partial mode around cluster.
|
||||
Fix archive file expiration.
|
||||
Fix dmeventd build.
|
||||
clvmd now uses libcman rather than cman ioctls.
|
||||
clvmd will allow new cman to shutdown on request.
|
||||
|
||||
Version 2.02.02 - 7th February 2006
|
||||
===================================
|
||||
|
||||
115
WHATS_NEW_DM
115
WHATS_NEW_DM
@@ -1,5 +1,116 @@
|
||||
Version 1.02.04 -
|
||||
============================
|
||||
Version 1.02.19 -
|
||||
====================================
|
||||
Remove unnecessary memset() return value checks.
|
||||
Fix a few leaks in reporting error paths. [1.02.15+]
|
||||
|
||||
Version 1.02.18 - 13th February 2007
|
||||
====================================
|
||||
Improve dmeventd messaging protocol: drain pipe and tag messages.
|
||||
|
||||
Version 1.02.17 - 29th January 2007
|
||||
===================================
|
||||
Add recent reporting options to dmsetup man page.
|
||||
Revise some report fields names.
|
||||
Add dmsetup 'help' command and update usage text.
|
||||
Use fixed-size fields in report interface and reorder.
|
||||
|
||||
Version 1.02.16 - 25th January 2007
|
||||
===================================
|
||||
Add some missing close() and fclose() return value checks.
|
||||
Migrate dmsetup column-based output over to new libdevmapper report framework.
|
||||
Add descriptions to reporting field definitions.
|
||||
Add a dso-private variable to dmeventd dso interface.
|
||||
Add dm_event_handler_[gs]et_timeout functions.
|
||||
Streamline dm_report_field_* interface.
|
||||
Add cmdline debug & version options to dmeventd.
|
||||
Add DM_LIB_VERSION definition to configure.h.
|
||||
Suppress 'Unrecognised field' error if report field is 'help'.
|
||||
Add --separator and --sort to dmsetup (unused).
|
||||
Make alignment flag optional when specifying report fields.
|
||||
|
||||
Version 1.02.15 - 17th January 2007
|
||||
===================================
|
||||
Add basic reporting functions to libdevmapper.
|
||||
Fix a malloc error path in dmsetup message.
|
||||
More libdevmapper-event interface changes and fixes.
|
||||
Rename dm_saprintf() to dm_asprintf().
|
||||
Report error if NULL pointer is supplied to dm_strdup_aux().
|
||||
Reinstate dm_event_get_registered_device.
|
||||
|
||||
Version 1.02.14 - 11th January 2007
|
||||
===================================
|
||||
Add dm_saprintf().
|
||||
Use CFLAGS when linking so mixed sparc builds can supply -m64.
|
||||
Add dm_tree_use_no_flush_suspend().
|
||||
Lots of dmevent changes including revised interface.
|
||||
Export dm_basename().
|
||||
Cope with a trailing space when comparing tables prior to possible reload.
|
||||
Fix dmeventd to cope if monitored device disappears.
|
||||
|
||||
Version 1.02.13 - 28 Nov 2006
|
||||
=============================
|
||||
Update dmsetup man page (setgeometry & message).
|
||||
Fix dmsetup free after getline with debug.
|
||||
Suppress encryption key in 'dmsetup table' output unless --showkeys supplied.
|
||||
|
||||
Version 1.02.12 - 13 Oct 2006
|
||||
=============================
|
||||
Avoid deptree attempting to suspend a device that's already suspended.
|
||||
|
||||
Version 1.02.11 - 12 Oct 2006
|
||||
==============================
|
||||
Add suspend noflush support.
|
||||
Add basic dmsetup loop support.
|
||||
Switch dmsetup to use dm_malloc and dm_free.
|
||||
|
||||
Version 1.02.10 - 19 Sep 2006
|
||||
=============================
|
||||
Add dm_snprintf(), dm_split_words() and dm_split_lvm_name() to libdevmapper.
|
||||
Reorder mm bounds_check code to reduce window for a dmeventd race.
|
||||
|
||||
Version 1.02.09 - 15 Aug 2006
|
||||
=============================
|
||||
Add --table argument to dmsetup for a one-line table.
|
||||
Abort if errors are found during cmdline option processing.
|
||||
Add lockfs indicator to debug output.
|
||||
|
||||
Version 1.02.08 - 17 July 2006
|
||||
==============================
|
||||
Append full patch to check in emails.
|
||||
Avoid duplicate dmeventd subdir with 'make distclean'.
|
||||
Update dmsetup man page.
|
||||
Add --force to dmsetup remove* to load error target.
|
||||
dmsetup remove_all also performs mknodes.
|
||||
Don't suppress identical table reloads if permission changes.
|
||||
Fix corelog segment line.
|
||||
Suppress some compiler warnings.
|
||||
|
||||
Version 1.02.07 - 11 May 2006
|
||||
=============================
|
||||
Add DM_CORELOG flag to dm_tree_node_add_mirror_target().
|
||||
Avoid a dmeventd compiler warning.
|
||||
|
||||
Version 1.02.06 - 10 May 2006
|
||||
=============================
|
||||
Move DEFS into configure.h.
|
||||
Fix leaks in error paths found by coverity.
|
||||
Remove dmsetup line buffer limitation.
|
||||
|
||||
Version 1.02.05 - 19 Apr 2006
|
||||
=============================
|
||||
Separate install_include target in makefiles.
|
||||
Separate out DEFS from CFLAGS.
|
||||
Support pkg-config.
|
||||
Check for libsepol.
|
||||
|
||||
Version 1.02.04 - 14 Apr 2006
|
||||
=============================
|
||||
Bring dmsetup man page up-to-date.
|
||||
Use name-based device refs if kernel doesn't support device number refs.
|
||||
Fix memory leak (struct dm_ioctl) when struct dm_task is reused.
|
||||
If _create_and_load_v4 fails part way through, revert the creation.
|
||||
dmeventd thread/fifo fixes.
|
||||
Add file & line to dm_strdup_aux().
|
||||
Add setgeometry.
|
||||
|
||||
Version 1.02.03 - 7 Feb 2006
|
||||
|
||||
88
configure.in
88
configure.in
@@ -18,6 +18,9 @@ AC_PREREQ(2.53)
|
||||
dnl -- Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(lib/device/dev-cache.h)
|
||||
|
||||
################################################################################
|
||||
AC_CONFIG_HEADERS(lib/misc/configure.h)
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the directory where autoconf has auxilary files
|
||||
AC_CONFIG_AUX_DIR(autoconf)
|
||||
@@ -39,6 +42,7 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
REALTIME=yes
|
||||
CLUSTER=internal
|
||||
FSADM=no ;;
|
||||
darwin*)
|
||||
@@ -53,6 +57,7 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
REALTIME=no
|
||||
CLUSTER=none
|
||||
FSADM=no ;;
|
||||
esac
|
||||
@@ -65,6 +70,8 @@ AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
AC_PATH_PROG(CFLOW_CMD, cflow)
|
||||
AC_PATH_PROG(CSCOPE_CMD, cscope)
|
||||
|
||||
################################################################################
|
||||
dnl -- Checks for header files.
|
||||
@@ -150,7 +157,7 @@ AC_ARG_ENABLE(lvm1_fallback, [ --enable-lvm1_fallback Use this to fall back an
|
||||
AC_MSG_RESULT($LVM1_FALLBACK)
|
||||
|
||||
if test x$LVM1_FALLBACK = xyes; then
|
||||
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
|
||||
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -170,7 +177,7 @@ if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||
fi;
|
||||
|
||||
if test x$LVM1 = xinternal; then
|
||||
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
|
||||
AC_DEFINE([LVM1_INTERNAL], 1, [Define to 1 to include built-in support for LVM1 metadata.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -190,7 +197,7 @@ if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]];
|
||||
fi;
|
||||
|
||||
if test x$POOL = xinternal; then
|
||||
CFLAGS="$CFLAGS -DPOOL_INTERNAL"
|
||||
AC_DEFINE([POOL_INTERNAL], 1, [Define to 1 to include built-in support for GFS pool metadata.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -209,7 +216,7 @@ if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared
|
||||
fi;
|
||||
|
||||
if test x$CLUSTER = xinternal; then
|
||||
CFLAGS="$CFLAGS -DCLUSTER_LOCKING_INTERNAL"
|
||||
AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1, [Define to 1 to include built-in support for clustered LVM locking.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -229,7 +236,7 @@ if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != x
|
||||
fi;
|
||||
|
||||
if test x$SNAPSHOTS = xinternal; then
|
||||
CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL"
|
||||
AC_DEFINE([SNAPSHOT_INTERNAL], 1, [Define to 1 to include built-in support for snapshots.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -249,7 +256,7 @@ if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared
|
||||
fi;
|
||||
|
||||
if test x$MIRRORS = xinternal; then
|
||||
CFLAGS="$CFLAGS -DMIRRORED_INTERNAL"
|
||||
AC_DEFINE([MIRRORED_INTERNAL], 1, [Define to 1 to include built-in support for mirrors.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -267,7 +274,7 @@ READLINE=$enableval, READLINE=no)
|
||||
AC_MSG_RESULT($READLINE)
|
||||
|
||||
if test x$READLINE = xyes; then
|
||||
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
|
||||
AC_DEFINE([READLINE_SUPPORT], 1, [Define to 1 to include the LVM readline shell.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -277,6 +284,13 @@ AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
|
||||
SELINUX=$enableval)
|
||||
AC_MSG_RESULT($SELINUX)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable realtime clock support
|
||||
AC_MSG_CHECKING(whether to enable realtime support)
|
||||
AC_ARG_ENABLE(realtime, [ --disable-realtime Disable realtime clock support],
|
||||
REALTIME=$enableval)
|
||||
AC_MSG_RESULT($REALTIME)
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
@@ -305,6 +319,8 @@ AC_MSG_RESULT($DEBUG)
|
||||
dnl -- Normally turn off optimisation for debug builds
|
||||
if test x$DEBUG = xyes; then
|
||||
COPTIMISE_FLAG=
|
||||
else
|
||||
CSCOPE_CMD=
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -323,7 +339,7 @@ DEVMAPPER=$enableval)
|
||||
AC_MSG_RESULT($DEVMAPPER)
|
||||
|
||||
if test x$DEVMAPPER = xyes; then
|
||||
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
|
||||
AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable device-mapper interaction.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -334,7 +350,7 @@ ODIRECT=$enableval)
|
||||
AC_MSG_RESULT($ODIRECT)
|
||||
|
||||
if test x$ODIRECT = xyes; then
|
||||
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
|
||||
AC_DEFINE([O_DIRECT_SUPPORT], 1, [Define to 1 to enable O_DIRECT support.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -344,10 +360,6 @@ AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library],
|
||||
CMDLIB=$enableval, CMDLIB=no)
|
||||
AC_MSG_RESULT($CMDLIB)
|
||||
|
||||
if test x$CMDLIB = xyes; then
|
||||
CFLAGS="$CFLAGS -DCMDLIB"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable fsadm
|
||||
AC_MSG_CHECKING(whether to build fsadm)
|
||||
@@ -370,7 +382,7 @@ AC_MSG_ERROR(
|
||||
fi
|
||||
|
||||
if test x$DMEVENTD = xyes; then
|
||||
CFLAGS="$CFLAGS -DDMEVENTD"
|
||||
AC_DEFINE([DMEVENTD], 1, [Define to 1 to enable the device-mapper event daemon.])
|
||||
fi
|
||||
################################################################################
|
||||
dnl -- Mess with default exec_prefix
|
||||
@@ -407,7 +419,7 @@ dnl -- Check for dlopen
|
||||
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
|
||||
|
||||
if [[ "x$HAVE_LIBDL" = xyes ]]; then
|
||||
CFLAGS="$CFLAGS -DHAVE_LIBDL"
|
||||
AC_DEFINE([HAVE_LIBDL], 1, [Define to 1 if dynamic libraries are available.])
|
||||
LIBS="-ldl $LIBS"
|
||||
else
|
||||
HAVE_LIBDL=no
|
||||
@@ -424,23 +436,40 @@ Features cannot be 'shared' when building statically
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for is_selinux_enabled
|
||||
dnl -- Check for selinux
|
||||
if test x$SELINUX = xyes; then
|
||||
AC_MSG_CHECKING(for is_selinux_enabled function)
|
||||
AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no)
|
||||
|
||||
if test x$HAVE_SEPOL = xyes; then
|
||||
LIBS="-lsepol $LIBS"
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
|
||||
AC_MSG_RESULT($HAVE_SELINUX)
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
||||
AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.])
|
||||
LIBS="-lselinux $LIBS"
|
||||
else
|
||||
AC_MSG_WARN(Disabling selinux)
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for realtime clock support
|
||||
if test x$REALTIME = xyes; then
|
||||
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||
LIBS="-lrt $LIBS"
|
||||
else
|
||||
AC_MSG_WARN(Disabling realtime clock)
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for getopt
|
||||
AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG")
|
||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 to if getopt_long is available.]))
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for readline (Shamelessly copied from parted 1.4.17)
|
||||
@@ -455,8 +484,7 @@ Note: if you are using precompiled packages you will also need the development
|
||||
package as well (which may be called readline-devel or something similar).
|
||||
)
|
||||
)
|
||||
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
|
||||
|
||||
AC_CHECK_FUNC(rl_completion_matches, AC_DEFINE([HAVE_RL_COMPLETION_MATCHES], 1, [Define to 1 if rl_completion_matches() is available.]))
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -492,6 +520,11 @@ AC_ARG_WITH(staticdir,
|
||||
[ STATICDIR="$withval" ],
|
||||
[ STATICDIR='${exec_prefix}/sbin' ])
|
||||
|
||||
AC_ARG_WITH(dmdir,
|
||||
[ --with-dmdir=DIR Build against device-mapper source tree in DIR],
|
||||
[ DMDIR="$withval" ],
|
||||
[ DMDIR= ])
|
||||
|
||||
################################################################################
|
||||
dnl -- Ensure additional headers required
|
||||
if test x$READLINE = xyes; then
|
||||
@@ -524,9 +557,7 @@ if test x$INTL = xyes; then
|
||||
AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$DEVMAPPER = xyes; then
|
||||
AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out))
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out))
|
||||
@@ -536,7 +567,7 @@ fi
|
||||
AC_PATH_PROG(MODPROBE_CMD, modprobe)
|
||||
|
||||
if test x$MODPROBE_CMD != x; then
|
||||
CFLAGS="$CFLAGS -DMODPROBE_CMD=\\\"$MODPROBE_CMD\\\""
|
||||
AC_DEFINE_UNQUOTED([MODPROBE_CMD], ["$MODPROBE_CMD"], [The path to 'modprobe', if available.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -570,17 +601,21 @@ AC_SUBST(DEBUG)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
AC_SUBST(HAVE_LIBDL)
|
||||
AC_SUBST(HAVE_SELINUX)
|
||||
AC_SUBST(HAVE_REALTIME)
|
||||
AC_SUBST(CMDLIB)
|
||||
AC_SUBST(MSGFMT)
|
||||
AC_SUBST(LOCALEDIR)
|
||||
AC_SUBST(CONFDIR)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(DMDIR)
|
||||
AC_SUBST(INTL_PACKAGE)
|
||||
AC_SUBST(INTL)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(FSADM)
|
||||
AC_SUBST(DMEVENTD)
|
||||
AC_SUBST(CFLOW_CMD)
|
||||
AC_SUBST(CSCOPE_CMD)
|
||||
|
||||
################################################################################
|
||||
dnl -- First and last lines should not contain files to generate in order to
|
||||
@@ -602,6 +637,7 @@ lib/mirror/Makefile \
|
||||
lib/snapshot/Makefile \
|
||||
man/Makefile \
|
||||
po/Makefile \
|
||||
scripts/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
tools/fsadm/Makefile \
|
||||
|
||||
@@ -19,6 +19,7 @@ SOURCES = \
|
||||
clvmd-command.c \
|
||||
clvmd.c \
|
||||
lvm-functions.c \
|
||||
refresh_clvmd.c \
|
||||
system-lv.c
|
||||
|
||||
ifeq ("@CLVMD@", "gulm")
|
||||
@@ -35,35 +36,34 @@ ifeq ("@CLVMD@", "all")
|
||||
endif
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
CFLAGS += -DDEBUG
|
||||
DEFS += -DDEBUG
|
||||
endif
|
||||
|
||||
ifeq ("$(GULM)", "yes")
|
||||
SOURCES += clvmd-gulm.c tcp-comms.c
|
||||
LMLIBS += -lccs -lgulm
|
||||
CFLAGS += -DUSE_GULM
|
||||
DEFS += -DUSE_GULM
|
||||
endif
|
||||
|
||||
ifeq ("$(CMAN)", "yes")
|
||||
SOURCES += clvmd-cman.c
|
||||
LMLIBS += -ldlm
|
||||
CFLAGS += -DUSE_CMAN
|
||||
LMLIBS += -ldlm -lcman
|
||||
DEFS += -DUSE_CMAN
|
||||
endif
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
LVMLIBS = -llvm
|
||||
LVMLIBS = -llvm -lpthread
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
LVMLIBS += -ldevmapper-event -lpthread
|
||||
LVMLIBS += -ldevmapper-event
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
LVMLIBS += -ldevmapper
|
||||
endif
|
||||
LVMLIBS += -ldevmapper
|
||||
|
||||
CFLAGS += -D_REENTRANT -fno-strict-aliasing
|
||||
DEFS += -D_REENTRANT
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
@@ -71,7 +71,8 @@ INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||
$(CC) -o clvmd $(OBJECTS) $(CFLAGS) $(LDFLAGS) \
|
||||
$(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
|
||||
@@ -63,4 +63,8 @@ static const char CLVMD_SOCKNAME[] = "\0clvmd";
|
||||
#define CLVMD_CMD_LOCK_LV 50
|
||||
#define CLVMD_CMD_LOCK_VG 51
|
||||
|
||||
/* Misc functions */
|
||||
#define CLVMD_CMD_REFRESH 40
|
||||
#define CLVMD_CMD_GET_CLUSTERNAME 41
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,19 +46,23 @@
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static int cluster_sock;
|
||||
static int num_nodes;
|
||||
static struct cl_cluster_node *nodes = NULL;
|
||||
static struct cman_node *nodes = NULL;
|
||||
static struct cman_node this_node;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static int max_updown_nodes = 50; /* Current size of the allocated array */
|
||||
/* Node up/down status, indexed by nodeid */
|
||||
static int *node_updown = NULL;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
static cman_handle_t c_handle;
|
||||
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
@@ -68,30 +72,23 @@ struct lock_wait {
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
struct sockaddr_cl saddr;
|
||||
int port = CLUSTER_PORT_CLVMD;
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
|
||||
if (cluster_sock == -1) {
|
||||
/* Don't print an error here because we could be just probing for CMAN */
|
||||
c_handle = cman_init(NULL);
|
||||
if (!c_handle) {
|
||||
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
|
||||
return -1;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
fcntl(cluster_sock, F_SETFD, 1);
|
||||
|
||||
/* Bind to our port number on the cluster.
|
||||
Writes to this will block if the cluster loses quorum */
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = port;
|
||||
|
||||
if (bind
|
||||
(cluster_sock, (struct sockaddr *) &saddr,
|
||||
sizeof(struct sockaddr_cl))) {
|
||||
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
|
||||
syslog(LOG_ERR, "Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cman_start_notification(c_handle, event_callback)) {
|
||||
syslog(LOG_ERR, "Can't start cluster event listening");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
@@ -114,152 +111,122 @@ static void _cluster_init_completed(void)
|
||||
|
||||
static int _get_main_cluster_fd()
|
||||
{
|
||||
return cluster_sock;
|
||||
return cman_get_fd(c_handle);
|
||||
}
|
||||
|
||||
static int _get_num_nodes()
|
||||
{
|
||||
return num_nodes;
|
||||
int i;
|
||||
int nnodes = 0;
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
int len = 0;
|
||||
int nodeid = 0;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_flags = 0;
|
||||
iov[0].iov_len = msglen;
|
||||
iov[0].iov_base = buf;
|
||||
if (csid)
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = CLUSTER_PORT_CLVMD;
|
||||
if (csid) {
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
} else { /* Cluster broadcast */
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
|
||||
{
|
||||
log_error(errtext);
|
||||
}
|
||||
|
||||
do {
|
||||
len = sendmsg(cluster_sock, &msg, 0);
|
||||
if (len < 0 && errno != EAGAIN)
|
||||
log_error(errtext);
|
||||
|
||||
} while (len == -1 && errno == EAGAIN);
|
||||
return len;
|
||||
return msglen;
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
int i;
|
||||
memset(csid, 0, CMAN_MAX_CSID_LEN);
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodes[i].us)
|
||||
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
|
||||
if (this_node.cn_nodeid == 0) {
|
||||
cman_get_node(c_handle, 0, &this_node);
|
||||
}
|
||||
memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node that known (down mean not running a clvmd) */
|
||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
|
||||
static int _cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *, char *,
|
||||
int))
|
||||
void (*callback) (struct local_client *, char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
|
||||
if (!node_updown[nodes[i].node_id])
|
||||
somedown = -1;
|
||||
if (nodes[i].cn_member) {
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
|
||||
if (!node_updown[nodes[i].cn_nodeid])
|
||||
somedown = -1;
|
||||
}
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
static void process_oob_msg(char *buf, int len, int nodeid)
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[256];
|
||||
switch (buf[0]) {
|
||||
case CLUSTER_OOB_MSG_PORTCLOSED:
|
||||
name_from_nodeid(nodeid, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got OOB message, removing node %s\n", namebuf);
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
node_updown[nodeid] = 0;
|
||||
switch (reason) {
|
||||
case CMAN_REASON_PORTCLOSED:
|
||||
name_from_nodeid(arg, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
|
||||
|
||||
node_updown[arg] = 0;
|
||||
break;
|
||||
|
||||
case CLUSTER_OOB_MSG_STATECHANGE:
|
||||
DEBUGLOG("Got OOB message, Cluster state change\n");
|
||||
case CMAN_REASON_STATECHANGE:
|
||||
DEBUGLOG("Got state change message, re-reading members list\n");
|
||||
get_members();
|
||||
break;
|
||||
|
||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
|
||||
case CMAN_REASON_PORTOPENED:
|
||||
/* Ignore this, wait for startup message from clvmd itself */
|
||||
break;
|
||||
|
||||
case CMAN_REASON_TRY_SHUTDOWN:
|
||||
DEBUGLOG("Got try shutdown, sending OK\n");
|
||||
cman_replyto_shutdown(c_handle, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown OOB message: %d\n", buf[0]);
|
||||
DEBUGLOG("Got unknown event callback message: %d\n", reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
static struct local_client *cman_client;
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
|
||||
/* Save this for data_callback */
|
||||
cman_client = fd;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
iov[0].iov_len = len;
|
||||
iov[0].iov_base = buf;
|
||||
return cman_dispatch(c_handle, 0);
|
||||
}
|
||||
|
||||
len = recvmsg(cluster_sock, &msg, MSG_OOB | O_NONBLOCK);
|
||||
if (len < 0 && errno == EAGAIN)
|
||||
return len;
|
||||
|
||||
DEBUGLOG("Read on cluster socket, len = %d\n", len);
|
||||
|
||||
/* A real error */
|
||||
if (len < 0) {
|
||||
log_error("read error on cluster socket: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF - we have left the cluster */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Is it OOB? probably a node gone down */
|
||||
if (msg.msg_flags & MSG_OOB) {
|
||||
process_oob_msg(iov[0].iov_base, len, saddr.scl_nodeid);
|
||||
|
||||
/* Tell the upper layer to ignore this message */
|
||||
len = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
else {
|
||||
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
|
||||
/* Send it back to clvmd */
|
||||
process_message(client, buf, len, csid);
|
||||
}
|
||||
return len;
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid)
|
||||
{
|
||||
/* Ignore looped back messages */
|
||||
if (nodeid == this_node.cn_nodeid)
|
||||
return;
|
||||
process_message(cman_client, buf, len, (char *)&nodeid);
|
||||
}
|
||||
|
||||
static void _add_up_node(char *csid)
|
||||
@@ -278,7 +245,7 @@ static void _add_up_node(char *csid)
|
||||
max_updown_nodes);
|
||||
} else {
|
||||
log_error
|
||||
("Realloc failed. Node status for clvmd will be wrong. quitting\n");
|
||||
("Realloc failed. Node status for clvmd will be wrong. quitting\n");
|
||||
exit(999);
|
||||
}
|
||||
}
|
||||
@@ -290,19 +257,15 @@ static void _cluster_closedown()
|
||||
{
|
||||
unlock_all();
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
close(cluster_sock);
|
||||
cman_finish(c_handle);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
struct cl_listen_request rq;
|
||||
int status;
|
||||
|
||||
rq.port = CLUSTER_PORT_CLVMD;
|
||||
rq.nodeid = nodeid;
|
||||
|
||||
do {
|
||||
status = ioctl(cluster_sock, SIOCCLUSTER_ISLISTENING, &rq);
|
||||
status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
|
||||
if (status < 0 && errno == EBUSY) { /* Don't busywait */
|
||||
sleep(1);
|
||||
errno = EBUSY; /* In case sleep trashes it */
|
||||
@@ -320,67 +283,61 @@ static void count_clvmds_running(void)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
node_updown[nodes[i].node_id] = is_listening(nodes[i].node_id);
|
||||
node_updown[nodes[i].cn_nodeid] = is_listening(nodes[i].cn_nodeid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members()
|
||||
{
|
||||
struct cl_cluster_nodelist nodelist;
|
||||
int retnodes;
|
||||
int status;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
|
||||
num_nodes = cman_get_node_count(c_handle);
|
||||
if (num_nodes == -1) {
|
||||
log_error("Unable to get node count");
|
||||
} else {
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
nodes = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cl_cluster_node));
|
||||
if (!nodes) {
|
||||
log_error("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
nodelist.max_members = count_nodes;
|
||||
nodelist.nodes = nodes;
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
nodes = NULL;
|
||||
}
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
|
||||
if (num_nodes <= 0) {
|
||||
log_error("Unable to get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Sanity check struct */
|
||||
if (nodes[0].size != sizeof(struct cl_cluster_node)) {
|
||||
log_error
|
||||
("sizeof(cl_cluster_node) does not match size returned from the kernel: aborting\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (node_updown == NULL) {
|
||||
node_updown =
|
||||
(int *) malloc(sizeof(int) *
|
||||
max(num_nodes, max_updown_nodes));
|
||||
memset(node_updown, 0,
|
||||
sizeof(int) * max(num_nodes, max_updown_nodes));
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cman_node));
|
||||
if (!nodes) {
|
||||
log_error("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
|
||||
if (status < 0) {
|
||||
log_error("Unable to get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
if (node_updown == NULL) {
|
||||
node_updown =
|
||||
(int *) malloc(sizeof(int) *
|
||||
max(num_nodes, max_updown_nodes));
|
||||
memset(node_updown, 0,
|
||||
sizeof(int) * max(num_nodes, max_updown_nodes));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
static int _csid_from_name(char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].name) == 0) {
|
||||
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
|
||||
if (strcmp(name, nodes[i].cn_name) == 0) {
|
||||
memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -393,8 +350,8 @@ static int _name_from_csid(char *csid, char *name)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].name);
|
||||
if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -409,8 +366,8 @@ static int name_from_nodeid(int nodeid, char *name)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].node_id) {
|
||||
strcpy(name, nodes[i].name);
|
||||
if (nodeid == nodes[i].cn_nodeid) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -431,7 +388,7 @@ static int nodeid_from_csid(char *csid)
|
||||
|
||||
static int _is_quorate()
|
||||
{
|
||||
return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
|
||||
return cman_is_quorate(c_handle);
|
||||
}
|
||||
|
||||
static void sync_ast_routine(void *arg)
|
||||
@@ -514,6 +471,18 @@ static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cman_cluster_t cluster_info;
|
||||
int status;
|
||||
|
||||
status = cman_get_cluster(c_handle, &cluster_info);
|
||||
if (!status) {
|
||||
strncpy(buf, cluster_info.ci_name, buflen);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
@@ -527,6 +496,7 @@ static struct cluster_ops _cluster_cman_ops = {
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
|
||||
/* This is where all the real work happens:
|
||||
NOTE: client will be NULL when this is executed on a remote node */
|
||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
@@ -117,11 +119,21 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
if (status == EIO) {
|
||||
*retlen =
|
||||
1 + snprintf(*buf, buflen,
|
||||
"Internal lvm error, check syslog");
|
||||
get_last_lvm_error());
|
||||
return EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
do_refresh_cache();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
status = clops->get_cluster_name(*buf, buflen);
|
||||
if (!status)
|
||||
*retlen = strlen(*buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Won't get here because command is validated in pre_command */
|
||||
break;
|
||||
@@ -179,12 +191,16 @@ static int lock_vg(struct local_client *client)
|
||||
dm_hash_remove(lock_hash, lockname);
|
||||
}
|
||||
else {
|
||||
|
||||
status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid);
|
||||
/* Read locks need to be PR; other modes get passed through */
|
||||
if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) {
|
||||
lock_cmd &= ~LCK_TYPE_MASK;
|
||||
lock_cmd |= LCK_PREAD;
|
||||
}
|
||||
status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid);
|
||||
if (status)
|
||||
status = errno;
|
||||
else
|
||||
dm_hash_insert(lock_hash, lockname, (void *)lkid);
|
||||
dm_hash_insert(lock_hash, lockname, (void *)(long)lkid);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -208,7 +224,7 @@ int do_pre_command(struct local_client *client)
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
|
||||
client->bits.localsock.private = (void *) lockid;
|
||||
client->bits.localsock.private = (void *)(long)lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
@@ -222,6 +238,10 @@ int do_pre_command(struct local_client *client)
|
||||
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown command %d received\n", header->cmd);
|
||||
status = EINVAL;
|
||||
|
||||
@@ -43,6 +43,8 @@ struct cluster_ops {
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*get_cluster_name)(char *buf, int buflen);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
|
||||
int (*sync_unlock) (const char *resource, int lockid);
|
||||
|
||||
@@ -56,15 +58,19 @@ struct cluster_ops *init_gulm_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_CMAN
|
||||
# include "cnxman-socket.h"
|
||||
# include <netinet/in.h>
|
||||
# include "libcman.h"
|
||||
# define CMAN_MAX_CSID_LEN 4
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
|
||||
# endif
|
||||
# undef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_NODENAME_LEN
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 1500
|
||||
# define CLUSTER_PORT_CLVMD 11
|
||||
struct cluster_ops *init_cman_cluster(void);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -730,7 +730,7 @@ static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for GULM */
|
||||
if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try;
|
||||
if (flags & LKF_NOQUEUE) flags = lg_lock_flag_Try;
|
||||
|
||||
dm_hash_insert(lock_hash, resource, &lwait);
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
@@ -828,6 +828,7 @@ static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_PREAD:
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
|
||||
if (status)
|
||||
@@ -864,6 +865,7 @@ static int _sync_unlock(const char *resource, int lockid)
|
||||
/* The held lock mode is in the lock id */
|
||||
assert(lockid == LCK_EXCL ||
|
||||
lockid == LCK_READ ||
|
||||
lockid == LCK_PREAD ||
|
||||
lockid == LCK_WRITE);
|
||||
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
@@ -973,6 +975,12 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
|
||||
return gulm_cluster_send_message(buf, msglen, csid, errtext);
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
strncpy(buf, cluster_name, buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_gulm_ops = {
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
@@ -987,6 +995,7 @@ static struct cluster_ops _cluster_gulm_ops = {
|
||||
.add_up_node = gulm_add_up_node,
|
||||
.reread_config = _reread_config,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
|
||||
/* DLM constant that clvmd uses as a generic NONBLOCK lock flag */
|
||||
#define LKF_NOQUEUE 1
|
||||
|
||||
extern int get_next_node_csid(void **context, char *csid);
|
||||
extern void add_down_node(char *csid);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -42,6 +43,7 @@
|
||||
#include "clvm.h"
|
||||
#include "version.h"
|
||||
#include "clvmd.h"
|
||||
#include "refresh_clvmd.h"
|
||||
#include "libdlm.h"
|
||||
#include "system-lv.h"
|
||||
#include "list.h"
|
||||
@@ -66,7 +68,7 @@ static struct local_client local_client_head;
|
||||
|
||||
static unsigned short global_xid = 0; /* Last transaction ID issued */
|
||||
|
||||
static struct cluster_ops *clops = NULL;
|
||||
struct cluster_ops *clops = NULL;
|
||||
|
||||
static char our_csid[MAX_CSID_LEN];
|
||||
static unsigned max_csid_len;
|
||||
@@ -84,6 +86,7 @@ struct lvm_thread_cmd {
|
||||
int msglen;
|
||||
unsigned short xid;
|
||||
};
|
||||
static int debug = 0;
|
||||
static pthread_t lvm_thread;
|
||||
static pthread_mutex_t lvm_thread_mutex;
|
||||
static pthread_cond_t lvm_thread_cond;
|
||||
@@ -98,6 +101,7 @@ static int child_pipe[2];
|
||||
#define DFAIL_LOCAL_SOCK 2
|
||||
#define DFAIL_CLUSTER_IF 3
|
||||
#define DFAIL_MALLOC 4
|
||||
#define DFAIL_TIMEOUT 5
|
||||
#define SUCCESS 0
|
||||
|
||||
/* Prototypes for code further down */
|
||||
@@ -121,7 +125,7 @@ static int process_reply(struct clvm_header *msg, int msglen, char *csid);
|
||||
static int open_local_sock(void);
|
||||
static struct local_client *find_client(int clientid);
|
||||
static void main_loop(int local_sock, int cmd_timeout);
|
||||
static void be_daemon(void);
|
||||
static void be_daemon(int start_timeout);
|
||||
static int check_all_clvmds_running(struct local_client *client);
|
||||
static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
int len, char *csid,
|
||||
@@ -143,7 +147,9 @@ static void usage(char *prog, FILE *file)
|
||||
fprintf(file, " -V Show version of clvmd\n");
|
||||
fprintf(file, " -h Show this help information\n");
|
||||
fprintf(file, " -d Don't fork, run in the foreground\n");
|
||||
fprintf(file, " -R Tell all running clvmds in the cluster to reload their device cache\n");
|
||||
fprintf(file, " -t<secs> Command timeout (default 60 seconds)\n");
|
||||
fprintf(file, " -T<secs> Startup timeout (default none)\n");
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
@@ -159,21 +165,36 @@ static void child_init_signal(int status)
|
||||
}
|
||||
|
||||
|
||||
void debuglog(const char *fmt, ...)
|
||||
{
|
||||
time_t P;
|
||||
va_list ap;
|
||||
|
||||
if (!debug)
|
||||
return;
|
||||
|
||||
va_start(ap,fmt);
|
||||
time(&P);
|
||||
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 );
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int local_sock;
|
||||
struct local_client *newfd;
|
||||
struct utsname nodeinfo;
|
||||
signed char opt;
|
||||
int debug = 0;
|
||||
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
|
||||
int start_timeout = 0;
|
||||
sigset_t ss;
|
||||
int using_gulm = 0;
|
||||
|
||||
/* Deal with command-line arguments */
|
||||
opterr = 0;
|
||||
optind = 0;
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:RT:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@@ -183,6 +204,9 @@ int main(int argc, char *argv[])
|
||||
usage(argv[0], stderr);
|
||||
exit(0);
|
||||
|
||||
case 'R':
|
||||
return refresh_clvmd();
|
||||
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
@@ -195,6 +219,14 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
start_timeout = atoi(optarg);
|
||||
if (start_timeout <= 0) {
|
||||
fprintf(stderr, "startup timeout is invalid\n");
|
||||
usage(argv[0], stderr);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf("Cluster LVM daemon version: %s\n", LVM_VERSION);
|
||||
@@ -209,7 +241,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Fork into the background (unless requested not to) */
|
||||
if (!debug) {
|
||||
be_daemon();
|
||||
be_daemon(start_timeout);
|
||||
}
|
||||
|
||||
DEBUGLOG("CLVMD started\n");
|
||||
@@ -247,7 +279,7 @@ int main(int argc, char *argv[])
|
||||
if ((clops = init_cman_cluster())) {
|
||||
max_csid_len = CMAN_MAX_CSID_LEN;
|
||||
max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE;
|
||||
max_cluster_member_name_len = CMAN_MAX_CLUSTER_MEMBER_NAME_LEN;
|
||||
max_cluster_member_name_len = CMAN_MAX_NODENAME_LEN;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
|
||||
}
|
||||
#endif
|
||||
@@ -293,7 +325,8 @@ 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");
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
|
||||
(void *)(long)using_gulm);
|
||||
|
||||
/* Tell the rest of the cluster our version number */
|
||||
/* CMAN can do this immediately, gulm needs to wait until
|
||||
@@ -380,16 +413,17 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(int));
|
||||
|
||||
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
|
||||
thisfd->fd, len, *(int *) buffer);
|
||||
|
||||
if (len == sizeof(int)) {
|
||||
status = *(int *) buffer;
|
||||
memcpy(&status, buffer, sizeof(int));
|
||||
}
|
||||
|
||||
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
|
||||
thisfd->fd, len, status);
|
||||
|
||||
/* EOF on pipe or an error, close it */
|
||||
if (len <= 0) {
|
||||
int jstat;
|
||||
void *ret = &status;
|
||||
close(thisfd->fd);
|
||||
|
||||
/* Clear out the cross-link */
|
||||
@@ -399,9 +433,7 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
|
||||
/* Reap child thread */
|
||||
if (thisfd->bits.pipe.threadid) {
|
||||
jstat =
|
||||
pthread_join(thisfd->bits.pipe.threadid,
|
||||
(void **) &status);
|
||||
jstat = pthread_join(thisfd->bits.pipe.threadid, &ret);
|
||||
thisfd->bits.pipe.threadid = 0;
|
||||
if (thisfd->bits.pipe.client != NULL)
|
||||
thisfd->bits.pipe.client->bits.localsock.
|
||||
@@ -509,6 +541,7 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
int quorate = clops->is_quorate();
|
||||
|
||||
/* 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 != NULL;
|
||||
thisfd = thisfd->next) {
|
||||
@@ -641,16 +674,66 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
close(local_sock);
|
||||
}
|
||||
|
||||
static __attribute__ ((noreturn)) void wait_for_child(int c_pipe, int timeout)
|
||||
{
|
||||
int child_status;
|
||||
int sstat;
|
||||
fd_set fds;
|
||||
struct timeval tv = {timeout, 0};
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(c_pipe, &fds);
|
||||
|
||||
sstat = select(c_pipe+1, &fds, NULL, NULL, timeout? &tv: NULL);
|
||||
if (sstat == 0) {
|
||||
fprintf(stderr, "clvmd startup timed out\n");
|
||||
exit(DFAIL_TIMEOUT);
|
||||
}
|
||||
if (sstat == 1) {
|
||||
if (read(c_pipe, &child_status, sizeof(child_status)) !=
|
||||
sizeof(child_status)) {
|
||||
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
exit(DFAIL_INIT);
|
||||
}
|
||||
else {
|
||||
switch (child_status) {
|
||||
case SUCCESS:
|
||||
break;
|
||||
case DFAIL_INIT:
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
break;
|
||||
case DFAIL_LOCAL_SOCK:
|
||||
fprintf(stderr, "clvmd could not create local socket\n");
|
||||
fprintf(stderr, "Another clvmd is probably already running\n");
|
||||
break;
|
||||
case DFAIL_CLUSTER_IF:
|
||||
fprintf(stderr, "clvmd could not connect to cluster manager\n");
|
||||
fprintf(stderr, "Consult syslog for more information\n");
|
||||
break;
|
||||
case DFAIL_MALLOC:
|
||||
fprintf(stderr, "clvmd failed, not enough memory\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "clvmd failed, error was %d\n", child_status);
|
||||
break;
|
||||
}
|
||||
exit(child_status);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "clvmd startup, select failed: %s\n", strerror(errno));
|
||||
exit(DFAIL_INIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork into the background and detach from our parent process.
|
||||
* In the interests of user-friendliness we wait for the daemon
|
||||
* to complete initialisation before returning its status
|
||||
* the the user.
|
||||
*/
|
||||
static void be_daemon()
|
||||
static void be_daemon(int timeout)
|
||||
{
|
||||
pid_t pid;
|
||||
int child_status;
|
||||
int devnull = open("/dev/null", O_RDWR);
|
||||
if (devnull == -1) {
|
||||
perror("Can't open /dev/null");
|
||||
@@ -670,36 +753,7 @@ static void be_daemon()
|
||||
|
||||
default: /* Parent */
|
||||
close(child_pipe[1]);
|
||||
if (read(child_pipe[0], &child_status, sizeof(child_status)) !=
|
||||
sizeof(child_status)) {
|
||||
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
exit(DFAIL_INIT);
|
||||
}
|
||||
else {
|
||||
switch (child_status) {
|
||||
case SUCCESS:
|
||||
break;
|
||||
case DFAIL_INIT:
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
break;
|
||||
case DFAIL_LOCAL_SOCK:
|
||||
fprintf(stderr, "clvmd could not create local socket\n");
|
||||
fprintf(stderr, "Another clvmd is probably already running\n");
|
||||
break;
|
||||
case DFAIL_CLUSTER_IF:
|
||||
fprintf(stderr, "clvmd could not connect to cluster manager\n");
|
||||
fprintf(stderr, "Consult syslog for more information\n");
|
||||
break;
|
||||
case DFAIL_MALLOC:
|
||||
fprintf(stderr, "clvmd failed, not enough memory\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "clvmd failed, error was %d\n", child_status);
|
||||
break;
|
||||
}
|
||||
exit(child_status);
|
||||
}
|
||||
wait_for_child(child_pipe[0], timeout);
|
||||
}
|
||||
|
||||
/* Detach ourself from the calling environment */
|
||||
@@ -1085,8 +1139,8 @@ static int distribute_command(struct local_client *thisfd)
|
||||
}
|
||||
|
||||
/* Process a command from a remote node and return the result */
|
||||
void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
char *csid)
|
||||
static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
char *csid)
|
||||
{
|
||||
char *replyargs;
|
||||
char nodename[max_cluster_member_name_len];
|
||||
@@ -1110,11 +1164,12 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
(struct clvm_header *) malloc(msg->arglen +
|
||||
sizeof(struct clvm_header));
|
||||
if (newmsg) {
|
||||
if (system_lv_read_data
|
||||
(nodename, (char *) newmsg,
|
||||
(size_t *) &msglen) == 0) {
|
||||
ssize_t len;
|
||||
if (system_lv_read_data(nodename, (char *) newmsg,
|
||||
&len) == 0) {
|
||||
msg = newmsg;
|
||||
msg_malloced = 1;
|
||||
msglen = len;
|
||||
} else {
|
||||
struct clvm_header head;
|
||||
DEBUGLOG("System LV read failed\n");
|
||||
@@ -1160,8 +1215,11 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
/* Version check is internal - don't bother exposing it in
|
||||
clvmd-command.c */
|
||||
if (msg->cmd == CLVMD_CMD_VERSION) {
|
||||
int *version_nums = (int *) msg->args;
|
||||
int version_nums[3];
|
||||
char node[256];
|
||||
|
||||
memcpy(version_nums, msg->args, sizeof(version_nums));
|
||||
|
||||
clops->name_from_csid(csid, node);
|
||||
DEBUGLOG("Remote node %s is version %d.%d.%d\n",
|
||||
node,
|
||||
@@ -1333,7 +1391,7 @@ static void add_reply_to_list(struct local_client *client, int status,
|
||||
}
|
||||
|
||||
/* This is the thread that runs the PRE and post commands for a particular connection */
|
||||
static void *pre_and_post_thread(void *arg)
|
||||
static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
{
|
||||
struct local_client *client = (struct local_client *) arg;
|
||||
int status;
|
||||
@@ -1368,6 +1426,8 @@ static void *pre_and_post_thread(void *arg)
|
||||
DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd);
|
||||
/* Tell the parent process we have finished this bit */
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
if (status)
|
||||
continue; /* Wait for another PRE command */
|
||||
|
||||
/* We may need to wait for the condition variable before running the post command */
|
||||
pthread_mutex_lock(&client->bits.localsock.mutex);
|
||||
@@ -1401,7 +1461,6 @@ static void *pre_and_post_thread(void *arg)
|
||||
}
|
||||
DEBUGLOG("Subthread finished\n");
|
||||
pthread_exit((void *) 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process a command on the local node and store the result */
|
||||
@@ -1510,7 +1569,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
|
||||
if (thisreply->status)
|
||||
clientreply->flags |= CLVMD_FLAG_NODEERRS;
|
||||
|
||||
*(int *) ptr = thisreply->status;
|
||||
memcpy(ptr, &thisreply->status, sizeof(int));
|
||||
ptr += sizeof(int);
|
||||
|
||||
if (thisreply->replymsg) {
|
||||
@@ -1566,19 +1625,22 @@ static void send_version_message()
|
||||
{
|
||||
char message[sizeof(struct clvm_header) + sizeof(int) * 3];
|
||||
struct clvm_header *msg = (struct clvm_header *) message;
|
||||
int *version_nums = (int *) msg->args;
|
||||
int version_nums[3];
|
||||
|
||||
msg->cmd = CLVMD_CMD_VERSION;
|
||||
msg->status = 0;
|
||||
msg->flags = 0;
|
||||
msg->clientid = 0;
|
||||
msg->arglen = sizeof(int) * 3;
|
||||
msg->arglen = sizeof(version_nums);
|
||||
|
||||
version_nums[0] = htonl(CLVMD_MAJOR_VERSION);
|
||||
version_nums[1] = htonl(CLVMD_MINOR_VERSION);
|
||||
version_nums[2] = htonl(CLVMD_PATCH_VERSION);
|
||||
|
||||
memcpy(&msg->args, version_nums, sizeof(version_nums));
|
||||
|
||||
hton_clvm(msg);
|
||||
|
||||
clops->cluster_send_message(message, sizeof(message), NULL,
|
||||
"Error Sending version number");
|
||||
}
|
||||
@@ -1635,11 +1697,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
/*
|
||||
* Routine that runs in the "LVM thread".
|
||||
*/
|
||||
static void *lvm_thread_fn(void *arg)
|
||||
static __attribute__ ((noreturn)) void *lvm_thread_fn(void *arg)
|
||||
{
|
||||
struct list *cmdl, *tmp;
|
||||
sigset_t ss;
|
||||
int using_gulm = (int)arg;
|
||||
int using_gulm = (int)(long)arg;
|
||||
|
||||
/* Don't let anyone else to do work until we are started */
|
||||
pthread_mutex_lock(&lvm_start_mutex);
|
||||
|
||||
@@ -95,11 +95,7 @@ struct local_client {
|
||||
} bits;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
|
||||
#else
|
||||
#define DEBUGLOG(fmt, args...)
|
||||
#endif
|
||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args);
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
@@ -117,6 +113,7 @@ extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
extern void process_message(struct local_client *client, char *buf, int len, char *csid);
|
||||
extern void debuglog(const char *fmt, ... );
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
@@ -45,16 +45,23 @@
|
||||
#include "log.h"
|
||||
#include "activate.h"
|
||||
#include "locking.h"
|
||||
#include "defaults.h"
|
||||
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
char *get_last_lvm_error()
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
/* Return the mode a lock is currently held at (or -1 if not held) */
|
||||
static int get_current_lock(char *resource)
|
||||
{
|
||||
@@ -200,8 +207,17 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
|
||||
/* Try to get the lock if it's a clustered volume group */
|
||||
if (lock_flags & LCK_CLUSTER_VG) {
|
||||
status = hold_lock(resource, mode, LKF_NOQUEUE);
|
||||
if (status)
|
||||
if (status) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
* rather than the strerror text for EAGAIN.
|
||||
*/
|
||||
if (errno == EAGAIN) {
|
||||
sprintf(last_error, "Volume is busy on another node");
|
||||
errno = EIO;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
@@ -227,7 +243,7 @@ static int do_resume_lv(char *resource)
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
DEBUGLOG("do_resume_lv, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
@@ -303,6 +319,15 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
}
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_PARTIAL_MODE)
|
||||
init_partial(1);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(0);
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, lock_flags, LKM_EXMODE);
|
||||
@@ -331,6 +356,15 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_PARTIAL_MODE)
|
||||
init_partial(0);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
@@ -397,6 +431,13 @@ int do_check_lvm1(char *vgname)
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
int do_refresh_cache()
|
||||
{
|
||||
DEBUGLOG("Refreshing context\n");
|
||||
log_notice("Refreshing context");
|
||||
return refresh_toolcontext(cmd)==1?0:-1;
|
||||
}
|
||||
|
||||
|
||||
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
|
||||
that might be hanging around if we died for any reason
|
||||
@@ -432,7 +473,8 @@ static void drop_vg_locks()
|
||||
sync_unlock(vg, LCK_EXCL);
|
||||
|
||||
}
|
||||
fclose(vgs);
|
||||
if (fclose(vgs))
|
||||
DEBUGLOG("vgs fclose failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -482,16 +524,31 @@ static void *get_initial_state()
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(lvs);
|
||||
if (fclose(lvs))
|
||||
DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lvm2_log_fn(int level, const char *file, int line,
|
||||
const char *message)
|
||||
{
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
return;
|
||||
|
||||
strncpy(last_error, message, sizeof(last_error));
|
||||
last_error[sizeof(last_error)-1] = '\0';
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config()
|
||||
{
|
||||
int locking_type;
|
||||
|
||||
locking_type = find_config_int(cmd->cft->root, "global/locking_type", 1);
|
||||
locking_type = find_config_tree_int(cmd, "global/locking_type", 1);
|
||||
|
||||
if (locking_type == 3) /* compiled-in cluster support */
|
||||
return;
|
||||
@@ -499,7 +556,7 @@ static void check_config()
|
||||
if (locking_type == 2) { /* External library, check name */
|
||||
const char *libname;
|
||||
|
||||
libname = find_config_str(cmd->cft->root, "global/locking_library",
|
||||
libname = find_config_tree_str(cmd, "global/locking_library",
|
||||
"");
|
||||
if (strstr(libname, "liblvm2clusterlock.so"))
|
||||
return;
|
||||
@@ -520,7 +577,7 @@ void init_lvhash()
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(int using_gulm)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL))) {
|
||||
if (!(cmd = create_toolcontext(NULL, 0, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
@@ -538,5 +595,8 @@ int init_lvm(int using_gulm)
|
||||
|
||||
get_initial_state();
|
||||
|
||||
/* Trap log messages so we can pass them back to the user */
|
||||
init_log_fn(lvm2_log_fn);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(char *vgname);
|
||||
extern int do_refresh_cache(void);
|
||||
extern int init_lvm(int using_gulm);
|
||||
extern void init_lvhash(void);
|
||||
|
||||
extern int hold_unlock(char *resource);
|
||||
extern int hold_lock(char *resource, int mode, int flags);
|
||||
extern void unlock_all(void);
|
||||
extern char *get_last_lvm_error(void);
|
||||
|
||||
#endif
|
||||
|
||||
320
daemons/clvmd/refresh_clvmd.c
Normal file
320
daemons/clvmd/refresh_clvmd.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tell all clvmds in a cluster to refresh their toolcontext
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "refresh_clvmd.h"
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
} lvm_response_t;
|
||||
|
||||
/*
|
||||
* This gets stuck at the start of memory we allocate so we
|
||||
* can sanity-check it at deallocation time
|
||||
*/
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
static int _clvmd_sock = -1;
|
||||
|
||||
/* Open connection to the Cluster Manager daemon */
|
||||
static int _open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
/* Open local socket */
|
||||
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
|
||||
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
fprintf(stderr, "connect() failed on local socket: %s\n",
|
||||
strerror(errno));
|
||||
if (close(local_socket))
|
||||
return -1;
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
int buflen;
|
||||
int err;
|
||||
|
||||
/* Send it to CLVMD */
|
||||
rewrite:
|
||||
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
|
||||
if (err == -1 && errno == EINTR)
|
||||
goto rewrite;
|
||||
fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the response */
|
||||
reread:
|
||||
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
if (errno == EINTR)
|
||||
goto reread;
|
||||
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
buflen = len + outheader->arglen;
|
||||
*retbuf = dm_malloc(buflen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
while (off <= outheader->arglen && len > 0) {
|
||||
len = read(_clvmd_sock, outheader->args + off,
|
||||
buflen - off - offsetof(struct clvm_header, args));
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
|
||||
if (node) {
|
||||
/*
|
||||
* Allow a couple of special node names:
|
||||
* "*" for all nodes,
|
||||
* "." for the local node only
|
||||
*/
|
||||
if (strcmp(node, "*") == 0) {
|
||||
head->node[0] = '\0';
|
||||
} else if (strcmp(node, ".") == 0) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else
|
||||
strcpy(head->node, node);
|
||||
} else
|
||||
head->node[0] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to a(or all) node(s) in the cluster and wait for replies
|
||||
*/
|
||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
_clvmd_sock = _open_local_sock();
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
_build_header(head, cmd, node, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status = _send_request(outbuf, sizeof(struct clvm_header) +
|
||||
strlen(head->node) + len, &retbuf);
|
||||
if (!status)
|
||||
goto out;
|
||||
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate response array.
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
*response = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!*response) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
free(*response);
|
||||
errno = ENOMEM;
|
||||
status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
|
||||
out:
|
||||
if (retbuf)
|
||||
dm_free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refresh_clvmd()
|
||||
{
|
||||
int num_responses;
|
||||
char args[1]; // No args really.
|
||||
lvm_response_t *response;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error resetting node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
2
daemons/clvmd/refresh_clvmd.h
Normal file
2
daemons/clvmd/refresh_clvmd.h
Normal file
@@ -0,0 +1,2 @@
|
||||
int refresh_clvmd(void);
|
||||
|
||||
@@ -57,7 +57,7 @@ int init_comms(unsigned short port)
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
sock_hash = dm_hash_create(100);
|
||||
tcp_port = port ? port : DEFAULT_TCP_PORT;
|
||||
tcp_port = port ? : DEFAULT_TCP_PORT;
|
||||
|
||||
listen_fd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
dm_event_register
|
||||
dm_event_unregister
|
||||
dm_event_handler_create
|
||||
dm_event_handler_destroy
|
||||
dm_event_handler_set_dso
|
||||
dm_event_handler_set_dev_name
|
||||
dm_event_handler_set_uuid
|
||||
dm_event_handler_set_major
|
||||
dm_event_handler_set_minor
|
||||
dm_event_handler_set_event_mask
|
||||
dm_event_handler_get_dso
|
||||
dm_event_handler_get_devname
|
||||
dm_event_handler_get_uuid
|
||||
dm_event_handler_get_major
|
||||
dm_event_handler_get_minor
|
||||
dm_event_handler_get_event_mask
|
||||
dm_event_register_handler
|
||||
dm_event_unregister_handler
|
||||
dm_event_get_registered_device
|
||||
dm_event_set_timeout
|
||||
dm_event_get_timeout
|
||||
dm_event_handler_set_timeout
|
||||
dm_event_handler_get_timeout
|
||||
|
||||
@@ -15,8 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES = libdevmapper-event.c \
|
||||
dmeventd.c
|
||||
SOURCES = libdevmapper-event.c
|
||||
|
||||
LIB_STATIC = libdevmapper-event.a
|
||||
|
||||
@@ -26,11 +25,20 @@ else
|
||||
LIB_SHARED = libdevmapper-event.so
|
||||
endif
|
||||
|
||||
TARGETS = dmeventd
|
||||
CLEAN_TARGETS = dmeventd.o
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
LDFLAGS += -ldl -ldevmapper -lpthread
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
.PHONY: install_dynamic install_static
|
||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||
$(CC) -o $@ dmeventd.o $(CFLAGS) $(LDFLAGS) \
|
||||
-L. -ldevmapper-event $(LIBS) -rdynamic
|
||||
|
||||
.PHONY: install_dynamic install_static install_include \
|
||||
install_pkgconfig install_dmeventd
|
||||
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
@@ -38,18 +46,38 @@ ifeq ("@STATIC_LINK@", "yes")
|
||||
INSTALL_TYPE += install_static
|
||||
endif
|
||||
|
||||
install: $(INSTALL_TYPE)
|
||||
ifeq ("@PKGCONFIG@", "yes")
|
||||
INSTALL_TYPE += install_pkgconfig
|
||||
endif
|
||||
|
||||
install: $(INSTALL_TYPE) install_include install_dmeventd
|
||||
|
||||
install_include:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
|
||||
$(includedir)/libdevmapper-event.h
|
||||
|
||||
install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION)
|
||||
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
|
||||
$(includedir)/libdevmapper-event.h
|
||||
|
||||
install_dmeventd: dmeventd
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< $(sbindir)/$<
|
||||
|
||||
install_pkgconfig:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.pc \
|
||||
$(usrlibdir)/pkgconfig/devmapper-event.pc
|
||||
|
||||
install_static: libdevmapper-event.a
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/libdevmapper-event.a.$(LIB_VERSION)
|
||||
$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a
|
||||
|
||||
.PHONY: distclean_lib distclean
|
||||
|
||||
distclean_lib:
|
||||
$(RM) libdevmapper-event.pc
|
||||
|
||||
distclean: distclean_lib
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,52 @@
|
||||
#ifndef __DMEVENTD_DOT_H__
|
||||
#define __DMEVENTD_DOT_H__
|
||||
|
||||
/* FIXME This stuff must be configurable. */
|
||||
|
||||
#define DM_EVENT_DAEMON "/sbin/dmeventd"
|
||||
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
|
||||
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DM_EVENT_DEFAULT_TIMEOUT 10
|
||||
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dm_event_command {
|
||||
DM_EVENT_CMD_ACTIVE = 1,
|
||||
DM_EVENT_CMD_REGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
DM_EVENT_CMD_HELLO,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct dm_event_daemon_message {
|
||||
uint32_t cmd;
|
||||
uint32_t size;
|
||||
char *data;
|
||||
};
|
||||
|
||||
/* FIXME Is this meant to be exported? I can't see where the
|
||||
interface uses it. */
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct dm_event_fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
|
||||
/* EXIT_SUCCESS 0 -- stdlib.h */
|
||||
/* EXIT_FAILURE 1 -- stdlib.h */
|
||||
#define EXIT_LOCKFILE_INUSE 2
|
||||
#define EXIT_DESC_CLOSE_FAILURE 3
|
||||
#define EXIT_OPEN_PID_FAILURE 4
|
||||
#define EXIT_FIFO_FAILURE 5
|
||||
#define EXIT_CHDIR_FAILURE 6
|
||||
|
||||
void dmeventd(void)
|
||||
__attribute((noreturn));
|
||||
#define EXIT_DESC_OPEN_FAILURE 4
|
||||
#define EXIT_OPEN_PID_FAILURE 5
|
||||
#define EXIT_FIFO_FAILURE 6
|
||||
#define EXIT_CHDIR_FAILURE 7
|
||||
|
||||
#endif /* __DMEVENTD_DOT_H__ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,86 +23,84 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* FIXME This stuff must be configurable. */
|
||||
/*
|
||||
* Event library interface.
|
||||
*/
|
||||
|
||||
#define DM_EVENT_DAEMON "/sbin/dmeventd"
|
||||
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
|
||||
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
|
||||
enum dm_event_mask {
|
||||
DM_EVENT_SETTINGS_MASK = 0x0000FF,
|
||||
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
|
||||
|
||||
#define DM_EVENT_DEFAULT_TIMEOUT 10
|
||||
DM_EVENT_ERROR_MASK = 0x00FF00,
|
||||
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
|
||||
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dm_event_command {
|
||||
DM_EVENT_CMD_ACTIVE = 1,
|
||||
DM_EVENT_CMD_REGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
DM_EVENT_STATUS_MASK = 0xFF0000,
|
||||
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
|
||||
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
|
||||
|
||||
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct dm_event_daemon_message {
|
||||
union {
|
||||
unsigned int cmd; /* FIXME Use fixed size. */
|
||||
int status; /* FIXME Use fixed size. */
|
||||
} opcode;
|
||||
char msg[252]; /* FIXME Why is this 252 ? */
|
||||
} __attribute__((packed)); /* FIXME Do this properly! */
|
||||
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
|
||||
|
||||
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct dm_event_fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
struct dm_event_handler;
|
||||
|
||||
/* Event type definitions. */
|
||||
/* FIXME Use masks to separate the types and provide for extension. */
|
||||
enum dm_event_type {
|
||||
DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x02, /* Report all of them. */
|
||||
struct dm_event_handler *dm_event_handler_create(void);
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh);
|
||||
|
||||
DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
|
||||
/*
|
||||
* Path of shared library to handle events.
|
||||
*
|
||||
* All of dso, device_name and uuid strings are duplicated, you do not
|
||||
* need to keep the pointers valid after the call succeeds. Thes may
|
||||
* return -ENOMEM though.
|
||||
*/
|
||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
|
||||
|
||||
DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
/*
|
||||
* Identify the device to monitor by exactly one of device_name, uuid or
|
||||
* device number. String arguments are duplicated, see above.
|
||||
*/
|
||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
|
||||
|
||||
/* FIXME Use a mask. */
|
||||
#define DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
|
||||
DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
|
||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major);
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor);
|
||||
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout);
|
||||
|
||||
/* FIXME Replace device with standard name/uuid/devno choice */
|
||||
/* Interface changes:
|
||||
First register a handler, passing in a unique ref for the device. */
|
||||
// int dm_event_register_handler(const char *dso_name, const char *device);
|
||||
// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
|
||||
/* Or (better?) add to task structure and use existing functions - run a task to register/unregister events - we may need to run task withe that with the new event mechanism anyway, then the dso calls just hook in.
|
||||
*/
|
||||
|
||||
/* FIXME Missing consts? */
|
||||
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
|
||||
int dm_event_unregister(char *dso_name, char *device,
|
||||
enum dm_event_type events);
|
||||
int dm_event_get_registered_device(char **dso_name, char **device,
|
||||
enum dm_event_type *events, int next);
|
||||
int dm_event_set_timeout(char *device, uint32_t timeout);
|
||||
int dm_event_get_timeout(char *device, uint32_t *timeout);
|
||||
/*
|
||||
* Specify mask for events to monitor.
|
||||
*/
|
||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
|
||||
enum dm_event_mask evmask);
|
||||
|
||||
/* Prototypes for DSO interface. */
|
||||
void process_event(const char *device, enum dm_event_type event);
|
||||
int register_device(const char *device);
|
||||
int unregister_device(const char *device);
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh);
|
||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* FIXME Review interface (what about this next thing?) */
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
||||
|
||||
/*
|
||||
* Initiate monitoring using dmeventd.
|
||||
*/
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||
detailed descriptions. */
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user);
|
||||
int register_device(const char *device_name, const char *uuid, int major, int minor, void **user);
|
||||
int unregister_device(const char *device_name, const char *uuid, int major,
|
||||
int minor, void **user);
|
||||
|
||||
#endif
|
||||
|
||||
12
daemons/dmeventd/libdevmapper-event.pc.in
Normal file
12
daemons/dmeventd/libdevmapper-event.pc.in
Normal file
@@ -0,0 +1,12 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: devmapper-event
|
||||
Description: device-mapper event library
|
||||
Version: @DM_LIB_VERSION@
|
||||
Requires: devmapper
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -ldevmapper-event
|
||||
Libs.private: -lpthread -ldl
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -26,147 +25,167 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
* Only one device may be registered or unregistered at a time.
|
||||
*/
|
||||
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* Number of active registrations.
|
||||
*/
|
||||
static int _register_count = 0;
|
||||
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
/*
|
||||
* Currently only one event can be processed at a time.
|
||||
*/
|
||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int _get_mirror_event(char *params)
|
||||
{
|
||||
int i, rtn = ME_INSYNC;
|
||||
int max_args = 30; /* should support at least 8-way mirrors */
|
||||
char *args[max_args];
|
||||
int i, r = ME_INSYNC;
|
||||
char **args = NULL;
|
||||
char *dev_status_str;
|
||||
char *log_status_str;
|
||||
char *sync_str;
|
||||
char *p;
|
||||
int log_argc, num_devs, num_failures=0;
|
||||
|
||||
if (max_args <= split_words(params, max_args, args)) {
|
||||
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
|
||||
return -E2BIG;
|
||||
}
|
||||
char *p = NULL;
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
*/
|
||||
num_devs = atoi(args[0]);
|
||||
dev_status_str = args[3 + num_devs];
|
||||
log_argc = atoi(args[4 + num_devs]);
|
||||
log_status_str = args[4 + num_devs + log_argc];
|
||||
sync_str = args[1 + num_devs];
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
if (!dm_split_words(params, 1, 0, &p))
|
||||
goto out_parse;
|
||||
|
||||
if (!(num_devs = atoi(p)))
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
log_argc = atoi(args[3 + num_devs]);
|
||||
log_status_str = args[3 + num_devs + log_argc];
|
||||
sync_str = args[num_devs];
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
for (i = 0; i < num_devs; i++)
|
||||
if (dev_status_str[i] == 'D') {
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
|
||||
num_failures++;
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bad log device */
|
||||
if (log_status_str[0] == 'D') {
|
||||
/* Check for bad disk log device */
|
||||
if (log_argc > 1 && log_status_str[0] == 'D') {
|
||||
syslog(LOG_ERR, "Log device, %s, has failed.\n",
|
||||
args[3 + num_devs + log_argc]);
|
||||
num_failures++;
|
||||
args[2 + num_devs + log_argc]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
if (num_failures) {
|
||||
rtn = ME_FAILURE;
|
||||
if (r == ME_FAILURE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = strstr(sync_str, "/");
|
||||
if (p) {
|
||||
p[0] = '\0';
|
||||
if (strcmp(sync_str, p+1))
|
||||
rtn = ME_IGNORE;
|
||||
r = ME_IGNORE;
|
||||
p[0] = '/';
|
||||
} else {
|
||||
/*
|
||||
* How the hell did we get this?
|
||||
* Might mean all our parameters are screwed.
|
||||
*/
|
||||
syslog(LOG_ERR, "Unable to parse sync string.");
|
||||
rtn = ME_IGNORE;
|
||||
}
|
||||
out:
|
||||
return rtn;
|
||||
} else
|
||||
goto out_parse;
|
||||
|
||||
out:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
return r;
|
||||
|
||||
out_parse:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
|
||||
static void _temporary_log_fn(int level, const char *file,
|
||||
int line, const char *format)
|
||||
{
|
||||
return;
|
||||
syslog(LOG_DEBUG, "%s", format);
|
||||
if (!strncmp(format, "WARNING: ", 9) && (level < 5))
|
||||
syslog(LOG_CRIT, "%s", format);
|
||||
else
|
||||
syslog(LOG_DEBUG, "%s", format);
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
{
|
||||
int r;
|
||||
void *handle;
|
||||
int cmd_size = 256; /* FIXME Use system restriction */
|
||||
char cmd_str[cmd_size];
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
char *vg = NULL, *lv = NULL, *layer = NULL;
|
||||
|
||||
if (strlen(device) > 200)
|
||||
return -ENAMETOOLONG;
|
||||
if (strlen(device) > 200) /* FIXME Use real restriction */
|
||||
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
|
||||
|
||||
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
|
||||
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s",
|
||||
device);
|
||||
return -ENOMEM;
|
||||
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG;
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
handle = lvm2_init();
|
||||
lvm2_log_level(handle, 1);
|
||||
r = lvm2_run(handle, cmd_str);
|
||||
r = lvm2_run(_lvm_handle, cmd_str);
|
||||
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1)? 0: -1;
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void process_event(const char *device, enum dm_event_type event)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
/* FIXME Move inside libdevmapper */
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
syslog(LOG_ERR, "Unable to create dm_task.\n");
|
||||
goto fail;
|
||||
if (pthread_mutex_trylock(&_event_mutex)) {
|
||||
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
}
|
||||
|
||||
if (!dm_task_set_name(dmt, device)) {
|
||||
syslog(LOG_ERR, "Unable to set device name.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
syslog(LOG_ERR, "Unable to run task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.\n", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
|
||||
continue;
|
||||
@@ -183,6 +202,7 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s\n", device);
|
||||
if (_remove_failed_devices(device))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
@@ -194,53 +214,68 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.\n");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
fail:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
pthread_mutex_unlock(&_event_mutex);
|
||||
}
|
||||
|
||||
int register_device(const char *device)
|
||||
int register_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
syslog(LOG_INFO, "Monitoring %s for events\n", device);
|
||||
int r = 0;
|
||||
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
||||
goto out;
|
||||
|
||||
if (!mem_pool)
|
||||
return 0;
|
||||
|
||||
register_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device)
|
||||
{
|
||||
syslog(LOG_INFO, "Stopped monitoring %s for events\n", device);
|
||||
|
||||
if (!(--register_count)) {
|
||||
dm_pool_destroy(mem_pool);
|
||||
mem_pool = NULL;
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
goto out;
|
||||
}
|
||||
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
}
|
||||
|
||||
return 1;
|
||||
_register_count++;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
|
||||
device);
|
||||
|
||||
if (!--_register_count) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -26,147 +25,167 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
* Only one device may be registered or unregistered at a time.
|
||||
*/
|
||||
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* Number of active registrations.
|
||||
*/
|
||||
static int _register_count = 0;
|
||||
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
/*
|
||||
* Currently only one event can be processed at a time.
|
||||
*/
|
||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int _get_mirror_event(char *params)
|
||||
{
|
||||
int i, rtn = ME_INSYNC;
|
||||
int max_args = 30; /* should support at least 8-way mirrors */
|
||||
char *args[max_args];
|
||||
int i, r = ME_INSYNC;
|
||||
char **args = NULL;
|
||||
char *dev_status_str;
|
||||
char *log_status_str;
|
||||
char *sync_str;
|
||||
char *p;
|
||||
int log_argc, num_devs, num_failures=0;
|
||||
|
||||
if (max_args <= split_words(params, max_args, args)) {
|
||||
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
|
||||
return -E2BIG;
|
||||
}
|
||||
char *p = NULL;
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
*/
|
||||
num_devs = atoi(args[0]);
|
||||
dev_status_str = args[3 + num_devs];
|
||||
log_argc = atoi(args[4 + num_devs]);
|
||||
log_status_str = args[4 + num_devs + log_argc];
|
||||
sync_str = args[1 + num_devs];
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
if (!dm_split_words(params, 1, 0, &p))
|
||||
goto out_parse;
|
||||
|
||||
if (!(num_devs = atoi(p)))
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
log_argc = atoi(args[3 + num_devs]);
|
||||
log_status_str = args[3 + num_devs + log_argc];
|
||||
sync_str = args[num_devs];
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
for (i = 0; i < num_devs; i++)
|
||||
if (dev_status_str[i] == 'D') {
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
|
||||
num_failures++;
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bad log device */
|
||||
if (log_status_str[0] == 'D') {
|
||||
/* Check for bad disk log device */
|
||||
if (log_argc > 1 && log_status_str[0] == 'D') {
|
||||
syslog(LOG_ERR, "Log device, %s, has failed.\n",
|
||||
args[3 + num_devs + log_argc]);
|
||||
num_failures++;
|
||||
args[2 + num_devs + log_argc]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
if (num_failures) {
|
||||
rtn = ME_FAILURE;
|
||||
if (r == ME_FAILURE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = strstr(sync_str, "/");
|
||||
if (p) {
|
||||
p[0] = '\0';
|
||||
if (strcmp(sync_str, p+1))
|
||||
rtn = ME_IGNORE;
|
||||
r = ME_IGNORE;
|
||||
p[0] = '/';
|
||||
} else {
|
||||
/*
|
||||
* How the hell did we get this?
|
||||
* Might mean all our parameters are screwed.
|
||||
*/
|
||||
syslog(LOG_ERR, "Unable to parse sync string.");
|
||||
rtn = ME_IGNORE;
|
||||
}
|
||||
out:
|
||||
return rtn;
|
||||
} else
|
||||
goto out_parse;
|
||||
|
||||
out:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
return r;
|
||||
|
||||
out_parse:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
|
||||
static void _temporary_log_fn(int level, const char *file,
|
||||
int line, const char *format)
|
||||
{
|
||||
return;
|
||||
syslog(LOG_DEBUG, "%s", format);
|
||||
if (!strncmp(format, "WARNING: ", 9) && (level < 5))
|
||||
syslog(LOG_CRIT, "%s", format);
|
||||
else
|
||||
syslog(LOG_DEBUG, "%s", format);
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
{
|
||||
int r;
|
||||
void *handle;
|
||||
int cmd_size = 256; /* FIXME Use system restriction */
|
||||
char cmd_str[cmd_size];
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
char *vg = NULL, *lv = NULL, *layer = NULL;
|
||||
|
||||
if (strlen(device) > 200)
|
||||
return -ENAMETOOLONG;
|
||||
if (strlen(device) > 200) /* FIXME Use real restriction */
|
||||
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
|
||||
|
||||
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
|
||||
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s",
|
||||
device);
|
||||
return -ENOMEM;
|
||||
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG;
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
handle = lvm2_init();
|
||||
lvm2_log_level(handle, 1);
|
||||
r = lvm2_run(handle, cmd_str);
|
||||
r = lvm2_run(_lvm_handle, cmd_str);
|
||||
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1)? 0: -1;
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void process_event(const char *device, enum dm_event_type event)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
/* FIXME Move inside libdevmapper */
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
syslog(LOG_ERR, "Unable to create dm_task.\n");
|
||||
goto fail;
|
||||
if (pthread_mutex_trylock(&_event_mutex)) {
|
||||
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
}
|
||||
|
||||
if (!dm_task_set_name(dmt, device)) {
|
||||
syslog(LOG_ERR, "Unable to set device name.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
syslog(LOG_ERR, "Unable to run task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.\n", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
|
||||
continue;
|
||||
@@ -183,6 +202,7 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s\n", device);
|
||||
if (_remove_failed_devices(device))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
@@ -194,53 +214,68 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.\n");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
fail:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
pthread_mutex_unlock(&_event_mutex);
|
||||
}
|
||||
|
||||
int register_device(const char *device)
|
||||
int register_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
syslog(LOG_INFO, "Monitoring %s for events\n", device);
|
||||
int r = 0;
|
||||
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
||||
goto out;
|
||||
|
||||
if (!mem_pool)
|
||||
return 0;
|
||||
|
||||
register_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device)
|
||||
{
|
||||
syslog(LOG_INFO, "Stopped monitoring %s for events\n", device);
|
||||
|
||||
if (!(--register_count)) {
|
||||
dm_pool_destroy(mem_pool);
|
||||
mem_pool = NULL;
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
goto out;
|
||||
}
|
||||
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
}
|
||||
|
||||
return 1;
|
||||
_register_count++;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
|
||||
device);
|
||||
|
||||
if (!--_register_count) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
100
doc/example.conf
100
doc/example.conf
@@ -56,10 +56,14 @@ devices {
|
||||
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
|
||||
|
||||
# The results of the filtering are cached on disk to avoid
|
||||
# rescanning dud devices (which can take a very long time). By
|
||||
# default this cache file is hidden in the /etc/lvm directory.
|
||||
# It is safe to delete this file: the tools regenerate it.
|
||||
cache = "/etc/lvm/.cache"
|
||||
# rescanning dud devices (which can take a very long time).
|
||||
# By default this cache is stored in the /etc/lvm/cache directory
|
||||
# in a file called '.cache'.
|
||||
# It is safe to delete the contents: the tools regenerate it.
|
||||
# (The old setting 'cache' is still respected if neither of
|
||||
# these new ones is present.)
|
||||
cache_dir = "/etc/lvm/cache"
|
||||
cache_file_prefix = ""
|
||||
|
||||
# You can turn off writing this cache file by setting this to 0.
|
||||
write_cache_state = 1
|
||||
@@ -79,6 +83,12 @@ devices {
|
||||
# software RAID (md) devices by looking for md superblocks.
|
||||
# 1 enables; 0 disables.
|
||||
md_component_detection = 1
|
||||
|
||||
# If, while scanning the system for PVs, LVM2 encounters a device-mapper
|
||||
# device that has its I/O suspended, it waits for it to become accessible.
|
||||
# Set this to 1 to skip such devices. This should only be needed
|
||||
# in recovery situations.
|
||||
ignore_suspended_devices = 0
|
||||
}
|
||||
|
||||
# This section that allows you to configure the nature of the
|
||||
@@ -182,6 +192,9 @@ global {
|
||||
# command. Defaults to off.
|
||||
test = 0
|
||||
|
||||
# Default value for --units argument
|
||||
units = "h"
|
||||
|
||||
# Whether or not to communicate with the kernel device-mapper.
|
||||
# Set to 0 if you want to use the tools to manipulate LVM metadata
|
||||
# without activating any logical volumes.
|
||||
@@ -207,11 +220,26 @@ global {
|
||||
# Location of proc filesystem
|
||||
proc = "/proc"
|
||||
|
||||
# Type of locking to use. Defaults to file-based locking (1).
|
||||
# Type of locking to use. Defaults to local file-based locking (1).
|
||||
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
|
||||
# if LVM2 commands get run concurrently).
|
||||
# Type 2 uses the external shared library locking_library.
|
||||
# Type 3 uses built-in clustered locking.
|
||||
locking_type = 1
|
||||
|
||||
# If using external locking (type 2) and initialisation fails,
|
||||
# with this set to 1 an attempt will be made to use the built-in
|
||||
# clustered locking.
|
||||
# If you are using a customised locking_library you should set this to 0.
|
||||
fallback_to_clustered_locking = 1
|
||||
|
||||
# If an attempt to initialise type 2 or type 3 locking failed, perhaps
|
||||
# because cluster components such as clvmd are not running, with this set
|
||||
# to 1 an attempt will be made to use local file-based locking (type 1).
|
||||
# If this succeeds, only commands against local volume groups will proceed.
|
||||
# Volume Groups marked as clustered will be ignored.
|
||||
fallback_to_local_locking = 1
|
||||
|
||||
# Local non-LV directory that holds file-based locks while commands are
|
||||
# in progress. A directory like /tmp that may get wiped on reboot is OK.
|
||||
locking_dir = "/var/lock/lvm"
|
||||
@@ -223,6 +251,9 @@ global {
|
||||
|
||||
# Search this directory first for shared libraries.
|
||||
# library_dir = "/lib"
|
||||
|
||||
# The external locking library to load if locking_type is set to 2.
|
||||
# locking_library = "liblvm2clusterlock.so"
|
||||
}
|
||||
|
||||
activation {
|
||||
@@ -232,9 +263,6 @@ activation {
|
||||
# target or make it return zeros.
|
||||
missing_stripe_filler = "/dev/ioerror"
|
||||
|
||||
# Size (in KB) of each copy operation when mirroring
|
||||
mirror_region_size = 512
|
||||
|
||||
# How much stack (in KB) to reserve for use while devices suspended
|
||||
reserved_stack = 256
|
||||
|
||||
@@ -251,6 +279,54 @@ activation {
|
||||
# "@*" matches if any tag defined on the host is also set in the LV or VG
|
||||
#
|
||||
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
|
||||
|
||||
# Size (in KB) of each copy operation when mirroring
|
||||
mirror_region_size = 512
|
||||
|
||||
# 'mirror_image_fault_policy' and 'mirror_log_fault_policy' define
|
||||
# how a device failure affecting a mirror is handled.
|
||||
# A mirror is composed of mirror images (copies) and a log.
|
||||
# A disk log ensures that a mirror does not need to be re-synced
|
||||
# (all copies made the same) every time a machine reboots or crashes.
|
||||
#
|
||||
# In the event of a failure, the specified policy will be used to
|
||||
# determine what happens:
|
||||
#
|
||||
# "remove" - Simply remove the faulty device and run without it. If
|
||||
# the log device fails, the mirror would convert to using
|
||||
# an in-memory log. This means the mirror will not
|
||||
# remember its sync status across crashes/reboots and
|
||||
# the entire mirror will be re-synced. If a
|
||||
# mirror image fails, the mirror will convert to a
|
||||
# non-mirrored device if there is only one remaining good
|
||||
# copy.
|
||||
#
|
||||
# "allocate" - Remove the faulty device and try to allocate space on
|
||||
# a new device to be a replacement for the failed device.
|
||||
# Using this policy for the log is fast and maintains the
|
||||
# ability to remember sync state through crashes/reboots.
|
||||
# Using this policy for a mirror device is slow, as it
|
||||
# requires the mirror to resynchronize the devices, but it
|
||||
# will preserve the mirror characteristic of the device.
|
||||
# This policy acts like "remove" if no suitable device and
|
||||
# space can be allocated for the replacement.
|
||||
# Currently this is not implemented properly and behaves
|
||||
# similarly to:
|
||||
#
|
||||
# "allocate_anywhere" - Operates like "allocate", but it does not
|
||||
# require that the new space being allocated be on a
|
||||
# device is not part of the mirror. For a log device
|
||||
# failure, this could mean that the log is allocated on
|
||||
# the same device as a mirror device. For a mirror
|
||||
# device, this could mean that the mirror device is
|
||||
# allocated on the same device as another mirror device.
|
||||
# This policy would not be wise for mirror devices
|
||||
# because it would break the redundant nature of the
|
||||
# mirror. This policy acts like "remove" if no suitable
|
||||
# device and space can be allocated for the replacement.
|
||||
|
||||
mirror_log_fault_policy = "allocate"
|
||||
mirror_device_fault_policy = "remove"
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +367,13 @@ activation {
|
||||
|
||||
# Event daemon
|
||||
#
|
||||
#dmeventd {
|
||||
# dmeventd {
|
||||
# mirror_library is the library used when monitoring a mirror device.
|
||||
#
|
||||
# "libdevmapper-event-lvm2mirror.so" attempts to recover from failures.
|
||||
# It removes failed devices from a volume group and reconfigures a
|
||||
# mirror as necessary.
|
||||
#
|
||||
# mirror_library = "libdevmapper-event-lvm2mirror.so"
|
||||
#}
|
||||
|
||||
|
||||
@@ -34,12 +34,14 @@
|
||||
../lib/metadata/segtype.h
|
||||
../lib/mm/memlock.h
|
||||
../lib/mm/xlate.h
|
||||
../lib/misc/configure.h
|
||||
../lib/misc/crc.h
|
||||
../lib/misc/intl.h
|
||||
../lib/misc/lib.h
|
||||
../lib/misc/lvm-exec.h
|
||||
../lib/misc/lvm-file.h
|
||||
../lib/misc/lvm-string.h
|
||||
../lib/misc/lvm-wrappers.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/report/report.h
|
||||
|
||||
@@ -41,3 +41,5 @@ install:
|
||||
|
||||
install_cluster:
|
||||
|
||||
cflow:
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ SOURCES =\
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
datastruct/btree.c \
|
||||
datastruct/list.c \
|
||||
datastruct/str_list.c \
|
||||
device/dev-cache.c \
|
||||
device/dev-io.c \
|
||||
@@ -77,6 +78,8 @@ SOURCES =\
|
||||
misc/lvm-exec.c \
|
||||
misc/lvm-file.c \
|
||||
misc/lvm-string.c \
|
||||
misc/lvm-wrappers.c \
|
||||
misc/timestamp.c \
|
||||
mm/memlock.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
@@ -141,5 +144,14 @@ LIB_STATIC = liblvm.a
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
||||
CLEAN_TARGETS += liblvm.cflow
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
liblvm.cflow: $(SOURCES)
|
||||
set -e; (echo -n "SOURCES += "; \
|
||||
echo $(SOURCES) | \
|
||||
sed "s/^/ /;s/ / $(top_srcdir)\/lib\//g;s/$$//"; \
|
||||
) > $@
|
||||
|
||||
cflow: liblvm.cflow
|
||||
|
||||
@@ -39,7 +39,7 @@ int lvm1_present(struct cmd_context *cmd)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
|
||||
if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
|
||||
< 0) {
|
||||
log_error("LVM1 proc global snprintf failed");
|
||||
return 0;
|
||||
@@ -51,6 +51,66 @@ int lvm1_present(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
unsigned int s;
|
||||
struct lv_segment *seg2, *snap_seg;
|
||||
struct list *snh;
|
||||
|
||||
if (seg->segtype->ops->modules_needed &&
|
||||
!seg->segtype->ops->modules_needed(mem, seg, modules)) {
|
||||
log_error("module string allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_origin(seg->lv))
|
||||
list_iterate(snh, &seg->lv->snapshot_segs)
|
||||
if (!list_lv_modules(mem,
|
||||
list_struct_base(snh,
|
||||
struct lv_segment,
|
||||
origin_list)->cow,
|
||||
modules))
|
||||
return_0;
|
||||
|
||||
if (lv_is_cow(seg->lv)) {
|
||||
snap_seg = find_cow(seg->lv);
|
||||
if (snap_seg->segtype->ops->modules_needed &&
|
||||
!snap_seg->segtype->ops->modules_needed(mem, snap_seg,
|
||||
modules)) {
|
||||
log_error("snap_seg module string allocation failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s));
|
||||
if (seg2 && !list_segment_modules(mem, seg2, modules))
|
||||
return_0;
|
||||
break;
|
||||
case AREA_PV:
|
||||
case AREA_UNASSIGNED:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
struct list *modules)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
if (!list_segment_modules(mem, seg, modules))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef DEVMAPPER_SUPPORT
|
||||
void set_activation(int act)
|
||||
{
|
||||
@@ -81,7 +141,7 @@ int target_version(const char *target_name, uint32_t *maj,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int target_present(const char *target_name)
|
||||
int target_present(const char *target_name, int use_modprobe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -95,12 +155,12 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, float *percent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
|
||||
uint32_t *event_nr)
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int wait, float *percent, uint32_t *event_nr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -108,6 +168,10 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lvs_in_vg_opened(struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
@@ -151,12 +215,17 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void activation_release(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void activation_exit(void)
|
||||
{
|
||||
return;
|
||||
@@ -193,7 +262,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
char *str;
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
|
||||
if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) {
|
||||
/* If no host tags defined, activate */
|
||||
if (list_empty(&cmd->tags))
|
||||
return 1;
|
||||
@@ -252,9 +321,9 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
continue;
|
||||
}
|
||||
/* vgname/lvname */
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
|
||||
lv->name) < 0) {
|
||||
log_error("lvm_snprintf error from %s/%s", lv->vg->name,
|
||||
log_error("dm_snprintf error from %s/%s", lv->vg->name,
|
||||
lv->name);
|
||||
continue;
|
||||
}
|
||||
@@ -337,7 +406,7 @@ int target_present(const char *target_name, int use_modprobe)
|
||||
if (target_version(target_name, &maj, &min, &patchlevel))
|
||||
return 1;
|
||||
|
||||
if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name)
|
||||
if (dm_snprintf(module, sizeof(module), "dm-%s", target_name)
|
||||
< 0) {
|
||||
log_error("target_present module name too long: %s",
|
||||
target_name);
|
||||
@@ -356,21 +425,23 @@ int target_present(const char *target_name, int use_modprobe)
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
*/
|
||||
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int with_mknodes,
|
||||
struct lvinfo *info, int with_open_count)
|
||||
struct lvinfo *info, int with_open_count, unsigned by_uuid_only)
|
||||
{
|
||||
struct dm_info dminfo;
|
||||
char *name;
|
||||
char *name = NULL;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
|
||||
if (!by_uuid_only &&
|
||||
!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
log_debug("Getting device info for %s", name);
|
||||
if (!dev_manager_info(lv->vg->cmd->mem, name, lv, with_mknodes,
|
||||
with_open_count, &dminfo)) {
|
||||
dm_pool_free(cmd->mem, name);
|
||||
if (name)
|
||||
dm_pool_free(cmd->mem, name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -383,14 +454,16 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, in
|
||||
info->live_table = dminfo.live_table;
|
||||
info->inactive_table = dminfo.inactive_table;
|
||||
|
||||
dm_pool_free(cmd->mem, name);
|
||||
if (name)
|
||||
dm_pool_free(cmd->mem, name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, struct lvinfo *info,
|
||||
int with_open_count)
|
||||
{
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count);
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
|
||||
}
|
||||
|
||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
@@ -401,13 +474,13 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
return 0;
|
||||
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count);
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, float *percent)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -427,8 +500,8 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
}
|
||||
|
||||
/* FIXME Merge with snapshot_percent */
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wait, float *percent,
|
||||
uint32_t *event_nr)
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int wait, float *percent, uint32_t *event_nr)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -454,11 +527,12 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wa
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
unsigned by_uuid_only)
|
||||
{
|
||||
struct lvinfo info;
|
||||
|
||||
if (!lv_info(cmd, lv, &info, 0)) {
|
||||
if (!_lv_info(cmd, lv, 0, &info, 0, by_uuid_only)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
@@ -523,7 +597,7 @@ static int _lv_deactivate(struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_suspend_lv(struct logical_volume *lv)
|
||||
static int _lv_suspend_lv(struct logical_volume *lv, int lockfs)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -531,7 +605,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
|
||||
return_0;
|
||||
|
||||
if (!(r = dev_manager_suspend(dm, lv)))
|
||||
if (!(r = dev_manager_suspend(dm, lv, lockfs)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
@@ -542,7 +616,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
|
||||
* These two functions return the number of visible LVs in the state,
|
||||
* or -1 on error.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
static int _lvs_in_vg_activated(struct volume_group *vg, unsigned by_uuid_only)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
int count = 0;
|
||||
@@ -552,12 +626,22 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(vg->cmd, lvl->lv) == 1);
|
||||
count += (_lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
|
||||
{
|
||||
return _lvs_in_vg_activated(vg, 1);
|
||||
}
|
||||
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
return _lvs_in_vg_activated(vg, 0);
|
||||
}
|
||||
|
||||
int lvs_in_vg_opened(struct volume_group *vg)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
@@ -574,36 +658,96 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
return count;
|
||||
}
|
||||
|
||||
static int _register_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg)
|
||||
/*
|
||||
* Returns 0 if an attempt to (un)monitor the device failed.
|
||||
* Returns 1 otherwise.
|
||||
*/
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int monitor)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
int i, pending = 0, monitored;
|
||||
int r = 1;
|
||||
struct list *tmp;
|
||||
struct lv_segment *seg;
|
||||
int (*reg) (struct dm_pool *mem, struct lv_segment *,
|
||||
struct config_tree *cft, int events);
|
||||
int (*monitor_fn) (struct lv_segment *s, int e);
|
||||
|
||||
/* skip dmeventd code altogether */
|
||||
if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Nothing to do if dmeventd configured not to be used.
|
||||
*/
|
||||
if (monitor && !dmeventd_monitor_mode())
|
||||
return 1;
|
||||
|
||||
list_iterate(tmp, &lv->segments) {
|
||||
seg = list_item(tmp, struct lv_segment);
|
||||
|
||||
reg = NULL;
|
||||
if (!seg_monitored(seg) || (seg->status & PVMOVE))
|
||||
continue;
|
||||
|
||||
if (do_reg) {
|
||||
if (seg->segtype->ops->target_register_events)
|
||||
reg = seg->segtype->ops->target_register_events;
|
||||
} else if (seg->segtype->ops->target_unregister_events)
|
||||
reg = seg->segtype->ops->target_unregister_events;
|
||||
monitor_fn = NULL;
|
||||
|
||||
if (reg)
|
||||
/* FIXME specify events */
|
||||
if (!reg(cmd->mem, seg, cmd->cft, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
/* Check monitoring status */
|
||||
if (seg->segtype->ops->target_monitored)
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
else
|
||||
continue; /* segtype doesn't support registration */
|
||||
|
||||
/*
|
||||
* FIXME: We should really try again if pending
|
||||
*/
|
||||
monitored = (pending) ? 0 : monitored;
|
||||
|
||||
if (monitor) {
|
||||
if (monitored)
|
||||
log_verbose("%s/%s already monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_monitor_events)
|
||||
monitor_fn = seg->segtype->ops->target_monitor_events;
|
||||
} else {
|
||||
if (!monitored)
|
||||
log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_unmonitor_events)
|
||||
monitor_fn = seg->segtype->ops->target_unmonitor_events;
|
||||
}
|
||||
|
||||
/* Do [un]monitor */
|
||||
if (!monitor_fn)
|
||||
continue;
|
||||
|
||||
log_verbose("%sonitoring %s/%s", monitor ? "M" : "Not m", lv->vg->name, lv->name);
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!monitor_fn(seg, 0)) {
|
||||
log_error("%s/%s: %s segment monitoring function failed.",
|
||||
lv->vg->name, lv->name, seg->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check [un]monitor results */
|
||||
/* Try a couple times if pending, but not forever... */
|
||||
for (i = 0; i < 10; i++) {
|
||||
pending = 0;
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
if (pending ||
|
||||
(!monitored && monitor) ||
|
||||
(monitored && !monitor))
|
||||
log_very_verbose("%s/%s %smonitoring still pending: waiting...",
|
||||
lv->vg->name, lv->name, monitor ? "" : "un");
|
||||
else
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
r = (monitored && monitor) || (!monitored && !monitor);
|
||||
}
|
||||
|
||||
#endif
|
||||
return r;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
@@ -611,6 +755,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
{
|
||||
struct logical_volume *lv, *lv_pre;
|
||||
struct lvinfo info;
|
||||
int lockfs = 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
@@ -641,11 +786,16 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
}
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 0))
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
/* FIXME Consider aborting here */
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
if (!_lv_suspend_lv(lv)) {
|
||||
|
||||
if (lv_is_origin(lv_pre) || lv_is_cow(lv_pre))
|
||||
lockfs = 1;
|
||||
|
||||
if (!_lv_suspend_lv(lv, lockfs)) {
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
return 0;
|
||||
@@ -694,7 +844,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 1))
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
@@ -740,7 +890,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 0))
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
@@ -813,7 +963,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 1))
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
@@ -842,7 +992,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!_lv_info(cmd, lv, 1, &info, 0))
|
||||
if (!_lv_info(cmd, lv, 1, &info, 0, 0))
|
||||
return_0;
|
||||
|
||||
if (info.exists)
|
||||
@@ -859,28 +1009,21 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
* Does PV use VG somewhere in its construction?
|
||||
* Returns 1 on failure.
|
||||
*/
|
||||
int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
int r;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!dm_is_dm_major(MAJOR(pv->dev->dev)))
|
||||
return 0;
|
||||
|
||||
if (!(dm = dev_manager_create(cmd, vg->name))) {
|
||||
stack;
|
||||
return 1;
|
||||
}
|
||||
return dev_manager_device_uses_vg(pv->dev, vg);
|
||||
}
|
||||
|
||||
r = dev_manager_device_uses_vg(dm, pv->dev, vg);
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
void activation_release(void)
|
||||
{
|
||||
dev_manager_release();
|
||||
}
|
||||
|
||||
void activation_exit(void)
|
||||
|
||||
@@ -39,7 +39,12 @@ int lvm1_present(struct cmd_context *cmd);
|
||||
int target_present(const char *target_name, int use_modprobe);
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel);
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
struct list *modules);
|
||||
|
||||
void activation_release(void);
|
||||
void activation_exit(void);
|
||||
|
||||
int lv_suspend(struct cmd_context *cmd, const char *lvid_s);
|
||||
@@ -70,20 +75,30 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
/*
|
||||
* Returns 1 if percent has been set, else 0.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wait, float *percent,
|
||||
uint32_t *event_nr);
|
||||
int lv_snapshot_percent(const struct logical_volume *lv, float *percent);
|
||||
int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int wait, float *percent, uint32_t *event_nr);
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are active.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg);
|
||||
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
|
||||
int lvs_in_vg_opened(struct volume_group *vg);
|
||||
|
||||
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg);
|
||||
|
||||
/*
|
||||
* Returns 1 if PV has a dependency tree that uses anything in VG.
|
||||
*/
|
||||
int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Returns 1 if mapped device is not suspended.
|
||||
*/
|
||||
int device_is_usable(dev_t dev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "targets.h"
|
||||
#include "config.h"
|
||||
#include "filter.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
@@ -37,6 +38,7 @@ typedef enum {
|
||||
ACTIVATE,
|
||||
DEACTIVATE,
|
||||
SUSPEND,
|
||||
SUSPEND_WITH_LOCKFS,
|
||||
CLEAN
|
||||
} action_t;
|
||||
|
||||
@@ -85,7 +87,7 @@ char *build_dlid(struct dev_manager *dm, const char *lvid, const char *layer)
|
||||
return _build_dlid(dm->mem, lvid, layer);
|
||||
}
|
||||
|
||||
static inline int _read_only_lv(struct logical_volume *lv)
|
||||
static int _read_only_lv(struct logical_volume *lv)
|
||||
{
|
||||
return (!(lv->vg->status & LVM_WRITE) || !(lv->status & LVM_WRITE));
|
||||
}
|
||||
@@ -116,12 +118,10 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
|
||||
}
|
||||
|
||||
static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
int mknodes, int with_open_count, struct dm_pool *mem,
|
||||
char **uuid_out)
|
||||
int mknodes, int with_open_count)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
const char *u;
|
||||
int dmtask;
|
||||
|
||||
dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO;
|
||||
@@ -141,11 +141,58 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
if (!dm_task_get_info(dmt, info))
|
||||
goto_out;
|
||||
|
||||
if (info->exists && uuid_out) {
|
||||
if (!(u = dm_task_get_uuid(dmt)))
|
||||
goto_out;
|
||||
*uuid_out = dm_pool_strdup(mem, u);
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
int device_is_usable(dev_t dev)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
const char *name;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
void *next = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
log_error("Failed to allocate dm_task struct to check dev status");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_set_major(dmt, MAJOR(dev)) || !dm_task_set_minor(dmt, MINOR(dev)))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("Failed to get state of mapped device");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists || info.suspended)
|
||||
goto out;
|
||||
|
||||
name = dm_task_get_name(dmt);
|
||||
|
||||
/* FIXME Also check for mirror block_on_error and mpath no paths */
|
||||
/* For now, we exclude all mirrors */
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
/* Skip if target type doesn't match */
|
||||
if (!strcmp(target_type, "mirror"))
|
||||
goto out;
|
||||
} while (next);
|
||||
|
||||
/* FIXME Also check dependencies? */
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -154,23 +201,20 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
}
|
||||
|
||||
static int _info(const char *name, const char *dlid, int mknodes,
|
||||
int with_open_count, struct dm_info *info,
|
||||
struct dm_pool *mem, char **uuid_out)
|
||||
int with_open_count, struct dm_info *info)
|
||||
{
|
||||
if (!mknodes && dlid && *dlid) {
|
||||
if (_info_run(NULL, dlid, info, 0, with_open_count, mem,
|
||||
uuid_out) &&
|
||||
if (_info_run(NULL, dlid, info, 0, with_open_count) &&
|
||||
info->exists)
|
||||
return 1;
|
||||
else if (_info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
|
||||
0, with_open_count, mem, uuid_out) &&
|
||||
0, with_open_count) &&
|
||||
info->exists)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (name)
|
||||
return _info_run(name, NULL, info, mknodes, with_open_count,
|
||||
mem, uuid_out);
|
||||
return _info_run(name, NULL, info, mknodes, with_open_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -186,8 +230,7 @@ int dev_manager_info(struct dm_pool *mem, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _info(name, dlid, with_mknodes, with_open_count, info,
|
||||
NULL, NULL);
|
||||
return _info(name, dlid, with_mknodes, with_open_count, info);
|
||||
}
|
||||
|
||||
/* FIXME Interface must cope with multiple targets */
|
||||
@@ -329,7 +372,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
||||
|
||||
if (segtype->ops->target_percent &&
|
||||
!segtype->ops->target_percent(&dm->target_state, dm->mem,
|
||||
dm->cmd->cft, seg, params,
|
||||
dm->cmd, seg, params,
|
||||
&total_numerator,
|
||||
&total_denominator,
|
||||
percent))
|
||||
@@ -401,7 +444,7 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
dm->mem = mem;
|
||||
|
||||
if (!stripe_filler) {
|
||||
stripe_filler = find_config_str(cmd->cft->root,
|
||||
stripe_filler = find_config_tree_str(cmd,
|
||||
"activation/missing_stripe_filler",
|
||||
DEFAULT_STRIPE_FILLER);
|
||||
}
|
||||
@@ -426,13 +469,19 @@ void dev_manager_destroy(struct dev_manager *dm)
|
||||
dm_pool_destroy(dm->mem);
|
||||
}
|
||||
|
||||
void dev_manager_release(void)
|
||||
{
|
||||
dm_lib_release();
|
||||
}
|
||||
|
||||
void dev_manager_exit(void)
|
||||
{
|
||||
dm_lib_exit();
|
||||
}
|
||||
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, float *percent)
|
||||
const struct logical_volume *lv,
|
||||
float *percent)
|
||||
{
|
||||
char *name;
|
||||
const char *dlid;
|
||||
@@ -586,7 +635,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return_0;
|
||||
|
||||
log_debug("Getting device info for %s [%s]", name, dlid);
|
||||
if (!_info(name, dlid, 0, 1, &info, dm->mem, NULL)) {
|
||||
if (!_info(name, dlid, 0, 1, &info)) {
|
||||
log_error("Failed to get info for %s [%s].", name, dlid);
|
||||
return 0;
|
||||
}
|
||||
@@ -615,6 +664,9 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struc
|
||||
if (!_add_dev_to_dtree(dm, dtree, lv, "cow"))
|
||||
return_0;
|
||||
|
||||
if (!_add_dev_to_dtree(dm, dtree, lv, "_mlog"))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -660,7 +712,8 @@ fail:
|
||||
}
|
||||
|
||||
int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
struct dm_tree_node *node, int start_area, int areas)
|
||||
struct dm_tree_node *node, uint32_t start_area,
|
||||
uint32_t areas)
|
||||
{
|
||||
uint64_t extent_size = seg->lv->vg->extent_size;
|
||||
uint32_t s;
|
||||
@@ -674,7 +727,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
|
||||
dm_tree_node_add_target_area(node,
|
||||
dm->stripe_filler,
|
||||
NULL, 0);
|
||||
NULL, UINT64_C(0));
|
||||
else if (seg_type(seg, s) == AREA_PV)
|
||||
dm_tree_node_add_target_area(node,
|
||||
dev_name(seg_dev(seg, s)),
|
||||
@@ -699,7 +752,6 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
}
|
||||
|
||||
static int _add_origin_target_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
struct dm_tree_node *dnode,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
@@ -715,7 +767,6 @@ static int _add_origin_target_to_dtree(struct dev_manager *dm,
|
||||
}
|
||||
|
||||
static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
struct dm_tree_node *dnode,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
@@ -744,7 +795,6 @@ static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
|
||||
}
|
||||
|
||||
static int _add_target_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
struct dm_tree_node *dnode,
|
||||
struct lv_segment *seg)
|
||||
{
|
||||
@@ -756,7 +806,7 @@ static int _add_target_to_dtree(struct dev_manager *dm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd->cft,
|
||||
return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd,
|
||||
&dm->target_state, seg,
|
||||
dnode,
|
||||
extent_size * seg->len,
|
||||
@@ -774,12 +824,19 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
{
|
||||
uint32_t s;
|
||||
struct list *snh;
|
||||
struct lv_segment *seg_present;
|
||||
|
||||
/* Ensure required device-mapper targets are loaded */
|
||||
if (seg->segtype->ops->target_present &&
|
||||
!seg->segtype->ops->target_present()) {
|
||||
seg_present = find_cow(seg->lv) ? : seg;
|
||||
|
||||
log_debug("Checking kernel supports %s segment type for %s%s%s",
|
||||
seg_present->segtype->name, seg->lv->name,
|
||||
layer ? "-" : "", layer ? : "");
|
||||
|
||||
if (seg_present->segtype->ops->target_present &&
|
||||
!seg_present->segtype->ops->target_present(seg_present)) {
|
||||
log_error("Can't expand LV %s: %s target support missing "
|
||||
"from kernel?", seg->lv->name, seg->segtype->name);
|
||||
"from kernel?", seg->lv->name, seg_present->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -809,12 +866,12 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
|
||||
/* Now we've added its dependencies, we can add the target itself */
|
||||
if (lv_is_origin(seg->lv) && !layer) {
|
||||
if (!_add_origin_target_to_dtree(dm, dtree, dnode, seg->lv))
|
||||
if (!_add_origin_target_to_dtree(dm, dnode, seg->lv))
|
||||
return_0;
|
||||
} else if (lv_is_cow(seg->lv) && !layer) {
|
||||
if (!_add_snapshot_target_to_dtree(dm, dtree, dnode, seg->lv))
|
||||
if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv))
|
||||
return_0;
|
||||
} else if (!_add_target_to_dtree(dm, dtree, dnode, seg))
|
||||
} else if (!_add_target_to_dtree(dm, dnode, seg))
|
||||
return_0;
|
||||
|
||||
if (lv_is_origin(seg->lv) && !layer)
|
||||
@@ -859,10 +916,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
* Major/minor settings only apply to the visible layer.
|
||||
*/
|
||||
if (!(dnode = dm_tree_add_new_dev(dtree, name, dlid,
|
||||
layer ? lv->major : 0,
|
||||
layer ? lv->minor : 0,
|
||||
layer ? UINT32_C(0) : (uint32_t) lv->major,
|
||||
layer ? UINT32_C(0) : (uint32_t) lv->minor,
|
||||
_read_only_lv(lv),
|
||||
lv->vg->status & PRECOMMITTED,
|
||||
(lv->vg->status & PRECOMMITTED) ? 1 : 0,
|
||||
lvlayer)))
|
||||
return_0;
|
||||
|
||||
@@ -904,7 +961,7 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
|
||||
name = dm_tree_node_get_name(child);
|
||||
|
||||
if (name && lvlayer->old_name && *lvlayer->old_name && strcmp(name, lvlayer->old_name)) {
|
||||
if (!split_dm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) {
|
||||
if (!dm_split_lvm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) {
|
||||
log_error("_create_lv_symlinks: Couldn't split up old device name %s", lvlayer->old_name);
|
||||
return 0;
|
||||
}
|
||||
@@ -916,7 +973,7 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _clean_tree(struct dev_manager *dm, struct logical_volume *lv, struct dm_tree_node *root)
|
||||
static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root)
|
||||
{
|
||||
void *handle = NULL;
|
||||
struct dm_tree_node *child;
|
||||
@@ -930,7 +987,7 @@ static int _clean_tree(struct dev_manager *dm, struct logical_volume *lv, struct
|
||||
if (!(uuid = dm_tree_node_get_uuid(child)))
|
||||
continue;
|
||||
|
||||
if (!split_dm_name(dm->mem, name, &vgname, &lvname, &layer)) {
|
||||
if (!dm_split_lvm_name(dm->mem, name, &vgname, &lvname, &layer)) {
|
||||
log_error("_clean_tree: Couldn't split up device name %s.", name);
|
||||
return 0;
|
||||
}
|
||||
@@ -968,7 +1025,7 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
|
||||
switch(action) {
|
||||
case CLEAN:
|
||||
/* Deactivate any unused non-toplevel nodes */
|
||||
if (!_clean_tree(dm, lv, root))
|
||||
if (!_clean_tree(dm, root))
|
||||
goto_out;
|
||||
break;
|
||||
case DEACTIVATE:
|
||||
@@ -977,8 +1034,10 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
|
||||
goto_out;
|
||||
break;
|
||||
case SUSPEND:
|
||||
if (!lv_is_origin(lv) && !lv_is_cow(lv))
|
||||
dm_tree_skip_lockfs(root);
|
||||
dm_tree_skip_lockfs(root);
|
||||
if ((lv->status & MIRRORED) && !(lv->status & PVMOVE))
|
||||
dm_tree_use_no_flush_suspend(root);
|
||||
case SUSPEND_WITH_LOCKFS:
|
||||
if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
|
||||
goto_out;
|
||||
break;
|
||||
@@ -1042,21 +1101,22 @@ int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv)
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
|
||||
int lockfs)
|
||||
{
|
||||
return _tree_action(dm, lv, SUSPEND);
|
||||
return _tree_action(dm, lv, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does device use VG somewhere in its construction?
|
||||
* Returns 1 if uncertain.
|
||||
*/
|
||||
int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev,
|
||||
int dev_manager_device_uses_vg(struct device *dev,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
struct dm_tree *dtree;
|
||||
struct dm_tree_node *root;
|
||||
char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1];
|
||||
char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1] __attribute((aligned(8)));
|
||||
int r = 1;
|
||||
|
||||
if (!(dtree = dm_tree_create())) {
|
||||
@@ -1064,7 +1124,7 @@ int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!dm_tree_add_dev(dtree, MAJOR(dev->dev), MINOR(dev->dev))) {
|
||||
if (!dm_tree_add_dev(dtree, (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev))) {
|
||||
log_error("Failed to add device %s (%" PRIu32 ":%" PRIu32") to dtree",
|
||||
dev_name(dev), (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev));
|
||||
goto out;
|
||||
|
||||
@@ -29,6 +29,7 @@ struct device;
|
||||
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
const char *vg_name);
|
||||
void dev_manager_destroy(struct dev_manager *dm);
|
||||
void dev_manager_release(void);
|
||||
void dev_manager_exit(void);
|
||||
|
||||
/*
|
||||
@@ -41,11 +42,13 @@ int dev_manager_info(struct dm_pool *mem, const char *name,
|
||||
const struct logical_volume *lv,
|
||||
int mknodes, int with_open_count, struct dm_info *info);
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, float *percent);
|
||||
const struct logical_volume *lv,
|
||||
float *percent);
|
||||
int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, int wait,
|
||||
float *percent, uint32_t *event_nr);
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
|
||||
int lockfs);
|
||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
@@ -58,7 +61,7 @@ int dev_manager_lv_rmnodes(const struct logical_volume *lv);
|
||||
*/
|
||||
int dev_manager_execute(struct dev_manager *dm);
|
||||
|
||||
int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev,
|
||||
int dev_manager_device_uses_vg(struct device *dev,
|
||||
struct volume_group *vg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
dev_dir, vg_name) == -1) {
|
||||
log_error("Couldn't construct name of volume "
|
||||
"group directory.");
|
||||
@@ -53,7 +53,7 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
dev_dir, vg_name) == -1) {
|
||||
log_error("Couldn't construct name of volume "
|
||||
"group directory.");
|
||||
@@ -87,7 +87,7 @@ static void _rm_blks(const char *dir)
|
||||
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
||||
continue;
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
|
||||
log_error("Couldn't create path for %s", name);
|
||||
continue;
|
||||
}
|
||||
@@ -109,28 +109,28 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
|
||||
char vg_path[PATH_MAX];
|
||||
struct stat buf;
|
||||
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
dev_dir, vg_name) == -1) {
|
||||
log_error("Couldn't create path for volume group dir %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
|
||||
if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
|
||||
lv_name) == -1) {
|
||||
log_error("Couldn't create source pathname for "
|
||||
"logical volume link %s", lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
|
||||
if (dm_snprintf(link_path, sizeof(link_path), "%s/%s",
|
||||
dm_dir(), dev) == -1) {
|
||||
log_error("Couldn't create destination pathname for "
|
||||
"logical volume link for %s", lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
|
||||
if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
|
||||
vg_path) == -1) {
|
||||
log_error("Couldn't create pathname for LVM1 group file for %s",
|
||||
vg_name);
|
||||
@@ -190,7 +190,7 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
|
||||
struct stat buf;
|
||||
char lv_path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||
if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||
dev_dir, vg_name, lv_name) == -1) {
|
||||
log_error("Couldn't determine link pathname.");
|
||||
return 0;
|
||||
|
||||
@@ -24,7 +24,7 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
int start_area, int areas);
|
||||
|
||||
int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
struct dm_tree_node *node, int start_area, int areas);
|
||||
struct dm_tree_node *node, uint32_t start_area, uint32_t areas);
|
||||
|
||||
int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf,
|
||||
size_t bufsize, const char *desc);
|
||||
|
||||
373
lib/cache/lvmcache.c
vendored
373
lib/cache/lvmcache.c
vendored
@@ -50,7 +50,7 @@ int lvmcache_init(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only)
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only __attribute((unused)))
|
||||
{
|
||||
if (!_lock_hash && !lvmcache_init()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
@@ -86,7 +86,8 @@ int vgs_locked(void)
|
||||
return _vgs_locked;
|
||||
}
|
||||
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
/* If vgid supplied, require a match. */
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
@@ -96,10 +97,16 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
|
||||
return NULL;
|
||||
|
||||
if (vgid)
|
||||
do
|
||||
if (!strncmp(vgid, vginfo->vgid, ID_LEN))
|
||||
return vginfo;
|
||||
while ((vginfo = vginfo->next));
|
||||
|
||||
return vginfo;
|
||||
}
|
||||
|
||||
const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
@@ -107,19 +114,25 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
struct list *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname)))
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
|
||||
return NULL;
|
||||
|
||||
/* This function is normally called before reading metadata so
|
||||
* we check cached labels here. Unfortunately vginfo is volatile. */
|
||||
list_init(&devs);
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
devl = dm_malloc(sizeof(*devl));
|
||||
if (!(devl = dm_malloc(sizeof(*devl)))) {
|
||||
log_error("device_list element allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
devl->dev = info->dev;
|
||||
list_add(&devs, &devl->list);
|
||||
}
|
||||
|
||||
memcpy(vgid_found, vginfo->vgid, sizeof(vgid_found));
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
@@ -127,13 +140,18 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
dm_free(devl);
|
||||
}
|
||||
|
||||
/* If vginfo changed, caller needs to rescan */
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) ||
|
||||
strncmp(vginfo->vgid, vgid_found, ID_LEN))
|
||||
return NULL;
|
||||
|
||||
return vginfo->fmt;
|
||||
}
|
||||
|
||||
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
char id[ID_LEN + 1];
|
||||
char id[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!_vgid_hash || !vgid)
|
||||
return NULL;
|
||||
@@ -148,10 +166,27 @@ struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
|
||||
return vginfo;
|
||||
}
|
||||
|
||||
const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
const char *vgname = NULL;
|
||||
|
||||
if (!*vgid)
|
||||
vgname = ORPHAN;
|
||||
|
||||
if ((vginfo = vginfo_from_vgid(vgid)))
|
||||
vgname = vginfo->vgname;
|
||||
|
||||
if (mem && vgname)
|
||||
return dm_pool_strdup(mem, vgname);
|
||||
|
||||
return vgname;
|
||||
}
|
||||
|
||||
struct lvmcache_info *info_from_pvid(const char *pvid)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
char id[ID_LEN + 1];
|
||||
char id[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!_pvid_hash || !pvid)
|
||||
return NULL;
|
||||
@@ -206,7 +241,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
|
||||
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
|
||||
log_error("dev_iter creation failed");
|
||||
goto out;
|
||||
}
|
||||
@@ -232,10 +267,33 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
return r;
|
||||
}
|
||||
|
||||
struct list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct list *vgids;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
lvmcache_label_scan(cmd, full_scan);
|
||||
|
||||
if (!(vgids = str_list_create(cmd->mem))) {
|
||||
log_error("vgids list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(vginfo, &_vginfos) {
|
||||
if (!str_list_add(cmd->mem, vgids,
|
||||
dm_pool_strdup(cmd->mem, vginfo->vgid))) {
|
||||
log_error("strlist allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return vgids;
|
||||
}
|
||||
|
||||
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct list *vgnames;
|
||||
struct lvmcache_vginfo *vgi;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
lvmcache_label_scan(cmd, full_scan);
|
||||
|
||||
@@ -244,9 +302,9 @@ struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(vgi, &_vginfos) {
|
||||
list_iterate_items(vginfo, &_vginfos) {
|
||||
if (!str_list_add(cmd->mem, vgnames,
|
||||
dm_pool_strdup(cmd->mem, vgi->vgname))) {
|
||||
dm_pool_strdup(cmd->mem, vginfo->vgname))) {
|
||||
log_error("strlist allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -255,6 +313,32 @@ struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||
return vgnames;
|
||||
}
|
||||
|
||||
struct list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid)
|
||||
{
|
||||
struct list *pvids;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(pvids = str_list_create(cmd->mem))) {
|
||||
log_error("pvids list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
|
||||
return pvids;
|
||||
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
if (!str_list_add(cmd->mem, pvids,
|
||||
dm_pool_strdup(cmd->mem, info->dev->pvid))) {
|
||||
log_error("strlist allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pvids;
|
||||
}
|
||||
|
||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
{
|
||||
struct label *label;
|
||||
@@ -297,7 +381,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _drop_vginfo(struct lvmcache_info *info)
|
||||
static int _drop_vginfo(struct lvmcache_info *info)
|
||||
{
|
||||
if (!list_empty(&info->list)) {
|
||||
list_del(&info->list);
|
||||
@@ -306,8 +390,18 @@ static void _drop_vginfo(struct lvmcache_info *info)
|
||||
|
||||
if (info->vginfo && list_empty(&info->vginfo->infos)) {
|
||||
dm_hash_remove(_vgname_hash, info->vginfo->vgname);
|
||||
if (info->vginfo->next) {
|
||||
if (!dm_hash_insert(_vgname_hash, info->vginfo->vgname, info->vginfo->next)) {
|
||||
log_error("vg hash re-insertion failed: %s",
|
||||
info->vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->vginfo->vgname)
|
||||
dm_free(info->vginfo->vgname);
|
||||
if (info->vginfo->creation_host)
|
||||
dm_free(info->vginfo->creation_host);
|
||||
if (*info->vginfo->vgid)
|
||||
dm_hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||
list_del(&info->vginfo->list);
|
||||
@@ -315,6 +409,8 @@ static void _drop_vginfo(struct lvmcache_info *info)
|
||||
}
|
||||
|
||||
info->vginfo = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Unused
|
||||
@@ -350,36 +446,130 @@ static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
|
||||
|
||||
static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
|
||||
{
|
||||
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
|
||||
sizeof(info->vginfo->vgid)))
|
||||
if (!vgid || !info->vginfo ||
|
||||
!strncmp(info->vginfo->vgid, vgid, ID_LEN))
|
||||
return 1;
|
||||
|
||||
if (info->vginfo && *info->vginfo->vgid)
|
||||
dm_hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||
if (!vgid)
|
||||
if (!vgid) {
|
||||
log_debug("lvmcache: %s: clearing VGID", dev_name(info->dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
|
||||
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
|
||||
strncpy(info->vginfo->vgid, vgid, ID_LEN);
|
||||
info->vginfo->vgid[ID_LEN] = '\0';
|
||||
if (!dm_hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) {
|
||||
log_error("_lvmcache_update: vgid hash insertion failed: %s",
|
||||
info->vginfo->vgid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("lvmcache: %s: setting %s VGID to %s", dev_name(info->dev),
|
||||
info->vginfo->vgname, info->vginfo->vgid);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host,
|
||||
struct lvmcache_vginfo *primary_vginfo)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_vginfo *last_vginfo = primary_vginfo;
|
||||
char uuid_primary[64] __attribute((aligned(8)));
|
||||
char uuid_new[64] __attribute((aligned(8)));
|
||||
int use_new = 0;
|
||||
|
||||
/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
|
||||
if (primary_vginfo) {
|
||||
if (!id_write_format((const struct id *)vgid, uuid_new, sizeof(uuid_new)))
|
||||
return_0;
|
||||
|
||||
if (!id_write_format((const struct id *)&primary_vginfo->vgid, uuid_primary,
|
||||
sizeof(uuid_primary)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* If Primary not exported, new exported => keep
|
||||
* Else Primary exported, new not exported => change
|
||||
* Else Primary has hostname for this machine => keep
|
||||
* Else Primary has no hostname, new has one => change
|
||||
* Else New has hostname for this machine => change
|
||||
* Else Keep primary.
|
||||
*/
|
||||
if (!(primary_vginfo->status & EXPORTED_VG) &&
|
||||
(vgstatus & EXPORTED_VG))
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"Existing %s takes precedence over "
|
||||
"exported %s", new_vginfo->vgname,
|
||||
uuid_primary, uuid_new);
|
||||
else if ((primary_vginfo->status & EXPORTED_VG) &&
|
||||
!(vgstatus & EXPORTED_VG)) {
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"%s takes precedence over exported %s",
|
||||
new_vginfo->vgname, uuid_new,
|
||||
uuid_primary);
|
||||
use_new = 1;
|
||||
} else if (primary_vginfo->creation_host &&
|
||||
!strcmp(primary_vginfo->creation_host,
|
||||
primary_vginfo->fmt->cmd->hostname))
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"Existing %s (created here) takes precedence "
|
||||
"over %s", new_vginfo->vgname, uuid_primary,
|
||||
uuid_new);
|
||||
else if (!primary_vginfo->creation_host && creation_host) {
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"%s (with creation_host) takes precedence over %s",
|
||||
new_vginfo->vgname, uuid_new,
|
||||
uuid_primary);
|
||||
use_new = 1;
|
||||
} else if (creation_host &&
|
||||
!strcmp(creation_host,
|
||||
primary_vginfo->fmt->cmd->hostname)) {
|
||||
log_error("WARNING: Duplicate VG name %s: "
|
||||
"%s (created here) takes precedence over %s",
|
||||
new_vginfo->vgname, uuid_new,
|
||||
uuid_primary);
|
||||
use_new = 1;
|
||||
}
|
||||
|
||||
if (!use_new) {
|
||||
while (last_vginfo->next)
|
||||
last_vginfo = last_vginfo->next;
|
||||
last_vginfo->next = new_vginfo;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dm_hash_remove(_vgname_hash, primary_vginfo->vgname);
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) {
|
||||
log_error("cache_update: vg hash insertion failed: %s",
|
||||
new_vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (primary_vginfo)
|
||||
new_vginfo->next = primary_vginfo;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vgname(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo, *primary_vginfo;
|
||||
// struct lvmcache_vginfo *old_vginfo, *next;
|
||||
|
||||
/* If vgname is NULL and we don't already have a vgname,
|
||||
* assume ORPHAN - we want every entry to have a vginfo
|
||||
* attached for scanning reasons.
|
||||
*/
|
||||
if (!vgname && !info->vginfo)
|
||||
if (!vgname && !info->vginfo) {
|
||||
vgname = ORPHAN;
|
||||
vgid = ORPHAN;
|
||||
}
|
||||
|
||||
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
|
||||
return 1;
|
||||
@@ -388,7 +578,43 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
_drop_vginfo(info);
|
||||
|
||||
/* Get existing vginfo or create new one */
|
||||
if (!(vginfo = vginfo_from_vgname(vgname))) {
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
|
||||
/*** FIXME - vginfo ends up duplicated instead of renamed.
|
||||
// Renaming? This lookup fails.
|
||||
if ((vginfo = vginfo_from_vgid(vgid))) {
|
||||
next = vginfo->next;
|
||||
old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
|
||||
if (old_vginfo == vginfo) {
|
||||
dm_hash_remove(_vgname_hash, old_vginfo->vgname);
|
||||
if (old_vginfo->next) {
|
||||
if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) {
|
||||
log_error("vg hash re-insertion failed: %s",
|
||||
old_vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else do {
|
||||
if (old_vginfo->next == vginfo) {
|
||||
old_vginfo->next = vginfo->next;
|
||||
break;
|
||||
}
|
||||
} while ((old_vginfo = old_vginfo->next));
|
||||
vginfo->next = NULL;
|
||||
|
||||
dm_free(vginfo->vgname);
|
||||
if (!(vginfo->vgname = dm_strdup(vgname))) {
|
||||
log_error("cache vgname alloc failed for %s", vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Rename so can assume new name does not already exist
|
||||
if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) {
|
||||
log_error("vg hash re-insertion failed: %s",
|
||||
vginfo->vgname);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
***/
|
||||
if (!(vginfo = dm_malloc(sizeof(*vginfo)))) {
|
||||
log_error("lvmcache_update_vgname: list alloc failed");
|
||||
return 0;
|
||||
@@ -400,9 +626,9 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
return 0;
|
||||
}
|
||||
list_init(&vginfo->infos);
|
||||
if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
|
||||
log_error("cache_update: vg hash insertion failed: %s",
|
||||
vginfo->vgname);
|
||||
primary_vginfo = vginfo_from_vgname(vgname, NULL);
|
||||
if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
|
||||
primary_vginfo)) {
|
||||
dm_free(vginfo->vgname);
|
||||
dm_free(vginfo);
|
||||
return 0;
|
||||
@@ -412,6 +638,9 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
list_add(&_vginfos, &vginfo->list);
|
||||
else
|
||||
list_add_h(&_vginfos, &vginfo->list);
|
||||
/***
|
||||
}
|
||||
***/
|
||||
}
|
||||
|
||||
info->vginfo = vginfo;
|
||||
@@ -420,8 +649,59 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
/* FIXME Check consistency of list! */
|
||||
vginfo->fmt = info->fmt;
|
||||
|
||||
log_debug("lvmcache: %s now %s%s", dev_name(info->dev),
|
||||
*vgname ? "in VG " : "orphaned", vgname);
|
||||
log_debug("lvmcache: %s: now %s%s%s%s%s", dev_name(info->dev),
|
||||
*vgname ? "in VG " : "orphaned", vgname,
|
||||
vginfo->vgid[0] ? " (" : "",
|
||||
vginfo->vgid[0] ? vginfo->vgid : "",
|
||||
vginfo->vgid[0] ? ")" : "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
|
||||
const char *creation_host)
|
||||
{
|
||||
if (!info || !info->vginfo)
|
||||
return 1;
|
||||
|
||||
if ((info->vginfo->status & EXPORTED_VG) != (vgstatus & EXPORTED_VG))
|
||||
log_debug("lvmcache: %s: VG %s %s exported",
|
||||
dev_name(info->dev), info->vginfo->vgname,
|
||||
vgstatus & EXPORTED_VG ? "now" : "no longer");
|
||||
|
||||
info->vginfo->status = vgstatus;
|
||||
|
||||
if (!creation_host)
|
||||
return 1;
|
||||
|
||||
if (info->vginfo->creation_host && !strcmp(creation_host,
|
||||
info->vginfo->creation_host))
|
||||
return 1;
|
||||
|
||||
if (info->vginfo->creation_host)
|
||||
dm_free(info->vginfo->creation_host);
|
||||
|
||||
if (!(info->vginfo->creation_host = dm_strdup(creation_host))) {
|
||||
log_error("cache creation host alloc failed for %s",
|
||||
creation_host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("lvmcache: %s: VG %s: Set creation host to %s.",
|
||||
dev_name(info->dev), info->vginfo->vgname, creation_host);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host)
|
||||
{
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
|
||||
creation_host) ||
|
||||
!_lvmcache_update_vgid(info, vgid) ||
|
||||
!_lvmcache_update_vgstatus(info, vgstatus, creation_host))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -430,21 +710,18 @@ int lvmcache_update_vg(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
int vgid_updated = 0;
|
||||
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||
if ((info = info_from_pvid(pvid_s))) {
|
||||
lvmcache_update_vgname(info, vg->name);
|
||||
if (!vgid_updated) {
|
||||
_lvmcache_update_vgid(info, (char *) &vg->id);
|
||||
vgid_updated = 1;
|
||||
}
|
||||
}
|
||||
if ((info = info_from_pvid(pvid_s)) &&
|
||||
!lvmcache_update_vgname_and_id(info, vg->name,
|
||||
(char *) &vg->id,
|
||||
vg->status, NULL))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -452,11 +729,12 @@ int lvmcache_update_vg(struct volume_group *vg)
|
||||
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid)
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus)
|
||||
{
|
||||
struct label *label;
|
||||
struct lvmcache_info *existing, *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!_vgname_hash && !lvmcache_init()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
@@ -548,7 +826,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!lvmcache_update_vgname(info, vgname)) {
|
||||
if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
|
||||
if (!existing) {
|
||||
dm_hash_remove(_pvid_hash, pvid_s);
|
||||
strcpy(info->dev->pvid, "");
|
||||
@@ -558,10 +836,6 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_lvmcache_update_vgid(info, vgid))
|
||||
/* Non-critical */
|
||||
stack;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -576,12 +850,19 @@ static void _lvmcache_destroy_entry(struct lvmcache_info *info)
|
||||
|
||||
static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
|
||||
{
|
||||
if (vginfo->vgname)
|
||||
dm_free(vginfo->vgname);
|
||||
dm_free(vginfo);
|
||||
struct lvmcache_vginfo *next;
|
||||
|
||||
do {
|
||||
next = vginfo->next;
|
||||
if (vginfo->vgname)
|
||||
dm_free(vginfo->vgname);
|
||||
if (vginfo->creation_host)
|
||||
dm_free(vginfo->creation_host);
|
||||
dm_free(vginfo);
|
||||
} while ((vginfo = next));
|
||||
}
|
||||
|
||||
static void _lvmcache_destroy_lockname(int present)
|
||||
static void _lvmcache_destroy_lockname(int present __attribute((unused)))
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
26
lib/cache/lvmcache.h
vendored
26
lib/cache/lvmcache.h
vendored
@@ -33,15 +33,20 @@ struct cmd_context;
|
||||
struct format_type;
|
||||
struct volume_group;
|
||||
|
||||
/* One per VG */
|
||||
struct lvmcache_vginfo {
|
||||
struct list list; /* Join these vginfos together */
|
||||
struct list infos; /* List head for lvmcache_infos */
|
||||
const struct format_type *fmt;
|
||||
char *vgname; /* "" == orphan */
|
||||
uint32_t status;
|
||||
char vgid[ID_LEN + 1];
|
||||
char _padding[7];
|
||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||
char *creation_host;
|
||||
};
|
||||
|
||||
/* One per device */
|
||||
struct lvmcache_info {
|
||||
struct list list; /* Join VG members together */
|
||||
struct list mdas; /* list head for metadata areas */
|
||||
@@ -64,21 +69,26 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
|
||||
/* Add/delete a device */
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid);
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus);
|
||||
void lvmcache_del(struct lvmcache_info *info);
|
||||
|
||||
/* Update things */
|
||||
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname);
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *hostname);
|
||||
int lvmcache_update_vg(struct volume_group *vg);
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||
void lvmcache_unlock_vgname(const char *vgname);
|
||||
|
||||
/* Queries */
|
||||
const struct format_type *fmt_from_vgname(const char *vgname);
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname);
|
||||
const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid);
|
||||
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname,
|
||||
const char *vgid);
|
||||
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
|
||||
struct lvmcache_info *info_from_pvid(const char *pvid);
|
||||
const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid);
|
||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
|
||||
int vgs_locked(void);
|
||||
int vgname_is_locked(const char *vgname);
|
||||
@@ -87,4 +97,12 @@ int vgname_is_locked(const char *vgname);
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
/* Returns list of struct str_lists containing pool-allocated copy of vgids */
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
struct list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
/* Returns list of struct str_lists containing pool-allocated copy of pvids */
|
||||
struct list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -59,15 +59,13 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static FILE *_log;
|
||||
|
||||
static int _get_env_vars(struct cmd_context *cmd)
|
||||
{
|
||||
const char *e;
|
||||
|
||||
/* Set to "" to avoid using any system directory */
|
||||
if ((e = getenv("LVM_SYSTEM_DIR"))) {
|
||||
if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
|
||||
if (dm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
|
||||
"%s", e) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR environment variable "
|
||||
"is too long.");
|
||||
@@ -84,10 +82,11 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
time_t t;
|
||||
|
||||
const char *log_file;
|
||||
char timebuf[26];
|
||||
|
||||
/* Syslog */
|
||||
cmd->default_settings.syslog =
|
||||
find_config_int(cmd->cft->root, "log/syslog", DEFAULT_SYSLOG);
|
||||
find_config_tree_int(cmd, "log/syslog", DEFAULT_SYSLOG);
|
||||
if (cmd->default_settings.syslog != 1)
|
||||
fin_syslog();
|
||||
|
||||
@@ -96,37 +95,37 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
|
||||
/* Debug level for log file output */
|
||||
cmd->default_settings.debug =
|
||||
find_config_int(cmd->cft->root, "log/level", DEFAULT_LOGLEVEL);
|
||||
find_config_tree_int(cmd, "log/level", DEFAULT_LOGLEVEL);
|
||||
init_debug(cmd->default_settings.debug);
|
||||
|
||||
/* Verbose level for tty output */
|
||||
cmd->default_settings.verbose =
|
||||
find_config_int(cmd->cft->root, "log/verbose", DEFAULT_VERBOSE);
|
||||
find_config_tree_int(cmd, "log/verbose", DEFAULT_VERBOSE);
|
||||
init_verbose(cmd->default_settings.verbose + VERBOSE_BASE_LEVEL);
|
||||
|
||||
/* Log message formatting */
|
||||
init_indent(find_config_int(cmd->cft->root, "log/indent",
|
||||
init_indent(find_config_tree_int(cmd, "log/indent",
|
||||
DEFAULT_INDENT));
|
||||
|
||||
cmd->default_settings.msg_prefix = find_config_str(cmd->cft->root,
|
||||
cmd->default_settings.msg_prefix = find_config_tree_str(cmd,
|
||||
"log/prefix",
|
||||
DEFAULT_MSG_PREFIX);
|
||||
init_msg_prefix(cmd->default_settings.msg_prefix);
|
||||
|
||||
cmd->default_settings.cmd_name = find_config_int(cmd->cft->root,
|
||||
cmd->default_settings.cmd_name = find_config_tree_int(cmd,
|
||||
"log/command_names",
|
||||
DEFAULT_CMD_NAME);
|
||||
init_cmd_name(cmd->default_settings.cmd_name);
|
||||
|
||||
/* Test mode */
|
||||
cmd->default_settings.test =
|
||||
find_config_int(cmd->cft->root, "global/test", 0);
|
||||
find_config_tree_int(cmd, "global/test", 0);
|
||||
|
||||
/* Settings for logging to file */
|
||||
if (find_config_int(cmd->cft->root, "log/overwrite", DEFAULT_OVERWRITE))
|
||||
if (find_config_tree_int(cmd, "log/overwrite", DEFAULT_OVERWRITE))
|
||||
append = 0;
|
||||
|
||||
log_file = find_config_str(cmd->cft->root, "log/file", 0);
|
||||
log_file = find_config_tree_str(cmd, "log/file", 0);
|
||||
|
||||
if (log_file) {
|
||||
release_log_memory();
|
||||
@@ -134,15 +133,17 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
init_log_file(log_file, append);
|
||||
}
|
||||
|
||||
log_file = find_config_str(cmd->cft->root, "log/activate_file", 0);
|
||||
log_file = find_config_tree_str(cmd, "log/activate_file", 0);
|
||||
if (log_file)
|
||||
init_log_direct(log_file, append);
|
||||
|
||||
init_log_while_suspended(find_config_int(cmd->cft->root,
|
||||
init_log_while_suspended(find_config_tree_int(cmd,
|
||||
"log/activation", 0));
|
||||
|
||||
t = time(NULL);
|
||||
log_verbose("Logging initialised at %s", ctime(&t));
|
||||
ctime_r(&t, &timebuf[0]);
|
||||
timebuf[24] = '\0';
|
||||
log_verbose("Logging initialised at %s", timebuf);
|
||||
|
||||
/* Tell device-mapper about our logging */
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
@@ -155,7 +156,7 @@ static int _process_config(struct cmd_context *cmd)
|
||||
mode_t old_umask;
|
||||
|
||||
/* umask */
|
||||
cmd->default_settings.umask = find_config_int(cmd->cft->root,
|
||||
cmd->default_settings.umask = find_config_tree_int(cmd,
|
||||
"global/umask",
|
||||
DEFAULT_UMASK);
|
||||
|
||||
@@ -164,8 +165,8 @@ static int _process_config(struct cmd_context *cmd)
|
||||
log_verbose("Set umask to %04o", cmd->default_settings.umask);
|
||||
|
||||
/* dev dir */
|
||||
if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
|
||||
find_config_str(cmd->cft->root, "devices/dir",
|
||||
if (dm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
|
||||
find_config_tree_str(cmd, "devices/dir",
|
||||
DEFAULT_DEV_DIR)) < 0) {
|
||||
log_error("Device directory given in config file too long");
|
||||
return 0;
|
||||
@@ -175,8 +176,8 @@ static int _process_config(struct cmd_context *cmd)
|
||||
#endif
|
||||
|
||||
/* proc dir */
|
||||
if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
find_config_str(cmd->cft->root, "global/proc",
|
||||
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
find_config_tree_str(cmd, "global/proc",
|
||||
DEFAULT_PROC_DIR)) < 0) {
|
||||
log_error("Device directory given in config file too long");
|
||||
return 0;
|
||||
@@ -189,17 +190,17 @@ static int _process_config(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/* activation? */
|
||||
cmd->default_settings.activation = find_config_int(cmd->cft->root,
|
||||
cmd->default_settings.activation = find_config_tree_int(cmd,
|
||||
"global/activation",
|
||||
DEFAULT_ACTIVATION);
|
||||
set_activation(cmd->default_settings.activation);
|
||||
|
||||
cmd->default_settings.suffix = find_config_int(cmd->cft->root,
|
||||
cmd->default_settings.suffix = find_config_tree_int(cmd,
|
||||
"global/suffix",
|
||||
DEFAULT_SUFFIX);
|
||||
|
||||
if (!(cmd->default_settings.unit_factor =
|
||||
units_to_bytes(find_config_str(cmd->cft->root,
|
||||
units_to_bytes(find_config_tree_str(cmd,
|
||||
"global/units",
|
||||
DEFAULT_UNITS),
|
||||
&cmd->default_settings.unit_type))) {
|
||||
@@ -316,7 +317,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
if (*tag)
|
||||
filler = "_";
|
||||
|
||||
if (lvm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||
if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||
cmd->sys_dir, filler, tag) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR or tag was too long");
|
||||
return 0;
|
||||
@@ -327,7 +328,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cfl->cft = create_config_tree(config_file))) {
|
||||
if (!(cfl->cft = create_config_tree(config_file, 0))) {
|
||||
log_error("config_tree allocation failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -367,7 +368,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
|
||||
{
|
||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||
if (!*cmd->sys_dir) {
|
||||
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||
if (!(cmd->cft = create_config_tree(NULL, 0))) {
|
||||
log_error("Failed to create config tree");
|
||||
return 0;
|
||||
}
|
||||
@@ -405,7 +406,7 @@ static int _merge_config_files(struct cmd_context *cmd)
|
||||
|
||||
/* Replace temporary duplicate copy of lvm.conf */
|
||||
if (cmd->cft->root) {
|
||||
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||
if (!(cmd->cft = create_config_tree(NULL, 0))) {
|
||||
log_error("Failed to create config tree");
|
||||
return 0;
|
||||
}
|
||||
@@ -469,7 +470,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "devices/scan"))) {
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
log_error("Failed to add /dev to internal "
|
||||
"device cache");
|
||||
@@ -494,7 +495,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/loopfiles")))
|
||||
return 1;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@@ -536,14 +537,14 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
* Listed first because it's very efficient at eliminating
|
||||
* unavailable devices.
|
||||
*/
|
||||
if (find_config_bool(cmd->cft->root, "devices/sysfs_scan",
|
||||
if (find_config_tree_bool(cmd, "devices/sysfs_scan",
|
||||
DEFAULT_SYSFS_SCAN)) {
|
||||
if ((filters[nr_filt] = sysfs_filter_create(cmd->proc_dir)))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* regex filter. Optional. */
|
||||
if (!(cn = find_config_node(cmd->cft->root, "devices/filter")))
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/filter")))
|
||||
log_very_verbose("devices/filter not found in config file: "
|
||||
"no regex filter installed");
|
||||
|
||||
@@ -553,14 +554,14 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/* device type filter. Required. */
|
||||
cn = find_config_node(cmd->cft->root, "devices/types");
|
||||
cn = find_config_tree_node(cmd, "devices/types");
|
||||
if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
|
||||
log_error("Failed to create lvm type filter");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* md component filter. Optional, non-critical. */
|
||||
if (find_config_bool(cmd->cft->root, "devices/md_component_detection",
|
||||
if (find_config_tree_bool(cmd, "devices/md_component_detection",
|
||||
DEFAULT_MD_COMPONENT_DETECTION)) {
|
||||
init_md_filtering(1);
|
||||
if ((filters[nr_filt] = md_filter_create()))
|
||||
@@ -572,9 +573,9 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
filters[0] : composite_filter_create(nr_filt, filters);
|
||||
}
|
||||
|
||||
static int _init_filters(struct cmd_context *cmd)
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
|
||||
struct dev_filter *f3, *f4;
|
||||
struct stat st;
|
||||
char cache_file[PATH_MAX];
|
||||
@@ -584,30 +585,54 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
if (!(f3 = _init_filter_components(cmd)))
|
||||
return 0;
|
||||
|
||||
if (lvm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s/.cache", cmd->sys_dir) < 0) {
|
||||
log_error("Persistent cache filename too long ('%s/.cache').",
|
||||
cmd->sys_dir);
|
||||
init_ignore_suspended_devices(find_config_tree_int(cmd,
|
||||
"devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
|
||||
|
||||
/*
|
||||
* If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'.
|
||||
*/
|
||||
cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL);
|
||||
cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL);
|
||||
|
||||
if (cache_dir || cache_file_prefix) {
|
||||
if (dm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s%s%s/%s.cache",
|
||||
cache_dir ? "" : cmd->sys_dir,
|
||||
cache_dir ? "" : "/",
|
||||
cache_dir ? : DEFAULT_CACHE_SUBDIR,
|
||||
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
|
||||
log_error("Persistent cache filename too long.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
|
||||
(dm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s/%s/%s.cache",
|
||||
cmd->sys_dir, DEFAULT_CACHE_SUBDIR,
|
||||
DEFAULT_CACHE_FILE_PREFIX) < 0)) {
|
||||
log_error("Persistent cache filename too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_cache = find_config_str(cmd->cft->root, "devices/cache",
|
||||
cache_file);
|
||||
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
||||
if (!(f4 = persistent_filter_create(f3, dev_cache ? : cache_file))) {
|
||||
log_error("Failed to create persistent device filter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Should we ever dump persistent filter state? */
|
||||
if (find_config_int(cmd->cft->root, "devices/write_cache_state", 1))
|
||||
if (find_config_tree_int(cmd, "devices/write_cache_state", 1))
|
||||
cmd->dump_filter = 1;
|
||||
|
||||
if (!*cmd->sys_dir)
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
if (!stat(dev_cache, &st) &&
|
||||
(st.st_mtime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(f4))
|
||||
/*
|
||||
* Only load persistent filter device cache on startup if it is newer
|
||||
* than the config file and this is not a long-lived process.
|
||||
*/
|
||||
if (load_persistent_cache && !cmd->is_long_lived &&
|
||||
!stat(dev_cache, &st) &&
|
||||
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(f4, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
|
||||
@@ -643,8 +668,9 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs */
|
||||
if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) {
|
||||
/* Load any formats in shared libs if not static */
|
||||
if (!cmd->is_static &&
|
||||
(cn = find_config_tree_node(cmd, "global/format_libraries"))) {
|
||||
|
||||
struct config_value *cv;
|
||||
struct format_type *(*init_format_fn) (struct cmd_context *);
|
||||
@@ -656,8 +682,8 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
"global/format_libraries");
|
||||
return 0;
|
||||
}
|
||||
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
|
||||
"format"))) {
|
||||
if (!(lib = load_shared_library(cmd, cv->v.str,
|
||||
"format", 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -684,7 +710,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
|
||||
cmd->fmt_backup = fmt;
|
||||
|
||||
format = find_config_str(cmd->cft->root, "global/format",
|
||||
format = find_config_tree_str(cmd, "global/format",
|
||||
DEFAULT_FORMAT);
|
||||
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
@@ -737,13 +763,13 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs */
|
||||
if ((cn = find_config_node(cmd->cft->root, "global/segment_libraries"))) {
|
||||
/* Load any formats in shared libs unless static */
|
||||
if (!cmd->is_static &&
|
||||
(cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
|
||||
|
||||
struct config_value *cv;
|
||||
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
|
||||
void *lib;
|
||||
struct list *sgtl, *tmp;
|
||||
struct segment_type *segtype2;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@@ -752,8 +778,8 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
"global/segment_libraries");
|
||||
return 0;
|
||||
}
|
||||
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
|
||||
"segment type"))) {
|
||||
if (!(lib = load_shared_library(cmd, cv->v.str,
|
||||
"segment type", 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -770,18 +796,16 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
segtype->library = lib;
|
||||
list_add(&cmd->segtypes, &segtype->list);
|
||||
|
||||
list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
|
||||
segtype2 = list_item(sgtl, struct segment_type);
|
||||
if (!strcmp(segtype2->name, segtype->name)) {
|
||||
log_error("Duplicate segment type %s: "
|
||||
"unloading shared library %s",
|
||||
segtype->name, cv->v.str);
|
||||
list_del(&segtype->list);
|
||||
segtype->ops->destroy(segtype);
|
||||
dlclose(lib);
|
||||
break;
|
||||
}
|
||||
|
||||
list_iterate_items(segtype2, &cmd->segtypes) {
|
||||
if ((segtype == segtype2) ||
|
||||
strcmp(segtype2->name, segtype->name))
|
||||
continue;
|
||||
log_error("Duplicate segment type %s: "
|
||||
"unloading shared library %s",
|
||||
segtype->name, cv->v.str);
|
||||
list_del(&segtype->list);
|
||||
segtype->ops->destroy(segtype);
|
||||
dlclose(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,16 +851,16 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
|
||||
/* set up archiving */
|
||||
cmd->default_settings.archive =
|
||||
find_config_bool(cmd->cft->root, "backup/archive",
|
||||
find_config_tree_bool(cmd, "backup/archive",
|
||||
DEFAULT_ARCHIVE_ENABLED);
|
||||
|
||||
days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
|
||||
days = (uint32_t) find_config_tree_int(cmd, "backup/retain_days",
|
||||
DEFAULT_ARCHIVE_DAYS);
|
||||
|
||||
min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
|
||||
min = (uint32_t) find_config_tree_int(cmd, "backup/retain_min",
|
||||
DEFAULT_ARCHIVE_NUMBER);
|
||||
|
||||
if (lvm_snprintf
|
||||
if (dm_snprintf
|
||||
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
|
||||
DEFAULT_ARCHIVE_SUBDIR) == -1) {
|
||||
log_err("Couldn't create default archive path '%s/%s'.",
|
||||
@@ -844,7 +868,7 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dir = find_config_str(cmd->cft->root, "backup/archive_dir",
|
||||
dir = find_config_tree_str(cmd, "backup/archive_dir",
|
||||
default_dir);
|
||||
|
||||
if (!archive_init(cmd, dir, days, min)) {
|
||||
@@ -854,10 +878,10 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
|
||||
/* set up the backup */
|
||||
cmd->default_settings.backup =
|
||||
find_config_bool(cmd->cft->root, "backup/backup",
|
||||
find_config_tree_bool(cmd, "backup/backup",
|
||||
DEFAULT_BACKUP_ENABLED);
|
||||
|
||||
if (lvm_snprintf
|
||||
if (dm_snprintf
|
||||
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
|
||||
DEFAULT_BACKUP_SUBDIR) == -1) {
|
||||
log_err("Couldn't create default backup path '%s/%s'.",
|
||||
@@ -865,7 +889,7 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
|
||||
dir = find_config_tree_str(cmd, "backup/backup_dir", default_dir);
|
||||
|
||||
if (!backup_init(cmd, dir)) {
|
||||
log_debug("backup_init failed.");
|
||||
@@ -876,7 +900,8 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
|
||||
unsigned is_long_lived)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
@@ -899,6 +924,8 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
}
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->args = the_args;
|
||||
cmd->is_static = is_static;
|
||||
cmd->is_long_lived = is_long_lived;
|
||||
cmd->hosttags = 0;
|
||||
list_init(&cmd->formats);
|
||||
list_init(&cmd->segtypes);
|
||||
@@ -921,7 +948,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
|
||||
if (!(cmd->libmem = dm_pool_create("library", 4 * 1024))) {
|
||||
log_error("Library memory pool creation failed");
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!_init_lvm_conf(cmd))
|
||||
@@ -947,12 +974,12 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
if (!_init_filters(cmd, 1))
|
||||
goto error;
|
||||
|
||||
if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) {
|
||||
log_error("Command memory pool creation failed");
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memlock_init(cmd);
|
||||
@@ -1016,12 +1043,12 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
log_verbose("Reloading config files");
|
||||
|
||||
if (cmd->config_valid) {
|
||||
if (cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
}
|
||||
/*
|
||||
* Don't update the persistent filter cache as we will
|
||||
* perform a full rescan.
|
||||
*/
|
||||
|
||||
activation_exit();
|
||||
activation_release();
|
||||
lvmcache_destroy();
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
@@ -1058,7 +1085,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_dev_cache(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
if (!_init_filters(cmd, 0))
|
||||
return 0;
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
@@ -1067,6 +1094,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_segtypes(cmd))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we are a long-lived process, write out the updated persistent
|
||||
* device cache for the benefit of short-lived processes.
|
||||
*/
|
||||
if (cmd->is_long_lived && cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
|
||||
cmd->config_valid = 1;
|
||||
return 1;
|
||||
}
|
||||
@@ -1094,8 +1128,4 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
activation_exit();
|
||||
fin_log();
|
||||
fin_syslog();
|
||||
|
||||
if (_log)
|
||||
fclose(_log);
|
||||
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ struct cmd_context {
|
||||
struct command *command;
|
||||
struct arg *args;
|
||||
char **argv;
|
||||
unsigned is_static; /* Static binary? */
|
||||
unsigned is_long_lived; /* Optimises persistent_filter handling */
|
||||
|
||||
struct dev_filter *filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
@@ -71,6 +73,7 @@ struct cmd_context {
|
||||
struct list config_files;
|
||||
int config_valid;
|
||||
struct config_tree *cft;
|
||||
struct config_tree *cft_override;
|
||||
struct config_info default_settings;
|
||||
struct config_info current_settings;
|
||||
|
||||
@@ -86,7 +89,7 @@ struct cmd_context {
|
||||
char proc_dir[PATH_MAX];
|
||||
};
|
||||
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args);
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_toolcontext(struct cmd_context *cmd);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
|
||||
@@ -41,10 +41,10 @@ enum {
|
||||
};
|
||||
|
||||
struct parser {
|
||||
char *fb, *fe; /* file limits */
|
||||
const char *fb, *fe; /* file limits */
|
||||
|
||||
int t; /* token limits and type */
|
||||
char *tb, *te;
|
||||
const char *tb, *te;
|
||||
|
||||
int fd; /* descriptor for file being parsed */
|
||||
int line; /* line number we are on */
|
||||
@@ -58,6 +58,8 @@ struct cs {
|
||||
time_t timestamp;
|
||||
char *filename;
|
||||
int exists;
|
||||
int keep_open;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static void _get_token(struct parser *p, int tok_prev);
|
||||
@@ -77,7 +79,7 @@ static const int sep = '/';
|
||||
|
||||
#define match(t) do {\
|
||||
if (!_match_aux(p, (t))) {\
|
||||
log_error("Parse error at line %d: unexpected token", p->line); \
|
||||
log_error("Parse error at byte %d (line %d): unexpected token", p->tb - p->fb + 1, p->line); \
|
||||
return 0;\
|
||||
} \
|
||||
} while(0);
|
||||
@@ -95,18 +97,18 @@ static int _tok_match(const char *str, const char *b, const char *e)
|
||||
/*
|
||||
* public interface
|
||||
*/
|
||||
struct config_tree *create_config_tree(const char *filename)
|
||||
struct config_tree *create_config_tree(const char *filename, int keep_open)
|
||||
{
|
||||
struct cs *c;
|
||||
struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
log_error("Failed to allocate config pool.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
|
||||
stack;
|
||||
log_error("Failed to allocate config tree.");
|
||||
dm_pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -115,6 +117,8 @@ struct config_tree *create_config_tree(const char *filename)
|
||||
c->cft.root = (struct config_node *) NULL;
|
||||
c->timestamp = 0;
|
||||
c->exists = 0;
|
||||
c->keep_open = keep_open;
|
||||
c->dev = 0;
|
||||
if (filename)
|
||||
c->filename = dm_pool_strdup(c->mem, filename);
|
||||
return &c->cft;
|
||||
@@ -122,7 +126,52 @@ struct config_tree *create_config_tree(const char *filename)
|
||||
|
||||
void destroy_config_tree(struct config_tree *cft)
|
||||
{
|
||||
dm_pool_destroy(((struct cs *) cft)->mem);
|
||||
struct cs *c = (struct cs *) cft;
|
||||
|
||||
if (c->dev)
|
||||
dev_close(c->dev);
|
||||
|
||||
dm_pool_destroy(c->mem);
|
||||
}
|
||||
|
||||
static int _parse_config_file(struct parser *p, struct config_tree *cft)
|
||||
{
|
||||
p->tb = p->te = p->fb;
|
||||
p->line = 1;
|
||||
_get_token(p, TOK_SECTION_E);
|
||||
if (!(cft->root = _file(p)))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
|
||||
const char *config_settings)
|
||||
{
|
||||
struct cs *c;
|
||||
struct config_tree *cft;
|
||||
struct parser *p;
|
||||
|
||||
if (!(cft = create_config_tree(NULL, 0)))
|
||||
return_NULL;
|
||||
|
||||
c = (struct cs *) cft;
|
||||
if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
|
||||
log_error("Failed to allocate config tree parser.");
|
||||
destroy_config_tree(cft);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->mem = c->mem;
|
||||
p->fb = config_settings;
|
||||
p->fe = config_settings + strlen(config_settings);
|
||||
|
||||
if (!_parse_config_file(p, cft)) {
|
||||
destroy_config_tree(cft);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
return cft;
|
||||
}
|
||||
|
||||
int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
@@ -134,6 +183,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
int r = 0;
|
||||
int use_mmap = 1;
|
||||
off_t mmap_offset = 0;
|
||||
char *buf;
|
||||
|
||||
if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
|
||||
stack;
|
||||
@@ -146,7 +196,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
use_mmap = 0;
|
||||
|
||||
if (use_mmap) {
|
||||
mmap_offset = offset % getpagesize();
|
||||
mmap_offset = offset % lvm_getpagesize();
|
||||
/* memory map the file */
|
||||
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
|
||||
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
|
||||
@@ -156,22 +206,23 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
}
|
||||
p->fb = p->fb + mmap_offset;
|
||||
} else {
|
||||
if (!(p->fb = dm_malloc(size + size2))) {
|
||||
if (!(buf = dm_malloc(size + size2))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_read(dev, (uint64_t) offset, size, p->fb)) {
|
||||
if (!dev_read(dev, (uint64_t) offset, size, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
if (size2) {
|
||||
if (!dev_read(dev, (uint64_t) offset2, size2,
|
||||
p->fb + size)) {
|
||||
buf + size)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
p->fb = buf;
|
||||
}
|
||||
|
||||
if (checksum_fn && checksum !=
|
||||
@@ -183,11 +234,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
|
||||
p->fe = p->fb + size + size2;
|
||||
|
||||
/* parse */
|
||||
p->tb = p->te = p->fb;
|
||||
p->line = 1;
|
||||
_get_token(p, TOK_SECTION_E);
|
||||
if (!(cft->root = _file(p))) {
|
||||
if (!_parse_config_file(p, cft)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -196,7 +243,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
|
||||
out:
|
||||
if (!use_mmap)
|
||||
dm_free(p->fb);
|
||||
dm_free(buf);
|
||||
else {
|
||||
/* unmap the file */
|
||||
if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
|
||||
@@ -212,7 +259,6 @@ int read_config_file(struct config_tree *cft)
|
||||
{
|
||||
struct cs *c = (struct cs *) cft;
|
||||
struct stat info;
|
||||
struct device *dev;
|
||||
int r = 1;
|
||||
|
||||
if (stat(c->filename, &info)) {
|
||||
@@ -234,22 +280,23 @@ int read_config_file(struct config_tree *cft)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
if (!c->dev) {
|
||||
if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
|
||||
r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0);
|
||||
|
||||
dev_close(dev);
|
||||
if (!c->keep_open) {
|
||||
dev_close(c->dev);
|
||||
c->dev = 0;
|
||||
}
|
||||
|
||||
c->timestamp = info.st_mtime;
|
||||
c->timestamp = info.st_ctime;
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -293,7 +340,7 @@ int config_file_changed(struct config_tree *cft)
|
||||
}
|
||||
|
||||
/* Unchanged? */
|
||||
if (c->timestamp == info.st_mtime)
|
||||
if (c->timestamp == info.st_ctime)
|
||||
return 0;
|
||||
|
||||
reload:
|
||||
@@ -326,7 +373,8 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
}
|
||||
}
|
||||
|
||||
static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
static int _write_config(struct config_node *n, int only_one, FILE *fp,
|
||||
int level)
|
||||
{
|
||||
char space[MAX_INDENT + 1];
|
||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||
@@ -339,12 +387,12 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
space[i] = '\t';
|
||||
space[i] = '\0';
|
||||
|
||||
while (n) {
|
||||
do {
|
||||
fprintf(fp, "%s%s", space, n->key);
|
||||
if (!n->v) {
|
||||
/* it's a sub section */
|
||||
fprintf(fp, " {\n");
|
||||
_write_config(n->child, fp, level + 1);
|
||||
_write_config(n->child, 0, fp, level + 1);
|
||||
fprintf(fp, "%s}", space);
|
||||
} else {
|
||||
/* it's a value */
|
||||
@@ -364,13 +412,15 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
n = n->sib;
|
||||
}
|
||||
} while (n && !only_one);
|
||||
/* FIXME: add error checking */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int write_config_file(struct config_tree *cft, const char *file)
|
||||
int write_config_file(struct config_tree *cft, const char *file,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct config_node *cn;
|
||||
int r = 1;
|
||||
FILE *fp;
|
||||
|
||||
@@ -383,13 +433,28 @@ int write_config_file(struct config_tree *cft, const char *file)
|
||||
}
|
||||
|
||||
log_verbose("Dumping configuration to %s", file);
|
||||
if (!_write_config(cft->root, fp, 0)) {
|
||||
log_error("Failure while writing configuration");
|
||||
r = 0;
|
||||
if (!argc) {
|
||||
if (!_write_config(cft->root, 0, fp, 0)) {
|
||||
log_error("Failure while writing to %s", file);
|
||||
r = 0;
|
||||
}
|
||||
} else while (argc--) {
|
||||
if ((cn = find_config_node(cft->root, *argv))) {
|
||||
if (!_write_config(cn, 1, fp, 0)) {
|
||||
log_error("Failure while writing to %s", file);
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
log_error("Configuration node %s not found", *argv);
|
||||
r = 0;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (fp != stdout)
|
||||
fclose(fp);
|
||||
if ((fp != stdout) && fclose(fp)) {
|
||||
log_sys_error("fclose", file);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -529,7 +594,7 @@ static struct config_value *_type(struct parser *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Parse error at line %d: expected a value", p->line);
|
||||
log_error("Parse error at byte %d (line %d): expected a value", p->tb - p->fb + 1, p->line);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
@@ -688,14 +753,20 @@ static void _eat_space(struct parser *p)
|
||||
static struct config_value *_create_value(struct parser *p)
|
||||
{
|
||||
struct config_value *v = dm_pool_alloc(p->mem, sizeof(*v));
|
||||
memset(v, 0, sizeof(*v));
|
||||
|
||||
if (v)
|
||||
memset(v, 0, sizeof(*v));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static struct config_node *_create_node(struct parser *p)
|
||||
{
|
||||
struct config_node *n = dm_pool_alloc(p->mem, sizeof(*n));
|
||||
memset(n, 0, sizeof(*n));
|
||||
|
||||
if (n)
|
||||
memset(n, 0, sizeof(*n));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -715,10 +786,11 @@ static char *_dup_tok(struct parser *p)
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
struct config_node *find_config_node(const struct config_node *cn,
|
||||
const char *path)
|
||||
static struct config_node *_find_config_node(const struct config_node *cn,
|
||||
const char *path)
|
||||
{
|
||||
const char *e;
|
||||
const struct config_node *cn_found = NULL;
|
||||
|
||||
while (cn) {
|
||||
/* trim any leading slashes */
|
||||
@@ -729,32 +801,62 @@ struct config_node *find_config_node(const struct config_node *cn,
|
||||
for (e = path; *e && (*e != sep); e++) ;
|
||||
|
||||
/* hunt for the node */
|
||||
cn_found = NULL;
|
||||
while (cn) {
|
||||
if (_tok_match(cn->key, path, e))
|
||||
break;
|
||||
if (_tok_match(cn->key, path, e)) {
|
||||
/* Inefficient */
|
||||
if (!cn_found)
|
||||
cn_found = cn;
|
||||
else
|
||||
log_error("WARNING: Ignoring duplicate"
|
||||
" config node: %s ("
|
||||
"seeking %s)", cn->key, path);
|
||||
}
|
||||
|
||||
cn = cn->sib;
|
||||
}
|
||||
|
||||
if (cn && *e)
|
||||
cn = cn->child;
|
||||
if (cn_found && *e)
|
||||
cn = cn_found->child;
|
||||
else
|
||||
break; /* don't move into the last node */
|
||||
|
||||
path = e;
|
||||
}
|
||||
|
||||
return (struct config_node *) cn;
|
||||
return (struct config_node *) cn_found;
|
||||
}
|
||||
|
||||
const char *find_config_str(const struct config_node *cn,
|
||||
const char *path, const char *fail)
|
||||
static struct config_node *_find_first_config_node(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path)
|
||||
{
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
struct config_node *cn;
|
||||
|
||||
if (n && n->v->type == CFG_STRING) {
|
||||
if (*n->v->v.str)
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
if (cn1 && (cn = _find_config_node(cn1, path)))
|
||||
return cn;
|
||||
|
||||
if (cn2 && (cn = _find_config_node(cn2, path)))
|
||||
return cn;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct config_node *find_config_node(const struct config_node *cn,
|
||||
const char *path)
|
||||
{
|
||||
return _find_config_node(cn, path);
|
||||
}
|
||||
|
||||
static const char *_find_config_str(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, const char *fail)
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
/* Empty strings are ignored */
|
||||
if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
return n->v->v.str;
|
||||
}
|
||||
|
||||
@@ -764,11 +866,19 @@ const char *find_config_str(const struct config_node *cn,
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
const char *find_config_str(const struct config_node *cn,
|
||||
const char *path, const char *fail)
|
||||
{
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
return _find_config_str(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
if (n && n->v->type == CFG_INT) {
|
||||
static int _find_config_int(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int fail)
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||
return n->v->v.i;
|
||||
}
|
||||
@@ -778,12 +888,18 @@ int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
return fail;
|
||||
}
|
||||
|
||||
float find_config_float(const struct config_node *cn, const char *path,
|
||||
float fail)
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
return _find_config_int(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
if (n && n->v->type == CFG_FLOAT) {
|
||||
static float _find_config_float(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, float fail)
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v && n->v->type == CFG_FLOAT) {
|
||||
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
||||
return n->v->v.r;
|
||||
}
|
||||
@@ -795,6 +911,36 @@ float find_config_float(const struct config_node *cn, const char *path,
|
||||
|
||||
}
|
||||
|
||||
float find_config_float(const struct config_node *cn, const char *path,
|
||||
float fail)
|
||||
{
|
||||
return _find_config_float(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
struct config_node *find_config_tree_node(struct cmd_context *cmd,
|
||||
const char *path)
|
||||
{
|
||||
return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
|
||||
}
|
||||
|
||||
const char *find_config_tree_str(struct cmd_context *cmd,
|
||||
const char *path, const char *fail)
|
||||
{
|
||||
return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
|
||||
}
|
||||
|
||||
int find_config_tree_int(struct cmd_context *cmd, const char *path,
|
||||
int fail)
|
||||
{
|
||||
return _find_config_int(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
|
||||
}
|
||||
|
||||
float find_config_tree_float(struct cmd_context *cmd, const char *path,
|
||||
float fail)
|
||||
{
|
||||
return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
|
||||
}
|
||||
|
||||
static int _str_in_array(const char *str, const char *values[])
|
||||
{
|
||||
int i;
|
||||
@@ -821,9 +967,11 @@ static int _str_to_bool(const char *str, int fail)
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_bool(const struct config_node *cn, const char *path, int fail)
|
||||
static int _find_config_bool(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int fail)
|
||||
{
|
||||
const struct config_node *n = find_config_node(cn, path);
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
struct config_value *v;
|
||||
|
||||
if (!n)
|
||||
@@ -842,6 +990,16 @@ int find_config_bool(const struct config_node *cn, const char *path, int fail)
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_bool(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
return _find_config_bool(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
|
||||
{
|
||||
return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
|
||||
}
|
||||
|
||||
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||
uint32_t *result)
|
||||
{
|
||||
|
||||
@@ -53,17 +53,20 @@ struct config_tree_list {
|
||||
struct config_tree *cft;
|
||||
};
|
||||
|
||||
struct config_tree *create_config_tree(const char *filename);
|
||||
struct config_tree *create_config_tree(const char *filename, int keep_open);
|
||||
struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
|
||||
const char *config_settings);
|
||||
void destroy_config_tree(struct config_tree *cft);
|
||||
|
||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, const void *buf, uint32_t size);
|
||||
|
||||
int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||
|
||||
int read_config_file(struct config_tree *cft);
|
||||
int write_config_file(struct config_tree *cft, const char *file);
|
||||
int write_config_file(struct config_tree *cft, const char *file,
|
||||
int argc, char **argv);
|
||||
time_t config_file_timestamp(struct config_tree *cft);
|
||||
int config_file_changed(struct config_tree *cft);
|
||||
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
@@ -71,20 +74,30 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
|
||||
struct config_node *find_config_node(const struct config_node *cn,
|
||||
const char *path);
|
||||
|
||||
const char *find_config_str(const struct config_node *cn, const char *path,
|
||||
const char *fail);
|
||||
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail);
|
||||
|
||||
float find_config_float(const struct config_node *cn, const char *path,
|
||||
float fail);
|
||||
|
||||
/*
|
||||
* These versions check an override tree, if present, first.
|
||||
*/
|
||||
struct config_node *find_config_tree_node(struct cmd_context *cmd,
|
||||
const char *path);
|
||||
const char *find_config_tree_str(struct cmd_context *cmd,
|
||||
const char *path, const char *fail);
|
||||
int find_config_tree_int(struct cmd_context *cmd, const char *path,
|
||||
int fail);
|
||||
float find_config_tree_float(struct cmd_context *cmd, const char *path,
|
||||
float fail);
|
||||
|
||||
/*
|
||||
* Understands (0, ~0), (y, n), (yes, no), (on,
|
||||
* off), (true, false).
|
||||
*/
|
||||
int find_config_bool(const struct config_node *cn, const char *path, int fail);
|
||||
int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail);
|
||||
|
||||
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||
uint32_t *result);
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#define DEFAULT_ARCHIVE_SUBDIR "archive"
|
||||
#define DEFAULT_BACKUP_SUBDIR "backup"
|
||||
#define DEFAULT_CACHE_SUBDIR "cache"
|
||||
#define DEFAULT_CACHE_FILE_PREFIX ""
|
||||
|
||||
#define DEFAULT_ARCHIVE_DAYS 30
|
||||
#define DEFAULT_ARCHIVE_NUMBER 10
|
||||
@@ -30,11 +32,17 @@
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
|
||||
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
||||
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
||||
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
||||
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_DEV_FAULT_POLICY "remove"
|
||||
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
|
||||
#define DEFAULT_DMEVENTD_MONITOR 1
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ void *btree_get_data(struct btree_iter *it)
|
||||
return ((struct node *) it)->data;
|
||||
}
|
||||
|
||||
static inline struct node *_left(struct node *n)
|
||||
static struct node *_left(struct node *n)
|
||||
{
|
||||
while (n->l)
|
||||
n = n->l;
|
||||
|
||||
136
lib/datastruct/list.c
Normal file
136
lib/datastruct/list.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
/*
|
||||
* Initialise a list before use.
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
void list_init(struct list *head)
|
||||
{
|
||||
head->n = head->p = head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
void list_add(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head;
|
||||
elem->p = head->p;
|
||||
|
||||
head->p->n = elem;
|
||||
head->p = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
void list_add_h(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head->n;
|
||||
elem->p = head;
|
||||
|
||||
head->n->p = elem;
|
||||
head->n = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
void list_del(struct list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
int list_empty(struct list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
int list_start(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->p == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
int list_end(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
struct list *list_first(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
struct list *list_last(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
struct list *list_prev(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_start(head, elem) ? NULL : elem->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
struct list *list_next(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
unsigned int list_size(const struct list *head)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
const struct list *v;
|
||||
|
||||
list_iterate(v, head)
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -33,107 +33,61 @@ struct list {
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
#define LIST_INIT(name) struct list name = { &(name), &(name) }
|
||||
static inline void list_init(struct list *head)
|
||||
{
|
||||
head->n = head->p = head;
|
||||
}
|
||||
void list_init(struct list *head);
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
static inline void list_add(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head;
|
||||
elem->p = head->p;
|
||||
|
||||
head->p->n = elem;
|
||||
head->p = elem;
|
||||
}
|
||||
void list_add(struct list *head, struct list *elem);
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
static inline void list_add_h(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head->n;
|
||||
elem->p = head;
|
||||
|
||||
head->n->p = elem;
|
||||
head->n = elem;
|
||||
}
|
||||
void list_add_h(struct list *head, struct list *elem);
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
static inline void list_del(struct list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
void list_del(struct list *elem);
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
static inline int list_empty(struct list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
int list_empty(struct list *head);
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
static inline int list_start(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->p == head;
|
||||
}
|
||||
int list_start(struct list *head, struct list *elem);
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
static inline int list_end(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
int list_end(struct list *head, struct list *elem);
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
static inline struct list *list_first(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
struct list *list_first(struct list *head);
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
static inline struct list *list_last(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->p);
|
||||
}
|
||||
struct list *list_last(struct list *head);
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
static inline struct list *list_prev(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_start(head, elem) ? NULL : elem->p);
|
||||
}
|
||||
struct list *list_prev(struct list *head, struct list *elem);
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
struct list *list_next(struct list *head, struct list *elem);
|
||||
|
||||
/*
|
||||
* Given the address v of an instance of 'struct list' called 'head'
|
||||
@@ -244,15 +198,6 @@ static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
static inline unsigned int list_size(const struct list *head)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
const struct list *v;
|
||||
|
||||
list_iterate(v, head)
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
unsigned int list_size(const struct list *head);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -479,7 +479,7 @@ static void _check_closed(struct device *dev)
|
||||
log_err("Device '%s' has been left open.", dev_name(dev));
|
||||
}
|
||||
|
||||
static inline void _check_for_open_devices(void)
|
||||
static void _check_for_open_devices(void)
|
||||
{
|
||||
dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
|
||||
}
|
||||
@@ -645,8 +645,7 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (dev_scan) {
|
||||
if (dev_scan && !trust_cache()) {
|
||||
/* Flag gets reset between each command */
|
||||
if (!full_scan_done())
|
||||
persistent_filter_wipe(f); /* Calls _full_scan(1) */
|
||||
@@ -664,7 +663,7 @@ void dev_iter_destroy(struct dev_iter *iter)
|
||||
dm_free(iter);
|
||||
}
|
||||
|
||||
static inline struct device *_iter_next(struct dev_iter *iter)
|
||||
static struct device *_iter_next(struct dev_iter *iter)
|
||||
{
|
||||
struct device *d = btree_get_data(iter->current);
|
||||
iter->current = btree_next(iter->current);
|
||||
@@ -682,3 +681,14 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dev_fd(struct device *dev)
|
||||
{
|
||||
return dev->fd;
|
||||
}
|
||||
|
||||
const char *dev_name(const struct device *dev)
|
||||
{
|
||||
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
|
||||
"unknown device";
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ static int _aligned_io(struct device_area *where, void *buffer,
|
||||
}
|
||||
|
||||
if (!block_size)
|
||||
block_size = getpagesize();
|
||||
block_size = lvm_getpagesize();
|
||||
|
||||
_widen_region(block_size, where, &widened);
|
||||
|
||||
@@ -292,11 +292,14 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &s) < 0) {
|
||||
log_sys_error("ioctl BLKSSZGET", name);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
|
||||
*size = (uint32_t) s;
|
||||
|
||||
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
|
||||
@@ -602,10 +605,10 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
return _aligned_io(&where, buffer, 1);
|
||||
}
|
||||
|
||||
int dev_zero(struct device *dev, uint64_t offset, size_t len)
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
|
||||
{
|
||||
size_t s;
|
||||
char buffer[4096];
|
||||
char buffer[4096] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
@@ -620,7 +623,7 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len)
|
||||
" sectors", dev_name(dev), offset >> SECTOR_SHIFT,
|
||||
len >> SECTOR_SHIFT);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(buffer, value, sizeof(buffer));
|
||||
while (1) {
|
||||
s = len > sizeof(buffer) ? sizeof(buffer) : len;
|
||||
if (!dev_write(dev, offset, s, buffer))
|
||||
|
||||
@@ -53,8 +53,10 @@ int dev_is_md(struct device *dev, uint64_t *sb)
|
||||
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
|
||||
|
||||
/* Check if it is an md component device. */
|
||||
/* Version 1 is little endian; version 0.90.0 is machine endian */
|
||||
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
|
||||
(md_magic == xlate32(MD_SB_MAGIC))) {
|
||||
((md_magic == xlate32(MD_SB_MAGIC)) ||
|
||||
(md_magic == MD_SB_MAGIC))) {
|
||||
if (sb)
|
||||
*sb = sb_offset;
|
||||
ret = 1;
|
||||
|
||||
@@ -53,7 +53,7 @@ static int _has_partition_table(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned p;
|
||||
uint8_t buf[SECTOR_SIZE];
|
||||
uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)];
|
||||
uint16_t *part_magic;
|
||||
struct partition *part;
|
||||
|
||||
@@ -62,7 +62,7 @@ static int _has_partition_table(struct device *dev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dev_read(dev, 0, sizeof(buf), &buf)) {
|
||||
if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -70,9 +70,9 @@ static int _has_partition_table(struct device *dev)
|
||||
/* FIXME Check for other types of partition table too */
|
||||
|
||||
/* Check for msdos partition table */
|
||||
part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET);
|
||||
part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
|
||||
if ((*part_magic == xlate16(PART_MAGIC))) {
|
||||
part = (struct partition *) (buf + PART_OFFSET);
|
||||
part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
|
||||
for (p = 0; p < 4; p++, part++) {
|
||||
/* Table is invalid if boot indicator not 0 or 0x80 */
|
||||
if ((part->boot_ind & 0x7f)) {
|
||||
|
||||
@@ -74,26 +74,18 @@ int dev_close_immediate(struct device *dev);
|
||||
void dev_close_all(void);
|
||||
int dev_test_excl(struct device *dev);
|
||||
|
||||
static inline int dev_fd(struct device *dev)
|
||||
{
|
||||
return dev->fd;
|
||||
}
|
||||
int dev_fd(struct device *dev);
|
||||
const char *dev_name(const struct device *dev);
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_append(struct device *dev, size_t len, void *buffer);
|
||||
int dev_zero(struct device *dev, uint64_t offset, size_t len);
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value);
|
||||
void dev_flush(struct device *dev);
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct str_list *alias, int use_malloc);
|
||||
|
||||
static inline const char *dev_name(const struct device *dev)
|
||||
{
|
||||
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
|
||||
"unknown device";
|
||||
}
|
||||
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||
|
||||
|
||||
@@ -22,12 +22,15 @@
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
||||
|
||||
static struct {
|
||||
alloc_policy_t alloc;
|
||||
const char *str;
|
||||
} _policies[] = {
|
||||
{
|
||||
ALLOC_CONTIGUOUS, "contiguous"}, {
|
||||
ALLOC_CLING, "cling"}, {
|
||||
ALLOC_NORMAL, "normal"}, {
|
||||
ALLOC_ANYWHERE, "anywhere"}, {
|
||||
ALLOC_INHERIT, "inherit"}
|
||||
@@ -79,6 +82,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
|
||||
case 't':
|
||||
v *= KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'p':
|
||||
v *= KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'e':
|
||||
v *= KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
#define KILO UINT64_C(1000)
|
||||
case 'K':
|
||||
@@ -93,6 +102,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
|
||||
case 'T':
|
||||
v *= KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'P':
|
||||
v *= KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'E':
|
||||
v *= KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
default:
|
||||
return 0;
|
||||
@@ -132,7 +147,7 @@ alloc_policy_t get_alloc_from_string(const char *str)
|
||||
}
|
||||
|
||||
/* Size supplied in sectors */
|
||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
{
|
||||
int s;
|
||||
int suffix = 1, precision;
|
||||
@@ -140,6 +155,8 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
const char *size_str[][3] = {
|
||||
{" Exabyte", " EB", "E"},
|
||||
{" Petabyte", " PB", "P"},
|
||||
{" Terabyte", " TB", "T"},
|
||||
{" Gigabyte", " GB", "G"},
|
||||
{" Megabyte", " MB", "M"},
|
||||
@@ -158,7 +175,7 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
|
||||
suffix = cmd->current_settings.suffix;
|
||||
|
||||
for (s = 0; s < 8; s++)
|
||||
for (s = 0; s < 10; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[s][2])
|
||||
break;
|
||||
@@ -168,7 +185,7 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
if (s < 8) {
|
||||
if (s < 10) {
|
||||
byte = cmd->current_settings.unit_factor;
|
||||
size *= UINT64_C(512);
|
||||
} else {
|
||||
@@ -178,7 +195,7 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
units = UINT64_C(1000);
|
||||
else
|
||||
units = UINT64_C(1024);
|
||||
byte = units * units * units;
|
||||
byte = units * units * units * units * units;
|
||||
s = 0;
|
||||
while (size_str[s] && size < byte)
|
||||
s++, byte /= units;
|
||||
@@ -200,9 +217,24 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
const char *display_size_long(struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_LONG);
|
||||
}
|
||||
|
||||
const char *display_size_units(struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_UNIT);
|
||||
}
|
||||
|
||||
const char *display_size(struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_SHORT);
|
||||
}
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv)
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return;
|
||||
@@ -228,9 +260,9 @@ void pvdisplay_colons(struct physical_volume *pv)
|
||||
|
||||
/* FIXME Include label fields */
|
||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle)
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
const char *size;
|
||||
|
||||
uint32_t pe_free;
|
||||
@@ -248,18 +280,17 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
log_print("VG Name %s%s", pv->vg_name,
|
||||
pv->status & EXPORTED_VG ? " (exported)" : "");
|
||||
|
||||
size = display_size(cmd, (uint64_t) pv->size, SIZE_SHORT);
|
||||
size = display_size(cmd, (uint64_t) pv->size);
|
||||
if (pv->pe_size && pv->pe_count) {
|
||||
|
||||
/******** FIXME display LVM on-disk data size
|
||||
size2 = display_size(pv->size, SIZE_SHORT);
|
||||
size2 = display_size(cmd, pv->size);
|
||||
********/
|
||||
|
||||
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||
size,
|
||||
display_size(cmd, (pv->size -
|
||||
(uint64_t) pv->pe_count * pv->pe_size),
|
||||
SIZE_SHORT));
|
||||
(uint64_t) pv->pe_count * pv->pe_size)));
|
||||
|
||||
} else
|
||||
log_print("PV Size %s", size);
|
||||
@@ -288,10 +319,12 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
return;
|
||||
}
|
||||
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv, void *handle)
|
||||
int pvdisplay_short(struct cmd_context *cmd __attribute((unused)),
|
||||
struct volume_group *vg __attribute((unused)),
|
||||
struct physical_volume *pv,
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return 0;
|
||||
@@ -334,11 +367,11 @@ void lvdisplay_colons(struct logical_volume *lv)
|
||||
}
|
||||
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
struct lvinfo info;
|
||||
int inkernel, snap_active = 0;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
struct lv_segment *snap_seg = NULL;
|
||||
float snap_percent; /* fused, fsize; */
|
||||
|
||||
@@ -404,23 +437,21 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
log_print("LV Size %s",
|
||||
display_size(cmd,
|
||||
snap_seg ? snap_seg->origin->size : lv->size,
|
||||
SIZE_SHORT));
|
||||
snap_seg ? snap_seg->origin->size : lv->size));
|
||||
|
||||
log_print("Current LE %u",
|
||||
snap_seg ? snap_seg->origin->le_count : lv->le_count);
|
||||
|
||||
if (snap_seg) {
|
||||
log_print("COW-table size %s",
|
||||
display_size(cmd, (uint64_t) lv->size, SIZE_SHORT));
|
||||
display_size(cmd, (uint64_t) lv->size));
|
||||
log_print("COW-table LE %u", lv->le_count);
|
||||
|
||||
if (snap_active)
|
||||
log_print("Allocated to snapshot %.2f%% ", snap_percent);
|
||||
|
||||
log_print("Snapshot chunk size %s",
|
||||
display_size(cmd, (uint64_t) snap_seg->chunk_size,
|
||||
SIZE_SHORT));
|
||||
display_size(cmd, (uint64_t) snap_seg->chunk_size));
|
||||
}
|
||||
|
||||
log_print("Segments %u", list_size(&lv->segments));
|
||||
@@ -497,7 +528,7 @@ int lvdisplay_segments(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void vgdisplay_extents(struct volume_group *vg)
|
||||
void vgdisplay_extents(struct volume_group *vg __attribute((unused)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -506,7 +537,7 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
{
|
||||
uint32_t access;
|
||||
uint32_t active_pvs;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
@@ -544,7 +575,7 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||
/****** FIXME Max LV Size
|
||||
log_print ( "MAX LV Size %s",
|
||||
( s1 = display_size ( LVM_LV_SIZE_MAX(vg), SIZE_SHORT)));
|
||||
( s1 = display_size ( LVM_LV_SIZE_MAX(vg))));
|
||||
free ( s1);
|
||||
*********/
|
||||
log_print("Max PV %u", vg->max_pv);
|
||||
@@ -553,12 +584,10 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
|
||||
log_print("VG Size %s",
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->extent_count * vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
(uint64_t) vg->extent_count * vg->extent_size));
|
||||
|
||||
log_print("PE Size %s",
|
||||
display_size(vg->cmd, (uint64_t) vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
display_size(vg->cmd, (uint64_t) vg->extent_size));
|
||||
|
||||
log_print("Total PE %u", vg->extent_count);
|
||||
|
||||
@@ -566,12 +595,11 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
vg->extent_count - vg->free_count,
|
||||
display_size(vg->cmd,
|
||||
((uint64_t) vg->extent_count - vg->free_count) *
|
||||
vg->extent_size, SIZE_SHORT));
|
||||
vg->extent_size));
|
||||
|
||||
log_print("Free PE / Size %u / %s", vg->free_count,
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->free_count * vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
(uint64_t) vg->free_count * vg->extent_size));
|
||||
|
||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
@@ -588,7 +616,7 @@ void vgdisplay_colons(struct volume_group *vg)
|
||||
{
|
||||
uint32_t active_pvs;
|
||||
const char *access;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
@@ -641,15 +669,12 @@ void vgdisplay_short(struct volume_group *vg)
|
||||
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
|
||||
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->extent_count * vg->extent_size,
|
||||
SIZE_SHORT),
|
||||
(uint64_t) vg->extent_count * vg->extent_size),
|
||||
display_size(vg->cmd,
|
||||
((uint64_t) vg->extent_count -
|
||||
vg->free_count) * vg->extent_size,
|
||||
SIZE_SHORT),
|
||||
vg->free_count) * vg->extent_size),
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->free_count * vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
(uint64_t) vg->free_count * vg->extent_size));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
||||
|
||||
uint64_t units_to_bytes(const char *units, char *unit_type);
|
||||
|
||||
/* Specify size in KB */
|
||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
|
||||
const char *display_size(struct cmd_context *cmd, uint64_t size);
|
||||
const char *display_size_long(struct cmd_context *cmd, uint64_t size);
|
||||
const char *display_size_units(struct cmd_context *cmd, uint64_t size);
|
||||
|
||||
char *display_uuid(char *uuidstr);
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre);
|
||||
|
||||
|
||||
@@ -23,13 +23,14 @@
|
||||
#include "targets.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
#include "str_list.h"
|
||||
|
||||
static const char *_name(const struct lv_segment *seg)
|
||||
static const char *_errseg_name(const struct lv_segment *seg)
|
||||
{
|
||||
return seg->segtype->name;
|
||||
}
|
||||
|
||||
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
static int _errseg_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
{
|
||||
seg1->len += seg2->len;
|
||||
seg1->area_len += seg2->area_len;
|
||||
@@ -38,43 +39,58 @@ static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
}
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem,
|
||||
struct config_tree *cft, void **target_state,
|
||||
struct lv_segment *seg,
|
||||
static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)),
|
||||
struct dm_pool *mem __attribute((unused)),
|
||||
struct cmd_context *cmd __attribute((unused)),
|
||||
void **target_state __attribute((unused)),
|
||||
struct lv_segment *seg __attribute((unused)),
|
||||
struct dm_tree_node *node, uint64_t len,
|
||||
uint32_t *pvmove_mirror_count)
|
||||
uint32_t *pvmove_mirror_count __attribute((unused)))
|
||||
{
|
||||
return dm_tree_node_add_error_target(node, len);
|
||||
}
|
||||
|
||||
static int _target_present(void)
|
||||
static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int checked = 0;
|
||||
static int present = 0;
|
||||
static int _errseg_checked = 0;
|
||||
static int _errseg_present = 0;
|
||||
|
||||
/* Reported truncated in older kernels */
|
||||
if (!checked &&
|
||||
if (!_errseg_checked &&
|
||||
(target_present("error", 0) || target_present("erro", 0)))
|
||||
present = 1;
|
||||
_errseg_present = 1;
|
||||
|
||||
checked = 1;
|
||||
return present;
|
||||
_errseg_checked = 1;
|
||||
return _errseg_present;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _destroy(const struct segment_type *segtype)
|
||||
static int _errseg_modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
dm_free((void *) segtype);
|
||||
if (!str_list_add(mem, modules, "error")) {
|
||||
log_error("error module string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _errseg_destroy(const struct segment_type *segtype)
|
||||
{
|
||||
dm_free((void *)segtype);
|
||||
}
|
||||
|
||||
static struct segtype_handler _error_ops = {
|
||||
name:_name,
|
||||
merge_segments:_merge_segments,
|
||||
.name = _errseg_name,
|
||||
.merge_segments = _errseg_merge_segments,
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
add_target_line:_add_target_line,
|
||||
target_present:_target_present,
|
||||
.add_target_line = _errseg_add_target_line,
|
||||
.target_present = _errseg_target_present,
|
||||
#endif
|
||||
destroy:_destroy,
|
||||
.modules_needed = _errseg_modules_needed,
|
||||
.destroy = _errseg_destroy,
|
||||
};
|
||||
|
||||
struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
|
||||
@@ -33,7 +33,7 @@ static int _and_p(struct dev_filter *f, struct device *dev)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
static void _composite_destroy(struct dev_filter *f)
|
||||
{
|
||||
struct dev_filter **filters = (struct dev_filter **) f->private;
|
||||
|
||||
@@ -70,7 +70,7 @@ struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
}
|
||||
|
||||
cft->passes_filter = _and_p;
|
||||
cft->destroy = _destroy;
|
||||
cft->destroy = _composite_destroy;
|
||||
cft->private = filters_copy;
|
||||
|
||||
return cft;
|
||||
|
||||
@@ -18,14 +18,6 @@
|
||||
|
||||
#ifdef linux
|
||||
|
||||
/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
|
||||
|
||||
#define MD_SB_MAGIC 0xa92b4efc
|
||||
#define MD_RESERVED_BYTES (64 * 1024)
|
||||
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
|
||||
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
|
||||
- MD_RESERVED_SECTORS)
|
||||
|
||||
static int _ignore_md(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "config.h"
|
||||
#include "dev-cache.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "lvm-file.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -26,11 +27,12 @@ struct pfilter {
|
||||
char *file;
|
||||
struct dm_hash_table *devices;
|
||||
struct dev_filter *real;
|
||||
time_t ctime;
|
||||
};
|
||||
|
||||
/*
|
||||
* entries in the table can be in one of these
|
||||
* states.
|
||||
* The hash table holds one of these two states
|
||||
* against each entry.
|
||||
*/
|
||||
#define PF_BAD_DEVICE ((void *) 1)
|
||||
#define PF_GOOD_DEVICE ((void *) 2)
|
||||
@@ -93,22 +95,26 @@ static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int persistent_filter_load(struct dev_filter *f)
|
||||
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
int r = 0;
|
||||
struct config_tree *cft;
|
||||
struct stat info;
|
||||
int r = 0;
|
||||
|
||||
if (!(cft = create_config_tree(pf->file))) {
|
||||
stack;
|
||||
return 0;
|
||||
if (!stat(pf->file, &info))
|
||||
pf->ctime = info.st_ctime;
|
||||
else {
|
||||
log_very_verbose("%s: stat failed: %s", pf->file,
|
||||
strerror(errno));
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!read_config_file(cft)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
if (!(cft = create_config_tree(pf->file, 1)))
|
||||
return_0;
|
||||
|
||||
if (!read_config_file(cft))
|
||||
goto_out;
|
||||
|
||||
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
|
||||
PF_GOOD_DEVICE);
|
||||
@@ -126,7 +132,10 @@ int persistent_filter_load(struct dev_filter *f)
|
||||
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
|
||||
|
||||
out:
|
||||
destroy_config_tree(cft);
|
||||
if (r && cft_out)
|
||||
*cft_out = cft;
|
||||
else
|
||||
destroy_config_tree(cft);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -163,8 +172,12 @@ static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
|
||||
int persistent_filter_dump(struct dev_filter *f)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
char *tmp_file;
|
||||
struct stat info, info2;
|
||||
struct config_tree *cft = NULL;
|
||||
FILE *fp;
|
||||
int lockfd;
|
||||
int r = 0;
|
||||
|
||||
if (!dm_hash_get_num_entries(pf->devices)) {
|
||||
log_very_verbose("Internal persistent device cache empty "
|
||||
@@ -179,11 +192,43 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
|
||||
log_very_verbose("Dumping persistent device cache to %s", pf->file);
|
||||
|
||||
fp = fopen(pf->file, "w");
|
||||
if (!fp) {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("fopen", pf->file);
|
||||
return 0;
|
||||
while (1) {
|
||||
if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0)
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* Ensure we locked the file we expected
|
||||
*/
|
||||
if (fstat(lockfd, &info)) {
|
||||
log_sys_error("fstat", pf->file);
|
||||
goto out;
|
||||
}
|
||||
if (stat(pf->file, &info2)) {
|
||||
log_sys_error("stat", pf->file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!memcmp(&info.st_ino, &info2.st_ino, sizeof(ino_t)))
|
||||
break;
|
||||
|
||||
fcntl_unlock_file(lockfd);
|
||||
}
|
||||
|
||||
/*
|
||||
* If file contents changed since we loaded it, merge new contents
|
||||
*/
|
||||
if (info.st_ctime != pf->ctime)
|
||||
/* Keep cft open to avoid losing lock */
|
||||
persistent_filter_load(f, &cft);
|
||||
|
||||
tmp_file = alloca(strlen(pf->file) + 5);
|
||||
sprintf(tmp_file, "%s.tmp", pf->file);
|
||||
|
||||
if (!(fp = fopen(tmp_file, "w"))) {
|
||||
/* EACCES has been reported over NFS */
|
||||
if (errno != EROFS && errno != EACCES)
|
||||
log_sys_error("fopen", tmp_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(fp, "# This file is automatically maintained by lvm.\n\n");
|
||||
@@ -194,8 +239,24 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
return 1;
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", tmp_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rename(tmp_file, pf->file))
|
||||
log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
|
||||
strerror(errno));
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
fcntl_unlock_file(lockfd);
|
||||
|
||||
if (cft)
|
||||
destroy_config_tree(cft);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
@@ -217,7 +278,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
return (l == PF_BAD_DEVICE) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
static void _persistent_destroy(struct dev_filter *f)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
@@ -258,7 +319,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
}
|
||||
|
||||
f->passes_filter = _lookup_p;
|
||||
f->destroy = _destroy;
|
||||
f->destroy = _persistent_destroy;
|
||||
f->private = pf;
|
||||
|
||||
return f;
|
||||
|
||||
@@ -22,7 +22,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *f,
|
||||
const char *file);
|
||||
|
||||
int persistent_filter_wipe(struct dev_filter *f);
|
||||
int persistent_filter_load(struct dev_filter *f);
|
||||
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
|
||||
int persistent_filter_dump(struct dev_filter *f);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -191,7 +191,7 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
return !rejected;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
static void _regex_destroy(struct dev_filter *f)
|
||||
{
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
dm_pool_destroy(rf->mem);
|
||||
@@ -226,7 +226,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
}
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _destroy;
|
||||
f->destroy = _regex_destroy;
|
||||
f->private = rf;
|
||||
return f;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(proc_mounts, sizeof(proc_mounts),
|
||||
if (dm_snprintf(proc_mounts, sizeof(proc_mounts),
|
||||
"%s/mounts", proc) < 0) {
|
||||
log_error("Failed to create /proc/mounts string");
|
||||
return 0;
|
||||
@@ -44,9 +44,9 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
if (split_words(buffer, 4, split) == 4 &&
|
||||
if (dm_split_words(buffer, 4, 0, split) == 4 &&
|
||||
!strcmp(split[2], "sysfs")) {
|
||||
if (lvm_snprintf(path, len, "%s/%s", split[1],
|
||||
if (dm_snprintf(path, len, "%s/%s", split[1],
|
||||
"block") >= 0) {
|
||||
r = 1;
|
||||
}
|
||||
@@ -54,7 +54,9 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", proc_mounts);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ static struct dev_set *_dev_set_create(struct dm_pool *mem, const char *sys_bloc
|
||||
return ds;
|
||||
}
|
||||
|
||||
static inline unsigned _hash_dev(dev_t dev)
|
||||
static unsigned _hash_dev(dev_t dev)
|
||||
{
|
||||
return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
|
||||
}
|
||||
@@ -156,7 +158,9 @@ static int _read_dev(const char *file, dev_t *result)
|
||||
}
|
||||
|
||||
r = _parse_dev(file, fp, result);
|
||||
fclose(fp);
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", file);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -183,7 +187,7 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||
continue;
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir,
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
|
||||
d->d_name) < 0) {
|
||||
log_error("sysfs path name too long: %s in %s",
|
||||
d->d_name, dir);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "config.h"
|
||||
#include "metadata.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
@@ -37,6 +38,7 @@ typedef struct {
|
||||
} device_info_t;
|
||||
|
||||
static int _md_major = -1;
|
||||
static int _device_mapper_major = -1;
|
||||
|
||||
int md_major(void)
|
||||
{
|
||||
@@ -90,6 +92,13 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip suspended devices */
|
||||
if (MAJOR(dev->dev) == _device_mapper_major &&
|
||||
ignore_suspended_devices() && !device_is_usable(dev->dev)) {
|
||||
log_debug("%s: Skipping: Suspended dm device", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
|
||||
log_debug("%s: Skipping: open failed", name);
|
||||
@@ -145,7 +154,7 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
/* All types unrecognised initially */
|
||||
memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
|
||||
|
||||
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
||||
if (dm_snprintf(proc_devices, sizeof(proc_devices),
|
||||
"%s/devices", proc) < 0) {
|
||||
log_error("Failed to create /proc/devices string");
|
||||
return 0;
|
||||
@@ -182,10 +191,14 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
|
||||
_md_major = line_maj;
|
||||
|
||||
/* Look for device-mapper device */
|
||||
/* FIXME Cope with multiple majors */
|
||||
if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
|
||||
_device_mapper_major = line_maj;
|
||||
|
||||
/* Go through the valid device names and if there is a
|
||||
match store max number of partitions */
|
||||
for (j = 0; device_info[j].name != NULL; j++) {
|
||||
|
||||
dev_len = strlen(device_info[j].name);
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
!strncmp(device_info[j].name, line + i, dev_len) &&
|
||||
@@ -204,6 +217,8 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Expecting string in devices/types "
|
||||
"in config file");
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
dev_len = strlen(cv->v.str);
|
||||
@@ -213,12 +228,16 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
log_error("Max partition count missing for %s "
|
||||
"in devices/types in config file",
|
||||
name);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (!cv->v.i) {
|
||||
log_error("Zero partition count invalid for "
|
||||
"%s in devices/types in config file",
|
||||
name);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
@@ -229,7 +248,10 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(pd);
|
||||
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -254,6 +276,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||
|
||||
if (!_scan_proc_dev(proc, cn)) {
|
||||
stack;
|
||||
dm_free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ static void _xlate_vgd(struct vg_disk *disk)
|
||||
|
||||
static void _xlate_extents(struct pe_disk *extents, uint32_t count)
|
||||
{
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
extents[i].lv_num = xlate16(extents[i].lv_num);
|
||||
@@ -116,7 +116,7 @@ static void _xlate_extents(struct pe_disk *extents, uint32_t count)
|
||||
static int _munge_formats(struct pv_disk *pvd)
|
||||
{
|
||||
uint32_t pe_start;
|
||||
int b, e;
|
||||
unsigned b, e;
|
||||
|
||||
switch (pvd->version) {
|
||||
case 1:
|
||||
@@ -153,8 +153,10 @@ static int _munge_formats(struct pv_disk *pvd)
|
||||
}
|
||||
|
||||
/* If UUID is missing, create one */
|
||||
if (pvd->pv_uuid[0] == '\0')
|
||||
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
|
||||
if (pvd->pv_uuid[0] == '\0') {
|
||||
uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number);
|
||||
pvd->pv_uuid[ID_LEN] = '\0';
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -172,9 +174,9 @@ static void _munge_exported_vg(struct pv_disk *pvd)
|
||||
return;
|
||||
/* FIXME also check vgd->status & VG_EXPORTED? */
|
||||
|
||||
l = strlen(pvd->vg_name);
|
||||
l = strlen((char *)pvd->vg_name);
|
||||
s = sizeof(EXPORTED_TAG);
|
||||
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
|
||||
if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
|
||||
pvd->vg_name[l - s + 1] = '\0';
|
||||
pvd->pv_status |= VG_EXPORTED;
|
||||
}
|
||||
@@ -223,11 +225,11 @@ static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_vgd(struct disk_list *data)
|
||||
int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
|
||||
{
|
||||
struct vg_disk *vgd = &data->vgd;
|
||||
uint64_t pos = data->pvd.vg_on_disk.base;
|
||||
if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
|
||||
uint64_t pos = pvd->vg_on_disk.base;
|
||||
|
||||
if (!dev_read(dev, pos, sizeof(*vgd), vgd))
|
||||
fail;
|
||||
|
||||
_xlate_vgd(vgd);
|
||||
@@ -237,16 +239,16 @@ static int _read_vgd(struct disk_list *data)
|
||||
|
||||
/* If UUID is missing, create one */
|
||||
if (vgd->vg_uuid[0] == '\0')
|
||||
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
|
||||
uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_uuids(struct disk_list *data)
|
||||
{
|
||||
int num_read = 0;
|
||||
unsigned num_read = 0;
|
||||
struct uuid_list *ul;
|
||||
char buffer[NAME_LEN];
|
||||
char buffer[NAME_LEN] __attribute((aligned(8)));
|
||||
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
@@ -269,7 +271,7 @@ static int _read_uuids(struct disk_list *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int _check_lvd(struct lv_disk *lvd)
|
||||
static int _check_lvd(struct lv_disk *lvd)
|
||||
{
|
||||
return !(lvd->lv_name[0] == '\0');
|
||||
}
|
||||
@@ -319,13 +321,31 @@ static int _read_extents(struct disk_list *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __update_lvmcache(const struct format_type *fmt,
|
||||
struct disk_list *dl,
|
||||
struct device *dev, const char *vgid,
|
||||
unsigned exported)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev,
|
||||
(char *)dl->pvd.vg_name, vgid,
|
||||
exported ? EXPORTED_VG : 0))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
|
||||
list_init(&info->mdas);
|
||||
info->status &= ~CACHE_INVALID;
|
||||
}
|
||||
|
||||
static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
struct device *dev, struct dm_pool *mem,
|
||||
const char *vg_name)
|
||||
{
|
||||
struct disk_list *dl = dm_pool_alloc(mem, sizeof(*dl));
|
||||
struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl));
|
||||
const char *name = dev_name(dev);
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!dl) {
|
||||
stack;
|
||||
@@ -342,41 +362,32 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
||||
dl->pvd.vg_name, NULL)))
|
||||
stack;
|
||||
else {
|
||||
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
|
||||
list_init(&info->mdas);
|
||||
info->status &= ~CACHE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
*/
|
||||
if (!*dl->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any format1 VG", name);
|
||||
|
||||
/* Update VG cache */
|
||||
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
|
||||
|
||||
__update_lvmcache(fmt, dl, dev, NULL, 0);
|
||||
return (vg_name) ? NULL : dl;
|
||||
}
|
||||
|
||||
if (!_read_vgd(dl)) {
|
||||
if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) {
|
||||
log_error("Failed to read VG data from PV (%s)", name);
|
||||
__update_lvmcache(fmt, dl, dev, NULL, 0);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Update VG cache with what we found */
|
||||
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
|
||||
|
||||
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
||||
if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) {
|
||||
log_very_verbose("%s is not a member of the VG %s",
|
||||
name, vg_name);
|
||||
__update_lvmcache(fmt, dl, dev, NULL, 0);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
__update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid,
|
||||
dl->vgd.vg_status & VG_EXPORTED);
|
||||
|
||||
if (!_read_uuids(dl)) {
|
||||
log_error("Failed to read PV uuid list from %s", name);
|
||||
goto bad;
|
||||
@@ -428,7 +439,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
|
||||
list_iterate_items(diskl, head) {
|
||||
pvd = &diskl->pvd;
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid,
|
||||
sizeof(pvd->pv_uuid))) {
|
||||
if (MAJOR(data->dev->dev) != md_major()) {
|
||||
log_very_verbose("Ignoring duplicate PV %s on "
|
||||
@@ -447,7 +458,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
|
||||
/*
|
||||
* Build a list of pv_d's structures, allocated from mem.
|
||||
* We keep track of the first object allocated form the pool
|
||||
* We keep track of the first object allocated from the pool
|
||||
* so we can free off all the memory if something goes wrong.
|
||||
*/
|
||||
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
@@ -461,7 +472,7 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
struct lvmcache_info *info;
|
||||
|
||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
|
||||
vginfo->infos.n) {
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
dev = info->dev;
|
||||
@@ -565,7 +576,7 @@ static int _write_lvs(struct disk_list *data)
|
||||
|
||||
pos = data->pvd.lv_on_disk.base;
|
||||
|
||||
if (!dev_zero(data->dev, pos, data->pvd.lv_on_disk.size)) {
|
||||
if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) {
|
||||
log_error("Couldn't zero lv area on device '%s'",
|
||||
dev_name(data->dev));
|
||||
return 0;
|
||||
|
||||
@@ -73,16 +73,16 @@ struct data_area {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pv_disk {
|
||||
uint8_t id[2];
|
||||
int8_t id[2];
|
||||
uint16_t version; /* lvm version */
|
||||
struct data_area pv_on_disk;
|
||||
struct data_area vg_on_disk;
|
||||
struct data_area pv_uuidlist_on_disk;
|
||||
struct data_area lv_on_disk;
|
||||
struct data_area pe_on_disk;
|
||||
uint8_t pv_uuid[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
||||
int8_t pv_uuid[NAME_LEN];
|
||||
int8_t vg_name[NAME_LEN];
|
||||
int8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
||||
uint32_t pv_major;
|
||||
uint32_t pv_number;
|
||||
uint32_t pv_status;
|
||||
@@ -98,8 +98,8 @@ struct pv_disk {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct lv_disk {
|
||||
uint8_t lv_name[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
int8_t lv_name[NAME_LEN];
|
||||
int8_t vg_name[NAME_LEN];
|
||||
uint32_t lv_access;
|
||||
uint32_t lv_status;
|
||||
uint32_t lv_open;
|
||||
@@ -122,8 +122,8 @@ struct lv_disk {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct vg_disk {
|
||||
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
|
||||
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
|
||||
int8_t vg_uuid[ID_LEN]; /* volume group UUID */
|
||||
int8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
|
||||
uint32_t vg_number; /* volume group number */
|
||||
uint32_t vg_access; /* read/write */
|
||||
uint32_t vg_status; /* active or not */
|
||||
@@ -148,7 +148,7 @@ struct pe_disk {
|
||||
|
||||
struct uuid_list {
|
||||
struct list list;
|
||||
char uuid[NAME_LEN];
|
||||
char uuid[NAME_LEN] __attribute((aligned(8)));
|
||||
};
|
||||
|
||||
struct lvd_list {
|
||||
@@ -161,17 +161,18 @@ struct disk_list {
|
||||
struct dm_pool *mem;
|
||||
struct device *dev;
|
||||
|
||||
struct pv_disk pvd;
|
||||
struct vg_disk vgd;
|
||||
struct list uuids;
|
||||
struct list lvds;
|
||||
struct pe_disk *extents;
|
||||
struct pv_disk pvd __attribute((aligned(8)));
|
||||
struct vg_disk vgd __attribute((aligned(8)));
|
||||
struct list uuids __attribute((aligned(8)));
|
||||
struct list lvds __attribute((aligned(8)));
|
||||
struct pe_disk *extents __attribute((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
* Layout constants.
|
||||
*/
|
||||
#define METADATA_ALIGN 4096UL
|
||||
#define LVM1_PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */
|
||||
|
||||
#define METADATA_BASE 0UL
|
||||
#define PV_SIZE 1024UL
|
||||
@@ -202,9 +203,10 @@ int write_disks(const struct format_type *fmt, struct list *pvds);
|
||||
* Functions to translate to between disk and in
|
||||
* core structures.
|
||||
*/
|
||||
int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd);
|
||||
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
struct device *dev, struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd,
|
||||
struct vg_disk *vgd);
|
||||
int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct pv_disk *pvd, struct physical_volume *pv);
|
||||
@@ -222,7 +224,7 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
|
||||
int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count);
|
||||
struct list *pvds, struct list *results, uint32_t *count);
|
||||
|
||||
int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct list *pvds);
|
||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
@@ -237,6 +239,7 @@ void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||
|
||||
void export_pv_act(struct list *pvds);
|
||||
int munge_pvd(struct device *dev, struct pv_disk *pvd);
|
||||
int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd);
|
||||
|
||||
/* blech */
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
|
||||
@@ -173,7 +173,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct format_instance *fid,
|
||||
static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
@@ -264,7 +264,7 @@ static int _flatten_vg(struct format_instance *fid, struct dm_pool *mem,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||
static int _format1_vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct dm_pool *mem = dm_pool_create("lvm1 vg_write", 1024 * 10);
|
||||
@@ -287,7 +287,7 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
struct physical_volume *pv, struct list *mdas)
|
||||
{
|
||||
struct dm_pool *mem = dm_pool_create("lvm1 pv_read", 1024);
|
||||
@@ -312,7 +312,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
|
||||
if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -326,7 +326,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _pv_setup(const struct format_type *fmt,
|
||||
static int _format1_pv_setup(const struct format_type *fmt,
|
||||
uint64_t pe_start, uint32_t extent_count,
|
||||
uint32_t extent_size,
|
||||
int pvmetadatacopies,
|
||||
@@ -337,8 +337,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
pv->size--;
|
||||
if (pv->size > MAX_PV_SIZE) {
|
||||
log_error("Physical volumes cannot be bigger than %s",
|
||||
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE,
|
||||
SIZE_SHORT));
|
||||
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -364,7 +363,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
static int _format1_lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
{
|
||||
uint64_t max_size = UINT_MAX;
|
||||
|
||||
@@ -378,15 +377,14 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
}
|
||||
if (lv->size > max_size) {
|
||||
log_error("logical volumes cannot be larger than %s",
|
||||
display_size(fid->fmt->cmd, max_size,
|
||||
SIZE_SHORT));
|
||||
display_size(fid->fmt->cmd, max_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
static int _format1_pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t sector)
|
||||
{
|
||||
struct dm_pool *mem;
|
||||
@@ -396,7 +394,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
|
||||
pv->vg_name, NULL))) {
|
||||
pv->vg_name, NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -410,7 +408,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
|
||||
/* Ensure any residual PE structure is gone */
|
||||
pv->pe_size = pv->pe_count = 0;
|
||||
pv->pe_start = PE_ALIGN;
|
||||
pv->pe_start = LVM1_PE_ALIGN;
|
||||
|
||||
if (!(mem = dm_pool_create("lvm1 pv_write", 1024))) {
|
||||
stack;
|
||||
@@ -433,7 +431,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
dev_write in order to make other disk tools happy */
|
||||
dl->pvd.pv_on_disk.base = METADATA_BASE;
|
||||
dl->pvd.pv_on_disk.size = PV_SIZE;
|
||||
dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
|
||||
dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
|
||||
|
||||
list_add(&pvs, &dl->list);
|
||||
if (!write_disks(fmt, &pvs)) {
|
||||
@@ -449,7 +447,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
static int _format1_vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
{
|
||||
/* just check max_pv and max_lv */
|
||||
if (!vg->max_lv || vg->max_lv >= MAX_LV)
|
||||
@@ -460,18 +458,15 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
|
||||
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
||||
log_error("Extent size must be between %s and %s",
|
||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE,
|
||||
SIZE_SHORT),
|
||||
display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE,
|
||||
SIZE_SHORT));
|
||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE),
|
||||
display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg->extent_size % MIN_PE_SIZE) {
|
||||
log_error("Extent size must be multiple of %s",
|
||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE,
|
||||
SIZE_SHORT));
|
||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -484,8 +479,8 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _segtype_supported (struct format_instance *fid,
|
||||
struct segment_type *segtype)
|
||||
static int _format1_segtype_supported(struct format_instance *fid,
|
||||
const struct segment_type *segtype)
|
||||
{
|
||||
if (!(segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||
stack;
|
||||
@@ -496,12 +491,13 @@ static int _segtype_supported (struct format_instance *fid,
|
||||
}
|
||||
|
||||
static struct metadata_area_ops _metadata_format1_ops = {
|
||||
vg_read:_vg_read,
|
||||
vg_write:_vg_write,
|
||||
.vg_read = _format1_vg_read,
|
||||
.vg_write = _format1_vg_write,
|
||||
};
|
||||
|
||||
static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||
static struct format_instance *_format1_create_instance(const struct format_type *fmt,
|
||||
const char *vgname,
|
||||
const char *vgid,
|
||||
void *private)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
@@ -529,26 +525,26 @@ static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||
return fid;
|
||||
}
|
||||
|
||||
static void _destroy_instance(struct format_instance *fid)
|
||||
static void _format1_destroy_instance(struct format_instance *fid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void _destroy(const struct format_type *fmt)
|
||||
static void _format1_destroy(const struct format_type *fmt)
|
||||
{
|
||||
dm_free((void *) fmt);
|
||||
}
|
||||
|
||||
static struct format_handler _format1_ops = {
|
||||
pv_read:_pv_read,
|
||||
pv_setup:_pv_setup,
|
||||
pv_write:_pv_write,
|
||||
lv_setup:_lv_setup,
|
||||
vg_setup:_vg_setup,
|
||||
segtype_supported:_segtype_supported,
|
||||
create_instance:_create_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy:_destroy,
|
||||
.pv_read = _format1_pv_read,
|
||||
.pv_setup = _format1_pv_setup,
|
||||
.pv_write = _format1_pv_write,
|
||||
.lv_setup = _format1_lv_setup,
|
||||
.vg_setup = _format1_vg_setup,
|
||||
.segtype_supported = _format1_segtype_supported,
|
||||
.create_instance = _format1_create_instance,
|
||||
.destroy_instance = _format1_destroy_instance,
|
||||
.destroy = _format1_destroy,
|
||||
};
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "segtype.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -47,25 +48,30 @@ static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
|
||||
return dm_pool_strdup(mem, ptr);
|
||||
}
|
||||
|
||||
int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd)
|
||||
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
struct device *dev, struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd,
|
||||
struct vg_disk *vgd)
|
||||
{
|
||||
uint64_t size;
|
||||
|
||||
memset(pv, 0, sizeof(*pv));
|
||||
memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
|
||||
|
||||
pv->dev = dev;
|
||||
if (!(pv->vg_name = dm_pool_strdup(mem, pvd->vg_name))) {
|
||||
if (!(pv->vg_name = dm_pool_strdup(mem, (char *)pvd->vg_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
|
||||
|
||||
/* Store system_id from first PV if PV belongs to a VG */
|
||||
if (vg && !*vg->system_id)
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
|
||||
if (vg &&
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
|
||||
strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
dev_name(pv->dev), vg->system_id);
|
||||
@@ -86,6 +92,25 @@ int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
/* Fix up pv size if missing */
|
||||
if (!pv->size) {
|
||||
if (!dev_get_size(dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Fixing up missing format1 size (%s) "
|
||||
"for PV %s", display_size(fmt->cmd, pv->size),
|
||||
dev_name(pv->dev));
|
||||
if (vg) {
|
||||
size = pv->pe_count * (uint64_t) vg->extent_size +
|
||||
pv->pe_start;
|
||||
if (size > pv->size)
|
||||
log_error("WARNING: Physical Volume %s is too "
|
||||
"large for underlying device",
|
||||
dev_name(pv->dev));
|
||||
}
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
@@ -100,7 +125,7 @@ int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
|
||||
{
|
||||
|
||||
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
prefix, cmd->hostname, time(NULL)) < 0) {
|
||||
log_error("Generated system_id too long");
|
||||
return 0;
|
||||
@@ -121,19 +146,17 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
|
||||
memcpy(pvd->pv_uuid, pv->id.uuid, ID_LEN);
|
||||
|
||||
if (!_check_vg_name(pv->vg_name)) {
|
||||
stack;
|
||||
return 0;
|
||||
if (pv->vg_name) {
|
||||
if (!_check_vg_name(pv->vg_name)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
strncpy((char *)pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
|
||||
}
|
||||
|
||||
memset(pvd->vg_name, 0, sizeof(pvd->vg_name));
|
||||
|
||||
if (pv->vg_name)
|
||||
strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
|
||||
|
||||
/* Preserve existing system_id if it exists */
|
||||
if (vg && *vg->system_id)
|
||||
strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id));
|
||||
strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id));
|
||||
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && (vg->status & EXPORTED_VG)) {
|
||||
@@ -141,24 +164,24 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
if (!*vg->system_id ||
|
||||
strncmp(vg->system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(cmd, pvd->system_id, EXPORTED_TAG)) {
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (strlen(pvd->vg_name) + sizeof(EXPORTED_TAG) >
|
||||
if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) >
|
||||
sizeof(pvd->vg_name)) {
|
||||
log_error("Volume group name %s too long to export",
|
||||
pvd->vg_name);
|
||||
return 0;
|
||||
}
|
||||
strcat(pvd->vg_name, EXPORTED_TAG);
|
||||
strcat((char *)pvd->vg_name, EXPORTED_TAG);
|
||||
}
|
||||
|
||||
/* Is VG being imported? */
|
||||
if (vg && !(vg->status & EXPORTED_VG) && *vg->system_id &&
|
||||
!strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(cmd, pvd->system_id, IMPORTED_TAG)) {
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -166,7 +189,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
|
||||
/* Generate system_id if PV is in VG */
|
||||
if (!pvd->system_id || !*pvd->system_id)
|
||||
if (!_system_id(cmd, pvd->system_id, "")) {
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, "")) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -174,8 +197,8 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
/* Update internal system_id if we changed it */
|
||||
if (vg &&
|
||||
(!*vg->system_id ||
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
|
||||
//pvd->pv_major = MAJOR(pv->dev);
|
||||
|
||||
@@ -201,12 +224,12 @@ int import_vg(struct dm_pool *mem,
|
||||
struct vg_disk *vgd = &dl->vgd;
|
||||
memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
|
||||
|
||||
if (!_check_vg_name(dl->pvd.vg_name)) {
|
||||
if (!_check_vg_name((char *)dl->pvd.vg_name)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vg->name = dm_pool_strdup(mem, dl->pvd.vg_name))) {
|
||||
if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -289,7 +312,7 @@ int import_lv(struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lv
|
||||
{
|
||||
lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number);
|
||||
|
||||
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
|
||||
if (!(lv->name = _create_lv_name(mem, (char *)lvd->lv_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -339,10 +362,10 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *dev_dir)
|
||||
{
|
||||
memset(lvd, 0, sizeof(*lvd));
|
||||
snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
|
||||
snprintf((char *)lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
|
||||
dev_dir, vg->name, lv->name);
|
||||
|
||||
strcpy(lvd->vg_name, vg->name);
|
||||
strcpy((char *)lvd->vg_name, vg->name);
|
||||
|
||||
if (lv->status & LVM_READ)
|
||||
lvd->lv_access |= LV_READ;
|
||||
@@ -413,7 +436,7 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
|
||||
int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count)
|
||||
struct list *pvds, struct list *results, uint32_t *count)
|
||||
{
|
||||
struct disk_list *dl;
|
||||
struct pv_list *pvl;
|
||||
@@ -426,7 +449,7 @@ int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd)) {
|
||||
if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -475,7 +498,7 @@ int import_lvs(struct dm_pool *mem, struct volume_group *vg, struct list *pvds)
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
if (!find_lv(vg, lvd->lv_name) &&
|
||||
if (!find_lv(vg, (char *)lvd->lv_name) &&
|
||||
!_add_lv(mem, vg, lvd)) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -583,14 +606,14 @@ int import_snapshots(struct dm_pool *mem, struct volume_group *vg,
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
|
||||
if (lvnum > MAX_LV) {
|
||||
if (lvnum >= MAX_LV) {
|
||||
log_err("Logical volume number "
|
||||
"out of bounds.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lvs[lvnum] &&
|
||||
!(lvs[lvnum] = find_lv(vg, lvd->lv_name))) {
|
||||
!(lvs[lvnum] = find_lv(vg, (char *)lvd->lv_name))) {
|
||||
log_err("Couldn't find logical volume '%s'.",
|
||||
lvd->lv_name);
|
||||
return 0;
|
||||
|
||||
@@ -93,7 +93,7 @@ static int _fill_lv_array(struct lv_map **lvs,
|
||||
memset(lvs, 0, sizeof(*lvs) * MAX_LV);
|
||||
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
if (!(lvm = dm_hash_lookup(maps, strrchr(ll->lvd.lv_name, '/')
|
||||
if (!(lvm = dm_hash_lookup(maps, strrchr((char *)ll->lvd.lv_name, '/')
|
||||
+ 1))) {
|
||||
log_err("Physical volume (%s) contains an "
|
||||
"unknown logical volume (%s).",
|
||||
@@ -203,6 +203,19 @@ static int _check_maps_are_complete(struct dm_hash_table *maps)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t _area_length(struct lv_map *lvm, uint32_t le)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
|
||||
do
|
||||
len++;
|
||||
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
|
||||
(lvm->map[le].pv &&
|
||||
lvm->map[le + len].pe == lvm->map[le].pe + len));
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t le = 0, len;
|
||||
@@ -215,13 +228,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
len = 0;
|
||||
|
||||
do
|
||||
len++;
|
||||
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
|
||||
(lvm->map[le].pv &&
|
||||
lvm->map[le + len].pe == lvm->map[le].pe + len));
|
||||
len = _area_length(lvm, le);
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
|
||||
len, 0, 0, NULL, 1, len, 0, 0, 0))) {
|
||||
@@ -230,10 +237,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
|
||||
if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
|
||||
lvm->map[le].pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
lvm->map[le].pe))
|
||||
return_0;
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
@@ -244,7 +249,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
|
||||
static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
uint32_t seg_len, uint32_t base_le, uint32_t len)
|
||||
uint32_t area_len, uint32_t base_le,
|
||||
uint32_t total_area_len)
|
||||
{
|
||||
uint32_t st;
|
||||
|
||||
@@ -252,11 +258,11 @@ static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
* Is the next physical extent in every stripe adjacent to the last?
|
||||
*/
|
||||
for (st = 0; st < area_count; st++)
|
||||
if ((lvm->map[base_le + st * len + seg_len].pv !=
|
||||
lvm->map[base_le + st * len].pv) ||
|
||||
(lvm->map[base_le + st * len].pv &&
|
||||
lvm->map[base_le + st * len + seg_len].pe !=
|
||||
lvm->map[base_le + st * len].pe + seg_len))
|
||||
if ((lvm->map[base_le + st * total_area_len + area_len].pv !=
|
||||
lvm->map[base_le + st * total_area_len].pv) ||
|
||||
(lvm->map[base_le + st * total_area_len].pv &&
|
||||
lvm->map[base_le + st * total_area_len + area_len].pe !=
|
||||
lvm->map[base_le + st * total_area_len].pe + area_len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -264,7 +270,7 @@ static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
|
||||
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t st, le = 0, len;
|
||||
uint32_t st, first_area_le = 0, total_area_len;
|
||||
uint32_t area_len;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
@@ -277,26 +283,25 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
"with logical extent count (%u) for %s",
|
||||
lvm->stripes, lvm->lv->le_count, lvm->lv->name);
|
||||
}
|
||||
len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
total_area_len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
while (le < len) {
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
return_0;
|
||||
|
||||
while (first_area_le < total_area_len) {
|
||||
area_len = 1;
|
||||
|
||||
/*
|
||||
* Find how many blocks are contiguous in all stripes
|
||||
* Find how many extents are contiguous in all stripes
|
||||
* and so can form part of this segment
|
||||
*/
|
||||
while (_check_stripe(lvm, lvm->stripes,
|
||||
area_len * lvm->stripes, le, len))
|
||||
area_len, first_area_le, total_area_len))
|
||||
area_len++;
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
|
||||
lvm->stripes * le,
|
||||
lvm->stripes * first_area_le,
|
||||
lvm->stripes * area_len,
|
||||
0, lvm->stripe_size, NULL,
|
||||
lvm->stripes,
|
||||
@@ -310,15 +315,13 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++)
|
||||
if (!set_lv_segment_area_pv(seg, st,
|
||||
lvm->map[le + st * len].pv,
|
||||
lvm->map[le + st * len].pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
lvm->map[first_area_le + st * total_area_len].pv,
|
||||
lvm->map[first_area_le + st * total_area_len].pe))
|
||||
return_0;
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
le += seg->len;
|
||||
first_area_le += area_len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -19,16 +19,18 @@
|
||||
/*
|
||||
* Only works with powers of 2.
|
||||
*/
|
||||
static inline uint32_t _round_up(uint32_t n, uint32_t size)
|
||||
static uint32_t _round_up(uint32_t n, uint32_t size)
|
||||
{
|
||||
size--;
|
||||
return (n + size) & ~size;
|
||||
}
|
||||
|
||||
static inline uint32_t _div_up(uint32_t n, uint32_t size)
|
||||
/* Unused.
|
||||
static uint32_t _div_up(uint32_t n, uint32_t size)
|
||||
{
|
||||
return _round_up(n, size) / size;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each chunk of metadata should be aligned to
|
||||
@@ -151,7 +153,7 @@ int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
|
||||
if (pe_start && end < pe_start)
|
||||
end = pe_start;
|
||||
|
||||
pvd->pe_start = _round_up(end, PE_ALIGN);
|
||||
pvd->pe_start = _round_up(end, LVM1_PE_ALIGN);
|
||||
|
||||
} while ((pvd->pe_start + (pvd->pe_total * extent_size))
|
||||
> pv->size);
|
||||
|
||||
@@ -30,7 +30,7 @@ static void _not_supported(const char *op)
|
||||
op);
|
||||
}
|
||||
|
||||
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
static int _lvm1_can_handle(struct labeller *l, void *buf, uint64_t sector)
|
||||
{
|
||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||
uint32_t version;
|
||||
@@ -48,21 +48,30 @@ static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _write(struct label *label, char *buf)
|
||||
static int _lvm1_write(struct label *label, void *buf)
|
||||
{
|
||||
_not_supported("write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
static int _lvm1_read(struct labeller *l, struct device *dev, void *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||
struct vg_disk vgd;
|
||||
struct lvmcache_info *info;
|
||||
const char *vgid = NULL;
|
||||
unsigned exported = 0;
|
||||
|
||||
munge_pvd(dev, pvd);
|
||||
|
||||
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
|
||||
if (*pvd->vg_name && read_vgd(dev, &vgd, pvd)) {
|
||||
vgid = (char *) vgd.vg_uuid;
|
||||
exported = pvd->pv_status & VG_EXPORTED;
|
||||
}
|
||||
|
||||
if (!(info = lvmcache_add(l, (char *)pvd->pv_uuid, dev, (char *)pvd->vg_name, vgid,
|
||||
exported))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -76,31 +85,31 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _initialise_label(struct labeller *l, struct label *label)
|
||||
static int _lvm1_initialise_label(struct labeller *l, struct label *label)
|
||||
{
|
||||
strcpy(label->type, "LVM1");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_label(struct labeller *l, struct label *label)
|
||||
static void _lvm1_destroy_label(struct labeller *l, struct label *label)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void _destroy(struct labeller *l)
|
||||
static void _lvm1_destroy(struct labeller *l)
|
||||
{
|
||||
dm_free(l);
|
||||
}
|
||||
|
||||
struct label_ops _lvm1_ops = {
|
||||
can_handle:_can_handle,
|
||||
write:_write,
|
||||
read:_read,
|
||||
verify:_can_handle,
|
||||
initialise_label:_initialise_label,
|
||||
destroy_label:_destroy_label,
|
||||
destroy:_destroy
|
||||
.can_handle = _lvm1_can_handle,
|
||||
.write = _lvm1_write,
|
||||
.read = _lvm1_read,
|
||||
.verify = _lvm1_can_handle,
|
||||
.initialise_label = _lvm1_initialise_label,
|
||||
.destroy_label = _lvm1_destroy_label,
|
||||
.destroy = _lvm1_destroy,
|
||||
};
|
||||
|
||||
struct labeller *lvm1_labeller_create(struct format_type *fmt)
|
||||
|
||||
@@ -46,7 +46,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
memset(numbers, 0, sizeof(numbers));
|
||||
|
||||
list_iterate_items(dl, &all_pvs) {
|
||||
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
|
||||
if (!*dl->pvd.vg_name || !strcmp((char *)dl->pvd.vg_name, candidate_vg))
|
||||
continue;
|
||||
|
||||
numbers[dl->vgd.vg_number] = 1;
|
||||
|
||||
@@ -36,7 +36,7 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
|
||||
struct dm_pool *mem, struct pool_list *pl,
|
||||
const char *vg_name)
|
||||
{
|
||||
char buf[512];
|
||||
char buf[512] __attribute((aligned(8)));
|
||||
|
||||
/* FIXME: Need to check the cache here first */
|
||||
if (!dev_read(dev, UINT64_C(0), 512, buf)) {
|
||||
@@ -59,7 +59,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||
|
||||
list_iterate_items(pl, head) {
|
||||
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
|
||||
char uuid[ID_LEN + 7];
|
||||
char uuid[ID_LEN + 7] __attribute((aligned(8)));
|
||||
|
||||
id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
|
||||
|
||||
@@ -84,7 +84,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
struct lvmcache_info *info;
|
||||
struct id pvid;
|
||||
struct id vgid;
|
||||
char uuid[ID_LEN + 7];
|
||||
char uuid[ID_LEN + 7] __attribute((aligned(8)));
|
||||
struct pool_disk *pd = &pl->pd;
|
||||
|
||||
pool_label_in(pd, buf);
|
||||
@@ -98,7 +98,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
|
||||
|
||||
if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
|
||||
(char *) &vgid))) {
|
||||
(char *) &vgid, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -128,7 +128,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
* be able to interpret ondisk labels correctly. Always use
|
||||
* this function before writing to disk.
|
||||
*/
|
||||
void pool_label_out(struct pool_disk *pl, char *buf)
|
||||
void pool_label_out(struct pool_disk *pl, void *buf)
|
||||
{
|
||||
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||
|
||||
@@ -163,7 +163,7 @@ void pool_label_out(struct pool_disk *pl, char *buf)
|
||||
* correctly. Always use this function before using labels that
|
||||
* were read from disk.
|
||||
*/
|
||||
void pool_label_in(struct pool_disk *pl, char *buf)
|
||||
void pool_label_in(struct pool_disk *pl, void *buf)
|
||||
{
|
||||
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||
|
||||
@@ -248,7 +248,7 @@ static int _read_vg_pds(const struct format_type *fmt, struct dm_pool *mem,
|
||||
|
||||
uint32_t sp_count = 0;
|
||||
uint32_t *sp_devs = NULL;
|
||||
int i;
|
||||
uint32_t i;
|
||||
|
||||
/* FIXME: maybe should return a different error in memory
|
||||
* allocation failure */
|
||||
@@ -314,7 +314,7 @@ int read_pool_pds(const struct format_type *fmt, const char *vg_name,
|
||||
/*
|
||||
* If the cache scanning doesn't work, this will never work
|
||||
*/
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
|
||||
vginfo->infos.n) {
|
||||
|
||||
if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
|
||||
|
||||
@@ -134,8 +134,8 @@ struct user_device {
|
||||
|
||||
int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
struct device *dev, char *buf, struct label **label);
|
||||
void pool_label_out(struct pool_disk *pl, char *buf);
|
||||
void pool_label_in(struct pool_disk *pl, char *buf);
|
||||
void pool_label_out(struct pool_disk *pl, void *buf);
|
||||
void pool_label_in(struct pool_disk *pl, void *buf);
|
||||
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid);
|
||||
int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct list *pls);
|
||||
int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem,
|
||||
|
||||
@@ -79,7 +79,8 @@ static struct user_subpool *_build_usp(struct list *pls, struct dm_pool *mem,
|
||||
|
||||
static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count)
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
unsigned j;
|
||||
|
||||
for (i = 0; i < sp_count; i++) {
|
||||
if (!usp[i].initialized) {
|
||||
@@ -88,7 +89,7 @@ static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count)
|
||||
}
|
||||
for (j = 0; j < usp[i].num_devs; j++) {
|
||||
if (!usp[i].devs[j].initialized) {
|
||||
log_error("Missing device %d for subpool %d"
|
||||
log_error("Missing device %u for subpool %d"
|
||||
" in pool %s", j, i, vgname);
|
||||
return 0;
|
||||
}
|
||||
@@ -169,7 +170,7 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
|
||||
return vg;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct format_instance *fid,
|
||||
static struct volume_group *_pool_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
@@ -206,7 +207,7 @@ static struct volume_group *_vg_read(struct format_instance *fid,
|
||||
return vg;
|
||||
}
|
||||
|
||||
static int _pv_setup(const struct format_type *fmt,
|
||||
static int _pool_pv_setup(const struct format_type *fmt,
|
||||
uint64_t pe_start, uint32_t extent_count,
|
||||
uint32_t extent_size,
|
||||
int pvmetadatacopies,
|
||||
@@ -216,7 +217,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
static int _pool_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
struct physical_volume *pv, struct list *mdas)
|
||||
{
|
||||
struct dm_pool *mem = dm_pool_create("pool pv_read", 1024);
|
||||
@@ -262,12 +263,13 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static struct metadata_area_ops _metadata_format_pool_ops = {
|
||||
vg_read:_vg_read,
|
||||
.vg_read = _pool_vg_read,
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||
static struct format_instance *_pool_create_instance(const struct format_type *fmt,
|
||||
const char *vgname,
|
||||
const char *vgid,
|
||||
void *private)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
@@ -297,23 +299,23 @@ static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||
return fid;
|
||||
}
|
||||
|
||||
static void _destroy_instance(struct format_instance *fid)
|
||||
static void _pool_destroy_instance(struct format_instance *fid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void _destroy(const struct format_type *fmt)
|
||||
static void _pool_destroy(const struct format_type *fmt)
|
||||
{
|
||||
dm_free((void *) fmt);
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static struct format_handler _format_pool_ops = {
|
||||
pv_read:_pv_read,
|
||||
pv_setup:_pv_setup,
|
||||
create_instance:_create_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy:_destroy,
|
||||
.pv_read = _pool_pv_read,
|
||||
.pv_setup = _pool_pv_setup,
|
||||
.create_instance = _pool_create_instance,
|
||||
.destroy_instance = _pool_destroy_instance,
|
||||
.destroy = _pool_destroy,
|
||||
};
|
||||
/* *INDENT-ON */
|
||||
|
||||
|
||||
@@ -165,6 +165,7 @@ int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
log_error("Unable to duplicate vg_name string");
|
||||
return 0;
|
||||
}
|
||||
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
|
||||
pv->status = 0;
|
||||
pv->size = pd->pl_blocks;
|
||||
pv->pe_size = POOL_PE_SIZE;
|
||||
@@ -202,7 +203,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
int j;
|
||||
unsigned j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (usp->striping & (usp->striping - 1)) {
|
||||
@@ -248,7 +249,7 @@ static int _add_linear_seg(struct dm_pool *mem,
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
int j;
|
||||
unsigned j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static void _not_supported(const char *op)
|
||||
static void _pool_not_supported(const char *op)
|
||||
{
|
||||
log_error("The '%s' operation is not supported for the pool labeller.",
|
||||
op);
|
||||
}
|
||||
|
||||
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
static int _pool_can_handle(struct labeller *l, void *buf, uint64_t sector)
|
||||
{
|
||||
|
||||
struct pool_disk pd;
|
||||
@@ -50,13 +50,13 @@ static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _write(struct label *label, char *buf)
|
||||
static int _pool_write(struct label *label, void *buf)
|
||||
{
|
||||
_not_supported("write");
|
||||
_pool_not_supported("write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
static int _pool_read(struct labeller *l, struct device *dev, void *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct pool_list pl;
|
||||
@@ -64,31 +64,31 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
return read_pool_label(&pl, l, dev, buf, label);
|
||||
}
|
||||
|
||||
static int _initialise_label(struct labeller *l, struct label *label)
|
||||
static int _pool_initialise_label(struct labeller *l, struct label *label)
|
||||
{
|
||||
strcpy(label->type, "POOL");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_label(struct labeller *l, struct label *label)
|
||||
static void _pool_destroy_label(struct labeller *l, struct label *label)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void _destroy(struct labeller *l)
|
||||
static void _label_pool_destroy(struct labeller *l)
|
||||
{
|
||||
dm_free(l);
|
||||
}
|
||||
|
||||
struct label_ops _pool_ops = {
|
||||
can_handle:_can_handle,
|
||||
write:_write,
|
||||
read:_read,
|
||||
verify:_can_handle,
|
||||
initialise_label:_initialise_label,
|
||||
destroy_label:_destroy_label,
|
||||
destroy:_destroy
|
||||
.can_handle = _pool_can_handle,
|
||||
.write = _pool_write,
|
||||
.read = _pool_read,
|
||||
.verify = _pool_can_handle,
|
||||
.initialise_label = _pool_initialise_label,
|
||||
.destroy_label = _pool_destroy_label,
|
||||
.destroy = _label_pool_destroy,
|
||||
};
|
||||
|
||||
struct labeller *pool_labeller_create(struct format_type *fmt)
|
||||
|
||||
@@ -87,7 +87,7 @@ static int _split_vg(const char *filename, char *vgname, size_t vg_size,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _insert_file(struct list *head, struct archive_file *b)
|
||||
static void _insert_archive_file(struct list *head, struct archive_file *b)
|
||||
{
|
||||
struct archive_file *bf = NULL;
|
||||
|
||||
@@ -107,7 +107,7 @@ static void _insert_file(struct list *head, struct archive_file *b)
|
||||
list_add_h(&bf->list, &b->list);
|
||||
}
|
||||
|
||||
static char *_join(struct dm_pool *mem, const char *dir, const char *name)
|
||||
static char *_join_file_to_dir(struct dm_pool *mem, const char *dir, const char *name)
|
||||
{
|
||||
if (!dm_pool_begin_object(mem, 32) ||
|
||||
!dm_pool_grow_object(mem, dir, strlen(dir)) ||
|
||||
@@ -161,7 +161,7 @@ static struct list *_scan_archive(struct dm_pool *mem,
|
||||
if (strcmp(vgname, vgname_found))
|
||||
continue;
|
||||
|
||||
if (!(path = _join(mem, dir, dirent[i]->d_name))) {
|
||||
if (!(path = _join_file_to_dir(mem, dir, dirent[i]->d_name))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -181,7 +181,7 @@ static struct list *_scan_archive(struct dm_pool *mem,
|
||||
/*
|
||||
* Insert it to the correct part of the list.
|
||||
*/
|
||||
_insert_file(results, af);
|
||||
_insert_archive_file(results, af);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -207,8 +207,8 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
/* Convert retain_days into the time after which we must retain */
|
||||
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
|
||||
|
||||
/* Assume list is ordered oldest first (by index) */
|
||||
list_iterate_items(bf, archives) {
|
||||
/* Assume list is ordered newest first (by index) */
|
||||
list_iterate_back_items(bf, archives) {
|
||||
/* Get the mtime of the file and unlink if too old */
|
||||
if (stat(bf->path, &sb)) {
|
||||
log_sys_error("stat", bf->path);
|
||||
@@ -249,17 +249,23 @@ int archive_vg(struct volume_group *vg,
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_err("Couldn't create FILE object for archive.");
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text_vg_export_file(vg, desc, fp)) {
|
||||
stack;
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", temp_file);
|
||||
/* Leave file behind as evidence of failure */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we want to rename this file to <vg>_index.vg.
|
||||
@@ -277,7 +283,7 @@ int archive_vg(struct volume_group *vg,
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
||||
if (dm_snprintf(archive_name, sizeof(archive_name),
|
||||
"%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
|
||||
log_error("Archive file name too long.");
|
||||
return 0;
|
||||
@@ -311,7 +317,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||
|
||||
if (!(context = create_text_context(cmd, af->path, NULL)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
NULL, context))) {
|
||||
log_error("Couldn't create text instance object.");
|
||||
return;
|
||||
}
|
||||
@@ -328,7 +334,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||
}
|
||||
|
||||
log_print("VG name: \t%s", vg->name);
|
||||
log_print("Description:\t%s", desc ? desc : "<No description>");
|
||||
log_print("Description:\t%s", desc ? : "<No description>");
|
||||
log_print("Backup Time:\t%s", ctime(&when));
|
||||
|
||||
dm_pool_free(cmd->mem, vg);
|
||||
@@ -360,7 +366,7 @@ int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||
{
|
||||
struct archive_file af;
|
||||
|
||||
if (!(af.path = _join(cmd->mem, dir, vgname))) {
|
||||
if (!(af.path = _join_file_to_dir(cmd->mem, dir, vgname))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ static int __backup(struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(name, sizeof(name), "%s/%s",
|
||||
if (dm_snprintf(name, sizeof(name), "%s/%s",
|
||||
vg->cmd->backup_params->dir, vg->name) < 0) {
|
||||
log_error("Failed to generate volume group metadata backup "
|
||||
"filename.");
|
||||
@@ -233,7 +233,7 @@ int backup_remove(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s",
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s",
|
||||
cmd->backup_params->dir, vg_name) < 0) {
|
||||
log_err("Failed to generate backup filename (for removal).");
|
||||
return 0;
|
||||
@@ -257,7 +257,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
if (!(context = create_text_context(cmd, file,
|
||||
cmd->cmd_line)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
NULL, context))) {
|
||||
log_error("Couldn't create text format object.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -286,7 +286,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
/* Attempt to write out using currently active format */
|
||||
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
|
||||
NULL))) {
|
||||
NULL, NULL))) {
|
||||
log_error("Failed to allocate format instance");
|
||||
return 0;
|
||||
}
|
||||
@@ -342,7 +342,7 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s",
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s",
|
||||
cmd->backup_params->dir, vg_name) < 0) {
|
||||
log_err("Failed to generate backup filename (for restore).");
|
||||
return 0;
|
||||
@@ -365,7 +365,7 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
|
||||
|
||||
if (!(context = create_text_context(cmd, file, desc)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
NULL, context))) {
|
||||
log_error("Couldn't create backup object.");
|
||||
return 0;
|
||||
}
|
||||
@@ -397,7 +397,7 @@ void check_current_backup(struct volume_group *vg)
|
||||
if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
|
||||
return;
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s",
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s",
|
||||
vg->cmd->backup_params->dir, vg->name) < 0) {
|
||||
log_debug("Failed to generate backup filename.");
|
||||
return;
|
||||
|
||||
@@ -183,7 +183,8 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _out_with_comment_raw(struct formatter *f, const char *comment,
|
||||
static int _out_with_comment_raw(struct formatter *f,
|
||||
const char *comment __attribute((unused)),
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
int n;
|
||||
@@ -220,6 +221,8 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
"Megabytes",
|
||||
"Gigabytes",
|
||||
"Terabytes",
|
||||
"Petabytes",
|
||||
"Exabytes",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -232,7 +235,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
for (i = 0; (d > 1024.0) && _units[i]; i++)
|
||||
d /= 1024.0;
|
||||
|
||||
return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
|
||||
return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -281,7 +284,7 @@ int out_text(struct formatter *f, const char *fmt, ...)
|
||||
}
|
||||
|
||||
static int _print_header(struct formatter *f,
|
||||
struct volume_group *vg, const char *desc)
|
||||
const char *desc)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
@@ -354,8 +357,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
* Get the pv%d name from the formatters hash
|
||||
* table.
|
||||
*/
|
||||
static inline const char *_get_pv_name(struct formatter *f,
|
||||
struct physical_volume *pv)
|
||||
static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv)
|
||||
{
|
||||
return (pv) ? (const char *)
|
||||
dm_hash_lookup(f->pv_names, dev_name(pv->dev)) : "Missing";
|
||||
@@ -409,6 +411,11 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
||||
if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||
"pe_count = %u", pv->pe_count)) {
|
||||
@@ -613,46 +620,27 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
struct physical_volume *pv;
|
||||
char buffer[32], *name;
|
||||
|
||||
if (!(f->mem = dm_pool_create("text pv_names", 512))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f->mem = dm_pool_create("text pv_names", 512)))
|
||||
return_0;
|
||||
|
||||
if (!(f->pv_names = dm_hash_create(128))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f->pv_names = dm_hash_create(128)))
|
||||
return_0;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
/* FIXME But skip if there's already an LV called pv%d ! */
|
||||
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
|
||||
return_0;
|
||||
|
||||
if (!(name = dm_pool_strdup(f->mem, buffer))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(name = dm_pool_strdup(f->mem, buffer)))
|
||||
return_0;
|
||||
|
||||
if (!dm_hash_insert(f->pv_names, dev_name(pv->dev), name)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_hash_insert(f->pv_names, dev_name(pv->dev), name))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
if (f->mem)
|
||||
dm_pool_destroy(f->mem);
|
||||
|
||||
if (f->pv_names)
|
||||
dm_hash_destroy(f->pv_names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _text_vg_export(struct formatter *f,
|
||||
@@ -664,35 +652,33 @@ static int _text_vg_export(struct formatter *f,
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
#define fail do {stack; goto out;} while(0)
|
||||
|
||||
if (f->header && !_print_header(f, vg, desc))
|
||||
fail;
|
||||
if (f->header && !_print_header(f, desc))
|
||||
goto_out;
|
||||
|
||||
if (!out_text(f, "%s {", vg->name))
|
||||
fail;
|
||||
goto_out;
|
||||
|
||||
_inc_indent(f);
|
||||
|
||||
if (!_print_vg(f, vg))
|
||||
fail;
|
||||
goto_out;
|
||||
|
||||
outnl(f);
|
||||
if (!_print_pvs(f, vg))
|
||||
fail;
|
||||
goto_out;
|
||||
|
||||
outnl(f);
|
||||
if (!_print_lvs(f, vg))
|
||||
fail;
|
||||
goto_out;
|
||||
|
||||
_dec_indent(f);
|
||||
if (!out_text(f, "}"))
|
||||
fail;
|
||||
goto_out;
|
||||
|
||||
if (!f->header && !_print_header(f, vg, desc))
|
||||
fail;
|
||||
if (!f->header && !_print_header(f, desc))
|
||||
goto_out;
|
||||
|
||||
#undef fail
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
|
||||
@@ -53,6 +53,7 @@ static struct flag _lv_flags[] = {
|
||||
{VISIBLE_LV, "VISIBLE"},
|
||||
{PVMOVE, "PVMOVE"},
|
||||
{LOCKED, "LOCKED"},
|
||||
{MIRROR_NOTSYNCED, "NOTSYNCED"},
|
||||
{MIRROR_IMAGE, NULL},
|
||||
{MIRROR_LOG, NULL},
|
||||
{MIRRORED, NULL},
|
||||
|
||||
@@ -39,8 +39,9 @@
|
||||
#define FMT_TEXT_NAME "lvm2"
|
||||
#define FMT_TEXT_ALIAS "text"
|
||||
|
||||
static struct format_instance *_create_text_instance(const struct format_type
|
||||
static struct format_instance *_text_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
void *context);
|
||||
|
||||
struct text_fid_context {
|
||||
@@ -68,7 +69,8 @@ struct text_context {
|
||||
* NOTE: Currently there can be only one vg per text file.
|
||||
*/
|
||||
|
||||
static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
static int _text_vg_setup(struct format_instance *fid __attribute((unused)),
|
||||
struct volume_group *vg)
|
||||
{
|
||||
if (vg->extent_size & (vg->extent_size - 1)) {
|
||||
log_error("Extent size must be power of 2");
|
||||
@@ -78,13 +80,14 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
static int _text_lv_setup(struct format_instance *fid __attribute((unused)),
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
/******** FIXME Any LV size restriction?
|
||||
uint64_t max_size = UINT_MAX;
|
||||
|
||||
if (lv->size > max_size) {
|
||||
char *dummy = display_size(max_size, SIZE_SHORT);
|
||||
char *dummy = display_size(max_size);
|
||||
log_error("logical volumes cannot be larger than %s", dummy);
|
||||
dm_free(dummy);
|
||||
return 0;
|
||||
@@ -129,44 +132,47 @@ static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
|
||||
|
||||
if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) {
|
||||
stack;
|
||||
dm_pool_free(fmt->cmd->mem, mdah);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, mdah->magic,
|
||||
MDA_HEADER_SIZE -
|
||||
sizeof(mdah->checksum_xl)))) {
|
||||
log_error("Incorrect metadata area header checksum");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
_xlate_mdah(mdah);
|
||||
|
||||
if (strncmp(mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
|
||||
if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
|
||||
log_error("Wrong magic number in metadata area header");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mdah->version != FMTT_VERSION) {
|
||||
log_error("Incompatible metadata area header version: %d",
|
||||
mdah->version);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mdah->start != dev_area->start) {
|
||||
log_error("Incorrect start sector in metadata area header: %"
|
||||
PRIu64, mdah->start);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return mdah;
|
||||
|
||||
error:
|
||||
dm_pool_free(fmt->cmd->mem, mdah);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
uint64_t start_byte, struct mda_header *mdah)
|
||||
{
|
||||
strncpy(mdah->magic, FMTT_MAGIC, sizeof(mdah->magic));
|
||||
strncpy((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic));
|
||||
mdah->version = FMTT_VERSION;
|
||||
mdah->start = start_byte;
|
||||
|
||||
@@ -190,7 +196,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
int *precommitted)
|
||||
{
|
||||
size_t len;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
char vgnamebuf[NAME_LEN + 2] __attribute((aligned(8)));
|
||||
struct raw_locn *rlocn, *rlocn_precommitted;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
@@ -219,7 +225,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
|
||||
error:
|
||||
if ((info = info_from_pvid(dev_area->dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -704,7 +710,8 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_sys_error("fdopen", temp_file);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -712,13 +719,15 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!text_vg_export_file(vg, tc->desc, fp)) {
|
||||
log_error("Failed to write metadata to %s.", temp_file);
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
|
||||
log_sys_error("fsync", tc->path_edit);
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", tc->path_edit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -850,7 +859,7 @@ static int _scan_file(const struct format_type *fmt)
|
||||
tmp != dirent->d_name + strlen(dirent->d_name)
|
||||
- 4)) {
|
||||
vgname = dirent->d_name;
|
||||
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
if (dm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
dl->dir, vgname) < 0) {
|
||||
log_error("Name too long %s/%s",
|
||||
dl->dir, vgname);
|
||||
@@ -858,9 +867,11 @@ static int _scan_file(const struct format_type *fmt)
|
||||
}
|
||||
|
||||
/* FIXME stat file to see if it's changed */
|
||||
fid = _create_text_instance(fmt, NULL, NULL);
|
||||
fid = _text_create_text_instance(fmt, NULL, NULL,
|
||||
NULL);
|
||||
if ((vg = _vg_read_file_name(fid, vgname,
|
||||
path)))
|
||||
/* FIXME Store creation host in vg */
|
||||
lvmcache_update_vg(vg);
|
||||
}
|
||||
|
||||
@@ -871,65 +882,99 @@ static int _scan_file(const struct format_type *fmt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||
char *buf, uint32_t size)
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint32_t *vgstatus, char **creation_host)
|
||||
{
|
||||
struct raw_locn *rlocn;
|
||||
struct mda_header *mdah;
|
||||
unsigned int len;
|
||||
int r = 0;
|
||||
uint32_t wrap = 0;
|
||||
const char *vgname = NULL;
|
||||
unsigned int len = 0;
|
||||
char buf[NAME_LEN + 1] __attribute((aligned(8)));
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_open(dev_area->dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fmt, dev_area))) {
|
||||
stack;
|
||||
if (!(mdah = _raw_read_mda_header(fmt, dev_area)))
|
||||
goto_out;
|
||||
|
||||
/* FIXME Cope with returning a list */
|
||||
rlocn = mdah->raw_locns;
|
||||
|
||||
/* Do quick check for a vgname */
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
NAME_LEN, buf))
|
||||
goto_out;
|
||||
|
||||
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
|
||||
len < (NAME_LEN - 1))
|
||||
len++;
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(buf))
|
||||
goto_out;
|
||||
|
||||
/* We found a VG - now check the metadata */
|
||||
if (rlocn->offset + rlocn->size > mdah->size)
|
||||
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
|
||||
|
||||
if (wrap > rlocn->offset) {
|
||||
log_error("%s: metadata too large for circular buffer",
|
||||
dev_name(dev_area->dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
/* FIXME 64-bit */
|
||||
if (!(vgname = text_vgname_import(fmt, dev_area->dev,
|
||||
(off_t) (dev_area->start +
|
||||
rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (dev_area->start +
|
||||
MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, rlocn->checksum,
|
||||
vgid, vgstatus, creation_host)))
|
||||
goto_out;
|
||||
|
||||
while (rlocn->offset) {
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
size, buf)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
len = 0;
|
||||
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
|
||||
len < (size - 1))
|
||||
len++;
|
||||
buf[len] = '\0';
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(buf)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
break;
|
||||
|
||||
/* FIXME Cope with returning a list */
|
||||
rlocn++;
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(vgname)) {
|
||||
stack;
|
||||
vgname = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!id_write_format(vgid, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
vgname = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_debug("%s: Found metadata at %" PRIu64 " size %" PRIu64
|
||||
" for %s (%s)",
|
||||
dev_name(dev_area->dev), dev_area->start + rlocn->offset,
|
||||
rlocn->size, vgname, uuid);
|
||||
|
||||
out:
|
||||
if (!dev_close(dev_area->dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
return vgname;
|
||||
}
|
||||
|
||||
static int _scan_raw(const struct format_type *fmt)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct list *raw_list;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
const char *vgname;
|
||||
struct volume_group *vg;
|
||||
struct format_instance fid;
|
||||
struct id vgid;
|
||||
uint32_t vgstatus;
|
||||
|
||||
raw_list = &((struct mda_lists *) fmt->private)->raws;
|
||||
|
||||
@@ -938,9 +983,9 @@ static int _scan_raw(const struct format_type *fmt)
|
||||
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME We're reading mdah twice here... */
|
||||
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
|
||||
if ((vgname = vgname_from_mda(fmt, &rl->dev_area, &vgid, &vgstatus,
|
||||
NULL))) {
|
||||
if ((vg = _vg_read_raw_area(&fid, vgname,
|
||||
&rl->dev_area, 0)))
|
||||
lvmcache_update_vg(vg);
|
||||
}
|
||||
@@ -949,13 +994,13 @@ static int _scan_raw(const struct format_type *fmt)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _scan(const struct format_type *fmt)
|
||||
static int _text_scan(const struct format_type *fmt)
|
||||
{
|
||||
return (_scan_file(fmt) & _scan_raw(fmt));
|
||||
}
|
||||
|
||||
/* For orphan, creates new mdas according to policy.
|
||||
Always have an mda between end-of-label and PE_ALIGN boundary */
|
||||
Always have an mda between end-of-label and pe_align() boundary */
|
||||
static int _mda_setup(const struct format_type *fmt,
|
||||
uint64_t pe_start, uint64_t pe_end,
|
||||
int pvmetadatacopies,
|
||||
@@ -966,15 +1011,12 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
uint64_t start1, mda_size1; /* First area - start of disk */
|
||||
uint64_t start2, mda_size2; /* Second area - end of disk */
|
||||
uint64_t wipe_size = 8 << SECTOR_SHIFT;
|
||||
size_t pagesize = getpagesize();
|
||||
size_t pagesize = lvm_getpagesize();
|
||||
|
||||
if (!pvmetadatacopies) {
|
||||
/* Space available for PEs */
|
||||
pv->size -= PE_ALIGN;
|
||||
if (!pvmetadatacopies)
|
||||
return 1;
|
||||
}
|
||||
|
||||
alignment = PE_ALIGN << SECTOR_SHIFT;
|
||||
alignment = pe_align() << SECTOR_SHIFT;
|
||||
disk_size = pv->size << SECTOR_SHIFT;
|
||||
pe_start <<= SECTOR_SHIFT;
|
||||
pe_end <<= SECTOR_SHIFT;
|
||||
@@ -988,9 +1030,6 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
/* Requested metadatasize */
|
||||
mda_size1 = pvmetadatasize << SECTOR_SHIFT;
|
||||
|
||||
/* Space available for PEs (before any mdas created) */
|
||||
pv->size -= LABEL_SCAN_SECTORS;
|
||||
|
||||
/* Place mda straight after label area at start of disk */
|
||||
start1 = LABEL_SCAN_SIZE;
|
||||
|
||||
@@ -998,11 +1037,8 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
if ((!pe_start && !pe_end) ||
|
||||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
|
||||
mda_adjustment = start1 % pagesize;
|
||||
if (mda_adjustment) {
|
||||
if (mda_adjustment)
|
||||
start1 += (pagesize - mda_adjustment);
|
||||
pv->size -= ((pagesize - mda_adjustment) >>
|
||||
SECTOR_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure it's not going to be bigger than the disk! */
|
||||
@@ -1016,7 +1052,7 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
pvmetadatacopies = 1;
|
||||
}
|
||||
|
||||
/* Round up to PE_ALIGN boundary */
|
||||
/* Round up to pe_align() boundary */
|
||||
mda_adjustment = (mda_size1 + start1) % alignment;
|
||||
if (mda_adjustment)
|
||||
mda_size1 += (alignment - mda_adjustment);
|
||||
@@ -1032,16 +1068,16 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
/* FIXME If creating new mdas, wipe them! */
|
||||
if (mda_size1) {
|
||||
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
|
||||
mda_size1)) return 0;
|
||||
mda_size1))
|
||||
return 0;
|
||||
|
||||
if (!dev_zero((struct device *) pv->dev, start1,
|
||||
(size_t) (mda_size1 >
|
||||
wipe_size ? wipe_size : mda_size1))) {
|
||||
if (!dev_set((struct device *) pv->dev, start1,
|
||||
(size_t) (mda_size1 >
|
||||
wipe_size ? : mda_size1), 0)) {
|
||||
log_error("Failed to wipe new metadata area");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv->size -= mda_size1 >> SECTOR_SHIFT;
|
||||
if (pvmetadatacopies == 1)
|
||||
return 1;
|
||||
} else
|
||||
@@ -1080,13 +1116,12 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
if (mda_size2) {
|
||||
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
|
||||
mda_size2)) return 0;
|
||||
if (!dev_zero(pv->dev, start2,
|
||||
(size_t) (mda_size1 >
|
||||
wipe_size ? wipe_size : mda_size1))) {
|
||||
if (!dev_set(pv->dev, start2,
|
||||
(size_t) (mda_size1 >
|
||||
wipe_size ? : mda_size1), 0)) {
|
||||
log_error("Failed to wipe new metadata area");
|
||||
return 0;
|
||||
}
|
||||
pv->size -= mda_size2 >> SECTOR_SHIFT;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
@@ -1095,21 +1130,21 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
|
||||
/* Only for orphans */
|
||||
/* Set label_sector to -1 if rewriting existing label into same sector */
|
||||
static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector)
|
||||
{
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct mda_context *mdac;
|
||||
struct metadata_area *mda;
|
||||
char buf[MDA_HEADER_SIZE];
|
||||
char buf[MDA_HEADER_SIZE] __attribute((aligned(8)));
|
||||
struct mda_header *mdah = (struct mda_header *) buf;
|
||||
uint64_t adjustment;
|
||||
|
||||
/* FIXME Test mode don't update cache? */
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
|
||||
ORPHAN, NULL))) {
|
||||
ORPHAN, NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1150,22 +1185,22 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
|
||||
/* Set pe_start to first aligned sector after any metadata
|
||||
* areas that begin before pe_start */
|
||||
pv->pe_start = PE_ALIGN;
|
||||
pv->pe_start = pe_align();
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (pv->dev == mdac->area.dev &&
|
||||
(mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) &&
|
||||
(mdac->area.start <= (pv->pe_start << SECTOR_SHIFT)) &&
|
||||
(mdac->area.start + mdac->area.size >
|
||||
(pv->pe_start << SECTOR_SHIFT))) {
|
||||
pv->pe_start = (mdac->area.start + mdac->area.size)
|
||||
>> SECTOR_SHIFT;
|
||||
adjustment = pv->pe_start % PE_ALIGN;
|
||||
adjustment = pv->pe_start % pe_align();
|
||||
if (adjustment)
|
||||
pv->pe_start += (PE_ALIGN - adjustment);
|
||||
pv->pe_start += (pe_align() - adjustment);
|
||||
}
|
||||
}
|
||||
if (!add_da
|
||||
(fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0))) {
|
||||
(NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1220,7 +1255,7 @@ static int _add_raw(struct list *raw_list, struct device_area *dev_area)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
struct physical_volume *pv, struct list *mdas)
|
||||
{
|
||||
struct label *label;
|
||||
@@ -1245,7 +1280,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
/* Have we already cached vgname? */
|
||||
if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
info->vginfo->vgid, info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1256,6 +1291,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
if (info->vginfo && info->vginfo->vgname &&
|
||||
*info->vginfo->vgname &&
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->vginfo->vgid,
|
||||
info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1301,7 +1337,7 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_instance(struct format_instance *fid)
|
||||
static void _text_destroy_instance(struct format_instance *fid __attribute((unused)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1326,7 +1362,7 @@ static void _free_raws(struct list *raw_list)
|
||||
}
|
||||
}
|
||||
|
||||
static void _destroy(const struct format_type *fmt)
|
||||
static void _text_destroy(const struct format_type *fmt)
|
||||
{
|
||||
if (fmt->private) {
|
||||
_free_dirs(&((struct mda_lists *) fmt->private)->dirs);
|
||||
@@ -1334,36 +1370,36 @@ static void _destroy(const struct format_type *fmt)
|
||||
dm_free(fmt->private);
|
||||
}
|
||||
|
||||
dm_free((void *) fmt);
|
||||
dm_free((void *)fmt);
|
||||
}
|
||||
|
||||
static struct metadata_area_ops _metadata_text_file_ops = {
|
||||
vg_read:_vg_read_file,
|
||||
vg_read_precommit:_vg_read_precommit_file,
|
||||
vg_write:_vg_write_file,
|
||||
vg_remove:_vg_remove_file,
|
||||
vg_commit:_vg_commit_file
|
||||
.vg_read = _vg_read_file,
|
||||
.vg_read_precommit = _vg_read_precommit_file,
|
||||
.vg_write = _vg_write_file,
|
||||
.vg_remove = _vg_remove_file,
|
||||
.vg_commit = _vg_commit_file
|
||||
};
|
||||
|
||||
static struct metadata_area_ops _metadata_text_file_backup_ops = {
|
||||
vg_read:_vg_read_file,
|
||||
vg_write:_vg_write_file,
|
||||
vg_remove:_vg_remove_file,
|
||||
vg_commit:_vg_commit_file_backup
|
||||
.vg_read = _vg_read_file,
|
||||
.vg_write = _vg_write_file,
|
||||
.vg_remove = _vg_remove_file,
|
||||
.vg_commit = _vg_commit_file_backup
|
||||
};
|
||||
|
||||
static struct metadata_area_ops _metadata_text_raw_ops = {
|
||||
vg_read:_vg_read_raw,
|
||||
vg_read_precommit:_vg_read_precommit_raw,
|
||||
vg_write:_vg_write_raw,
|
||||
vg_remove:_vg_remove_raw,
|
||||
vg_precommit:_vg_precommit_raw,
|
||||
vg_commit:_vg_commit_raw,
|
||||
vg_revert:_vg_revert_raw
|
||||
.vg_read = _vg_read_raw,
|
||||
.vg_read_precommit = _vg_read_precommit_raw,
|
||||
.vg_write = _vg_write_raw,
|
||||
.vg_remove = _vg_remove_raw,
|
||||
.vg_precommit = _vg_precommit_raw,
|
||||
.vg_commit = _vg_commit_raw,
|
||||
.vg_revert = _vg_revert_raw
|
||||
};
|
||||
|
||||
/* pvmetadatasize in sectors */
|
||||
static int _pv_setup(const struct format_type *fmt,
|
||||
static int _text_pv_setup(const struct format_type *fmt,
|
||||
uint64_t pe_start, uint32_t extent_count,
|
||||
uint32_t extent_size,
|
||||
int pvmetadatacopies,
|
||||
@@ -1376,11 +1412,12 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
struct lvmcache_info *info;
|
||||
int found;
|
||||
uint64_t pe_end = 0;
|
||||
|
||||
/* FIXME if vg, adjust start/end of pe area to avoid mdas! */
|
||||
unsigned mda_count = 0;
|
||||
uint64_t mda_size2 = 0;
|
||||
uint64_t pe_count;
|
||||
|
||||
/* FIXME Cope with pvchange */
|
||||
/* FIXME Merge code with _create_text_instance */
|
||||
/* FIXME Merge code with _text_create_text_instance */
|
||||
|
||||
/* If new vg, add any further mdas on this PV to the fid's mda list */
|
||||
if (vg) {
|
||||
@@ -1388,11 +1425,16 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
if ((info = info_from_pvid(pv->dev->pvid))) {
|
||||
pvmdas = &info->mdas;
|
||||
list_iterate_items(mda, pvmdas) {
|
||||
mda_count++;
|
||||
mdac =
|
||||
(struct mda_context *) mda->metadata_locn;
|
||||
|
||||
/* FIXME Check it isn't already in use */
|
||||
|
||||
/* Reduce usable device size */
|
||||
if (mda_count > 1)
|
||||
mda_size2 = mdac->area.size >> SECTOR_SHIFT;
|
||||
|
||||
/* Ensure it isn't already on list */
|
||||
found = 0;
|
||||
list_iterate_items(mda2, mdas) {
|
||||
@@ -1430,6 +1472,26 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME Cope with genuine pe_count 0 */
|
||||
|
||||
/* If missing, estimate pv->size from file-based metadata */
|
||||
if (!pv->size && pv->pe_count)
|
||||
pv->size = pv->pe_count * (uint64_t) vg->extent_size +
|
||||
pv->pe_start + mda_size2;
|
||||
|
||||
/* Recalculate number of extents that will fit */
|
||||
if (!pv->pe_count) {
|
||||
pe_count = (pv->size - pv->pe_start - mda_size2) /
|
||||
vg->extent_size;
|
||||
if (pe_count > UINT32_MAX) {
|
||||
log_error("PV %s too large for extent size %s.",
|
||||
dev_name(pv->dev),
|
||||
display_size(vg->cmd, (uint64_t) vg->extent_size));
|
||||
return 0;
|
||||
}
|
||||
pv->pe_count = (uint32_t) pe_count;
|
||||
}
|
||||
|
||||
/* Unlike LVM1, we don't store this outside a VG */
|
||||
/* FIXME Default from config file? vgextend cmdline flag? */
|
||||
pv->status |= ALLOCATABLE_PV;
|
||||
@@ -1448,8 +1510,9 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
}
|
||||
|
||||
/* NULL vgname means use only the supplied context e.g. an archive file */
|
||||
static struct format_instance *_create_text_instance(const struct format_type
|
||||
static struct format_instance *_text_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
void *context)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
@@ -1492,7 +1555,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
dir_list = &((struct mda_lists *) fmt->private)->dirs;
|
||||
|
||||
list_iterate_items(dl, dir_list) {
|
||||
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
if (dm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
dl->dir, vgname) < 0) {
|
||||
log_error("Name too long %s/%s", dl->dir,
|
||||
vgname);
|
||||
@@ -1535,7 +1598,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
|
||||
/* Scan PVs in VG for any further MDAs */
|
||||
lvmcache_label_scan(fmt->cmd, 0);
|
||||
if (!(vginfo = vginfo_from_vgname(vgname))) {
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -1569,7 +1632,6 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
|
||||
out:
|
||||
return fid;
|
||||
|
||||
}
|
||||
|
||||
void *create_text_context(struct cmd_context *cmd, const char *path,
|
||||
@@ -1618,15 +1680,15 @@ void *create_text_context(struct cmd_context *cmd, const char *path,
|
||||
}
|
||||
|
||||
static struct format_handler _text_handler = {
|
||||
scan:_scan,
|
||||
pv_read:_pv_read,
|
||||
pv_setup:_pv_setup,
|
||||
pv_write:_pv_write,
|
||||
vg_setup:_vg_setup,
|
||||
lv_setup:_lv_setup,
|
||||
create_instance:_create_text_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy:_destroy
|
||||
.scan = _text_scan,
|
||||
.pv_read = _text_pv_read,
|
||||
.pv_setup = _text_pv_setup,
|
||||
.pv_write = _text_pv_write,
|
||||
.vg_setup = _text_vg_setup,
|
||||
.lv_setup = _text_lv_setup,
|
||||
.create_instance = _text_create_text_instance,
|
||||
.destroy_instance = _text_destroy_instance,
|
||||
.destroy = _text_destroy
|
||||
};
|
||||
|
||||
static int _add_dir(const char *dir, struct list *dir_list)
|
||||
@@ -1686,7 +1748,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (!(dev_area.dev = device_from_pvid(cmd, &id))) {
|
||||
char buffer[64];
|
||||
char buffer[64] __attribute((aligned(8)));
|
||||
|
||||
if (!id_write_format(&id, buffer, sizeof(buffer)))
|
||||
log_err("Couldn't find device.");
|
||||
@@ -1716,10 +1778,12 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
fmt->name = FMT_TEXT_NAME;
|
||||
fmt->alias = FMT_TEXT_ALIAS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
|
||||
FMT_UNLIMITED_VOLS | FMT_RESIZE_PV;
|
||||
FMT_UNLIMITED_VOLS | FMT_RESIZE_PV |
|
||||
FMT_UNLIMITED_STRIPESIZE;
|
||||
|
||||
if (!(mda_lists = dm_malloc(sizeof(struct mda_lists)))) {
|
||||
log_error("Failed to allocate dir_list");
|
||||
dm_free(fmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1731,15 +1795,17 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
|
||||
if (!(fmt->labeller = text_labeller_create(fmt))) {
|
||||
log_error("Couldn't create text label handler.");
|
||||
dm_free(fmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_register_handler(FMT_TEXT_NAME, fmt->labeller))) {
|
||||
log_error("Couldn't register text label handler.");
|
||||
dm_free(fmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((cn = find_config_node(cmd->cft->root, "metadata/dirs"))) {
|
||||
if ((cn = find_config_tree_node(cmd, "metadata/dirs"))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
@@ -1755,7 +1821,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if ((cn = find_config_node(cmd->cft->root, "metadata/disk_areas"))) {
|
||||
if ((cn = find_config_tree_node(cmd, "metadata/disk_areas"))) {
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
|
||||
goto err;
|
||||
|
||||
@@ -46,7 +46,7 @@ struct labeller *text_labeller_create(const struct format_type *fmt);
|
||||
|
||||
int pvhdr_read(struct device *dev, char *buf);
|
||||
|
||||
int add_da(const struct format_type *fmt, struct dm_pool *mem, struct list *das,
|
||||
int add_da(struct dm_pool *mem, struct list *das,
|
||||
uint64_t start, uint64_t size);
|
||||
void del_das(struct list *das);
|
||||
|
||||
@@ -54,7 +54,8 @@ int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct list *mda
|
||||
struct device *dev, uint64_t start, uint64_t size);
|
||||
void del_mdas(struct list *mdas);
|
||||
|
||||
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||
char *buf, uint32_t size);
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint32_t *vgstatus, char **creation_host);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,6 +47,10 @@ struct text_vg_version_ops {
|
||||
struct config_tree * cf);
|
||||
void (*read_desc) (struct dm_pool * mem, struct config_tree * cf,
|
||||
time_t *when, char **desc);
|
||||
const char *(*read_vgname) (const struct format_type *fmt,
|
||||
struct config_tree *cft,
|
||||
struct id *vgid, uint32_t *vgstatus,
|
||||
char **creation_host);
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||
@@ -70,5 +74,12 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
checksum_fn_t checksum_fn,
|
||||
uint32_t checksum,
|
||||
time_t *when, char **desc);
|
||||
const char *text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
struct id *vgid, uint32_t *vgstatus,
|
||||
char **creation_host);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,53 @@
|
||||
/* FIXME Use tidier inclusion method */
|
||||
static struct text_vg_version_ops *(_text_vsn_list[2]);
|
||||
|
||||
const char *text_vgname_import(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
struct id *vgid, uint32_t *vgstatus,
|
||||
char **creation_host)
|
||||
{
|
||||
struct config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
const char *vgname = NULL;
|
||||
|
||||
static int _text_import_initialised = 0;
|
||||
|
||||
if (!_text_import_initialised) {
|
||||
_text_vsn_list[0] = text_vg_vsn1_init();
|
||||
_text_vsn_list[1] = NULL;
|
||||
_text_import_initialised = 1;
|
||||
}
|
||||
|
||||
if (!(cft = create_config_tree(NULL, 0)))
|
||||
return_NULL;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
(dev && !read_config_fd(cft, dev, offset, size,
|
||||
offset2, size2, checksum_fn, checksum)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Find a set of version functions that can read this file
|
||||
*/
|
||||
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(vgname = (*vsn)->read_vgname(fmt, cft, vgid, vgstatus,
|
||||
creation_host)))
|
||||
goto_out;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
destroy_config_tree(cft);
|
||||
return vgname;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct device *dev,
|
||||
@@ -36,21 +83,19 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
struct config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
|
||||
static int _initialised = 0;
|
||||
static int _text_vg_import_initialised = 0;
|
||||
|
||||
if (!_initialised) {
|
||||
if (!_text_vg_import_initialised) {
|
||||
_text_vsn_list[0] = text_vg_vsn1_init();
|
||||
_text_vsn_list[1] = NULL;
|
||||
_initialised = 1;
|
||||
_text_vg_import_initialised = 1;
|
||||
}
|
||||
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cft = create_config_tree(file))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
if (!(cft = create_config_tree(file, 0)))
|
||||
return_NULL;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
(dev && !read_config_fd(cft, dev, offset, size,
|
||||
@@ -84,6 +129,6 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc)
|
||||
{
|
||||
return text_vg_import_fd(fid, file, NULL, 0, 0, 0, 0, NULL, 0,
|
||||
return text_vg_import_fd(fid, file, NULL, (off_t)0, 0, (off_t)0, 0, NULL, 0,
|
||||
when, desc);
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct config_node *cn;
|
||||
uint64_t size;
|
||||
|
||||
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
||||
@@ -148,7 +149,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
* Convert the uuid into a device.
|
||||
*/
|
||||
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
|
||||
char buffer[64];
|
||||
char buffer[64] __attribute((aligned(8)));
|
||||
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
log_error("Couldn't find device.");
|
||||
@@ -167,6 +168,8 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
|
||||
|
||||
if (!(cn = find_config_node(pvn, "status"))) {
|
||||
log_error("Couldn't find status flags for physical volume.");
|
||||
return 0;
|
||||
@@ -177,6 +180,9 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Late addition */
|
||||
_read_int64(pvn, "dev_size", &pv->size);
|
||||
|
||||
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
|
||||
log_error("Couldn't read extent size for volume group.");
|
||||
return 0;
|
||||
@@ -204,10 +210,29 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
vg->free_count += pv->pe_count;
|
||||
|
||||
pv->pe_size = vg->extent_size;
|
||||
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
|
||||
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fmt = fid->fmt;
|
||||
|
||||
/* Fix up pv size if missing */
|
||||
if (!pv->size && pv->dev) {
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Fixing up missing format1 size (%s) "
|
||||
"for PV %s", display_size(fid->fmt->cmd, pv->size),
|
||||
dev_name(pv->dev));
|
||||
if (vg) {
|
||||
size = pv->pe_count * (uint64_t) vg->extent_size +
|
||||
pv->pe_start;
|
||||
if (size > pv->size)
|
||||
log_error("WARNING: Physical Volume %s is too "
|
||||
"large for underlying device",
|
||||
dev_name(pv->dev));
|
||||
}
|
||||
}
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -368,7 +393,7 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
} else {
|
||||
log_error("Couldn't find volume '%s' "
|
||||
"for segment '%s'.",
|
||||
cv->v.str ? cv->v.str : "NULL", seg_name);
|
||||
cv->v.str ? : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -798,13 +823,62 @@ static void _read_desc(struct dm_pool *mem,
|
||||
*when = u;
|
||||
}
|
||||
|
||||
static const char *_read_vgname(const struct format_type *fmt,
|
||||
struct config_tree *cft, struct id *vgid,
|
||||
uint32_t *vgstatus, char **creation_host)
|
||||
{
|
||||
struct config_node *vgn, *cn;
|
||||
struct dm_pool *mem = fmt->cmd->mem;
|
||||
char *vgname;
|
||||
int old_suppress;
|
||||
|
||||
old_suppress = log_suppress(2);
|
||||
*creation_host = dm_pool_strdup(mem,
|
||||
find_config_str(cft->root,
|
||||
"creation_host", ""));
|
||||
log_suppress(old_suppress);
|
||||
|
||||
/* skip any top-level values */
|
||||
for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
||||
|
||||
if (!vgn) {
|
||||
log_error("Couldn't find volume group in file.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vgname = dm_pool_strdup(mem, vgn->key)))
|
||||
return_0;
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
if (!_read_id(vgid, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(vgn, "status"))) {
|
||||
log_error("Couldn't find status flags for volume group %s.",
|
||||
vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(read_flags(vgstatus, VG_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for volume group %s.",
|
||||
vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vgname;
|
||||
}
|
||||
|
||||
static struct text_vg_version_ops _vsn1_ops = {
|
||||
check_version:_check_version,
|
||||
read_vg:_read_vg,
|
||||
read_desc:_read_desc
|
||||
.check_version = _check_version,
|
||||
.read_vg = _read_vg,
|
||||
.read_desc = _read_desc,
|
||||
.read_vgname = _read_vgname,
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void)
|
||||
{
|
||||
return &_vsn1_ops;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ struct data_area_list {
|
||||
/* Fields with the suffix _xl should be xlate'd wherever they appear */
|
||||
/* On disk */
|
||||
struct pv_header {
|
||||
uint8_t pv_uuid[ID_LEN];
|
||||
int8_t pv_uuid[ID_LEN];
|
||||
|
||||
/* This size can be overridden if PV belongs to a VG */
|
||||
uint64_t device_size_xl; /* Bytes */
|
||||
@@ -58,7 +58,7 @@ struct raw_locn {
|
||||
/* Structure size limited to one sector */
|
||||
struct mda_header {
|
||||
uint32_t checksum_xl; /* Checksum of rest of mda_header */
|
||||
uint8_t magic[16]; /* To aid scans for metadata */
|
||||
int8_t magic[16]; /* To aid scans for metadata */
|
||||
uint32_t version;
|
||||
uint64_t start; /* Absolute start byte of mda_header */
|
||||
uint64_t size; /* Size of metadata area */
|
||||
@@ -83,6 +83,6 @@ struct mda_context {
|
||||
#define FMTT_VERSION 1
|
||||
#define MDA_HEADER_SIZE 512
|
||||
#define LVM2_LABEL "LVM2 001"
|
||||
#define MDA_SIZE_MIN (8 * getpagesize())
|
||||
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,17 +23,19 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
static int _text_can_handle(struct labeller *l __attribute((unused)),
|
||||
void *buf,
|
||||
uint64_t sector __attribute((unused)))
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
|
||||
if (!strncmp(lh->type, LVM2_LABEL, sizeof(lh->type)))
|
||||
if (!strncmp((char *)lh->type, LVM2_LABEL, sizeof(lh->type)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _write(struct label *label, char *buf)
|
||||
static int _text_write(struct label *label, void *buf)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
struct pv_header *pvhdr;
|
||||
@@ -46,7 +48,7 @@ static int _write(struct label *label, char *buf)
|
||||
/* FIXME Move to where label is created */
|
||||
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
|
||||
|
||||
strncpy(lh->type, label->type, sizeof(label->type));
|
||||
strncpy((char *)lh->type, label->type, sizeof(label->type));
|
||||
|
||||
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
@@ -86,7 +88,7 @@ static int _write(struct label *label, char *buf)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_da(const struct format_type *fmt, struct dm_pool *mem, struct list *das,
|
||||
int add_da(struct dm_pool *mem, struct list *das,
|
||||
uint64_t start, uint64_t size)
|
||||
{
|
||||
struct data_area_list *dal;
|
||||
@@ -179,14 +181,15 @@ void del_mdas(struct list *mdas)
|
||||
}
|
||||
}
|
||||
|
||||
static int _initialise_label(struct labeller *l, struct label *label)
|
||||
static int _text_initialise_label(struct labeller *l __attribute((unused)),
|
||||
struct label *label)
|
||||
{
|
||||
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
static int _text_read(struct labeller *l, struct device *dev, void *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
@@ -195,13 +198,16 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
struct disk_locn *dlocn_xl;
|
||||
uint64_t offset;
|
||||
struct metadata_area *mda;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct id vgid;
|
||||
struct mda_context *mdac;
|
||||
const char *vgname;
|
||||
uint32_t vgstatus;
|
||||
char *creation_host;
|
||||
|
||||
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||
|
||||
if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
|
||||
return 0;
|
||||
if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev, NULL, NULL, 0)))
|
||||
return_0;
|
||||
*label = info->label;
|
||||
|
||||
info->device_size = xlate64(pvhdr->device_size_xl);
|
||||
@@ -217,7 +223,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
/* Data areas holding the PEs */
|
||||
dlocn_xl = pvhdr->disk_areas_xl;
|
||||
while ((offset = xlate64(dlocn_xl->offset))) {
|
||||
add_da(info->fmt, NULL, &info->das, offset,
|
||||
add_da(NULL, &info->das, offset,
|
||||
xlate64(dlocn_xl->size));
|
||||
dlocn_xl++;
|
||||
}
|
||||
@@ -232,10 +238,12 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
lvmcache_update_vgname(info, vgnamebuf);
|
||||
}
|
||||
if ((vgname = vgname_from_mda(info->fmt, &mdac->area,
|
||||
&vgid, &vgstatus, &creation_host)) &&
|
||||
!lvmcache_update_vgname_and_id(info, vgname,
|
||||
(char *) &vgid, vgstatus,
|
||||
creation_host))
|
||||
return_0;
|
||||
}
|
||||
|
||||
info->status &= ~CACHE_INVALID;
|
||||
@@ -243,7 +251,8 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_label(struct labeller *l, struct label *label)
|
||||
static void _text_destroy_label(struct labeller *l __attribute((unused)),
|
||||
struct label *label)
|
||||
{
|
||||
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
|
||||
|
||||
@@ -253,19 +262,19 @@ static void _destroy_label(struct labeller *l, struct label *label)
|
||||
del_das(&info->das);
|
||||
}
|
||||
|
||||
static void _destroy(struct labeller *l)
|
||||
static void _fmt_text_destroy(struct labeller *l)
|
||||
{
|
||||
dm_free(l);
|
||||
}
|
||||
|
||||
struct label_ops _text_ops = {
|
||||
can_handle:_can_handle,
|
||||
write:_write,
|
||||
read:_read,
|
||||
verify:_can_handle,
|
||||
initialise_label:_initialise_label,
|
||||
destroy_label:_destroy_label,
|
||||
destroy:_destroy
|
||||
.can_handle = _text_can_handle,
|
||||
.write = _text_write,
|
||||
.read = _text_read,
|
||||
.verify = _text_can_handle,
|
||||
.initialise_label = _text_initialise_label,
|
||||
.destroy_label = _text_destroy_label,
|
||||
.destroy = _fmt_text_destroy,
|
||||
};
|
||||
|
||||
struct labeller *text_labeller_create(const struct format_type *fmt)
|
||||
|
||||
@@ -115,16 +115,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
struct lvmcache_info *info;
|
||||
uint64_t sector;
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
@@ -137,7 +128,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
lh = (struct label_header *) (readbuf +
|
||||
(sector << SECTOR_SHIFT));
|
||||
|
||||
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (found) {
|
||||
log_error("Ignoring additional label on %s at "
|
||||
"sector %" PRIu64, dev_name(dev),
|
||||
@@ -184,21 +175,19 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
out:
|
||||
if (!found) {
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME Also wipe associated metadata area headers? */
|
||||
int label_remove(struct device *dev)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
int r = 1;
|
||||
uint64_t sector;
|
||||
int wipe;
|
||||
@@ -233,7 +222,7 @@ int label_remove(struct device *dev)
|
||||
|
||||
wipe = 0;
|
||||
|
||||
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (xlate64(lh->sector_xl) == sector)
|
||||
wipe = 1;
|
||||
} else {
|
||||
@@ -269,26 +258,39 @@ int label_remove(struct device *dev)
|
||||
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct labeller *l;
|
||||
uint64_t sector;
|
||||
int r;
|
||||
struct lvmcache_info *info;
|
||||
int r = 0;
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
goto_out;
|
||||
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
(*result)->sector = sector;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Caller may need to use label_get_handler to create label struct! */
|
||||
int label_write(struct device *dev, struct label *label)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
int r = 1;
|
||||
|
||||
@@ -305,7 +307,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
|
||||
memset(buf, 0, LABEL_SIZE);
|
||||
|
||||
strncpy(lh->id, LABEL_ID, sizeof(lh->id));
|
||||
strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
|
||||
lh->sector_xl = xlate64(label->sector);
|
||||
lh->offset_xl = xlate32(sizeof(*lh));
|
||||
|
||||
@@ -335,18 +337,33 @@ int label_write(struct device *dev, struct label *label)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Unused */
|
||||
int label_verify(struct device *dev)
|
||||
{
|
||||
struct labeller *l;
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
uint64_t sector;
|
||||
struct lvmcache_info *info;
|
||||
int r = 0;
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||
stack;
|
||||
return 0;
|
||||
if (!dev_open(dev)) {
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
|
||||
return_0;
|
||||
}
|
||||
|
||||
return ((l->ops->verify) ? l->ops->verify(l, buf, sector) : 1);
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
goto_out;
|
||||
|
||||
r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void label_destroy(struct label *label)
|
||||
|
||||
@@ -28,11 +28,11 @@ struct labeller;
|
||||
|
||||
/* On disk - 32 bytes */
|
||||
struct label_header {
|
||||
uint8_t id[8]; /* LABELONE */
|
||||
int8_t id[8]; /* LABELONE */
|
||||
uint64_t sector_xl; /* Sector number of this label */
|
||||
uint32_t crc_xl; /* From next field to end of sector */
|
||||
uint32_t offset_xl; /* Offset from start of struct to contents */
|
||||
uint8_t type[8]; /* LVM2 001 */
|
||||
int8_t type[8]; /* LVM2 001 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* In core */
|
||||
@@ -49,23 +49,23 @@ struct label_ops {
|
||||
/*
|
||||
* Is the device labelled with this format ?
|
||||
*/
|
||||
int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
|
||||
int (*can_handle) (struct labeller * l, void *buf, uint64_t sector);
|
||||
|
||||
/*
|
||||
* Write a label to a volume.
|
||||
*/
|
||||
int (*write) (struct label * label, char *buf);
|
||||
int (*write) (struct label * label, void *buf);
|
||||
|
||||
/*
|
||||
* Read a label from a volume.
|
||||
*/
|
||||
int (*read) (struct labeller * l, struct device * dev,
|
||||
char *buf, struct label ** label);
|
||||
void *buf, struct label ** label);
|
||||
|
||||
/*
|
||||
* Additional consistency checks for the paranoid.
|
||||
*/
|
||||
int (*verify) (struct labeller * l, char *buf, uint64_t sector);
|
||||
int (*verify) (struct labeller * l, void *buf, uint64_t sector);
|
||||
|
||||
/*
|
||||
* Populate label_type etc.
|
||||
|
||||
@@ -94,7 +94,7 @@ static int _open_local_sock(void)
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
char outbuf[PIPE_BUF] __attribute((aligned(8)));
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
@@ -195,8 +195,7 @@ static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute((aligned(8)));
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
@@ -236,17 +235,13 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
*response = dm_malloc(sizeof(lvm_response_t) * num_responses);
|
||||
if (!*response) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
@@ -256,7 +251,7 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
rarray[i].status = *(int *) inptr;
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
@@ -265,7 +260,7 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
free(outptr);
|
||||
free(*response);
|
||||
errno = ENOMEM;
|
||||
status = -1;
|
||||
goto out;
|
||||
@@ -287,25 +282,15 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response)
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(ptr);
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -330,6 +315,15 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
args[0] = flags & 0x7F; /* Maskoff lock flags */
|
||||
args[1] = flags & 0xC0; /* Bitmap flags */
|
||||
|
||||
if (partial_mode())
|
||||
args[1] |= LCK_PARTIAL_MODE;
|
||||
|
||||
if (mirror_in_sync())
|
||||
args[1] |= LCK_MIRROR_NOSYNC_MODE;
|
||||
|
||||
if (dmeventd_monitor_mode())
|
||||
args[1] |= LCK_DMEVENTD_MONITOR_MODE;
|
||||
|
||||
/*
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
* so we only need to do them on the local node because all
|
||||
@@ -365,7 +359,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response);
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
@@ -383,14 +377,15 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
|
||||
int cluster_cmd = 0;
|
||||
|
||||
assert(strlen(resource) < sizeof(lockname));
|
||||
assert(resource);
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
/* If the VG name is empty then lock the unused PVs */
|
||||
if (!resource || !*resource)
|
||||
lvm_snprintf(lockname, sizeof(lockname), "P_orphans");
|
||||
if (!*resource)
|
||||
dm_snprintf(lockname, sizeof(lockname), "P_orphans");
|
||||
else
|
||||
lvm_snprintf(lockname, sizeof(lockname), "V_%s",
|
||||
dm_snprintf(lockname, sizeof(lockname), "V_%s",
|
||||
resource);
|
||||
|
||||
cluster_cmd = CLVMD_CMD_LOCK_VG;
|
||||
@@ -442,7 +437,7 @@ void reset_locking(void)
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
int init_cluster_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
|
||||
{
|
||||
locking->lock_resource = _lock_resource;
|
||||
locking->fin_locking = _locking_end;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "locking_types.h"
|
||||
#include "defaults.h"
|
||||
#include "sharedlib.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
static void *_locking_lib = NULL;
|
||||
static void (*_reset_fn) (void) = NULL;
|
||||
@@ -55,7 +56,7 @@ static void _reset_external_locking(void)
|
||||
_reset_fn();
|
||||
}
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
int init_external_locking(struct locking_type *locking, struct cmd_context *cmd)
|
||||
{
|
||||
const char *libname;
|
||||
|
||||
@@ -69,10 +70,10 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
locking->reset_locking = _reset_external_locking;
|
||||
locking->flags = 0;
|
||||
|
||||
libname = find_config_str(cft->root, "global/locking_library",
|
||||
DEFAULT_LOCKING_LIB);
|
||||
libname = find_config_tree_str(cmd, "global/locking_library",
|
||||
DEFAULT_LOCKING_LIB);
|
||||
|
||||
if (!(_locking_lib = load_shared_library(cft, libname, "locking"))) {
|
||||
if (!(_locking_lib = load_shared_library(cmd, libname, "locking", 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -90,5 +91,5 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
}
|
||||
|
||||
log_verbose("Loaded external locking library %s", libname);
|
||||
return _init_fn(2, cft, &locking->flags);
|
||||
return _init_fn(2, cmd->cft, &locking->flags);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ static void _remove_ctrl_c_handler()
|
||||
log_sys_error("signal", "_remove_ctrl_c_handler");
|
||||
}
|
||||
|
||||
static void _trap_ctrl_c(int sig)
|
||||
static void _trap_ctrl_c(int sig __attribute((unused)))
|
||||
{
|
||||
_remove_ctrl_c_handler();
|
||||
log_error("CTRL-c detected: giving up waiting for lock");
|
||||
@@ -163,8 +163,8 @@ static int _lock_file(const char *file, int flags)
|
||||
log_very_verbose("Locking %s %c%c", ll->res, state,
|
||||
flags & LCK_NONBLOCK ? ' ' : 'B');
|
||||
do {
|
||||
if (ll->lf > -1)
|
||||
close(ll->lf);
|
||||
if ((ll->lf > -1) && close(ll->lf))
|
||||
log_sys_error("close", file);
|
||||
|
||||
if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
|
||||
< 0) {
|
||||
@@ -207,13 +207,15 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
{
|
||||
char lockfile[PATH_MAX];
|
||||
|
||||
assert(resource);
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
if (!resource || !*resource)
|
||||
lvm_snprintf(lockfile, sizeof(lockfile),
|
||||
if (!*resource)
|
||||
dm_snprintf(lockfile, sizeof(lockfile),
|
||||
"%s/P_orphans", _lock_dir);
|
||||
else
|
||||
lvm_snprintf(lockfile, sizeof(lockfile),
|
||||
dm_snprintf(lockfile, sizeof(lockfile),
|
||||
"%s/V_%s", _lock_dir, resource);
|
||||
|
||||
if (!_lock_file(lockfile, flags))
|
||||
@@ -269,7 +271,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_file_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
|
||||
{
|
||||
locking->lock_resource = _file_lock_resource;
|
||||
locking->reset_locking = _reset_file_locking;
|
||||
@@ -277,8 +279,8 @@ int init_file_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
locking->flags = 0;
|
||||
|
||||
/* Get lockfile directory from config file */
|
||||
strncpy(_lock_dir, find_config_str(cft->root, "global/locking_dir",
|
||||
DEFAULT_LOCK_DIR),
|
||||
strncpy(_lock_dir, find_config_tree_str(cmd, "global/locking_dir",
|
||||
DEFAULT_LOCK_DIR),
|
||||
sizeof(_lock_dir));
|
||||
|
||||
if (!create_dir(_lock_dir))
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "activate.h"
|
||||
#include "toolcontext.h"
|
||||
#include "memlock.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -33,7 +34,7 @@ static int _vg_lock_count = 0; /* Number of locks held */
|
||||
static int _vg_write_lock_held = 0; /* VG write lock held? */
|
||||
static int _signals_blocked = 0;
|
||||
|
||||
static void _block_signals(int flags)
|
||||
static void _block_signals(int flags __attribute((unused)))
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
@@ -102,7 +103,7 @@ void reset_locking(void)
|
||||
_unblock_signals();
|
||||
}
|
||||
|
||||
static inline void _update_vg_lock_count(int flags)
|
||||
static void _update_vg_lock_count(int flags)
|
||||
{
|
||||
if ((flags & LCK_SCOPE_MASK) != LCK_VG)
|
||||
return;
|
||||
@@ -122,36 +123,43 @@ static inline void _update_vg_lock_count(int flags)
|
||||
/*
|
||||
* Select a locking type
|
||||
*/
|
||||
int init_locking(int type, struct config_tree *cft)
|
||||
int init_locking(int type, struct cmd_context *cmd)
|
||||
{
|
||||
init_lockingfailed(0);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cft);
|
||||
init_no_locking(&_locking, cmd);
|
||||
log_print("WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
return 1;
|
||||
|
||||
case 1:
|
||||
if (!init_file_locking(&_locking, cft))
|
||||
log_very_verbose("File-based locking selected.");
|
||||
if (!init_file_locking(&_locking, cmd))
|
||||
break;
|
||||
log_very_verbose("File-based locking enabled.");
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
case 2:
|
||||
if (!init_external_locking(&_locking, cft))
|
||||
if (!cmd->is_static) {
|
||||
log_very_verbose("External locking selected.");
|
||||
if (init_external_locking(&_locking, cmd))
|
||||
return 1;
|
||||
}
|
||||
if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
|
||||
DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))
|
||||
break;
|
||||
log_very_verbose("External locking enabled.");
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
log_very_verbose("Falling back to internal clustered locking.");
|
||||
/* Fall through */
|
||||
|
||||
case 3:
|
||||
if (!init_cluster_locking(&_locking, cft))
|
||||
log_very_verbose("Cluster locking selected.");
|
||||
if (!init_cluster_locking(&_locking, cmd))
|
||||
break;
|
||||
log_very_verbose("Cluster locking enabled.");
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
@@ -160,13 +168,23 @@ int init_locking(int type, struct config_tree *cft)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((type == 2 || type == 3) &&
|
||||
find_config_tree_int(cmd, "locking/fallback_to_local_locking",
|
||||
DEFAULT_FALLBACK_TO_LOCAL_LOCKING)) {
|
||||
log_print("WARNING: Falling back to local file-based locking.");
|
||||
log_print("Volume Groups with the clustered attribute will "
|
||||
"be inaccessible.");
|
||||
if (init_file_locking(&_locking, cmd))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ignorelockingfailure())
|
||||
return 0;
|
||||
|
||||
/* FIXME Ensure only read ops are permitted */
|
||||
log_verbose("Locking disabled - only read operations permitted.");
|
||||
|
||||
init_no_locking(&_locking, cft);
|
||||
init_no_locking(&_locking, cmd);
|
||||
init_lockingfailed(1);
|
||||
|
||||
return 1;
|
||||
@@ -189,7 +207,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
|
||||
if (!*vgname)
|
||||
return 1;
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
|
||||
if (dm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
|
||||
vgname) < 0) {
|
||||
log_error("LVM1 proc VG pathname too long for %s", vgname);
|
||||
return 0;
|
||||
@@ -231,7 +249,7 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
|
||||
|
||||
int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
|
||||
{
|
||||
char resource[258];
|
||||
char resource[258] __attribute((aligned(8)));
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_LOCKING_H
|
||||
#define _LVM_LOCKING_H
|
||||
|
||||
#include "uuid.h"
|
||||
#include "config.h"
|
||||
|
||||
int init_locking(int type, struct config_tree *cf);
|
||||
int init_locking(int type, struct cmd_context *cmd);
|
||||
void fin_locking(void);
|
||||
void reset_locking(void);
|
||||
int vg_write_lock_held(void);
|
||||
@@ -47,7 +50,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
|
||||
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
|
||||
/* LCK$_CWMODE */
|
||||
/* LCK$_PRMODE */
|
||||
#define LCK_PREAD 0x00000003 /* LCK$_PRMODE */
|
||||
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
|
||||
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
|
||||
#define LCK_UNLOCK 0x00000006 /* This is ours */
|
||||
@@ -67,6 +70,14 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
#define LCK_LOCAL 0x00000040 /* Don't propagate to other nodes */
|
||||
#define LCK_CLUSTER_VG 0x00000080 /* VG is clustered */
|
||||
|
||||
/*
|
||||
* Additional lock bits for cluster communication
|
||||
*/
|
||||
#define LCK_PARTIAL_MODE 0x00000001 /* Running in partial mode */
|
||||
#define LCK_MIRROR_NOSYNC_MODE 0x00000002 /* Mirrors don't require sync */
|
||||
#define LCK_DMEVENTD_MONITOR_MODE 0x00000004 /* Register with dmeventd */
|
||||
|
||||
|
||||
/*
|
||||
* Common combinations
|
||||
*/
|
||||
@@ -104,3 +115,4 @@ int suspend_lvs(struct cmd_context *cmd, struct list *lvs);
|
||||
int resume_lvs(struct cmd_context *cmd, struct list *lvs);
|
||||
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,10 +36,10 @@ struct locking_type {
|
||||
/*
|
||||
* Locking types
|
||||
*/
|
||||
int init_no_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_no_locking(struct locking_type *locking, struct cmd_context *cmd);
|
||||
|
||||
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_file_locking(struct locking_type *locking, struct cmd_context *cmd);
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_external_locking(struct locking_type *locking, struct cmd_context *cmd);
|
||||
|
||||
int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd);
|
||||
|
||||
@@ -76,12 +76,12 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_no_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
int init_no_locking(struct locking_type *locking, struct cmd_context *cmd)
|
||||
{
|
||||
locking->lock_resource = _no_lock_resource;
|
||||
locking->reset_locking = _no_reset_locking;
|
||||
locking->fin_locking = _no_fin_locking;
|
||||
locking->flags = 0;
|
||||
locking->flags = LCK_CLUSTERED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "device.h"
|
||||
#include "memlock.h"
|
||||
#include "lvm-string.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
@@ -31,6 +32,7 @@ static int _partial = 0;
|
||||
static int _md_filtering = 0;
|
||||
static int _pvmove = 0;
|
||||
static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */
|
||||
static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
|
||||
static int _debug_level = 0;
|
||||
static int _syslog = 0;
|
||||
static int _log_to_file = 0;
|
||||
@@ -45,6 +47,9 @@ static int _security_level = SECURITY_LEVEL;
|
||||
static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
static int _already_logging = 0;
|
||||
static int _mirror_in_sync = 0;
|
||||
static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _ignore_suspended_devices = 0;
|
||||
|
||||
static lvm2_log_fn_t _lvm2_log_fn = NULL;
|
||||
|
||||
@@ -90,9 +95,13 @@ void init_syslog(int facility)
|
||||
_syslog = 1;
|
||||
}
|
||||
|
||||
void log_suppress(int suppress)
|
||||
int log_suppress(int suppress)
|
||||
{
|
||||
int old_suppress = _log_suppress;
|
||||
|
||||
_log_suppress = suppress;
|
||||
|
||||
return old_suppress;
|
||||
}
|
||||
|
||||
void release_log_memory(void)
|
||||
@@ -112,7 +121,8 @@ void fin_log(void)
|
||||
}
|
||||
|
||||
if (_log_to_file) {
|
||||
fclose(_log_file);
|
||||
if (fclose(_log_file))
|
||||
fprintf(stderr, "fclose() on log file failed: %s", strerror(errno));
|
||||
_log_to_file = 0;
|
||||
}
|
||||
}
|
||||
@@ -156,6 +166,11 @@ void init_full_scan_done(int level)
|
||||
_full_scan_done = level;
|
||||
}
|
||||
|
||||
void init_trust_cache(int trustcache)
|
||||
{
|
||||
_trust_cache = trustcache;
|
||||
}
|
||||
|
||||
void init_ignorelockingfailure(int level)
|
||||
{
|
||||
_ignorelockingfailure = level;
|
||||
@@ -171,6 +186,21 @@ void init_security_level(int level)
|
||||
_security_level = level;
|
||||
}
|
||||
|
||||
void init_mirror_in_sync(int in_sync)
|
||||
{
|
||||
_mirror_in_sync = in_sync;
|
||||
}
|
||||
|
||||
void init_dmeventd_monitor(int reg)
|
||||
{
|
||||
_dmeventd_monitor = reg;
|
||||
}
|
||||
|
||||
void init_ignore_suspended_devices(int ignore)
|
||||
{
|
||||
_ignore_suspended_devices = ignore;
|
||||
}
|
||||
|
||||
void init_cmd_name(int status)
|
||||
{
|
||||
_log_cmd_name = status;
|
||||
@@ -220,6 +250,11 @@ int full_scan_done()
|
||||
return _full_scan_done;
|
||||
}
|
||||
|
||||
int trust_cache()
|
||||
{
|
||||
return _trust_cache;
|
||||
}
|
||||
|
||||
int lockingfailed()
|
||||
{
|
||||
return _lockingfailed;
|
||||
@@ -235,6 +270,21 @@ int security_level()
|
||||
return _security_level;
|
||||
}
|
||||
|
||||
int mirror_in_sync(void)
|
||||
{
|
||||
return _mirror_in_sync;
|
||||
}
|
||||
|
||||
int dmeventd_monitor_mode(void)
|
||||
{
|
||||
return _dmeventd_monitor;
|
||||
}
|
||||
|
||||
int ignore_suspended_devices(void)
|
||||
{
|
||||
return _ignore_suspended_devices;
|
||||
}
|
||||
|
||||
void init_debug(int level)
|
||||
{
|
||||
_debug_level = level;
|
||||
@@ -253,6 +303,9 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
const char *message;
|
||||
const char *trformat; /* Translated format string */
|
||||
|
||||
if (_log_suppress == 2)
|
||||
return;
|
||||
|
||||
trformat = _(format);
|
||||
|
||||
if (_lvm2_log_fn) {
|
||||
@@ -277,7 +330,7 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
log_it:
|
||||
if (!_log_suppress) {
|
||||
if (_verbose_level > _LOG_DEBUG)
|
||||
lvm_snprintf(locn, sizeof(locn), "#%s:%d ",
|
||||
dm_snprintf(locn, sizeof(locn), "#%s:%d ",
|
||||
file, line);
|
||||
else
|
||||
locn[0] = '\0';
|
||||
@@ -372,7 +425,7 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
_already_logging = 1;
|
||||
memset(&buf, ' ', sizeof(buf));
|
||||
bufused = 0;
|
||||
if ((n = lvm_snprintf(buf, sizeof(buf) - bufused - 1,
|
||||
if ((n = dm_snprintf(buf, sizeof(buf) - bufused - 1,
|
||||
"%s:%d %s%s", file, line, _cmd_name,
|
||||
_msg_prefix)) == -1)
|
||||
goto done;
|
||||
|
||||
@@ -66,6 +66,7 @@ void init_partial(int level);
|
||||
void init_md_filtering(int level);
|
||||
void init_pvmove(int level);
|
||||
void init_full_scan_done(int level);
|
||||
void init_trust_cache(int trustcache);
|
||||
void init_debug(int level);
|
||||
void init_cmd_name(int status);
|
||||
void init_msg_prefix(const char *prefix);
|
||||
@@ -73,6 +74,9 @@ void init_indent(int indent);
|
||||
void init_ignorelockingfailure(int level);
|
||||
void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
void init_mirror_in_sync(int in_sync);
|
||||
void init_dmeventd_monitor(int reg);
|
||||
void init_ignore_suspended_devices(int ignore);
|
||||
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
|
||||
@@ -81,13 +85,20 @@ int partial_mode(void);
|
||||
int md_filtering(void);
|
||||
int pvmove_mode(void);
|
||||
int full_scan_done(void);
|
||||
int trust_cache(void);
|
||||
int debug_level(void);
|
||||
int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
int mirror_in_sync(void);
|
||||
int ignore_suspended_devices(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr */
|
||||
void log_suppress(int suppress);
|
||||
#define DMEVENTD_MONITOR_IGNORE -1
|
||||
int dmeventd_monitor_mode(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr (1) or everywhere (2) */
|
||||
/* Returns previous setting */
|
||||
int log_suppress(int suppress);
|
||||
|
||||
/* Suppress messages to syslog */
|
||||
void syslog_suppress(int suppress);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#ifndef _LVM_LV_ALLOC_H
|
||||
|
||||
struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
|
||||
struct segment_type *segtype,
|
||||
const struct segment_type *segtype,
|
||||
struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len,
|
||||
uint32_t status,
|
||||
@@ -44,7 +44,7 @@ void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
|
||||
struct alloc_handle;
|
||||
struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t stripes,
|
||||
uint32_t mirrors, uint32_t log_count,
|
||||
uint32_t extents,
|
||||
@@ -58,7 +58,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
int lv_add_segment(struct alloc_handle *ah,
|
||||
uint32_t first_area, uint32_t num_areas,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t stripe_size,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
@@ -68,12 +68,12 @@ int lv_add_segment(struct alloc_handle *ah,
|
||||
|
||||
int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
|
||||
int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
|
||||
uint32_t extents, struct segment_type *segtype);
|
||||
uint32_t extents, const struct segment_type *segtype);
|
||||
int lv_add_mirror_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t mirrors,
|
||||
struct segment_type *segtype,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user