mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-24 16:23:50 +03:00
Compare commits
272 Commits
dm_v1_02_1
...
dm_v1_02_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd2a3f40e1 | ||
|
|
78f76c1690 | ||
|
|
4788066a5f | ||
|
|
10e4254e7d | ||
|
|
0106e4df9d | ||
|
|
8ac718a3a2 | ||
|
|
46d45273a1 | ||
|
|
8da9ec3599 | ||
|
|
01fdf84d69 | ||
|
|
cc78386e75 | ||
|
|
3755157c61 | ||
|
|
80f8436f0a | ||
|
|
f88a4b7760 | ||
|
|
de229b8ab0 | ||
|
|
a3ba37e45e | ||
|
|
50c779b3c6 | ||
|
|
192372e1c3 | ||
|
|
f88fd88c38 | ||
|
|
6e15145af1 | ||
|
|
4b5fad4e48 | ||
|
|
7a13e71c80 | ||
|
|
3c10943900 | ||
|
|
696b8811c2 | ||
|
|
9fd2c8602a | ||
|
|
a3636a5af4 | ||
|
|
f2e5f07718 | ||
|
|
16c6fdde60 | ||
|
|
2155c93426 | ||
|
|
c394631e4c | ||
|
|
8b370b7cc1 | ||
|
|
607db9971c | ||
|
|
6768f64e2f | ||
|
|
f1813b1cc6 | ||
|
|
fb665bd0dd | ||
|
|
65dda2ef3d | ||
|
|
b162b992af | ||
|
|
67a3a3d130 | ||
|
|
92cd9bf7d2 | ||
|
|
bf97034485 | ||
|
|
1ded1fc509 | ||
|
|
e0592c58b3 | ||
|
|
5ead2706b4 | ||
|
|
52ada4853c | ||
|
|
c2b27a8298 | ||
|
|
3934c1d437 | ||
|
|
e366b68ad3 | ||
|
|
fb94fb980a | ||
|
|
b10cc18f53 | ||
|
|
a249de3b72 | ||
|
|
d04e972d65 | ||
|
|
b9f5a18a76 | ||
|
|
d3f157f08a | ||
|
|
2294fdb496 | ||
|
|
d7ba0e01a5 | ||
|
|
b6172b53fd | ||
|
|
477ec611d5 | ||
|
|
b6194edd67 | ||
|
|
dcdbbb3ecb | ||
|
|
7ef99ee4e6 | ||
|
|
1ac1418286 | ||
|
|
8fc854f38e | ||
|
|
1c2360b335 | ||
|
|
dd4477406b | ||
|
|
9d67bbb104 | ||
|
|
d6c8e1df61 | ||
|
|
5ec7c8fece | ||
|
|
86b21eaf83 | ||
|
|
228486a971 | ||
|
|
88c0caab26 | ||
|
|
5cd4679419 | ||
|
|
eeed5e0d19 | ||
|
|
369ab1e0b2 | ||
|
|
2e21519a10 | ||
|
|
ecc001ed08 | ||
|
|
cd96852696 | ||
|
|
b9f7f30158 | ||
|
|
ca5e423331 | ||
|
|
fa9407089c | ||
|
|
66f28e193a | ||
|
|
0d93f89f5c | ||
|
|
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 |
@@ -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
|
||||
|
||||
208
WHATS_NEW
208
WHATS_NEW
@@ -1,6 +1,210 @@
|
||||
Version 2.02.12 -
|
||||
Version 2.02.26 - 15th June 2007
|
||||
================================
|
||||
Update vgcfgrestore man page.
|
||||
Allow keyboard interrupt during user prompts when appropriate.
|
||||
Remove unused clvmd system-lv code.
|
||||
Replace many physical_volume struct dereferences with new get_pv_* functions.
|
||||
Suppress a benign compile-time warning.
|
||||
Convert find_pv_in_vg_by_uuid and pv_create to use PV handles.
|
||||
Add wrappers to some functions in preparation for external LVM library.
|
||||
Add -f to vgcfgrestore to list metadata backup files.
|
||||
Add vg_check_status to consolidate vg status checks and error messages.
|
||||
Add pvdisplay --maps implementation.
|
||||
Remove unsupported LVM1 options from vgcfgrestore man page.
|
||||
Update vgcfgrestore man page to show mandatory VG name.
|
||||
Update vgrename man page to include UUID and be consistent with lvrename.
|
||||
Add (experimental) OpenAIS support to clvmd.
|
||||
Fix deactivation code to follow dependencies and remove symlinks.
|
||||
Fix and clarify vgsplit error messages.
|
||||
Fix a segfault in device_is_usable() if a device has no table.
|
||||
Add some more debug messages to clvmd startup.
|
||||
Misc clvmd cleanups.
|
||||
|
||||
Version 2.02.25 - 27th April 2007
|
||||
=================================
|
||||
Fix get_config_uint64() to read a 64-bit value not a 32-bit one.
|
||||
Add -Wformat-security and change one fprintf() to fputs().
|
||||
Move regex functions into libdevmapper.
|
||||
Change some #include lines to search only standard system directories.
|
||||
Add devices/preferred_names config regex list for displayed device names.
|
||||
Free a temporary dir string in fcntl_lock_file() after use.
|
||||
Fix a dm_pool_destroy() in matcher_create().
|
||||
Introduce goto_bad macro.
|
||||
Fix warnings on x86_64 involving ptrdiff_t in log_error messages.
|
||||
Update pvck to include text metadata area and record detection.
|
||||
Add support functions for token counting in config file extracts.
|
||||
Update pvck to read labels on disk, with --labelsector parameter.
|
||||
Add count_chars and count_chars_len functions.
|
||||
Add /sys/block listings to lvm_dump.sh.
|
||||
Make lvm_dump.sh list /dev recursively.
|
||||
Fix thread race in clvmd.
|
||||
Add scan_sector param to label_read and _find_labeller.
|
||||
Make clvmd cope with quorum devices.
|
||||
Add extra internal error checking to clvmd.
|
||||
Add dev_read_circular.
|
||||
Add pvck command stub.
|
||||
Update lists of attribute characters in man pages.
|
||||
Change cling alloc policy attribute character from 'C' to l'.
|
||||
Fix creation and conversion of mirrors with tags.
|
||||
Fix vgsplit for lvm1 format (set and validate VG name in PVs metadata).
|
||||
Split metadata areas in vgsplit properly.
|
||||
|
||||
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
|
||||
===================================
|
||||
Propogate clustered flag in vgsplit and require resizeable flag.
|
||||
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
|
||||
===================================
|
||||
|
||||
67
WHATS_NEW_DM
67
WHATS_NEW_DM
@@ -1,3 +1,70 @@
|
||||
Version 1.02.20 - 15th June 2007
|
||||
================================
|
||||
Fix default dmsetup report buffering and add --unbuffered.
|
||||
Add tree-based and dependency fields to dmsetup reports.
|
||||
|
||||
Version 1.02.19 - 27th April 2007
|
||||
=================================
|
||||
Standardise protective include file #defines.
|
||||
Add regex functions to library.
|
||||
Avoid trailing separator in reports when there are hidden sort fields.
|
||||
Fix segfault in 'dmsetup status' without --showkeys against crypt target.
|
||||
Deal with some more compiler warnings.
|
||||
Introduce _add_field() and _is_same_field() to libdm-report.c.
|
||||
Fix some libdevmapper-event and dmeventd memory leaks.
|
||||
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.
|
||||
|
||||
29
configure
vendored
29
configure
vendored
@@ -310,7 +310,7 @@ ac_includes_default="\
|
||||
#endif"
|
||||
|
||||
ac_default_prefix=/usr
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR DMDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
|
||||
ac_subst_files=''
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@@ -883,6 +883,7 @@ Optional Packages:
|
||||
--with-localedir=DIR Translation files in DIR PREFIX/share/locale
|
||||
--with-confdir=DIR Configuration files in DIR /etc
|
||||
--with-staticdir=DIR Static binary in DIR EXEC_PREFIX/sbin
|
||||
--with-dmdir=DIR Build against device-mapper source tree in DIR
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
@@ -8267,8 +8268,6 @@ fi
|
||||
|
||||
################################################################################
|
||||
if test x$SELINUX = xyes; then
|
||||
echo "$as_me:$LINENO: checking for sepol_check_context function" >&5
|
||||
echo $ECHO_N "checking for sepol_check_context function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for sepol_check_context in -lsepol" >&5
|
||||
echo $ECHO_N "checking for sepol_check_context in -lsepol... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then
|
||||
@@ -8339,15 +8338,11 @@ else
|
||||
HAVE_SEPOL=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_SEPOL" >&5
|
||||
echo "${ECHO_T}$HAVE_SEPOL" >&6
|
||||
|
||||
if test x$HAVE_SEPOL = xyes; then
|
||||
LIBS="-lsepol $LIBS"
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: checking for is_selinux_enabled function" >&5
|
||||
echo $ECHO_N "checking for is_selinux_enabled function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5
|
||||
echo $ECHO_N "checking for is_selinux_enabled in -lselinux... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then
|
||||
@@ -8418,8 +8413,6 @@ else
|
||||
HAVE_SELINUX=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_SELINUX" >&5
|
||||
echo "${ECHO_T}$HAVE_SELINUX" >&6
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
|
||||
@@ -8436,8 +8429,6 @@ fi
|
||||
|
||||
################################################################################
|
||||
if test x$REALTIME = xyes; then
|
||||
echo "$as_me:$LINENO: checking for clock_gettime function" >&5
|
||||
echo $ECHO_N "checking for clock_gettime function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
|
||||
echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
|
||||
@@ -8508,8 +8499,6 @@ else
|
||||
HAVE_REALTIME=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_REALTIME" >&5
|
||||
echo "${ECHO_T}$HAVE_REALTIME" >&6
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
|
||||
@@ -8964,6 +8953,15 @@ else
|
||||
STATICDIR='${exec_prefix}/sbin'
|
||||
fi;
|
||||
|
||||
|
||||
# Check whether --with-dmdir or --without-dmdir was given.
|
||||
if test "${with_dmdir+set}" = set; then
|
||||
withval="$with_dmdir"
|
||||
DMDIR="$withval"
|
||||
else
|
||||
DMDIR=
|
||||
fi;
|
||||
|
||||
################################################################################
|
||||
if test x$READLINE = xyes; then
|
||||
|
||||
@@ -11200,10 +11198,11 @@ fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile scripts/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
# tests run on this system so they can be shared between configure
|
||||
@@ -11745,6 +11744,7 @@ do
|
||||
"lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
|
||||
"man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
|
||||
"po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
|
||||
"scripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
|
||||
"tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
|
||||
"tools/version.h" ) CONFIG_FILES="$CONFIG_FILES tools/version.h" ;;
|
||||
"tools/fsadm/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/fsadm/Makefile" ;;
|
||||
@@ -11899,6 +11899,7 @@ s,@CMDLIB@,$CMDLIB,;t t
|
||||
s,@LOCALEDIR@,$LOCALEDIR,;t t
|
||||
s,@CONFDIR@,$CONFDIR,;t t
|
||||
s,@STATICDIR@,$STATICDIR,;t t
|
||||
s,@DMDIR@,$DMDIR,;t t
|
||||
s,@INTL_PACKAGE@,$INTL_PACKAGE,;t t
|
||||
s,@INTL@,$INTL,;t t
|
||||
s,@CLVMD@,$CLVMD,;t t
|
||||
|
||||
13
configure.in
13
configure.in
@@ -438,17 +438,13 @@ fi
|
||||
################################################################################
|
||||
dnl -- Check for selinux
|
||||
if test x$SELINUX = xyes; then
|
||||
AC_MSG_CHECKING(for sepol_check_context function)
|
||||
AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no)
|
||||
AC_MSG_RESULT($HAVE_SEPOL)
|
||||
|
||||
if test x$HAVE_SEPOL = xyes; then
|
||||
LIBS="-lsepol $LIBS"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for is_selinux_enabled function)
|
||||
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
|
||||
AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.])
|
||||
@@ -461,9 +457,7 @@ fi
|
||||
################################################################################
|
||||
dnl -- Check for realtime clock support
|
||||
if test x$REALTIME = xyes; then
|
||||
AC_MSG_CHECKING(for clock_gettime function)
|
||||
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
|
||||
AC_MSG_RESULT($HAVE_REALTIME)
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||
@@ -526,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
|
||||
@@ -608,6 +607,7 @@ 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)
|
||||
@@ -637,6 +637,7 @@ lib/mirror/Makefile \
|
||||
lib/snapshot/Makefile \
|
||||
man/Makefile \
|
||||
po/Makefile \
|
||||
scripts/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
tools/fsadm/Makefile \
|
||||
|
||||
@@ -19,8 +19,7 @@ SOURCES = \
|
||||
clvmd-command.c \
|
||||
clvmd.c \
|
||||
lvm-functions.c \
|
||||
refresh_clvmd.c \
|
||||
system-lv.c
|
||||
refresh_clvmd.c
|
||||
|
||||
ifeq ("@CLVMD@", "gulm")
|
||||
GULM = yes
|
||||
@@ -30,9 +29,16 @@ ifeq ("@CLVMD@", "cman")
|
||||
CMAN = yes
|
||||
endif
|
||||
|
||||
ifeq ("@CLVMD@", "openais")
|
||||
OPENAIS = yes
|
||||
GULM = no
|
||||
CMAN = no
|
||||
endif
|
||||
|
||||
ifeq ("@CLVMD@", "all")
|
||||
GULM = yes
|
||||
CMAN = yes
|
||||
OPENAIS = no
|
||||
endif
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
@@ -51,6 +57,12 @@ ifeq ("$(CMAN)", "yes")
|
||||
DEFS += -DUSE_CMAN
|
||||
endif
|
||||
|
||||
ifeq ("$(OPENAIS)", "yes")
|
||||
SOURCES += clvmd-openais.c
|
||||
LMLIBS += -lSaLck -lSaClm -lcpg
|
||||
DEFS += -DUSE_OPENAIS
|
||||
endif
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
@@ -71,7 +83,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
|
||||
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
@@ -58,7 +58,7 @@ 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 nodeid_from_csid(const char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
@@ -78,6 +78,7 @@ static int _init_cluster(void)
|
||||
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Connected to CMAN\n");
|
||||
|
||||
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
|
||||
syslog(LOG_ERR, "Can't bind cluster socket: %m");
|
||||
@@ -93,6 +94,8 @@ static int _init_cluster(void)
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
|
||||
DEBUGLOG("CMAN initialisation complete\n");
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
@@ -100,7 +103,7 @@ static int _init_cluster(void)
|
||||
return -1;
|
||||
}
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -121,14 +124,15 @@ static int _get_num_nodes()
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member)
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
int nodeid = 0;
|
||||
|
||||
@@ -137,7 +141,7 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
|
||||
|
||||
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
|
||||
{
|
||||
log_error(errtext);
|
||||
log_error("%s", errtext);
|
||||
}
|
||||
return msglen;
|
||||
}
|
||||
@@ -152,14 +156,15 @@ static void _get_our_csid(char *csid)
|
||||
|
||||
/* 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 *,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
if (nodes[i].cn_member) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid) {
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
|
||||
if (!node_updown[nodes[i].cn_nodeid])
|
||||
somedown = -1;
|
||||
@@ -168,8 +173,7 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
/* Process OOB messages from the cluster socket */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
@@ -206,7 +210,8 @@ static void event_callback(cman_handle_t handle, void *private, int reason, int
|
||||
}
|
||||
|
||||
static struct local_client *cman_client;
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
|
||||
@@ -229,7 +234,7 @@ static void data_callback(cman_handle_t handle, void *private,
|
||||
process_message(cman_client, buf, len, (char *)&nodeid);
|
||||
}
|
||||
|
||||
static void _add_up_node(char *csid)
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
/* It's up ! */
|
||||
int nodeid = nodeid_from_csid(csid);
|
||||
@@ -321,17 +326,16 @@ static void get_members()
|
||||
}
|
||||
|
||||
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));
|
||||
size_t buf_len = sizeof(int) * max(num_nodes, max_updown_nodes);
|
||||
node_updown = malloc(buf_len);
|
||||
if (node_updown)
|
||||
memset(node_updown, 0, buf_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
static int _csid_from_name(char *csid, char *name)
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -345,7 +349,7 @@ static int _csid_from_name(char *csid, char *name)
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node name */
|
||||
static int _name_from_csid(char *csid, char *name)
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -377,7 +381,7 @@ static int name_from_nodeid(int nodeid, char *name)
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node ID */
|
||||
static int nodeid_from_csid(char *csid)
|
||||
static int nodeid_from_csid(const char *csid)
|
||||
{
|
||||
int nodeid;
|
||||
|
||||
|
||||
@@ -64,8 +64,9 @@
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
@@ -73,7 +74,6 @@
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
|
||||
@@ -95,13 +95,22 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
/* Just a test message */
|
||||
case CLVMD_CMD_TEST:
|
||||
if (arglen > buflen) {
|
||||
char *new_buf;
|
||||
buflen = arglen + 200;
|
||||
*buf = realloc(*buf, buflen);
|
||||
new_buf = realloc(*buf, buflen);
|
||||
if (new_buf == NULL) {
|
||||
status = errno;
|
||||
free (*buf);
|
||||
}
|
||||
*buf = new_buf;
|
||||
}
|
||||
if (*buf) {
|
||||
uname(&nodeinfo);
|
||||
*retlen = 1 + snprintf(*buf, buflen,
|
||||
"TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
}
|
||||
uname(&nodeinfo);
|
||||
*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
@@ -118,7 +127,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
/* Replace EIO with something less scary */
|
||||
if (status == EIO) {
|
||||
*retlen =
|
||||
1 + snprintf(*buf, buflen,
|
||||
1 + snprintf(*buf, buflen, "%s",
|
||||
get_last_lvm_error());
|
||||
return EIO;
|
||||
}
|
||||
@@ -131,7 +140,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
status = clops->get_cluster_name(*buf, buflen);
|
||||
if (!status)
|
||||
*retlen = strlen(*buf);
|
||||
*retlen = strlen(*buf)+1;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -141,7 +150,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
|
||||
/* Check the status of the command and return the error text */
|
||||
if (status) {
|
||||
*retlen = 1 + snprintf(*buf, buflen, strerror(status));
|
||||
*retlen = 1 + snprintf(*buf, buflen, "%s", strerror(status));
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -191,12 +200,16 @@ static int lock_vg(struct local_client *client)
|
||||
dm_hash_remove(lock_hash, lockname);
|
||||
}
|
||||
else {
|
||||
|
||||
/* 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;
|
||||
@@ -220,7 +233,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:
|
||||
|
||||
@@ -25,27 +25,31 @@ struct local_client;
|
||||
struct cluster_ops {
|
||||
void (*cluster_init_completed) (void);
|
||||
|
||||
int (*cluster_send_message) (void *buf, int msglen, char *csid,
|
||||
const char *errtext);
|
||||
int (*name_from_csid) (char *csid, char *name);
|
||||
int (*csid_from_name) (char *csid, char *name);
|
||||
int (*cluster_send_message) (const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext);
|
||||
int (*name_from_csid) (const char *csid, char *name);
|
||||
int (*csid_from_name) (char *csid, const char *name);
|
||||
int (*get_num_nodes) (void);
|
||||
int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
|
||||
char *csid, struct local_client **new_client);
|
||||
const char *csid,
|
||||
struct local_client **new_client);
|
||||
int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */
|
||||
int (*cluster_do_node_callback) (struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
char *csid, int node_up));
|
||||
void (*callback) (struct local_client *,
|
||||
const char *csid,
|
||||
int node_up));
|
||||
int (*is_quorate) (void);
|
||||
|
||||
void (*get_our_csid) (char *csid);
|
||||
void (*add_up_node) (char *csid);
|
||||
void (*add_up_node) (const char *csid);
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*get_cluster_name)(char *buf, int buflen);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
|
||||
int (*sync_lock) (const char *resource, int mode,
|
||||
int flags, int *lockid);
|
||||
int (*sync_unlock) (const char *resource, int lockid);
|
||||
|
||||
};
|
||||
@@ -71,6 +75,23 @@ struct cluster_ops *init_gulm_cluster(void);
|
||||
struct cluster_ops *init_cman_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENAIS
|
||||
# include <openais/saAis.h>
|
||||
# include <openais/totem/totem.h>
|
||||
# define OPENAIS_CSID_LEN (sizeof(int))
|
||||
# define OPENAIS_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_openais_cluster(void);
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,9 +40,10 @@
|
||||
#include <utmpx.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <ccs.h>
|
||||
#include <libgulm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "ccs.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
@@ -51,7 +52,6 @@
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "libgulm.h"
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
756
daemons/clvmd/clvmd-openais.c
Normal file
756
daemons/clvmd/clvmd-openais.c
Normal file
@@ -0,0 +1,756 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) 2007 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* This provides the interface between clvmd and OpenAIS as the cluster
|
||||
* and lock manager.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <utmpx.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
|
||||
#include <openais/saAis.h>
|
||||
#include <openais/saLck.h>
|
||||
#include <openais/saClm.h>
|
||||
#include <openais/cpg.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
/* Timeout value for several openais calls */
|
||||
#define TIMEOUT 10
|
||||
|
||||
static void lck_lock_callback(SaInvocationT invocation,
|
||||
SaLckLockStatusT lockStatus,
|
||||
SaAisErrorT error);
|
||||
static void lck_unlock_callback(SaInvocationT invocation,
|
||||
SaAisErrorT error);
|
||||
static void cpg_deliver_callback (cpg_handle_t handle,
|
||||
struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
int msg_len);
|
||||
static void cpg_confchg_callback(cpg_handle_t handle,
|
||||
struct cpg_name *groupName,
|
||||
struct cpg_address *member_list, int member_list_entries,
|
||||
struct cpg_address *left_list, int left_list_entries,
|
||||
struct cpg_address *joined_list, int joined_list_entries);
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* For associating lock IDs & resource handles */
|
||||
static struct dm_hash_table *lock_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* OpenAIS handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static SaLckHandleT lck_handle;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Openais callback structs */
|
||||
cpg_callbacks_t cpg_callbacks = {
|
||||
.cpg_deliver_fn = cpg_deliver_callback,
|
||||
.cpg_confchg_fn = cpg_confchg_callback,
|
||||
};
|
||||
|
||||
SaLckCallbacksT lck_callbacks = {
|
||||
.saLckLockGrantCallback = lck_lock_callback,
|
||||
.saLckResourceUnlockCallback = lck_unlock_callback
|
||||
};
|
||||
|
||||
/* We only call Clm to get our node id */
|
||||
SaClmCallbacksT clm_callbacks;
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
struct lock_info
|
||||
{
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaLckLockIdT lock_id;
|
||||
SaNameT lock_name;
|
||||
};
|
||||
|
||||
struct lock_wait
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
int status;
|
||||
};
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int ais_to_errno(SaAisErrorT err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case SA_AIS_OK:
|
||||
return 0;
|
||||
case SA_AIS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case SA_AIS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case SA_AIS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case SA_AIS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case SA_AIS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case SA_AIS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int add_internal_client(int fd, fd_callback_t callback)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
|
||||
|
||||
client = malloc(sizeof(struct local_client));
|
||||
if (!client)
|
||||
{
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(client, 0, sizeof(struct local_client));
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_INTERNAL;
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpg_deliver_callback (cpg_handle_t handle,
|
||||
struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
int msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("Got message from nodeid %d for %d. len %d\n",
|
||||
nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (target_nodeid == our_nodeid)
|
||||
process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
|
||||
msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void cpg_confchg_callback(cpg_handle_t handle,
|
||||
struct cpg_name *groupName,
|
||||
struct cpg_address *member_list, int member_list_entries,
|
||||
struct cpg_address *left_list, int left_list_entries,
|
||||
struct cpg_address *joined_list, int joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %d joined, %d left, %d members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
num_nodes = joined_list_entries;
|
||||
}
|
||||
|
||||
static void lck_lock_callback(SaInvocationT invocation,
|
||||
SaLckLockStatusT lockStatus,
|
||||
SaAisErrorT error)
|
||||
{
|
||||
struct lock_wait *lwait = (struct lock_wait *)(long)invocation;
|
||||
|
||||
DEBUGLOG("lck_lock_callback, error = %d\n", error);
|
||||
|
||||
lwait->status = error;
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
}
|
||||
|
||||
static void lck_unlock_callback(SaInvocationT invocation,
|
||||
SaAisErrorT error)
|
||||
{
|
||||
struct lock_wait *lwait = (struct lock_wait *)(long)invocation;
|
||||
|
||||
DEBUGLOG("lck_unlock_callback\n");
|
||||
|
||||
lwait->status = SA_AIS_OK;
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
}
|
||||
|
||||
static int lck_dispatch(struct local_client *client, char *buf, int len,
|
||||
const char *csid, struct local_client **new_client)
|
||||
{
|
||||
*new_client = NULL;
|
||||
saLckDispatch(lck_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
SaVersionT ver = { 'B', 1, 1 };
|
||||
SaClmHandleT clm_handle;
|
||||
int select_fd;
|
||||
SaClmClusterNodeT cluster_node;
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
lock_hash = dm_hash_create(10);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&cpg_callbacks);
|
||||
if (err != SA_AIS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckInitialize(&lck_handle,
|
||||
&lck_callbacks,
|
||||
&ver);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_initialize(&cpg_handle, &cpg_callbacks);
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group\n");
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* A brief foray into Clm to get our node id */
|
||||
err = saClmInitialize(&clm_handle, &clm_callbacks, &ver);
|
||||
if (err != SA_AIS_OK) {
|
||||
syslog(LOG_ERR, "Could not initialize OpenAIS membership service %d\n", err);
|
||||
DEBUGLOG("Could not initialize OpenAIS Membership service %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saClmClusterNodeGet(clm_handle,
|
||||
SA_CLM_LOCAL_NODE_ID,
|
||||
TIMEOUT,
|
||||
&cluster_node);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
saClmFinalize(clm_handle);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
saClmFinalize(clm_handle);
|
||||
our_nodeid = cluster_node.nodeId;
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
|
||||
add_internal_client(select_fd, lck_dispatch);
|
||||
|
||||
DEBUGLOG("Connected to OpenAIS\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
DEBUGLOG("cluster_closedown\n");
|
||||
unlock_all();
|
||||
|
||||
saLckFinalize(lck_handle);
|
||||
cpg_inalize(cpg_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* OpenAIS doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes()
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
|
||||
print_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[OPENAIS_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct lock_wait lwait;
|
||||
struct lock_info *linfo;
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaAisErrorT err;
|
||||
SaLckLockIdT lock_id;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
|
||||
if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
|
||||
|
||||
linfo = malloc(sizeof(struct lock_info));
|
||||
if (!linfo)
|
||||
return -1;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
linfo->lock_name.length = strlen(resource)+1;
|
||||
strcpy((char *)linfo->lock_name.value, resource);
|
||||
|
||||
err = saLckResourceOpen(lck_handle, &linfo->lock_name,
|
||||
SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("ResourceOpen returned %d\n", err);
|
||||
free(linfo);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckResourceLockAsync(res_handle,
|
||||
(SaInvocationT)(long)&lwait,
|
||||
&lock_id,
|
||||
mode,
|
||||
flags,
|
||||
0);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
free(linfo);
|
||||
saLckResourceClose(res_handle);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%llx\n", lwait.status,
|
||||
lock_id);
|
||||
|
||||
linfo->lock_id = lock_id;
|
||||
linfo->res_handle = res_handle;
|
||||
|
||||
dm_hash_insert(lock_hash, resource, linfo);
|
||||
|
||||
return ais_to_errno(lwait.status);
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(char *resource, int lockid)
|
||||
{
|
||||
struct lock_wait lwait;
|
||||
SaAisErrorT err;
|
||||
struct lock_info *linfo;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
DEBUGLOG("unlock_resource %s\n", resource);
|
||||
linfo = dm_hash_lookup(lock_hash, resource);
|
||||
if (!linfo)
|
||||
return 0;
|
||||
|
||||
DEBUGLOG("unlock_resource: lockid: %llx\n", linfo->lock_id);
|
||||
err = saLckResourceUnlockAsync((SaInvocationT)(long)&lwait, linfo->lock_id);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
/* Release the resource */
|
||||
dm_hash_remove(lock_hash, resource);
|
||||
saLckResourceClose(linfo->res_handle);
|
||||
free(linfo);
|
||||
|
||||
return ais_to_errno(lwait.status);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock too then bail out */
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
|
||||
lockid);
|
||||
if (status == SA_LCK_LOCK_NOT_QUEUED)
|
||||
{
|
||||
_unlock_resource(lock1, *lockid);
|
||||
status = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_PREAD:
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock2, *lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock1, *lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*lockid = mode;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource, int lockid)
|
||||
{
|
||||
int status = 0;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
_unlock_resource(lock1, lockid);
|
||||
_unlock_resource(lock2, lockid);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* We are always quorate ! */
|
||||
static int _is_quorate()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
SaAisErrorT err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, OPENAIS_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* We don't have a cluster name to report here */
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
strncpy(buf, "OpenAIS", buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_openais_ops = {
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_openais_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_openais_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -30,12 +30,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
@@ -43,8 +45,6 @@
|
||||
#include "version.h"
|
||||
#include "clvmd.h"
|
||||
#include "refresh_clvmd.h"
|
||||
#include "libdlm.h"
|
||||
#include "system-lv.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
@@ -55,9 +55,7 @@
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* The maximum size of a message that will fit into a packet. Anything bigger
|
||||
than this is sent via the system LV */
|
||||
#define MAX_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
|
||||
#define MAX_RETRIES 4
|
||||
|
||||
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
|
||||
|
||||
@@ -85,6 +83,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;
|
||||
@@ -99,6 +98,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 */
|
||||
@@ -110,31 +110,32 @@ static void send_local_reply(struct local_client *client, int status,
|
||||
static void free_reply(struct local_client *client);
|
||||
static void send_version_message(void);
|
||||
static void *pre_and_post_thread(void *arg);
|
||||
static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
static int send_message(void *buf, int msglen, const char *csid, int fd,
|
||||
const char *errtext);
|
||||
static int read_from_local_sock(struct local_client *thisfd);
|
||||
static int process_local_command(struct clvm_header *msg, int msglen,
|
||||
struct local_client *client,
|
||||
unsigned short xid);
|
||||
static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
char *csid);
|
||||
static int process_reply(struct clvm_header *msg, int msglen, char *csid);
|
||||
const char *csid);
|
||||
static int process_reply(const struct clvm_header *msg, int msglen,
|
||||
const 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,
|
||||
int len, const char *csid,
|
||||
struct local_client **new_client);
|
||||
static void *lvm_thread_fn(void *);
|
||||
static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
|
||||
int msglen, char *csid);
|
||||
int msglen, const char *csid);
|
||||
static int distribute_command(struct local_client *thisfd);
|
||||
static void hton_clvm(struct clvm_header *hdr);
|
||||
static void ntoh_clvm(struct clvm_header *hdr);
|
||||
static void add_reply_to_list(struct local_client *client, int status,
|
||||
char *csid, const char *buf, int len);
|
||||
const char *csid, const char *buf, int len);
|
||||
|
||||
static void usage(char *prog, FILE *file)
|
||||
{
|
||||
@@ -146,6 +147,7 @@ static void usage(char *prog, FILE *file)
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -161,21 +163,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:R")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:RT:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@@ -200,6 +217,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);
|
||||
@@ -214,7 +239,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");
|
||||
@@ -266,6 +291,15 @@ int main(int argc, char *argv[])
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_OPENAIS
|
||||
if (!clops)
|
||||
if ((clops = init_openais_cluster())) {
|
||||
max_csid_len = OPENAIS_CSID_LEN;
|
||||
max_cluster_message = OPENAIS_MAX_CLUSTER_MESSAGE;
|
||||
max_cluster_member_name_len = OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to OpenAIS");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!clops) {
|
||||
DEBUGLOG("Can't initialise cluster interface\n");
|
||||
@@ -298,7 +332,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
|
||||
@@ -329,7 +364,8 @@ void clvmd_cluster_init_completed()
|
||||
|
||||
/* Data on a connected socket */
|
||||
static int local_sock_callback(struct local_client *thisfd, char *buf, int len,
|
||||
char *csid, struct local_client **new_client)
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
*new_client = NULL;
|
||||
return read_from_local_sock(thisfd);
|
||||
@@ -337,7 +373,7 @@ static int local_sock_callback(struct local_client *thisfd, char *buf, int len,
|
||||
|
||||
/* Data on a connected socket */
|
||||
static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
int len, char *csid,
|
||||
int len, const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
/* Someone connected to our local socket, accept it. */
|
||||
@@ -347,6 +383,9 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
socklen_t sl = sizeof(socka);
|
||||
int client_fd = accept(thisfd->fd, (struct sockaddr *) &socka, &sl);
|
||||
|
||||
if (client_fd == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
if (client_fd >= 0) {
|
||||
newfd = malloc(sizeof(struct local_client));
|
||||
if (!newfd) {
|
||||
@@ -375,7 +414,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
}
|
||||
|
||||
static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
int maxlen, char *csid,
|
||||
int maxlen, const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int len;
|
||||
@@ -384,17 +423,20 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
int status = -1; /* in error by default */
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(int));
|
||||
|
||||
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
|
||||
thisfd->fd, len, *(int *) buffer);
|
||||
if (len == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
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 */
|
||||
@@ -404,9 +446,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.
|
||||
@@ -450,7 +490,7 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
add one with "ETIMEDOUT".
|
||||
NOTE: This won't race with real replies because they happen in the same thread.
|
||||
*/
|
||||
static void timedout_callback(struct local_client *client, char *csid,
|
||||
static void timedout_callback(struct local_client *client, const char *csid,
|
||||
int node_up)
|
||||
{
|
||||
if (node_up) {
|
||||
@@ -647,16 +687,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");
|
||||
@@ -676,36 +766,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 */
|
||||
@@ -738,6 +799,8 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
char buffer[PIPE_BUF];
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(buffer));
|
||||
if (len == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len);
|
||||
|
||||
@@ -853,8 +916,12 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
len - strlen(inheader->node) - sizeof(struct clvm_header);
|
||||
missing_len = inheader->arglen - argslen;
|
||||
|
||||
if (missing_len < 0)
|
||||
missing_len = 0;
|
||||
|
||||
/* Save the message */
|
||||
thisfd->bits.localsock.cmd = malloc(len + missing_len);
|
||||
|
||||
if (!thisfd->bits.localsock.cmd) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
@@ -879,9 +946,8 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
DEBUGLOG
|
||||
("got %d bytes, need another %d (total %d)\n",
|
||||
argslen, missing_len, inheader->arglen);
|
||||
len =
|
||||
read(thisfd->fd, argptr + argslen,
|
||||
missing_len);
|
||||
len = read(thisfd->fd, argptr + argslen,
|
||||
missing_len);
|
||||
if (len >= 0) {
|
||||
missing_len -= len;
|
||||
argslen += len;
|
||||
@@ -991,31 +1057,6 @@ int add_client(struct local_client *new_client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send a long message using the System LV
|
||||
*/
|
||||
static int send_long_message(struct local_client *thisfd, struct clvm_header *inheader, int len)
|
||||
{
|
||||
struct clvm_header new_header;
|
||||
int status;
|
||||
|
||||
DEBUGLOG("Long message: being sent via system LV:\n");
|
||||
|
||||
/* Use System LV */
|
||||
status = system_lv_write_data((char *)inheader, len);
|
||||
if (status < 0)
|
||||
return errno;
|
||||
|
||||
/* Send message indicating System-LV is being used */
|
||||
memcpy(&new_header, inheader, sizeof(new_header));
|
||||
new_header.flags |= CLVMD_FLAG_SYSTEMLV;
|
||||
new_header.xid = thisfd->xid;
|
||||
|
||||
return send_message(&new_header, sizeof(new_header), NULL, -1,
|
||||
"Error forwarding long message to cluster");
|
||||
}
|
||||
|
||||
/* Called when the pre-command has completed successfully - we
|
||||
now execute the real command on all the requested nodes */
|
||||
static int distribute_command(struct local_client *thisfd)
|
||||
@@ -1042,13 +1083,9 @@ static int distribute_command(struct local_client *thisfd)
|
||||
add_to_lvmqueue(thisfd, inheader, len, NULL);
|
||||
|
||||
DEBUGLOG("Sending message to all cluster nodes\n");
|
||||
if (len > MAX_INLINE_MESSAGE) {
|
||||
send_long_message(thisfd, inheader, len );
|
||||
} else {
|
||||
inheader->xid = thisfd->xid;
|
||||
send_message(inheader, len, NULL, -1,
|
||||
"Error forwarding message to cluster");
|
||||
}
|
||||
inheader->xid = thisfd->xid;
|
||||
send_message(inheader, len, NULL, -1,
|
||||
"Error forwarding message to cluster");
|
||||
} else {
|
||||
/* Do it on a single node */
|
||||
char csid[MAX_CSID_LEN];
|
||||
@@ -1069,14 +1106,10 @@ static int distribute_command(struct local_client *thisfd)
|
||||
} else {
|
||||
DEBUGLOG("Sending message to single node: %s\n",
|
||||
inheader->node);
|
||||
if (len > MAX_INLINE_MESSAGE) {
|
||||
send_long_message(thisfd, inheader, len );
|
||||
} else {
|
||||
inheader->xid = thisfd->xid;
|
||||
send_message(inheader, len,
|
||||
csid, -1,
|
||||
"Error forwarding message to cluster node");
|
||||
}
|
||||
inheader->xid = thisfd->xid;
|
||||
send_message(inheader, len,
|
||||
csid, -1,
|
||||
"Error forwarding message to cluster node");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1091,8 +1124,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,
|
||||
const char *csid)
|
||||
{
|
||||
char *replyargs;
|
||||
char nodename[max_cluster_member_name_len];
|
||||
@@ -1107,54 +1140,6 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
DEBUGLOG("process_remote_command %d for clientid 0x%x XID %d on node %s\n",
|
||||
msg->cmd, msg->clientid, msg->xid, nodename);
|
||||
|
||||
/* Is the data to be found in the system LV ? */
|
||||
if (msg->flags & CLVMD_FLAG_SYSTEMLV) {
|
||||
struct clvm_header *newmsg;
|
||||
|
||||
DEBUGLOG("Reading message from system LV\n");
|
||||
newmsg =
|
||||
(struct clvm_header *) malloc(msg->arglen +
|
||||
sizeof(struct clvm_header));
|
||||
if (newmsg) {
|
||||
if (system_lv_read_data
|
||||
(nodename, (char *) newmsg,
|
||||
(size_t *) &msglen) == 0) {
|
||||
msg = newmsg;
|
||||
msg_malloced = 1;
|
||||
} else {
|
||||
struct clvm_header head;
|
||||
DEBUGLOG("System LV read failed\n");
|
||||
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = EFBIG;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
head.node[0] = '\0';
|
||||
send_message(&head, sizeof(struct clvm_header),
|
||||
csid, fd,
|
||||
"Error sending ENOMEM command reply");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
struct clvm_header head;
|
||||
DEBUGLOG
|
||||
("Error attempting to malloc %d bytes for system LV read\n",
|
||||
msg->arglen);
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = ENOMEM;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
head.node[0] = '\0';
|
||||
send_message(&head, sizeof(struct clvm_header), csid,
|
||||
fd, "Error sending ENOMEM command reply");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for GOAWAY and sulk */
|
||||
if (msg->cmd == CLVMD_CMD_GOAWAY) {
|
||||
|
||||
@@ -1166,8 +1151,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,
|
||||
@@ -1226,40 +1214,16 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
replyargs, replylen);
|
||||
|
||||
agghead->xid = msg->xid;
|
||||
|
||||
/* Use the system LV ? */
|
||||
if (replylen > MAX_INLINE_MESSAGE) {
|
||||
agghead->cmd = CLVMD_CMD_REPLY;
|
||||
agghead->status = status;
|
||||
agghead->flags = CLVMD_FLAG_SYSTEMLV;
|
||||
agghead->clientid = msg->clientid;
|
||||
agghead->arglen = replylen;
|
||||
agghead->node[0] = '\0';
|
||||
|
||||
/* If System LV operation failed then report it as EFBIG but only do it
|
||||
if the data buffer has something in it. */
|
||||
if (system_lv_write_data(aggreply,
|
||||
replylen + sizeof(struct clvm_header)) < 0
|
||||
&& replylen > 0)
|
||||
agghead->status = EFBIG;
|
||||
|
||||
send_message(agghead,
|
||||
sizeof(struct clvm_header), csid,
|
||||
fd,
|
||||
"Error sending long command reply");
|
||||
|
||||
} else {
|
||||
agghead->cmd = CLVMD_CMD_REPLY;
|
||||
agghead->status = status;
|
||||
agghead->flags = 0;
|
||||
agghead->clientid = msg->clientid;
|
||||
agghead->arglen = replylen;
|
||||
agghead->node[0] = '\0';
|
||||
send_message(aggreply,
|
||||
sizeof(struct clvm_header) +
|
||||
replylen, csid, fd,
|
||||
"Error sending command reply");
|
||||
}
|
||||
agghead->cmd = CLVMD_CMD_REPLY;
|
||||
agghead->status = status;
|
||||
agghead->flags = 0;
|
||||
agghead->clientid = msg->clientid;
|
||||
agghead->arglen = replylen;
|
||||
agghead->node[0] = '\0';
|
||||
send_message(aggreply,
|
||||
sizeof(struct clvm_header) +
|
||||
replylen, csid, fd,
|
||||
"Error sending command reply");
|
||||
} else {
|
||||
struct clvm_header head;
|
||||
|
||||
@@ -1288,7 +1252,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
If we have got a full set then send them to the waiting client down the local
|
||||
socket */
|
||||
static void add_reply_to_list(struct local_client *client, int status,
|
||||
char *csid, const char *buf, int len)
|
||||
const char *csid, const char *buf, int len)
|
||||
{
|
||||
struct node_reply *reply;
|
||||
|
||||
@@ -1339,10 +1303,11 @@ 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;
|
||||
int write_status;
|
||||
sigset_t ss;
|
||||
int pipe_fd = client->bits.localsock.pipe;
|
||||
|
||||
@@ -1372,8 +1337,21 @@ static void *pre_and_post_thread(void *arg)
|
||||
client->bits.localsock.all_success = 0;
|
||||
|
||||
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));
|
||||
do {
|
||||
write_status = write(pipe_fd, &status, sizeof(int));
|
||||
if (write_status == sizeof(int))
|
||||
break;
|
||||
if (write_status < 0 &&
|
||||
(errno == EINTR || errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Error sending to pipe: %m\n");
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
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);
|
||||
@@ -1392,7 +1370,16 @@ static void *pre_and_post_thread(void *arg)
|
||||
status = 0;
|
||||
do_post_command(client);
|
||||
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
do {
|
||||
write_status = write(pipe_fd, &status, sizeof(int));
|
||||
if (write_status == sizeof(int))
|
||||
break;
|
||||
if (write_status < 0 &&
|
||||
(errno == EINTR || errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Error sending to pipe: %m\n");
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
DEBUGLOG("Waiting for next pre command\n");
|
||||
|
||||
@@ -1407,7 +1394,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 */
|
||||
@@ -1443,7 +1429,7 @@ static int process_local_command(struct clvm_header *msg, int msglen,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int process_reply(struct clvm_header *msg, int msglen, char *csid)
|
||||
static int process_reply(const struct clvm_header *msg, int msglen, const char *csid)
|
||||
{
|
||||
struct local_client *client = NULL;
|
||||
|
||||
@@ -1516,7 +1502,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) {
|
||||
@@ -1572,28 +1558,36 @@ 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");
|
||||
}
|
||||
|
||||
/* Send a message to either a local client or another server */
|
||||
static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
static int send_message(void *buf, int msglen, const char *csid, int fd,
|
||||
const char *errtext)
|
||||
{
|
||||
int len;
|
||||
int saved_errno = 0;
|
||||
struct timespec delay;
|
||||
struct timespec remtime;
|
||||
|
||||
int retry_cnt = 0;
|
||||
|
||||
/* Send remote messages down the cluster socket */
|
||||
if (csid == NULL || !ISLOCAL_CSID(csid)) {
|
||||
@@ -1604,14 +1598,38 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
|
||||
/* Make sure it all goes */
|
||||
do {
|
||||
if (retry_cnt > MAX_RETRIES)
|
||||
{
|
||||
errno = saved_errno;
|
||||
log_error("%s", errtext);
|
||||
errno = saved_errno;
|
||||
break;
|
||||
}
|
||||
|
||||
len = write(fd, buf + ptr, msglen - ptr);
|
||||
|
||||
if (len <= 0) {
|
||||
log_error(errtext);
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN ||
|
||||
errno == EIO ||
|
||||
errno == ENOSPC) {
|
||||
saved_errno = errno;
|
||||
retry_cnt++;
|
||||
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_nsec = 100000;
|
||||
remtime.tv_sec = 0;
|
||||
remtime.tv_nsec = 0;
|
||||
(void) nanosleep (&delay, &remtime);
|
||||
|
||||
continue;
|
||||
}
|
||||
log_error("%s", errtext);
|
||||
break;
|
||||
}
|
||||
ptr += len;
|
||||
} while (len < msglen);
|
||||
} while (ptr < msglen);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -1641,11 +1659,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);
|
||||
@@ -1689,12 +1707,11 @@ static void *lvm_thread_fn(void *arg)
|
||||
}
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pass down some work to the LVM thread */
|
||||
static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
|
||||
int msglen, char *csid)
|
||||
int msglen, const char *csid)
|
||||
{
|
||||
struct lvm_thread_cmd *cmd;
|
||||
|
||||
@@ -1772,7 +1789,8 @@ static int open_local_sock()
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
void process_message(struct local_client *client, char *buf, int len, char *csid)
|
||||
void process_message(struct local_client *client, const char *buf, int len,
|
||||
const char *csid)
|
||||
{
|
||||
struct clvm_header *inheader;
|
||||
|
||||
@@ -1785,7 +1803,7 @@ void process_message(struct local_client *client, char *buf, int len, char *csid
|
||||
}
|
||||
|
||||
|
||||
static void check_all_callback(struct local_client *client, char *csid,
|
||||
static void check_all_callback(struct local_client *client, const char *csid,
|
||||
int node_up)
|
||||
{
|
||||
if (!node_up)
|
||||
|
||||
@@ -76,7 +76,8 @@ struct netsock_bits {
|
||||
};
|
||||
|
||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
|
||||
char *csid, struct local_client ** new_client);
|
||||
const char *csid,
|
||||
struct local_client ** new_client);
|
||||
|
||||
/* One of these for each fd we are listening on */
|
||||
struct local_client {
|
||||
@@ -95,11 +96,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))
|
||||
@@ -116,7 +113,9 @@ extern void cmd_client_cleanup(struct local_client *client);
|
||||
extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
extern void process_message(struct local_client *client, char *buf, int len, char *csid);
|
||||
extern void process_message(struct local_client *client, const char *buf,
|
||||
int len, const 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);
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "lvm-types.h"
|
||||
#include "libdlm.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
@@ -50,6 +50,7 @@
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static pthread_mutex_t lvm_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
@@ -243,7 +244,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 */
|
||||
}
|
||||
|
||||
@@ -311,10 +312,12 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %x\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
if (!cmd->config_valid || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -325,8 +328,8 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
|
||||
init_dmeventd_register(0);
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(0);
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
@@ -362,11 +365,12 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
|
||||
init_dmeventd_register(DEFAULT_DMEVENTD_MONITOR);
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
DEBUGLOG("Command return is %d\n", status);
|
||||
return status;
|
||||
@@ -393,6 +397,8 @@ int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if (command == LCK_LV_RESUME) {
|
||||
int oldmode;
|
||||
@@ -406,7 +412,10 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
if (oldmode == LKM_PWMODE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
status = lv_info_by_lvid(cmd, resource, &lvi, 0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
if (!status)
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
@@ -473,7 +482,8 @@ static void drop_vg_locks()
|
||||
sync_unlock(vg, LCK_EXCL);
|
||||
|
||||
}
|
||||
fclose(vgs);
|
||||
if (fclose(vgs))
|
||||
DEBUGLOG("vgs fclose failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -523,7 +533,8 @@ static void *get_initial_state()
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(lvs);
|
||||
if (fclose(lvs))
|
||||
DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -531,7 +542,7 @@ 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
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
@@ -570,12 +581,13 @@ void init_lvhash()
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = dm_hash_create(100);
|
||||
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||
pthread_mutex_init(&lvm_lock, NULL);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(int using_gulm)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL, 0))) {
|
||||
if (!(cmd = create_toolcontext(NULL, 0, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,6 @@ 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 *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
@@ -223,17 +222,14 @@ 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 +
|
||||
*response = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
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 */
|
||||
@@ -252,7 +248,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;
|
||||
@@ -274,25 +270,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;
|
||||
}
|
||||
@@ -327,7 +313,7 @@ int refresh_clvmd()
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response);
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Routines dealing with the System LV */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <mntent.h>
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "system-lv.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#ifdef HAVE_CCS
|
||||
#include "ccs.h"
|
||||
#endif
|
||||
|
||||
#define SYSTEM_LV_FILESYSTEM "ext2"
|
||||
#define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX"
|
||||
|
||||
extern char *config_filename(void);
|
||||
|
||||
static char system_lv_name[PATH_MAX] = { '\0' };
|
||||
static char mount_point[PATH_MAX] = { '\0' };
|
||||
static int mounted = 0;
|
||||
static int mounted_rw = 0;
|
||||
static int lockid;
|
||||
static const char *lock_name = "CLVM_SYSTEM_LV";
|
||||
|
||||
/* Look in /proc/mounts or (as a last resort) /etc/mtab to
|
||||
see if the system-lv is mounted. If it is mounted and we
|
||||
think it's not then abort because we don't have the right
|
||||
lock status and we don't know what other processes are doing with it.
|
||||
|
||||
Returns 1 for mounted, 0 for not mounted so it matches the condition
|
||||
of the "mounted" static variable above.
|
||||
*/
|
||||
static int is_really_mounted(void)
|
||||
{
|
||||
FILE *mountfile;
|
||||
struct mntent *ment;
|
||||
|
||||
mountfile = setmntent("/proc/mounts", "r");
|
||||
if (!mountfile) {
|
||||
mountfile = setmntent("/etc/mtab", "r");
|
||||
if (!mountfile) {
|
||||
log_error("Unable to open /proc/mounts or /etc/mtab");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for system LV name in the file */
|
||||
do {
|
||||
ment = getmntent(mountfile);
|
||||
if (ment) {
|
||||
if (strcmp(ment->mnt_fsname, system_lv_name) == 0) {
|
||||
endmntent(mountfile);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ment);
|
||||
|
||||
endmntent(mountfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the system LV name from the config file */
|
||||
static int find_system_lv(void)
|
||||
{
|
||||
if (system_lv_name[0] == '\0') {
|
||||
#ifdef HAVE_CCS
|
||||
int error;
|
||||
ccs_node_t *ctree;
|
||||
|
||||
/* Read the cluster config file */
|
||||
/* Open the config file */
|
||||
error = open_ccs_file(&ctree, "clvm.ccs");
|
||||
if (error) {
|
||||
perror("reading config file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(system_lv_name, find_ccs_str(ctree,
|
||||
"cluster/systemlv", '/',
|
||||
"/dev/vg/system_lv"));
|
||||
|
||||
/* Finished with config file */
|
||||
close_ccs_file(ctree);
|
||||
#else
|
||||
if (getenv("CLVMD_SYSTEM_LV"))
|
||||
strcpy(system_lv_name, getenv("CLVMD_SYSTEM_LV"));
|
||||
else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* See if it has been mounted outside our control */
|
||||
if (is_really_mounted() != mounted) {
|
||||
log_error
|
||||
("The system LV state has been mounted/umounted outside the control of clvmd\n"
|
||||
"it cannot not be used for cluster communications until this is fixed.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No prizes */
|
||||
int system_lv_umount(void)
|
||||
{
|
||||
if (!mounted)
|
||||
return 0;
|
||||
|
||||
if (umount(mount_point) < 0) {
|
||||
log_error("umount of system LV (%s) failed: %m\n",
|
||||
system_lv_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sync_unlock(lock_name, lockid);
|
||||
mounted = 0;
|
||||
|
||||
/* Remove the mount point */
|
||||
rmdir(mount_point);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int system_lv_mount(int readwrite)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
int fd;
|
||||
|
||||
if (find_system_lv()) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it already mounted suitably? */
|
||||
if (mounted) {
|
||||
if (!readwrite || (readwrite && mounted_rw)) {
|
||||
return 0;
|
||||
} else {
|
||||
/* Mounted RO and we need RW */
|
||||
if (system_lv_umount() < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Randomize the mount point */
|
||||
strcpy(mount_point, SYSTEM_LV_MOUNTPOINT);
|
||||
fd = mkstemp(mount_point);
|
||||
if (fd < 0) {
|
||||
log_error("mkstemp for system LV mount point failed: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Race condition here but there's no mkstemp for directories */
|
||||
close(fd);
|
||||
unlink(mount_point);
|
||||
mkdir(mount_point, 0600);
|
||||
|
||||
/* Make sure we have a system-lv lock */
|
||||
status =
|
||||
sync_lock(lock_name, (readwrite) ? LKM_EXMODE : LKM_CRMODE, 0,
|
||||
&lockid);
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
/* Mount it */
|
||||
if (mount(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
|
||||
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_SYNCHRONOUS
|
||||
| (readwrite ? 0 : MS_RDONLY), NULL) < 0) {
|
||||
/* mount(2) returns EINVAL if the volume has no FS on it. So, if we want to
|
||||
write to it we try to make a filesystem in it and retry the mount */
|
||||
if (errno == EINVAL && readwrite) {
|
||||
char cmd[256];
|
||||
|
||||
log_error("Attempting mkfs on system LV device %s\n",
|
||||
system_lv_name);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/mkfs -t %s %s",
|
||||
SYSTEM_LV_FILESYSTEM, system_lv_name);
|
||||
system(cmd);
|
||||
|
||||
if (mount
|
||||
(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
|
||||
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC |
|
||||
MS_SYNCHRONOUS | (readwrite ? 0 : MS_RDONLY),
|
||||
NULL) == 0)
|
||||
goto mounted;
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
log_error("mount of system LV (%s, %s, %s) failed: %m\n",
|
||||
system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM);
|
||||
sync_unlock(lock_name, lockid);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mounted:
|
||||
/* Set the internal flags */
|
||||
mounted = 1;
|
||||
mounted_rw = readwrite;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Erase *all* files in the root directory of the system LV.
|
||||
This *MUST* be called with an appropriate lock held!
|
||||
The LV is left mounted RW because it is assumed that the
|
||||
caller wants to write something here after clearing some space */
|
||||
int system_lv_eraseall(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char fname[PATH_MAX];
|
||||
|
||||
/* Must be mounted R/W */
|
||||
system_lv_mount(1);
|
||||
|
||||
dir = opendir(mount_point);
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
struct stat st;
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point,
|
||||
ent->d_name);
|
||||
|
||||
if (stat(fname, &st)) {
|
||||
if (S_ISREG(st.st_mode))
|
||||
unlink(fname);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a "high-level" routine - it mounts the system LV, writes
|
||||
the data into a file named after this node and then umounts the LV
|
||||
again */
|
||||
int system_lv_write_data(char *data, ssize_t len)
|
||||
{
|
||||
struct utsname nodeinfo;
|
||||
char fname[PATH_MAX];
|
||||
int outfile;
|
||||
ssize_t thiswrite;
|
||||
ssize_t written;
|
||||
|
||||
if (system_lv_mount(1))
|
||||
return -1;
|
||||
|
||||
/* Build the file name we are goingto use. */
|
||||
uname(&nodeinfo);
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point, nodeinfo.nodename);
|
||||
|
||||
/* Open the file for output */
|
||||
outfile = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (outfile < 0) {
|
||||
int saved_errno = errno;
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
written = 0;
|
||||
do {
|
||||
thiswrite = write(outfile, data + written, len - written);
|
||||
if (thiswrite > 0)
|
||||
written += thiswrite;
|
||||
|
||||
} while (written < len && thiswrite > 0);
|
||||
|
||||
close(outfile);
|
||||
|
||||
system_lv_umount();
|
||||
return (thiswrite < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* This is a "high-level" routine - it mounts the system LV, reads
|
||||
the data from a named file and then umounts the LV
|
||||
again */
|
||||
int system_lv_read_data(char *fname_base, char *data, ssize_t *len)
|
||||
{
|
||||
char fname[PATH_MAX];
|
||||
int outfile;
|
||||
struct stat st;
|
||||
ssize_t filesize;
|
||||
ssize_t thisread;
|
||||
ssize_t readbytes;
|
||||
|
||||
if (system_lv_mount(0))
|
||||
return -1;
|
||||
|
||||
/* Build the file name we are going to use. */
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point, fname_base);
|
||||
|
||||
/* Get the file size and stuff. Actually we only need the file size but
|
||||
this will also check that the file exists */
|
||||
if (stat(fname, &st) < 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("stat of file %s on system LV failed: %m\n", fname);
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
filesize = st.st_size;
|
||||
|
||||
outfile = open(fname, O_RDONLY);
|
||||
if (outfile < 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("open of file %s on system LV failed: %m\n", fname);
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
readbytes = 0;
|
||||
do {
|
||||
thisread =
|
||||
read(outfile, data + readbytes, filesize - readbytes);
|
||||
if (thisread > 0)
|
||||
readbytes += thisread;
|
||||
|
||||
} while (readbytes < filesize && thisread > 0);
|
||||
|
||||
close(outfile);
|
||||
|
||||
system_lv_umount();
|
||||
|
||||
*len = readbytes;
|
||||
return (thisread < 0) ? -1 : 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_SYSTEM_LV_H
|
||||
#define _CLVM_SYSTEM_LV_H
|
||||
|
||||
/* Prototypes for System-LV functions */
|
||||
|
||||
/* "low-level" functions */
|
||||
extern int system_lv_umount(void);
|
||||
extern int system_lv_mount(int readwrite);
|
||||
extern int system_lv_eraseall(void);
|
||||
|
||||
/* "high-level" functions */
|
||||
extern int system_lv_write_data(char *data, ssize_t len);
|
||||
extern int system_lv_read_data(char *fname_base, char *data, ssize_t *len);
|
||||
|
||||
#endif
|
||||
@@ -34,8 +34,8 @@
|
||||
#include <syslog.h>
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
@@ -92,41 +92,37 @@ int init_comms(unsigned short port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tcp_remove_client(char *csid)
|
||||
{
|
||||
void tcp_remove_client(const char *c_csid)
|
||||
{
|
||||
struct local_client *client;
|
||||
char csid[GULM_MAX_CSID_LEN];
|
||||
unsigned int i;
|
||||
memcpy(csid, c_csid, sizeof csid);
|
||||
DEBUGLOG("tcp_remove_client\n");
|
||||
|
||||
/* Don't actually close the socket here - that's the
|
||||
job of clvmd.c whch will do the job when it notices the
|
||||
other end has gone. We just need to remove the client(s) from
|
||||
the hash table so we don't try to use it for sending any more */
|
||||
client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (client)
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (client)
|
||||
{
|
||||
dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
}
|
||||
/* Look for a mangled one too, on the 2nd iteration. */
|
||||
csid[0] ^= 0x80;
|
||||
}
|
||||
|
||||
/* Look for a mangled one too */
|
||||
csid[0] ^= 0x80;
|
||||
|
||||
client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (client)
|
||||
{
|
||||
dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
}
|
||||
|
||||
/* Put it back as we found it */
|
||||
csid[0] ^= 0x80;
|
||||
}
|
||||
|
||||
int alloc_client(int fd, char *csid, struct local_client **new_client)
|
||||
int alloc_client(int fd, const char *c_csid, struct local_client **new_client)
|
||||
{
|
||||
struct local_client *client;
|
||||
char csid[GULM_MAX_CSID_LEN];
|
||||
memcpy(csid, c_csid, sizeof csid);
|
||||
|
||||
DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid));
|
||||
|
||||
@@ -315,7 +311,7 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
|
||||
return status;
|
||||
}
|
||||
|
||||
int gulm_connect_csid(char *csid, struct local_client **newclient)
|
||||
int gulm_connect_csid(const char *csid, struct local_client **newclient)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in6 addr;
|
||||
@@ -366,7 +362,7 @@ int gulm_connect_csid(char *csid, struct local_client **newclient)
|
||||
}
|
||||
|
||||
/* Send a message to a known CSID */
|
||||
static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const char *errtext)
|
||||
static int tcp_send_message(void *buf, int msglen, const char *csid, const char *errtext)
|
||||
{
|
||||
int status;
|
||||
struct local_client *client;
|
||||
@@ -465,7 +461,7 @@ static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6)
|
||||
}
|
||||
|
||||
/* Get someone else's IP address from DNS */
|
||||
int get_ip_address(char *node, char *addr)
|
||||
int get_ip_address(const char *node, char *addr)
|
||||
{
|
||||
struct hostent *he;
|
||||
|
||||
@@ -493,7 +489,7 @@ int get_ip_address(char *node, char *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *print_csid(char *csid)
|
||||
char *print_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int *icsid = (int *)csid;
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
#define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128
|
||||
|
||||
extern int init_comms(unsigned short);
|
||||
extern char *print_csid(char *);
|
||||
extern char *print_csid(const char *);
|
||||
int get_main_gulm_cluster_fd(void);
|
||||
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client);
|
||||
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext);
|
||||
void get_our_gulm_csid(char *csid);
|
||||
int gulm_connect_csid(char *csid, struct local_client **newclient);
|
||||
int gulm_connect_csid(const char *csid, struct local_client **newclient);
|
||||
|
||||
@@ -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,12 +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
|
||||
|
||||
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_pkgconfig install_dmeventd
|
||||
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
@@ -43,7 +50,7 @@ ifeq ("@PKGCONFIG@", "yes")
|
||||
INSTALL_TYPE += install_pkgconfig
|
||||
endif
|
||||
|
||||
install: $(INSTALL_TYPE) install_include
|
||||
install: $(INSTALL_TYPE) install_include install_dmeventd
|
||||
|
||||
install_include:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
|
||||
@@ -55,6 +62,9 @@ install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
|
||||
|
||||
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
|
||||
|
||||
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,11 +12,10 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
#include <libdevmapper-event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@@ -26,79 +25,104 @@
|
||||
#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
|
||||
|
||||
static pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
/*
|
||||
* 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 <= dm_split_words(params, max_args, 0, 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,
|
||||
@@ -113,69 +137,55 @@ static void _temporary_log_fn(int level, const char *file,
|
||||
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 (!dm_split_lvm_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);
|
||||
|
||||
if (pthread_mutex_trylock(&_lock)) {
|
||||
if (pthread_mutex_trylock(&_event_mutex)) {
|
||||
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
|
||||
pthread_mutex_lock(&_lock);
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
}
|
||||
/* FIXME Move inside libdevmapper */
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
syslog(LOG_ERR, "Unable to create dm_task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -192,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
|
||||
@@ -203,52 +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(&_lock);
|
||||
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 mirror device, %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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
#include <libdevmapper-event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@@ -26,79 +25,104 @@
|
||||
#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
|
||||
|
||||
static pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
/*
|
||||
* 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 <= dm_split_words(params, max_args, 0, 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,
|
||||
@@ -113,69 +137,55 @@ static void _temporary_log_fn(int level, const char *file,
|
||||
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 (!dm_split_lvm_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);
|
||||
|
||||
if (pthread_mutex_trylock(&_lock)) {
|
||||
if (pthread_mutex_trylock(&_event_mutex)) {
|
||||
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
|
||||
pthread_mutex_lock(&_lock);
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
}
|
||||
/* FIXME Move inside libdevmapper */
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
syslog(LOG_ERR, "Unable to create dm_task.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -192,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
|
||||
@@ -203,52 +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(&_lock);
|
||||
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 mirror device, %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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,14 @@ devices {
|
||||
# to use with LVM2.
|
||||
scan = [ "/dev" ]
|
||||
|
||||
# If several entries in the scanned directories correspond to the
|
||||
# same block device and the tools need to display a name for device,
|
||||
# all the pathnames are matched against each item in the following
|
||||
# list of regular expressions in turn and the first match is used.
|
||||
preferred_names = [ ]
|
||||
|
||||
# preferred_names = [ "^/dev/mpath/", "^/dev/[hs]d" ]
|
||||
|
||||
# A filter that tells LVM2 to only use a restricted set of devices.
|
||||
# The filter consists of an array of regular expressions. These
|
||||
# expressions can be delimited by a character of your choice, and
|
||||
@@ -56,10 +64,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 +91,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 +200,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.
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
../lib/misc/lvm-string.h
|
||||
../lib/misc/lvm-wrappers.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/report/report.h
|
||||
../lib/uuid/uuid.h
|
||||
../po/pogen.h
|
||||
|
||||
@@ -81,9 +81,6 @@ SOURCES =\
|
||||
misc/lvm-wrappers.c \
|
||||
misc/timestamp.c \
|
||||
mm/memlock.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
report/report.c \
|
||||
striped/striped.c \
|
||||
uuid/uuid.c \
|
||||
|
||||
@@ -141,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;
|
||||
}
|
||||
@@ -168,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;
|
||||
@@ -211,7 +215,7 @@ 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,
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
@@ -421,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;
|
||||
}
|
||||
|
||||
@@ -448,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,
|
||||
@@ -466,7 +474,7 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -519,11 +527,12 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
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;
|
||||
}
|
||||
@@ -607,7 +616,7 @@ static int _lv_suspend_lv(struct logical_volume *lv, int lockfs)
|
||||
* 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;
|
||||
@@ -617,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;
|
||||
@@ -640,50 +659,89 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
}
|
||||
|
||||
/*
|
||||
* register_dev_for_events
|
||||
*
|
||||
* This function uses proper error codes (but breaks convention)
|
||||
* to return:
|
||||
* -1 on error
|
||||
* 0 if the lv's targets don't do event [un]registration
|
||||
* 0 if the lv is already [un]registered -- FIXME: not implemented
|
||||
* 1 if the lv had a segment which was [un]registered
|
||||
*
|
||||
* Returns: -1 on error
|
||||
* Returns 0 if an attempt to (un)monitor the device failed.
|
||||
* Returns 1 otherwise.
|
||||
*/
|
||||
int register_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg)
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int monitor)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
int r = 0;
|
||||
int i, pending = 0, monitored;
|
||||
int r = 1;
|
||||
struct list *tmp;
|
||||
struct lv_segment *seg;
|
||||
int (*reg) (struct lv_segment *, int events);
|
||||
int (*monitor_fn) (struct lv_segment *s, int e);
|
||||
|
||||
if (do_reg && !dmeventd_register_mode())
|
||||
/* 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 (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;
|
||||
|
||||
if (!reg)
|
||||
if (!seg_monitored(seg) || (seg->status & PVMOVE))
|
||||
continue;
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!reg(seg, 0)) {
|
||||
stack;
|
||||
return -1;
|
||||
monitor_fn = NULL;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -728,7 +786,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
/* FIXME Consider aborting here */
|
||||
stack;
|
||||
|
||||
@@ -786,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) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
@@ -832,7 +890,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
@@ -905,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) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
@@ -934,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)
|
||||
|
||||
@@ -83,10 +83,11 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
* 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 register_dev_for_events(struct cmd_context *cmd,
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg);
|
||||
|
||||
/*
|
||||
@@ -95,4 +96,9 @@ int register_dev_for_events(struct cmd_context *cmd,
|
||||
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>
|
||||
@@ -117,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;
|
||||
@@ -142,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 (target_type && !strcmp(target_type, "mirror"))
|
||||
goto out;
|
||||
} while (next);
|
||||
|
||||
/* FIXME Also check dependencies? */
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -155,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;
|
||||
}
|
||||
@@ -187,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 */
|
||||
@@ -393,10 +435,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dm = dm_pool_alloc(mem, sizeof(*dm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dm = dm_pool_alloc(mem, sizeof(*dm))))
|
||||
goto_bad;
|
||||
|
||||
dm->cmd = cmd;
|
||||
dm->mem = mem;
|
||||
@@ -408,10 +448,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
}
|
||||
dm->stripe_filler = stripe_filler;
|
||||
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
|
||||
goto_bad;
|
||||
|
||||
dm->target_state = NULL;
|
||||
|
||||
@@ -593,7 +631,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;
|
||||
}
|
||||
@@ -782,12 +820,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;
|
||||
}
|
||||
|
||||
@@ -892,6 +937,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: symlinks should be created/destroyed at the same time
|
||||
* as the kernel devices but we can't do that from within libdevmapper
|
||||
* at present so we must walk the tree twice instead. */
|
||||
|
||||
/*
|
||||
* Create LV symlinks for children of supplied root node.
|
||||
*/
|
||||
@@ -924,6 +973,32 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove LV symlinks for children of supplied root node.
|
||||
*/
|
||||
static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root)
|
||||
{
|
||||
void *handle = NULL;
|
||||
struct dm_tree_node *child;
|
||||
char *vgname, *lvname, *layer;
|
||||
int r = 1;
|
||||
|
||||
while ((child = dm_tree_next_child(&handle, root, 0))) {
|
||||
if (!dm_split_lvm_name(dm->mem, dm_tree_node_get_name(child), &vgname, &lvname, &layer)) {
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* only top level layer has symlinks */
|
||||
if (*layer)
|
||||
continue;
|
||||
|
||||
fs_del_lv_byname(dm->cmd->dev_dir, vgname, lvname);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root)
|
||||
{
|
||||
void *handle = NULL;
|
||||
@@ -983,9 +1058,13 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
|
||||
/* Deactivate LV and all devices it references that nothing else has open. */
|
||||
if (!dm_tree_deactivate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
|
||||
goto_out;
|
||||
if (!_remove_lv_symlinks(dm, root))
|
||||
log_error("Failed to remove all device symlinks associated with %s.", lv->name);
|
||||
break;
|
||||
case SUSPEND:
|
||||
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;
|
||||
@@ -1065,7 +1144,7 @@ int dev_manager_device_uses_vg(struct device *dev,
|
||||
{
|
||||
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())) {
|
||||
|
||||
@@ -338,6 +338,11 @@ int fs_del_lv(const struct logical_volume *lv)
|
||||
"", "");
|
||||
}
|
||||
|
||||
int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name)
|
||||
{
|
||||
return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", "");
|
||||
}
|
||||
|
||||
int fs_rename_lv(struct logical_volume *lv,
|
||||
const char *dev, const char *old_name)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
int fs_add_lv(const struct logical_volume *lv, const char *dev);
|
||||
int fs_del_lv(const struct logical_volume *lv);
|
||||
int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name);
|
||||
int fs_rename_lv(struct logical_volume *lv,
|
||||
const char *dev, const char *old_name);
|
||||
void fs_unlock(void);
|
||||
|
||||
25
lib/cache/lvmcache.c
vendored
25
lib/cache/lvmcache.c
vendored
@@ -114,7 +114,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
struct list *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
char vgid_found[ID_LEN + 1];
|
||||
char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
|
||||
return NULL;
|
||||
@@ -135,7 +135,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
label_read(devl->dev, &label, UINT64_C(0));
|
||||
list_del(&devl->list);
|
||||
dm_free(devl);
|
||||
}
|
||||
@@ -151,7 +151,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
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;
|
||||
@@ -186,7 +186,7 @@ const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
|
||||
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;
|
||||
@@ -205,7 +205,7 @@ static void _rescan_entry(struct lvmcache_info *info)
|
||||
struct label *label;
|
||||
|
||||
if (info->status & CACHE_INVALID)
|
||||
label_read(info->dev, &label);
|
||||
label_read(info->dev, &label, UINT64_C(0));
|
||||
}
|
||||
|
||||
static int _scan_invalid(void)
|
||||
@@ -247,7 +247,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(iter)))
|
||||
label_read(dev, &label);
|
||||
label_read(dev, &label, UINT64_C(0));
|
||||
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
@@ -346,7 +346,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Already cached ? */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -357,7 +357,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -371,7 +371,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -476,7 +476,8 @@ static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
|
||||
struct lvmcache_vginfo *primary_vginfo)
|
||||
{
|
||||
struct lvmcache_vginfo *last_vginfo = primary_vginfo;
|
||||
char uuid_primary[64], uuid_new[64];
|
||||
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. */
|
||||
@@ -709,7 +710,7 @@ int lvmcache_update_vg(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
@@ -733,7 +734,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
{
|
||||
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");
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static FILE *_log;
|
||||
|
||||
static int _get_env_vars(struct cmd_context *cmd)
|
||||
{
|
||||
const char *e;
|
||||
@@ -330,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;
|
||||
}
|
||||
@@ -370,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;
|
||||
}
|
||||
@@ -408,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;
|
||||
}
|
||||
@@ -467,10 +465,8 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
const struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
if (!dev_cache_init()) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_cache_init(cmd))
|
||||
return_0;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
@@ -575,9 +571,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];
|
||||
@@ -587,16 +583,35 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
if (!(f3 = _init_filter_components(cmd)))
|
||||
return 0;
|
||||
|
||||
if (dm_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_tree_str(cmd, "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;
|
||||
}
|
||||
@@ -608,9 +623,14 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
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);
|
||||
|
||||
@@ -748,7 +768,6 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
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) {
|
||||
@@ -775,18 +794,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,7 +898,8 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
|
||||
unsigned is_long_lived)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
@@ -905,6 +923,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
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);
|
||||
@@ -953,7 +972,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
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))) {
|
||||
@@ -1022,10 +1041,10 @@ 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_release();
|
||||
lvmcache_destroy();
|
||||
@@ -1064,7 +1083,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))
|
||||
@@ -1073,6 +1092,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;
|
||||
}
|
||||
@@ -1100,8 +1126,4 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
activation_exit();
|
||||
fin_log();
|
||||
fin_syslog();
|
||||
|
||||
if (_log)
|
||||
fclose(_log);
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ struct cmd_context {
|
||||
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? */
|
||||
@@ -88,7 +89,7 @@ struct cmd_context {
|
||||
char proc_dir[PATH_MAX];
|
||||
};
|
||||
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static);
|
||||
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);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "device.h"
|
||||
#include "str_list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -26,6 +27,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define SECTION_B_CHAR '{'
|
||||
#define SECTION_E_CHAR '}'
|
||||
|
||||
enum {
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
@@ -58,6 +62,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 +83,8 @@ static const int sep = '/';
|
||||
|
||||
#define match(t) do {\
|
||||
if (!_match_aux(p, (t))) {\
|
||||
log_error("Parse error at byte %d (line %d): unexpected token", p->tb - p->fb + 1, p->line); \
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
|
||||
p->tb - p->fb + 1, p->line); \
|
||||
return 0;\
|
||||
} \
|
||||
} while(0);
|
||||
@@ -95,7 +102,7 @@ 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);
|
||||
@@ -115,6 +122,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 +131,12 @@ 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)
|
||||
@@ -143,7 +157,7 @@ struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
|
||||
struct config_tree *cft;
|
||||
struct parser *p;
|
||||
|
||||
if (!(cft = create_config_tree(NULL)))
|
||||
if (!(cft = create_config_tree(NULL, 0)))
|
||||
return_NULL;
|
||||
|
||||
c = (struct cs *) cft;
|
||||
@@ -174,7 +188,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;
|
||||
char *buf = NULL;
|
||||
|
||||
if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
|
||||
stack;
|
||||
@@ -201,18 +215,10 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_read(dev, (uint64_t) offset, size, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
if (!dev_read_circular(dev, (uint64_t) offset, size,
|
||||
(uint64_t) offset2, size2, buf)) {
|
||||
goto out;
|
||||
}
|
||||
if (size2) {
|
||||
if (!dev_read(dev, (uint64_t) offset2, size2,
|
||||
buf + size)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
p->fb = buf;
|
||||
}
|
||||
|
||||
@@ -250,7 +256,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)) {
|
||||
@@ -272,22 +277,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;
|
||||
}
|
||||
@@ -331,7 +337,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:
|
||||
@@ -351,7 +357,7 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
break;
|
||||
|
||||
case CFG_INT:
|
||||
fprintf(fp, "%d", v->v.i);
|
||||
fprintf(fp, "%" PRId64, v->v.i);
|
||||
break;
|
||||
|
||||
case CFG_EMPTY_ARRAY:
|
||||
@@ -364,7 +370,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;
|
||||
@@ -377,12 +384,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 */
|
||||
@@ -402,13 +409,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;
|
||||
|
||||
@@ -421,13 +430,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;
|
||||
}
|
||||
@@ -455,7 +479,7 @@ static struct config_node *_file(struct parser *p)
|
||||
|
||||
static struct config_node *_section(struct parser *p)
|
||||
{
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
|
||||
struct config_node *root, *n, *l = NULL;
|
||||
if (!(root = _create_node(p))) {
|
||||
stack;
|
||||
@@ -544,7 +568,7 @@ static struct config_value *_type(struct parser *p)
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
v->type = CFG_INT;
|
||||
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
|
||||
v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
|
||||
@@ -567,7 +591,8 @@ static struct config_value *_type(struct parser *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Parse error at byte %d (line %d): expected a value", p->tb - p->fb + 1, p->line);
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
|
||||
p->tb - p->fb + 1, p->line);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
@@ -604,12 +629,12 @@ static void _get_token(struct parser *p, int tok_prev)
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
case SECTION_B_CHAR:
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
case SECTION_E_CHAR:
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
@@ -689,8 +714,9 @@ static void _get_token(struct parser *p, int tok_prev)
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
|
||||
(*p->te != '}'))
|
||||
(*p->te != '#') && (*p->te != '=') &&
|
||||
(*p->te != SECTION_B_CHAR) &&
|
||||
(*p->te != SECTION_E_CHAR))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
@@ -763,6 +789,7 @@ 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 */
|
||||
@@ -773,22 +800,30 @@ static 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;
|
||||
}
|
||||
|
||||
static struct config_node *_find_first_config_node(const struct config_node *cn1,
|
||||
@@ -819,7 +854,7 @@ static const char *_find_config_str(const struct config_node *cn1,
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
/* Empty strings are ignored */
|
||||
if ((n && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
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;
|
||||
}
|
||||
@@ -836,25 +871,26 @@ const char *find_config_str(const struct config_node *cn,
|
||||
return _find_config_str(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
static int _find_config_int(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int fail)
|
||||
static int64_t _find_config_int64(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int64_t fail)
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||
if (n && n->v && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
|
||||
return n->v->v.i;
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %d",
|
||||
log_very_verbose("%s not found in config: defaulting to %" PRId64,
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
return _find_config_int(cn, NULL, path, fail);
|
||||
/* FIXME Add log_error message on overflow */
|
||||
return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
|
||||
}
|
||||
|
||||
static float _find_config_float(const struct config_node *cn1,
|
||||
@@ -863,7 +899,7 @@ static float _find_config_float(const struct config_node *cn1,
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v->type == CFG_FLOAT) {
|
||||
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;
|
||||
}
|
||||
@@ -896,7 +932,8 @@ const char *find_config_tree_str(struct cmd_context *cmd,
|
||||
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);
|
||||
/* FIXME Add log_error message on overflow */
|
||||
return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
|
||||
}
|
||||
|
||||
float find_config_tree_float(struct cmd_context *cmd, const char *path,
|
||||
@@ -988,7 +1025,6 @@ int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
if (!n || !n->v || n->v->type != CFG_INT)
|
||||
return 0;
|
||||
|
||||
/* FIXME Support 64-bit value! */
|
||||
*result = (uint64_t) n->v->v.i;
|
||||
return 1;
|
||||
}
|
||||
@@ -1118,3 +1154,61 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a token type to the char it represents.
|
||||
*/
|
||||
static char _token_type_to_char(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case TOK_SECTION_B:
|
||||
return SECTION_B_CHAR;
|
||||
case TOK_SECTION_E:
|
||||
return SECTION_E_CHAR;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* # of 'type' tokens in 'str'.
|
||||
*/
|
||||
static unsigned _count_tokens (const char *str, unsigned len, int type)
|
||||
{
|
||||
char c;
|
||||
|
||||
c = _token_type_to_char(type);
|
||||
|
||||
return(count_chars_len(str, len, c));
|
||||
}
|
||||
|
||||
/*
|
||||
* Heuristic function to make a quick guess as to whether a text
|
||||
* region probably contains a valid config "section". (Useful for
|
||||
* scanning areas of the disk for old metadata.)
|
||||
* Config sections contain various tokens, may contain other sections
|
||||
* and strings, and are delimited by begin (type 'TOK_SECTION_B') and
|
||||
* end (type 'TOK_SECTION_E') tokens. As a quick heuristic, we just
|
||||
* count the number of begin and end tokens, and see if they are
|
||||
* non-zero and the counts match.
|
||||
* Full validation of the section should be done with another function
|
||||
* (for example, read_config_fd).
|
||||
*
|
||||
* Returns:
|
||||
* 0 - probably is not a valid config section
|
||||
* 1 - probably _is_ a valid config section
|
||||
*/
|
||||
unsigned maybe_config_section(const char *str, unsigned len)
|
||||
{
|
||||
int begin_count;
|
||||
int end_count;
|
||||
|
||||
begin_count = _count_tokens(str, len, TOK_SECTION_B);
|
||||
end_count = _count_tokens(str, len, TOK_SECTION_E);
|
||||
|
||||
if (begin_count && end_count && (begin_count - end_count == 0))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ enum {
|
||||
struct config_value {
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
int64_t i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
@@ -53,7 +53,7 @@ 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);
|
||||
@@ -65,7 +65,8 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
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,
|
||||
@@ -107,4 +108,6 @@ int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
int get_config_str(const struct config_node *cn, const char *path,
|
||||
char **result);
|
||||
|
||||
unsigned maybe_config_section(const char *str, unsigned len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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,6 +32,7 @@
|
||||
#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 "liblvm2clusterlock.so"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "zu"
|
||||
#define PRIptrdiff_t "td"
|
||||
|
||||
struct str_list {
|
||||
struct list list;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "btree.h"
|
||||
#include "filter.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
@@ -38,6 +39,7 @@ static struct {
|
||||
struct dm_pool *mem;
|
||||
struct dm_hash_table *names;
|
||||
struct btree *devices;
|
||||
struct dm_regex *preferred_names_matcher;
|
||||
|
||||
int has_scanned;
|
||||
struct list dirs;
|
||||
@@ -129,15 +131,52 @@ static struct device *_dev_create(dev_t d)
|
||||
return dev;
|
||||
}
|
||||
|
||||
void dev_set_preferred_name(struct str_list *sl, struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Don't interfere with ordering specified in config file.
|
||||
*/
|
||||
if (_cache.preferred_names_matcher)
|
||||
return;
|
||||
|
||||
log_debug("%s: New preferred name", sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
|
||||
/* Return 1 if we prefer path1 else return 0 */
|
||||
static int _compare_paths(const char *path0, const char *path1)
|
||||
{
|
||||
int slash0 = 0, slash1 = 0;
|
||||
int m0, m1;
|
||||
const char *p;
|
||||
char p0[PATH_MAX], p1[PATH_MAX];
|
||||
char *s0, *s1;
|
||||
struct stat stat0, stat1;
|
||||
|
||||
/*
|
||||
* FIXME Better to compare patterns one-at-a-time against all names.
|
||||
*/
|
||||
if (_cache.preferred_names_matcher) {
|
||||
m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
|
||||
m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
|
||||
|
||||
if (m0 != m1) {
|
||||
if (m0 < 0)
|
||||
return 1;
|
||||
if (m1 < 0)
|
||||
return 0;
|
||||
if (m0 < m1)
|
||||
return 1;
|
||||
if (m1 < m0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Built-in rules.
|
||||
*/
|
||||
|
||||
/* Return the path with fewer slashes */
|
||||
for (p = path0; p++; p = (const char *) strchr(p, '/'))
|
||||
slash0++;
|
||||
@@ -441,7 +480,65 @@ void dev_cache_scan(int do_scan)
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
static int _init_preferred_names(struct cmd_context *cmd)
|
||||
{
|
||||
const struct config_node *cn;
|
||||
struct config_value *v;
|
||||
struct dm_pool *scratch = NULL;
|
||||
char **regex;
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
|
||||
cn->v->type == CFG_EMPTY_ARRAY) {
|
||||
log_very_verbose("devices/preferred_names not found in config file: "
|
||||
"using built-in preferences");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (v = cn->v; v; v = v->next) {
|
||||
if (v->type != CFG_STRING) {
|
||||
log_error("preferred_names patterns must be enclosed in quotes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
|
||||
return_0;
|
||||
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
log_error("Failed to allocate preferred device name "
|
||||
"pattern list.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (v = cn->v, i = count - 1; v; v = v->next, i--) {
|
||||
if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
|
||||
log_error("Failed to allocate a preferred device name "
|
||||
"pattern.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(_cache.preferred_names_matcher =
|
||||
dm_regex_create(_cache.mem,(const char **) regex, count))) {
|
||||
log_error("Preferred device name pattern matcher creation failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_pool_destroy(scratch);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_cache_init(struct cmd_context *cmd)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
@@ -466,6 +563,9 @@ int dev_cache_init(void)
|
||||
list_init(&_cache.dirs);
|
||||
list_init(&_cache.files);
|
||||
|
||||
if (!_init_preferred_names(cmd))
|
||||
goto_bad;
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
@@ -489,6 +589,9 @@ void dev_cache_exit(void)
|
||||
if (_cache.names)
|
||||
_check_for_open_devices();
|
||||
|
||||
if (_cache.preferred_names_matcher)
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (_cache.mem) {
|
||||
dm_pool_destroy(_cache.mem);
|
||||
_cache.mem = NULL;
|
||||
|
||||
@@ -30,7 +30,8 @@ struct dev_filter {
|
||||
/*
|
||||
* The global device cache.
|
||||
*/
|
||||
int dev_cache_init(void);
|
||||
struct cmd_context;
|
||||
int dev_cache_init(struct cmd_context *cmd);
|
||||
void dev_cache_exit(void);
|
||||
|
||||
/* Trigger(1) or avoid(0) a scan */
|
||||
@@ -41,6 +42,8 @@ int dev_cache_add_dir(const char *path);
|
||||
int dev_cache_add_loopfile(const char *path);
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
|
||||
void dev_set_preferred_name(struct str_list *sl, struct device *dev);
|
||||
|
||||
/*
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
@@ -561,6 +564,35 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
return _aligned_io(&where, buffer, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted
|
||||
* by (offset,len) and (offset2,len2). Thus, the total size of
|
||||
* 'buf' should be len+len2.
|
||||
*/
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, void *buf)
|
||||
{
|
||||
if (!dev_read(dev, offset, len, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The second region is optional, and allows for
|
||||
* a circular buffer on the device.
|
||||
*/
|
||||
if (!len2)
|
||||
return 1;
|
||||
|
||||
if (!dev_read(dev, offset2, len2, buf + len)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
|
||||
* But fails if concurrent processes writing
|
||||
*/
|
||||
@@ -605,7 +637,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -78,6 +78,8 @@ int dev_fd(struct device *dev);
|
||||
const char *dev_name(const struct device *dev);
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, void *buf);
|
||||
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_set(struct device *dev, uint64_t offset, size_t len, int value);
|
||||
|
||||
@@ -82,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':
|
||||
@@ -96,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;
|
||||
@@ -143,6 +155,8 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
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"},
|
||||
@@ -161,7 +175,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
|
||||
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;
|
||||
@@ -171,7 +185,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
if (s < 8) {
|
||||
if (s < 10) {
|
||||
byte = cmd->current_settings.unit_factor;
|
||||
size *= UINT64_C(512);
|
||||
} else {
|
||||
@@ -181,7 +195,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
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;
|
||||
@@ -220,7 +234,7 @@ const char *display_size(struct cmd_context *cmd, uint64_t size)
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv)
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return;
|
||||
@@ -244,11 +258,38 @@ void pvdisplay_colons(struct physical_volume *pv)
|
||||
return;
|
||||
}
|
||||
|
||||
void pvdisplay_segments(struct physical_volume *pv)
|
||||
{
|
||||
struct pv_segment *pvseg;
|
||||
|
||||
if (pv->pe_size)
|
||||
log_print("--- Physical Segments ---");
|
||||
|
||||
list_iterate_items(pvseg, &pv->segments) {
|
||||
log_print("Physical extent %u to %u:",
|
||||
pvseg->pe, pvseg->pe + pvseg->len - 1);
|
||||
|
||||
if (pvseg->lvseg) {
|
||||
log_print(" Logical volume\t%s%s/%s",
|
||||
pvseg->lvseg->lv->vg->cmd->dev_dir,
|
||||
pvseg->lvseg->lv->vg->name,
|
||||
pvseg->lvseg->lv->name);
|
||||
log_print(" Logical extents\t%d to %d",
|
||||
pvseg->lvseg->le, pvseg->lvseg->le +
|
||||
pvseg->lvseg->len - 1);
|
||||
} else
|
||||
log_print(" FREE");
|
||||
}
|
||||
|
||||
log_print(" ");
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME Include label fields */
|
||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
const char *size;
|
||||
|
||||
uint32_t pe_free;
|
||||
@@ -310,7 +351,7 @@ int pvdisplay_short(struct cmd_context *cmd __attribute((unused)),
|
||||
struct physical_volume *pv,
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return 0;
|
||||
@@ -357,7 +398,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
{
|
||||
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; */
|
||||
|
||||
@@ -523,7 +564,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);
|
||||
@@ -602,7 +643,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);
|
||||
|
||||
@@ -31,6 +31,7 @@ char *display_uuid(char *uuidstr);
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre);
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv);
|
||||
void pvdisplay_segments(struct physical_volume *pv);
|
||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle);
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
@@ -50,7 +50,7 @@ static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)),
|
||||
return dm_tree_node_add_error_target(node, len);
|
||||
}
|
||||
|
||||
static int _errseg_target_present(void)
|
||||
static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _errseg_checked = 0;
|
||||
static int _errseg_present = 0;
|
||||
|
||||
@@ -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)
|
||||
@@ -240,10 +301,9 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
}
|
||||
memset(pf, 0, sizeof(*pf));
|
||||
|
||||
if (!(pf->file = dm_malloc(strlen(file) + 1))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(pf->file = dm_malloc(strlen(file) + 1)))
|
||||
goto_bad;
|
||||
|
||||
strcpy(pf->file, file);
|
||||
pf->real = real;
|
||||
|
||||
@@ -252,10 +312,8 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_malloc(sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_malloc(sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _lookup_p;
|
||||
f->destroy = _persistent_destroy;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter-regex.h"
|
||||
#include "matcher.h"
|
||||
#include "device.h"
|
||||
|
||||
struct rfilter {
|
||||
struct dm_pool *mem;
|
||||
dm_bitset_t accept;
|
||||
struct matcher *engine;
|
||||
struct dm_regex *engine;
|
||||
};
|
||||
|
||||
static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
||||
@@ -98,18 +97,15 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
if (!(scratch = dm_pool_create("filter matcher", 1024))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!(scratch = dm_pool_create("filter dm_regex", 1024)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* count how many patterns we have.
|
||||
*/
|
||||
for (v = val; v; v = v->next) {
|
||||
|
||||
if (v->type != CFG_STRING) {
|
||||
log_info("filter patterns must be enclosed in quotes");
|
||||
log_error("filter patterns must be enclosed in quotes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -119,10 +115,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
/*
|
||||
* allocate space for them
|
||||
*/
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* create the accept/reject bitset
|
||||
@@ -136,15 +130,15 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
log_error("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* build the matcher.
|
||||
*/
|
||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
@@ -160,17 +154,12 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
struct str_list *sl;
|
||||
|
||||
list_iterate_items(sl, &dev->aliases) {
|
||||
m = matcher_run(rf->engine, sl->str);
|
||||
m = dm_regex_match(rf->engine, sl->str);
|
||||
|
||||
if (m >= 0) {
|
||||
if (dm_bit(rf->accept, m)) {
|
||||
|
||||
if (!first) {
|
||||
log_debug("%s: New preferred name",
|
||||
sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
if (!first)
|
||||
dev_set_preferred_name(sl, dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -208,22 +197,16 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(rf = dm_pool_alloc(mem, sizeof(*rf)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(rf = dm_pool_alloc(mem, sizeof(*rf))))
|
||||
goto_bad;
|
||||
|
||||
rf->mem = mem;
|
||||
|
||||
if (!_build_matcher(rf, patterns)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!_build_matcher(rf, patterns))
|
||||
goto_bad;
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _regex_destroy;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -280,10 +284,8 @@ struct dev_filter *sysfs_filter_create(const char *proc)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _destroy;
|
||||
|
||||
@@ -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);
|
||||
@@ -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,7 +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");
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
dev_len = strlen(cv->v.str);
|
||||
@@ -214,14 +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);
|
||||
fclose(pd);
|
||||
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);
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
@@ -232,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ static int _read_uuids(struct disk_list *data)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -357,10 +357,8 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
list_init(&dl->uuids);
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!_read_pvd(dev, &dl->pvd)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!_read_pvd(dev, &dl->pvd))
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
|
||||
@@ -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,11 +161,11 @@ 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)));
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -203,8 +203,8 @@ 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,
|
||||
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,
|
||||
|
||||
@@ -131,10 +131,10 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
int partial;
|
||||
|
||||
if (!vg)
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (list_empty(pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
@@ -146,24 +146,24 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
dl = list_item(pvs->n, struct disk_list);
|
||||
|
||||
if (!import_vg(mem, vg, dl, partial))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_lvs(mem, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_extents(fid->fmt->cmd, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_snapshots(mem, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return vg;
|
||||
|
||||
@@ -191,15 +191,11 @@ static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
||||
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
|
||||
|
||||
if (!read_pvs_in_vg
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
|
||||
goto_bad;
|
||||
|
||||
if (!(vg = _build_vg(fid, &pvs))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg = _build_vg(fid, &pvs)))
|
||||
goto_bad;
|
||||
|
||||
bad:
|
||||
dm_pool_destroy(mem);
|
||||
@@ -312,7 +308,7 @@ static int _format1_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, &dl->vgd)) {
|
||||
if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -415,17 +411,14 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dl = dm_pool_alloc(mem, sizeof(*dl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dl = dm_pool_alloc(mem, sizeof(*dl))))
|
||||
goto_bad;
|
||||
|
||||
dl->mem = mem;
|
||||
dl->dev = pv->dev;
|
||||
|
||||
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv))
|
||||
goto_bad;
|
||||
|
||||
/* must be set to be able to zero gap after PV structure in
|
||||
dev_write in order to make other disk tools happy */
|
||||
@@ -434,10 +427,8 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
|
||||
dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
|
||||
|
||||
list_add(&pvs, &dl->list);
|
||||
if (!write_disks(fmt, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!write_disks(fmt, &pvs))
|
||||
goto_bad;
|
||||
|
||||
dm_pool_destroy(mem);
|
||||
return 1;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "segtype.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -47,11 +48,13 @@ 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,
|
||||
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);
|
||||
|
||||
@@ -89,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);
|
||||
|
||||
@@ -427,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, &dl->vgd)) {
|
||||
if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -59,22 +59,16 @@ static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem,
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm))))
|
||||
goto_bad;
|
||||
|
||||
lvm->lv = ll->lv;
|
||||
if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map)
|
||||
* ll->lv->le_count))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
* ll->lv->le_count)))
|
||||
goto_bad;
|
||||
|
||||
if (!dm_hash_insert(maps, ll->lv->name, lvm)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_hash_insert(maps, ll->lv->name, lvm))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
return maps;
|
||||
@@ -203,6 +197,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 +222,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 +231,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 +243,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 +252,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 +264,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 +277,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 +309,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;
|
||||
|
||||
@@ -30,7 +30,7 @@ static void _not_supported(const char *op)
|
||||
op);
|
||||
}
|
||||
|
||||
static int _lvm1_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,13 +48,13 @@ static int _lvm1_can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvm1_write(struct label *label, char *buf)
|
||||
static int _lvm1_write(struct label *label, void *buf)
|
||||
{
|
||||
_not_supported("write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvm1_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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -29,7 +29,7 @@ static void _pool_not_supported(const char *op)
|
||||
op);
|
||||
}
|
||||
|
||||
static int _pool_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 _pool_can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pool_write(struct label *label, char *buf)
|
||||
static int _pool_write(struct label *label, void *buf)
|
||||
{
|
||||
_pool_not_supported("write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pool_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;
|
||||
|
||||
@@ -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.
|
||||
@@ -356,6 +362,22 @@ int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int archive_list_file(struct cmd_context *cmd, const char *file)
|
||||
{
|
||||
struct archive_file af;
|
||||
|
||||
af.path = (char *)file;
|
||||
|
||||
if (!path_exists(af.path)) {
|
||||
log_err("Archive file %s not found.", af.path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_display_archive(cmd, &af);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||
{
|
||||
struct archive_file af;
|
||||
|
||||
@@ -148,6 +148,17 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
|
||||
return r1 && r2;
|
||||
}
|
||||
|
||||
int archive_display_file(struct cmd_context *cmd, const char *file)
|
||||
{
|
||||
int r;
|
||||
|
||||
init_partial(1);
|
||||
r = archive_list_file(cmd, file);
|
||||
init_partial(0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int backup_init(struct cmd_context *cmd, const char *dir)
|
||||
{
|
||||
if (!(cmd->backup_params = dm_pool_zalloc(cmd->libmem,
|
||||
|
||||
@@ -38,6 +38,7 @@ void archive_exit(struct cmd_context *cmd);
|
||||
void archive_enable(struct cmd_context *cmd, int flag);
|
||||
int archive(struct volume_group *vg);
|
||||
int archive_display(struct cmd_context *cmd, const char *vg_name);
|
||||
int archive_display_file(struct cmd_context *cmd, const char *file);
|
||||
|
||||
int backup_init(struct cmd_context *cmd, const char *dir);
|
||||
void backup_exit(struct cmd_context *cmd);
|
||||
|
||||
@@ -160,7 +160,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
for (i = 0; i < f->indent; i++)
|
||||
white_space[i] = '\t';
|
||||
white_space[i] = '\0';
|
||||
fprintf(f->data.fp, white_space);
|
||||
fputs(white_space, f->data.fp);
|
||||
i = vfprintf(f->data.fp, fmt, ap);
|
||||
|
||||
if (comment) {
|
||||
@@ -176,7 +176,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
|
||||
while (++i < COMMENT_TAB);
|
||||
|
||||
fprintf(f->data.fp, comment);
|
||||
fputs(comment, f->data.fp);
|
||||
}
|
||||
fputc('\n', f->data.fp);
|
||||
|
||||
@@ -221,6 +221,8 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
"Megabytes",
|
||||
"Gigabytes",
|
||||
"Terabytes",
|
||||
"Petabytes",
|
||||
"Exabytes",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
#define FMT_TEXT_NAME "lvm2"
|
||||
#define FMT_TEXT_ALIAS "text"
|
||||
|
||||
static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
|
||||
struct device_area *dev_area);
|
||||
|
||||
static struct format_instance *_text_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
@@ -80,6 +83,164 @@ static int _text_vg_setup(struct format_instance *fid __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if metadata area belongs to vg
|
||||
*/
|
||||
static int _mda_in_vg_raw(struct format_instance *fid __attribute((unused)),
|
||||
struct volume_group *vg, struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pvl->pv->dev == mdac->area.dev)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For circular region between region_start and region_start + region_size,
|
||||
* back up one SECTOR_SIZE from 'region_ptr' and return the value.
|
||||
* This allows reverse traversal through text metadata area to find old
|
||||
* metadata.
|
||||
*
|
||||
* Parameters:
|
||||
* region_start: start of the region (bytes)
|
||||
* region_size: size of the region (bytes)
|
||||
* region_ptr: pointer within the region (bytes)
|
||||
* NOTE: region_start <= region_ptr <= region_start + region_size
|
||||
*/
|
||||
static uint64_t _get_prev_sector_circular(uint64_t region_start,
|
||||
uint64_t region_size,
|
||||
uint64_t region_ptr)
|
||||
{
|
||||
if (region_ptr >= region_start + SECTOR_SIZE)
|
||||
return region_ptr - SECTOR_SIZE;
|
||||
else
|
||||
return (region_start + region_size - SECTOR_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze a metadata area for old metadata records in the circular buffer.
|
||||
* This function just looks through and makes a first pass at the data in
|
||||
* the sectors for particular things.
|
||||
* FIXME: do something with each metadata area (try to extract vg, write
|
||||
* raw data to file, etc)
|
||||
*/
|
||||
static int _pv_analyze_mda_raw (const struct format_type * fmt,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_header *mdah;
|
||||
struct raw_locn *rlocn;
|
||||
uint64_t area_start;
|
||||
uint64_t area_size;
|
||||
uint64_t prev_sector;
|
||||
uint64_t latest_mrec_offset;
|
||||
int i;
|
||||
uint64_t offset;
|
||||
uint64_t offset2;
|
||||
uint64_t size;
|
||||
uint64_t size2;
|
||||
char *buf=NULL;
|
||||
struct device_area *area;
|
||||
struct mda_context *mdac;
|
||||
int r=0;
|
||||
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
log_print("Found text metadata area, offset=%"PRIu64", size=%"PRIu64,
|
||||
mdac->area.start,
|
||||
mdac->area.size);
|
||||
area = &mdac->area;
|
||||
|
||||
if (!dev_open(area->dev))
|
||||
return_0;
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fmt, area)))
|
||||
goto_out;
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
|
||||
/*
|
||||
* The device area includes the metadata header as well as the
|
||||
* records, so remove the metadata header from the start and size
|
||||
*/
|
||||
area_start = area->start + MDA_HEADER_SIZE;
|
||||
area_size = area->size - MDA_HEADER_SIZE;
|
||||
latest_mrec_offset = rlocn->offset + area->start;
|
||||
|
||||
/*
|
||||
* Start searching at rlocn (point of live metadata) and go
|
||||
* backwards.
|
||||
*/
|
||||
prev_sector = _get_prev_sector_circular(area_start, area_size,
|
||||
latest_mrec_offset);
|
||||
offset = prev_sector;
|
||||
size = SECTOR_SIZE;
|
||||
offset2 = size2 = 0;
|
||||
i = 0;
|
||||
while (prev_sector != latest_mrec_offset) {
|
||||
prev_sector = _get_prev_sector_circular(area_start, area_size,
|
||||
prev_sector);
|
||||
/*
|
||||
* FIXME: for some reason, the whole metadata region from
|
||||
* area->start to area->start+area->size is not used.
|
||||
* Only ~32KB seems to contain valid metadata records
|
||||
* (LVM2 format - format_text). As a result, I end up with
|
||||
* "maybe_config_section" returning true when there's no valid
|
||||
* metadata in a sector (sectors with all nulls).
|
||||
*/
|
||||
if (!(buf = dm_pool_alloc(fmt->cmd->mem, size + size2)))
|
||||
goto_out;
|
||||
|
||||
if (!dev_read_circular(area->dev, offset, size,
|
||||
offset2, size2, buf))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* FIXME: We could add more sophisticated metadata detection
|
||||
*/
|
||||
if (maybe_config_section(buf, size+size2)) {
|
||||
/* FIXME: Validate region, pull out timestamp?, etc */
|
||||
/* FIXME: Do something with this region */
|
||||
log_verbose ("Found LVM2 metadata record at "
|
||||
"offset=%"PRIu64", size=%"PRIu64", "
|
||||
"offset2=%"PRIu64" size2=%"PRIu64,
|
||||
offset, size, offset2, size2);
|
||||
offset = prev_sector;
|
||||
size = SECTOR_SIZE;
|
||||
offset2 = size2 = 0;
|
||||
} else {
|
||||
/*
|
||||
* Not a complete metadata record, assume we have
|
||||
* metadata and just increase the size and offset.
|
||||
* Start the second region if the previous sector is
|
||||
* wrapping around towards the end of the disk.
|
||||
*/
|
||||
if (prev_sector > offset) {
|
||||
offset2 = prev_sector;
|
||||
size2 += SECTOR_SIZE;
|
||||
} else {
|
||||
offset = prev_sector;
|
||||
size += SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
dm_pool_free(fmt->cmd->mem, buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (buf)
|
||||
dm_pool_free(fmt->cmd->mem, buf);
|
||||
if (!dev_close(area->dev))
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int _text_lv_setup(struct format_instance *fid __attribute((unused)),
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
@@ -132,37 +293,40 @@ 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((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,
|
||||
@@ -193,7 +357,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;
|
||||
|
||||
@@ -707,7 +871,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;
|
||||
}
|
||||
|
||||
@@ -715,13 +880,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;
|
||||
}
|
||||
|
||||
@@ -885,8 +1052,8 @@ const char *vgname_from_mda(const struct format_type *fmt,
|
||||
uint32_t wrap = 0;
|
||||
const char *vgname = NULL;
|
||||
unsigned int len = 0;
|
||||
char buf[NAME_LEN + 1];
|
||||
char uuid[64];
|
||||
char buf[NAME_LEN + 1] __attribute((aligned(8)));
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_open(dev_area->dev)) {
|
||||
stack;
|
||||
@@ -1131,7 +1298,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
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;
|
||||
|
||||
@@ -1265,7 +1432,7 @@ static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
}
|
||||
|
||||
/* FIXME Optimise out repeated reading when cache lock held */
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1389,7 +1556,9 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
|
||||
.vg_remove = _vg_remove_raw,
|
||||
.vg_precommit = _vg_precommit_raw,
|
||||
.vg_commit = _vg_commit_raw,
|
||||
.vg_revert = _vg_revert_raw
|
||||
.vg_revert = _vg_revert_raw,
|
||||
.mda_in_vg = _mda_in_vg_raw,
|
||||
.pv_analyze_mda = _pv_analyze_mda_raw,
|
||||
};
|
||||
|
||||
/* pvmetadatasize in sectors */
|
||||
@@ -1408,6 +1577,7 @@ static int _text_pv_setup(const struct format_type *fmt,
|
||||
uint64_t pe_end = 0;
|
||||
unsigned mda_count = 0;
|
||||
uint64_t mda_size2 = 0;
|
||||
uint64_t pe_count;
|
||||
|
||||
/* FIXME Cope with pvchange */
|
||||
/* FIXME Merge code with _text_create_text_instance */
|
||||
@@ -1473,8 +1643,17 @@ static int _text_pv_setup(const struct format_type *fmt,
|
||||
pv->pe_start + mda_size2;
|
||||
|
||||
/* Recalculate number of extents that will fit */
|
||||
if (!pv->pe_count)
|
||||
pv->pe_count = (pv->size - pv->pe_start - mda_size2) / vg->extent_size;
|
||||
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? */
|
||||
@@ -1732,7 +1911,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.");
|
||||
|
||||
@@ -33,6 +33,7 @@ int archive_vg(struct volume_group *vg,
|
||||
* Displays a list of vg backups in a particular archive directory.
|
||||
*/
|
||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname);
|
||||
int archive_list_file(struct cmd_context *cmd, const char *file);
|
||||
int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname);
|
||||
|
||||
/*
|
||||
|
||||
@@ -43,7 +43,7 @@ const char *text_vgname_import(const struct format_type *fmt,
|
||||
_text_import_initialised = 1;
|
||||
}
|
||||
|
||||
if (!(cft = create_config_tree(NULL)))
|
||||
if (!(cft = create_config_tree(NULL, 0)))
|
||||
return_NULL;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
@@ -94,7 +94,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cft = create_config_tree(file)))
|
||||
if (!(cft = create_config_tree(file, 0)))
|
||||
return_NULL;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
|
||||
@@ -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.");
|
||||
@@ -213,6 +214,25 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
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;
|
||||
@@ -640,15 +660,11 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||
vg->fid = fid;
|
||||
|
||||
if (!(vg->name = dm_pool_strdup(mem, vgn->key))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->name = dm_pool_strdup(mem, vgn->key)))
|
||||
goto_bad;
|
||||
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
static int _text_can_handle(struct labeller *l __attribute((unused)),
|
||||
char *buf,
|
||||
void *buf,
|
||||
uint64_t sector __attribute((unused)))
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
@@ -35,7 +35,7 @@ static int _text_can_handle(struct labeller *l __attribute((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _text_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;
|
||||
@@ -189,7 +189,7 @@ static int _text_initialise_label(struct labeller *l __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _text_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;
|
||||
|
||||
@@ -107,7 +107,8 @@ struct labeller *label_get_handler(const char *name)
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector)
|
||||
uint64_t *label_sector,
|
||||
uint64_t scan_sector)
|
||||
{
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
@@ -115,14 +116,15 @@ 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];
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||
if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
|
||||
LABEL_SCAN_SIZE, readbuf)) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Scan first few sectors for a valid label */
|
||||
/* Scan a few sectors for a valid label */
|
||||
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||
lh = (struct label_header *) (readbuf +
|
||||
@@ -132,13 +134,14 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
if (found) {
|
||||
log_error("Ignoring additional label on %s at "
|
||||
"sector %" PRIu64, dev_name(dev),
|
||||
sector);
|
||||
sector + scan_sector);
|
||||
}
|
||||
if (xlate64(lh->sector_xl) != sector) {
|
||||
if (xlate64(lh->sector_xl) != sector + scan_sector) {
|
||||
log_info("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
xlate64(lh->sector_xl), sector);
|
||||
xlate64(lh->sector_xl),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||
@@ -153,19 +156,21 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
}
|
||||
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||
sector + scan_sector)) {
|
||||
log_very_verbose("%s: %s label detected",
|
||||
dev_name(dev), li->name);
|
||||
if (found) {
|
||||
log_error("Ignoring additional label "
|
||||
"on %s at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
dev_name(dev),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
r = li->l;
|
||||
memcpy(buf, lh, LABEL_SIZE);
|
||||
if (label_sector)
|
||||
*label_sector = sector;
|
||||
*label_sector = sector + scan_sector;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -186,8 +191,8 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
/* 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;
|
||||
@@ -256,9 +261,10 @@ int label_remove(struct device *dev)
|
||||
}
|
||||
|
||||
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
int label_read(struct device *dev, struct label **result,
|
||||
uint64_t scan_sector)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct labeller *l;
|
||||
uint64_t sector;
|
||||
struct lvmcache_info *info;
|
||||
@@ -274,7 +280,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
if (!(l = _find_labeller(dev, buf, §or, scan_sector)))
|
||||
goto_out;
|
||||
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
@@ -290,7 +296,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
/* 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;
|
||||
|
||||
@@ -341,22 +347,20 @@ int label_write(struct device *dev, struct label *label)
|
||||
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 (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
|
||||
goto out;
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
if (!(l = _find_labeller(dev, buf, §or, UINT64_C(0))))
|
||||
goto_out;
|
||||
|
||||
r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
|
||||
|
||||
@@ -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.
|
||||
@@ -96,7 +96,8 @@ int label_register_handler(const char *name, struct labeller *handler);
|
||||
struct labeller *label_get_handler(const char *name);
|
||||
|
||||
int label_remove(struct device *dev);
|
||||
int label_read(struct device *dev, struct label **result);
|
||||
int label_read(struct device *dev, struct label **result,
|
||||
uint64_t scan_sector);
|
||||
int label_write(struct device *dev, struct label *label);
|
||||
int label_verify(struct device *dev);
|
||||
struct label *label_create(struct labeller *labeller);
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -336,8 +321,8 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
if (mirror_in_sync())
|
||||
args[1] |= LCK_MIRROR_NOSYNC_MODE;
|
||||
|
||||
if (dmeventd_register_mode())
|
||||
args[1] |= LCK_DMEVENTD_REGISTER_MODE;
|
||||
if (dmeventd_monitor_mode())
|
||||
args[1] |= LCK_DMEVENTD_MONITOR_MODE;
|
||||
|
||||
/*
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
@@ -374,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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -34,6 +34,87 @@ 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 volatile sig_atomic_t _sigint_caught = 0;
|
||||
static volatile sig_atomic_t _handler_installed;
|
||||
static struct sigaction _oldhandler;
|
||||
static int _oldmasked;
|
||||
|
||||
static void _catch_sigint(int unused __attribute__((unused)))
|
||||
{
|
||||
_sigint_caught = 1;
|
||||
}
|
||||
|
||||
int sigint_caught() {
|
||||
return _sigint_caught;
|
||||
}
|
||||
|
||||
void sigint_clear()
|
||||
{
|
||||
_sigint_caught = 0;
|
||||
}
|
||||
|
||||
/* Temporarily allow keyboard interrupts to be intercepted and noted;
|
||||
saves interrupt handler state for sigint_restore(). Users should
|
||||
use the sigint_caught() predicate to check whether interrupt was
|
||||
requested and act appropriately. Interrupt flags are never
|
||||
automatically cleared by this code, but lvm_run_command() clears
|
||||
the flag before running any command. All other places where the
|
||||
flag needs to be cleared need to call sigint_clear(). */
|
||||
|
||||
void sigint_allow()
|
||||
{
|
||||
struct sigaction handler;
|
||||
sigset_t sigs;
|
||||
|
||||
/* do not overwrite the backed up handler data with our
|
||||
override ones; we just increase nesting count */
|
||||
if (_handler_installed) {
|
||||
_handler_installed++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* grab old sigaction for SIGINT; shall not fail */
|
||||
sigaction(SIGINT, NULL, &handler);
|
||||
handler.sa_flags &= ~SA_RESTART; /* clear restart flag */
|
||||
handler.sa_handler = _catch_sigint;
|
||||
|
||||
_handler_installed = 1;
|
||||
|
||||
/* override the signal handler; shall not fail */
|
||||
sigaction(SIGINT, &handler, &_oldhandler);
|
||||
|
||||
/* unmask SIGINT, remember to mask it again on restore */
|
||||
sigprocmask(0, NULL, &sigs);
|
||||
if ((_oldmasked = sigismember(&sigs, SIGINT))) {
|
||||
sigdelset(&sigs, SIGINT);
|
||||
sigprocmask(SIG_SETMASK, &sigs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void sigint_restore()
|
||||
{
|
||||
/* extra call, ignore */
|
||||
if (!_handler_installed)
|
||||
return;
|
||||
|
||||
if (_handler_installed > 1) {
|
||||
_handler_installed--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* nesting count went down to 0 */
|
||||
_handler_installed = 0;
|
||||
|
||||
if (_oldmasked) {
|
||||
sigset_t sigs;
|
||||
sigprocmask(0, NULL, &sigs);
|
||||
sigaddset(&sigs, SIGINT);
|
||||
sigprocmask(SIG_SETMASK, &sigs, NULL);
|
||||
}
|
||||
|
||||
sigaction(SIGINT, &_oldhandler, NULL);
|
||||
}
|
||||
|
||||
static void _block_signals(int flags __attribute((unused)))
|
||||
{
|
||||
sigset_t set;
|
||||
@@ -144,18 +225,18 @@ int init_locking(int type, struct cmd_context *cmd)
|
||||
case 2:
|
||||
if (!cmd->is_static) {
|
||||
log_very_verbose("External locking selected.");
|
||||
if (!init_external_locking(&_locking, cmd))
|
||||
break;
|
||||
return 1;
|
||||
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("Falling back to clustered locking.");
|
||||
/* Fall through */
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
log_very_verbose("Falling back to internal clustered locking.");
|
||||
/* Fall through */
|
||||
|
||||
case 3:
|
||||
log_very_verbose("Cluster locking selected.");
|
||||
if (!init_cluster_locking(&_locking, cmd))
|
||||
@@ -249,7 +330,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:
|
||||
|
||||
@@ -50,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 */
|
||||
@@ -75,7 +75,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
*/
|
||||
#define LCK_PARTIAL_MODE 0x00000001 /* Running in partial mode */
|
||||
#define LCK_MIRROR_NOSYNC_MODE 0x00000002 /* Mirrors don't require sync */
|
||||
#define LCK_DMEVENTD_REGISTER_MODE 0x00000004 /* Register with dmeventd */
|
||||
#define LCK_DMEVENTD_MONITOR_MODE 0x00000004 /* Register with dmeventd */
|
||||
|
||||
|
||||
/*
|
||||
@@ -115,4 +115,11 @@ 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);
|
||||
|
||||
/* interrupt handling */
|
||||
|
||||
void sigint_clear();
|
||||
void sigint_allow();
|
||||
void sigint_restore();
|
||||
int sigint_caught();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -81,7 +81,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
static int _already_logging = 0;
|
||||
static int _mirror_in_sync = 0;
|
||||
static int _dmeventd_register = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _ignore_suspended_devices = 0;
|
||||
|
||||
static lvm2_log_fn_t _lvm2_log_fn = NULL;
|
||||
|
||||
@@ -120,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;
|
||||
}
|
||||
}
|
||||
@@ -189,9 +191,14 @@ void init_mirror_in_sync(int in_sync)
|
||||
_mirror_in_sync = in_sync;
|
||||
}
|
||||
|
||||
void init_dmeventd_register(int reg)
|
||||
void init_dmeventd_monitor(int reg)
|
||||
{
|
||||
_dmeventd_register = reg;
|
||||
_dmeventd_monitor = reg;
|
||||
}
|
||||
|
||||
void init_ignore_suspended_devices(int ignore)
|
||||
{
|
||||
_ignore_suspended_devices = ignore;
|
||||
}
|
||||
|
||||
void init_cmd_name(int status)
|
||||
@@ -268,9 +275,14 @@ int mirror_in_sync(void)
|
||||
return _mirror_in_sync;
|
||||
}
|
||||
|
||||
int dmeventd_register_mode(void)
|
||||
int dmeventd_monitor_mode(void)
|
||||
{
|
||||
return _dmeventd_register;
|
||||
return _dmeventd_monitor;
|
||||
}
|
||||
|
||||
int ignore_suspended_devices(void)
|
||||
{
|
||||
return _ignore_suspended_devices;
|
||||
}
|
||||
|
||||
void init_debug(int level)
|
||||
|
||||
@@ -75,7 +75,8 @@ 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_register(int reg);
|
||||
void init_dmeventd_monitor(int reg);
|
||||
void init_ignore_suspended_devices(int ignore);
|
||||
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
|
||||
@@ -90,7 +91,10 @@ int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
int mirror_in_sync(void);
|
||||
int dmeventd_register_mode(void);
|
||||
int ignore_suspended_devices(void);
|
||||
|
||||
#define DMEVENTD_MONITOR_IGNORE -1
|
||||
int dmeventd_monitor_mode(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr (1) or everywhere (2) */
|
||||
/* Returns previous setting */
|
||||
@@ -134,5 +138,6 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
#define return_0 do { stack; return 0; } while (0)
|
||||
#define return_NULL do { stack; return NULL; } while (0)
|
||||
#define goto_out do { stack; goto out; } while (0)
|
||||
#define goto_bad do { stack; goto bad; } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -415,6 +415,15 @@ struct alloc_handle {
|
||||
struct list alloced_areas[0]; /* Lists of areas in each stripe */
|
||||
};
|
||||
|
||||
static uint32_t calc_area_multiple(const struct segment_type *segtype,
|
||||
const uint32_t area_count)
|
||||
{
|
||||
if (!segtype_is_striped(segtype) || !area_count)
|
||||
return 1;
|
||||
|
||||
return area_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparation for a specific allocation attempt
|
||||
*/
|
||||
@@ -476,7 +485,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
|
||||
ah->area_count = area_count;
|
||||
ah->log_count = log_count;
|
||||
ah->alloc = alloc;
|
||||
ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1;
|
||||
ah->area_multiple = calc_area_multiple(segtype, area_count);
|
||||
|
||||
for (s = 0; s < ah->area_count; s++)
|
||||
list_init(&ah->alloced_areas[s]);
|
||||
@@ -553,7 +562,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
|
||||
if (mirrored_pv)
|
||||
extra_areas = 1;
|
||||
|
||||
area_multiple = segtype_is_striped(segtype) ? area_count : 1;
|
||||
area_multiple = calc_area_multiple(segtype, area_count);
|
||||
|
||||
/* log_lv gets set up elsehere */
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
|
||||
@@ -628,17 +637,17 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
|
||||
struct pv_area **areas,
|
||||
uint32_t *ix, struct pv_area *log_area)
|
||||
{
|
||||
uint32_t area_len, smallest, remaining;
|
||||
uint32_t area_len, remaining;
|
||||
uint32_t s;
|
||||
struct alloced_area *aa;
|
||||
|
||||
remaining = needed - *ix;
|
||||
area_len = remaining / ah->area_multiple;
|
||||
|
||||
smallest = areas[ah->area_count - 1]->count;
|
||||
|
||||
if (area_len > smallest)
|
||||
area_len = smallest;
|
||||
/* Reduce area_len to the smallest of the areas */
|
||||
for (s = 0; s < ah->area_count; s++)
|
||||
if (area_len > areas[s]->count)
|
||||
area_len = areas[s]->count;
|
||||
|
||||
if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) *
|
||||
(ah->area_count + (log_area ? 1 : 0))))) {
|
||||
@@ -707,7 +716,7 @@ static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (max_seg_len && *max_seg_len > remaining_seg_len)
|
||||
*max_seg_len = remaining_seg_len;
|
||||
|
||||
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
|
||||
area_multiple = calc_area_multiple(seg->segtype, seg->area_count);
|
||||
area_len = remaining_seg_len / area_multiple ? : 1;
|
||||
|
||||
for (s = first_area;
|
||||
@@ -890,8 +899,17 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
uint32_t next_le;
|
||||
struct seg_pvs *spvs;
|
||||
struct list *parallel_pvs;
|
||||
uint32_t free_pes;
|
||||
|
||||
/* Is there enough total space? */
|
||||
free_pes = pv_maps_size(pvms);
|
||||
if (needed - *allocated > free_pes) {
|
||||
log_error("Insufficient free space: %" PRIu32 " extents needed,"
|
||||
" but only %" PRIu32 " available",
|
||||
needed - *allocated, free_pes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Do calculations on free extent counts before selecting space */
|
||||
/* FIXME Select log PV appropriately if there isn't one yet */
|
||||
|
||||
/* Are there any preceding segments we must follow on from? */
|
||||
@@ -1057,6 +1075,7 @@ static int _allocate(struct alloc_handle *ah,
|
||||
int r = 0;
|
||||
struct list *pvms;
|
||||
uint32_t areas_size;
|
||||
alloc_policy_t alloc;
|
||||
|
||||
if (allocated >= new_extents && !ah->log_count) {
|
||||
log_error("_allocate called with no work to do!");
|
||||
@@ -1102,50 +1121,18 @@ static int _allocate(struct alloc_handle *ah,
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
/* Attempt each defined allocation policy in turn */
|
||||
for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, alloc, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents))
|
||||
goto_out;
|
||||
if ((allocated == new_extents) || (ah->alloc == alloc) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
break;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
finished:
|
||||
if (allocated != new_extents) {
|
||||
log_error("Insufficient suitable %sallocatable extents "
|
||||
"for logical volume %s: %u more required",
|
||||
@@ -1156,6 +1143,13 @@ static int _allocate(struct alloc_handle *ah,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ah->log_count && !ah->log_area.len) {
|
||||
log_error("Insufficient extents for log allocation "
|
||||
"for logical volume %s.",
|
||||
lv ? lv->name : "");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -1499,7 +1493,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
struct lv_list *ll = NULL;
|
||||
struct logical_volume *lv;
|
||||
char dname[32];
|
||||
char dname[NAME_LEN];
|
||||
|
||||
if (vg->max_lv && (vg->max_lv == vg->lv_count)) {
|
||||
log_error("Maximum number of logical volumes (%u) reached "
|
||||
|
||||
@@ -23,9 +23,44 @@
|
||||
#include "str_list.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "activate.h"
|
||||
#include "display.h"
|
||||
#include "locking.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
/*
|
||||
* FIXME: Check for valid handle before dereferencing field or log error?
|
||||
*/
|
||||
#define pv_field(handle, field) \
|
||||
(((struct physical_volume *)(handle))->field)
|
||||
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
const char *pv_name,
|
||||
struct list *mdas,
|
||||
uint64_t *label_sector,
|
||||
int warnings);
|
||||
|
||||
static struct physical_volume *_pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id, uint64_t size,
|
||||
uint64_t pe_start,
|
||||
uint32_t existing_extent_count,
|
||||
uint32_t existing_extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas);
|
||||
|
||||
static int _pv_write(struct cmd_context *cmd __attribute((unused)),
|
||||
struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector);
|
||||
|
||||
static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
|
||||
const char *pv_name);
|
||||
|
||||
static struct pv_list *_find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
|
||||
static struct physical_volume *_find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id);
|
||||
|
||||
unsigned long pe_align(void)
|
||||
{
|
||||
return MAX(65536UL, lvm_getpagesize()) >> SECTOR_SHIFT;
|
||||
@@ -48,7 +83,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
}
|
||||
|
||||
list_init(&mdas);
|
||||
if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL, 1))) {
|
||||
if (!(pv = _pv_read(fid->fmt->cmd, pv_name, &mdas, NULL, 1))) {
|
||||
log_error("%s not identified as an existing physical volume",
|
||||
pv_name);
|
||||
return 0;
|
||||
@@ -101,7 +136,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (find_pv_in_vg(vg, pv_name)) {
|
||||
if (_find_pv_in_vg(vg, pv_name)) {
|
||||
log_error("Physical volume '%s' listed more than once.",
|
||||
pv_name);
|
||||
return 0;
|
||||
@@ -122,6 +157,15 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
pvl->pv = pv;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
|
||||
log_error("Unable to add %s to %s: new extent count (%"
|
||||
PRIu64 ") exceeds limit (%" PRIu32 ").",
|
||||
pv_name, vg->name,
|
||||
(uint64_t) vg->extent_count + pv->pe_count,
|
||||
UINT32_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vg->pv_count++;
|
||||
vg->extent_count += pv->pe_count;
|
||||
vg->free_count += pv->pe_count;
|
||||
@@ -270,10 +314,9 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
vg->seqno = 0;
|
||||
|
||||
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
|
||||
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
*vg->system_id = '\0';
|
||||
|
||||
vg->extent_size = extent_size;
|
||||
@@ -310,7 +353,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
|
||||
/* attach the pv's */
|
||||
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return vg;
|
||||
|
||||
@@ -495,8 +538,72 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||
struct volume_group *vg_to)
|
||||
{
|
||||
struct metadata_area *mda, *mda2;
|
||||
struct list *mdas_from, *mdas_to;
|
||||
int common_mda = 0;
|
||||
|
||||
mdas_from = &vg_from->fid->metadata_areas;
|
||||
mdas_to = &vg_to->fid->metadata_areas;
|
||||
|
||||
list_iterate_items_safe(mda, mda2, mdas_from) {
|
||||
if (!mda->ops->mda_in_vg) {
|
||||
common_mda = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mda->ops->mda_in_vg(vg_from->fid, vg_from, mda)) {
|
||||
list_del(&mda->list);
|
||||
list_add(mdas_to, &mda->list);
|
||||
}
|
||||
}
|
||||
|
||||
if (list_empty(mdas_from) || list_empty(mdas_to))
|
||||
return common_mda;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_create - initialize a physical volume for use with a volume group
|
||||
* @fmt: format type
|
||||
* @dev: PV device to initialize
|
||||
* @id: PV UUID to use for initialization
|
||||
* @size: size of the PV in sectors
|
||||
* @pe_start: physical extent start
|
||||
* @existing_extent_count
|
||||
* @existing_extent_size
|
||||
* @pvmetadatacopies
|
||||
* @pvmetadatasize
|
||||
* @mdas
|
||||
*
|
||||
* Returns:
|
||||
* PV handle - physical volume initialized successfully
|
||||
* NULL - invalid parameter or problem initializing the physical volume
|
||||
*
|
||||
* Note:
|
||||
* FIXME - liblvm todo - tidy up arguments for external use (fmt, mdas, etc)
|
||||
*/
|
||||
pv_t *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id, uint64_t size,
|
||||
uint64_t pe_start,
|
||||
uint32_t existing_extent_count,
|
||||
uint32_t existing_extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas)
|
||||
{
|
||||
return _pv_create(fmt, dev, id, size, pe_start,
|
||||
existing_extent_count,
|
||||
existing_extent_size,
|
||||
pvmetadatacopies,
|
||||
pvmetadatasize, mdas);
|
||||
}
|
||||
|
||||
/* Sizes in sectors */
|
||||
struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
static struct physical_volume *_pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id, uint64_t size,
|
||||
uint64_t pe_start,
|
||||
@@ -523,10 +630,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
|
||||
pv->dev = dev;
|
||||
|
||||
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
@@ -574,7 +679,13 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: liblvm todo - make into function that returns handle */
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
|
||||
{
|
||||
return _find_pv_in_vg(vg, pv_name);
|
||||
}
|
||||
|
||||
static struct pv_list *_find_pv_in_vg(struct volume_group *vg, const char *pv_name)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
|
||||
@@ -596,8 +707,26 @@ int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id)
|
||||
/**
|
||||
* find_pv_in_vg_by_uuid - Find PV in VG by PV UUID
|
||||
* @vg: volume group to search
|
||||
* @id: UUID of the PV to match
|
||||
*
|
||||
* Returns:
|
||||
* PV handle - if UUID of PV found in VG
|
||||
* NULL - invalid parameter or UUID of PV not found in VG
|
||||
*
|
||||
* Note
|
||||
* FIXME - liblvm todo - make into function that takes VG handle
|
||||
*/
|
||||
pv_t *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id)
|
||||
{
|
||||
return _find_pv_in_vg_by_uuid(vg, id);
|
||||
}
|
||||
|
||||
|
||||
static struct physical_volume *_find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
|
||||
@@ -655,12 +784,20 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: liblvm todo - make into function that returns handle */
|
||||
struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
|
||||
const char *pv_name)
|
||||
{
|
||||
return _find_pv_by_name(cmd, pv_name);
|
||||
}
|
||||
|
||||
|
||||
static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
|
||||
const char *pv_name)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (!(pv = pv_read(cmd, pv_name, NULL, NULL, 1))) {
|
||||
if (!(pv = _pv_read(cmd, pv_name, NULL, NULL, 1))) {
|
||||
log_error("Physical volume %s not found", pv_name);
|
||||
return NULL;
|
||||
}
|
||||
@@ -728,7 +865,7 @@ int vg_validate(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
struct lv_list *lvl, *lvl2;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
int r = 1;
|
||||
|
||||
/* FIXME Also check there's no data/metadata overlap */
|
||||
@@ -749,6 +886,12 @@ int vg_validate(struct volume_group *vg)
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(pvl->pv->vg_name, vg->name)) {
|
||||
log_error("Internal error: VG name for PV %s is corrupted",
|
||||
dev_name(pvl->pv->dev));
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_pv_segments(vg)) {
|
||||
@@ -938,7 +1081,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
if (!(pv = pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
|
||||
if (!(pv = _pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
|
||||
continue;
|
||||
}
|
||||
if (!(pvl = dm_pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
||||
@@ -953,6 +1096,30 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
return vg;
|
||||
}
|
||||
|
||||
static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
list_iterate_items(pvl2, all_pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
/* PV is not on list so add it. Note that we don't copy it. */
|
||||
if (!(pvl2 = dm_pool_zalloc(vg->cmd->mem, sizeof(*pvl2)))) {
|
||||
log_error("pv_list allocation for '%s' failed",
|
||||
dev_name(pvl->pv->dev));
|
||||
return 0;
|
||||
}
|
||||
pvl2->pv = pvl->pv;
|
||||
list_add(all_pvs, &pvl2->list);
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Caller sets consistent to 1 if it's safe for vg_read to correct
|
||||
* inconsistent metadata on disk (i.e. the VG write lock is held).
|
||||
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
|
||||
@@ -972,9 +1139,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
struct volume_group *vg, *correct_vg = NULL;
|
||||
struct metadata_area *mda;
|
||||
int inconsistent = 0;
|
||||
int inconsistent_vgid = 0;
|
||||
int use_precommitted = precommitted;
|
||||
struct list *pvids;
|
||||
struct pv_list *pvl;
|
||||
struct pv_list *pvl, *pvl2;
|
||||
struct list all_pvs;
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!*vgname) {
|
||||
if (use_precommitted) {
|
||||
@@ -1059,6 +1229,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
list_init(&all_pvs);
|
||||
|
||||
/* Failed to find VG where we expected it - full scan and retry */
|
||||
if (!correct_vg) {
|
||||
inconsistent = 0;
|
||||
@@ -1094,13 +1266,25 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
if (!correct_vg) {
|
||||
correct_vg = vg;
|
||||
if (!_update_pv_list(&all_pvs, correct_vg))
|
||||
return_NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((char *)vg->id.uuid,
|
||||
(char *)correct_vg->id.uuid, ID_LEN)) {
|
||||
inconsistent = 1;
|
||||
inconsistent_vgid = 1;
|
||||
}
|
||||
|
||||
/* FIXME Also ensure contents same - checksums same? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
if (vg->seqno > correct_vg->seqno) {
|
||||
if (!_update_pv_list(&all_pvs, vg))
|
||||
return_NULL;
|
||||
correct_vg = vg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1133,17 +1317,42 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata copies found - updating "
|
||||
"to use version %u", correct_vg->seqno);
|
||||
/* Don't touch if vgids didn't match */
|
||||
if (inconsistent_vgid) {
|
||||
log_error("Inconsistent metadata UUIDs found for "
|
||||
"volume group %s", vgname);
|
||||
*consistent = 0;
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata found for VG %s - updating "
|
||||
"to use version %u", vgname, correct_vg->seqno);
|
||||
|
||||
if (!vg_write(correct_vg)) {
|
||||
log_error("Automatic metadata correction failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!vg_commit(correct_vg)) {
|
||||
log_error("Automatic metadata correction commit "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(pvl, &all_pvs) {
|
||||
list_iterate_items(pvl2, &correct_vg->pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
|
||||
return_NULL;
|
||||
log_error("Removing PV %s (%s) that no longer belongs to VG %s",
|
||||
dev_name(pvl->pv->dev), uuid, correct_vg->name);
|
||||
if (!pv_write_orphan(cmd, pvl->pv))
|
||||
return_NULL;
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
|
||||
@@ -1278,10 +1487,34 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
return lvl->lv;
|
||||
}
|
||||
|
||||
/* FIXME Use label functions instead of PV functions */
|
||||
/**
|
||||
* pv_read - read and return a handle to a physical volume
|
||||
* @cmd: LVM command initiating the pv_read
|
||||
* @pv_name: full device name of the PV, including the path
|
||||
* @mdas: list of metadata areas of the PV
|
||||
* @label_sector: sector number where the PV label is stored on @pv_name
|
||||
* @warnings:
|
||||
*
|
||||
* Returns:
|
||||
* PV handle - valid pv_name and successful read of the PV, or
|
||||
* NULL - invalid parameter or error in reading the PV
|
||||
*
|
||||
* Note:
|
||||
* FIXME - liblvm todo - make into function that returns handle
|
||||
*/
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
struct list *mdas, uint64_t *label_sector,
|
||||
int warnings)
|
||||
{
|
||||
return _pv_read(cmd, pv_name, mdas, label_sector, warnings);
|
||||
}
|
||||
|
||||
/* FIXME Use label functions instead of PV functions */
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
const char *pv_name,
|
||||
struct list *mdas,
|
||||
uint64_t *label_sector,
|
||||
int warnings)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct label *label;
|
||||
@@ -1293,7 +1526,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
if (warnings)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
@@ -1402,8 +1635,17 @@ struct list *get_pvs(struct cmd_context *cmd)
|
||||
return results;
|
||||
}
|
||||
|
||||
int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volume *pv,
|
||||
/* FIXME: liblvm todo - make into function that takes handle */
|
||||
int pv_write(struct cmd_context *cmd __attribute((unused)),
|
||||
struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector)
|
||||
{
|
||||
return _pv_write(cmd, pv, mdas, label_sector);
|
||||
}
|
||||
|
||||
static int _pv_write(struct cmd_context *cmd __attribute((unused)),
|
||||
struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector)
|
||||
{
|
||||
if (!pv->fmt->ops->pv_write) {
|
||||
log_error("Format does not support writing physical volumes");
|
||||
@@ -1423,3 +1665,176 @@ int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volu
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
const char *old_vg_name = pv->vg_name;
|
||||
|
||||
pv->vg_name = ORPHAN;
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_pv_write(cmd, pv, NULL, INT64_C(-1))) {
|
||||
log_error("Failed to clear metadata from physical "
|
||||
"volume \"%s\" after removal from \"%s\"",
|
||||
dev_name(pv->dev), old_vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_orphan - Determine whether a pv is an orphan based on its vg_name
|
||||
* @pv: handle to the physical volume
|
||||
*/
|
||||
int is_orphan(pv_t *pv)
|
||||
{
|
||||
return (pv_field(pv, vg_name)[0] ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 - fail
|
||||
* 1 - success
|
||||
*/
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
int64_t label_sector)
|
||||
{
|
||||
struct label *label;
|
||||
struct device *dev;
|
||||
struct metadata_area *mda;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
dev = dev_cache_get(pv_name, cmd->filter);
|
||||
if (!dev) {
|
||||
log_error("Device %s not found (or ignored by filtering).",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, scan for LVM labels.
|
||||
*/
|
||||
if (!label_read(dev, &label, label_sector)) {
|
||||
log_error("Could not find LVM label on %s",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("Found label on %s, sector %"PRIu64", type=%s",
|
||||
pv_name, label->sector, label->type);
|
||||
|
||||
/*
|
||||
* Next, loop through metadata areas
|
||||
*/
|
||||
info = label->info;
|
||||
list_iterate_items(mda, &info->mdas)
|
||||
mda->ops->pv_analyze_mda(info->fmt, mda);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* vg_check_status - check volume group status flags and log error
|
||||
* @vg - volume group to check status flags
|
||||
* @status_flags - specific status flags to check (e.g. EXPORTED_VG)
|
||||
*
|
||||
* Returns:
|
||||
* 0 - fail
|
||||
* 1 - success
|
||||
*/
|
||||
int vg_check_status(struct volume_group *vg, uint32_t status_flags)
|
||||
{
|
||||
if ((status_flags & CLUSTERED) &&
|
||||
(vg->status & CLUSTERED) && !locking_is_clustered() &&
|
||||
!lockingfailed()) {
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((status_flags & EXPORTED_VG) &&
|
||||
(vg->status & EXPORTED_VG)) {
|
||||
log_error("Volume group %s is exported", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((status_flags & LVM_WRITE) &&
|
||||
!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group %s is read-only", vg->name);
|
||||
return 0;
|
||||
}
|
||||
if ((status_flags & RESIZEABLE_VG) &&
|
||||
!(vg->status & RESIZEABLE_VG)) {
|
||||
log_error("Volume group %s is not resizeable.", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gets/Sets for external LVM library
|
||||
*/
|
||||
struct id get_pv_id(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, id);
|
||||
}
|
||||
|
||||
const struct format_type *get_pv_format_type(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, fmt);
|
||||
}
|
||||
|
||||
struct id get_pv_vgid(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, vgid);
|
||||
}
|
||||
|
||||
struct device *get_pv_dev(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, dev);
|
||||
}
|
||||
|
||||
const char *get_pv_vg_name(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, vg_name);
|
||||
}
|
||||
|
||||
uint64_t get_pv_size(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, size);
|
||||
}
|
||||
|
||||
uint32_t get_pv_status(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, status);
|
||||
}
|
||||
|
||||
uint32_t get_pv_pe_size(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, pe_size);
|
||||
}
|
||||
|
||||
uint64_t get_pv_pe_start(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, pe_start);
|
||||
}
|
||||
|
||||
uint32_t get_pv_pe_count(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, pe_count);
|
||||
}
|
||||
|
||||
uint32_t get_pv_pe_alloc_count(pv_t *pv)
|
||||
{
|
||||
return pv_field(pv, pe_alloc_count);
|
||||
}
|
||||
|
||||
@@ -78,17 +78,18 @@
|
||||
#define FMT_RESIZE_PV 0x00000080U /* Supports pvresize? */
|
||||
#define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */
|
||||
|
||||
/* Ordered list - see lv_manip.c */
|
||||
typedef enum {
|
||||
ALLOC_INVALID = 0,
|
||||
ALLOC_INHERIT,
|
||||
ALLOC_INVALID,
|
||||
ALLOC_CONTIGUOUS,
|
||||
ALLOC_CLING,
|
||||
ALLOC_NORMAL,
|
||||
ALLOC_ANYWHERE
|
||||
ALLOC_ANYWHERE,
|
||||
ALLOC_INHERIT
|
||||
} alloc_policy_t;
|
||||
|
||||
typedef enum {
|
||||
AREA_UNASSIGNED = 0,
|
||||
AREA_UNASSIGNED,
|
||||
AREA_PV,
|
||||
AREA_LV
|
||||
} area_type_t;
|
||||
@@ -141,6 +142,7 @@ struct physical_volume {
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
typedef struct physical_volume pv_t;
|
||||
struct metadata_area;
|
||||
struct format_instance;
|
||||
|
||||
@@ -177,6 +179,17 @@ struct metadata_area_ops {
|
||||
struct volume_group * vg, struct metadata_area * mda);
|
||||
int (*vg_remove) (struct format_instance * fi, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
/*
|
||||
* Check if metadata area belongs to vg
|
||||
*/
|
||||
int (*mda_in_vg) (struct format_instance * fi,
|
||||
struct volume_group * vg, struct metadata_area *mda);
|
||||
/*
|
||||
* Analyze a metadata area on a PV.
|
||||
*/
|
||||
int (*pv_analyze_mda) (const struct format_type * fmt,
|
||||
struct metadata_area *mda);
|
||||
|
||||
};
|
||||
|
||||
struct metadata_area {
|
||||
@@ -285,7 +298,7 @@ struct logical_volume {
|
||||
int32_t major;
|
||||
int32_t minor;
|
||||
|
||||
uint64_t size;
|
||||
uint64_t size; /* Sectors */
|
||||
uint32_t le_count;
|
||||
|
||||
uint32_t origin_count;
|
||||
@@ -422,20 +435,24 @@ struct list *get_vgids(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector);
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
int is_orphan(pv_t *pv);
|
||||
|
||||
/* pe_start and pe_end relate to any existing data so that new metadata
|
||||
* areas can avoid overlap */
|
||||
struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id,
|
||||
uint64_t size,
|
||||
uint64_t pe_start,
|
||||
uint32_t existing_extent_count,
|
||||
uint32_t existing_extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas);
|
||||
pv_t *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id,
|
||||
uint64_t size,
|
||||
uint64_t pe_start,
|
||||
uint32_t existing_extent_count,
|
||||
uint32_t existing_extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas);
|
||||
int pv_resize(struct physical_volume *pv, struct volume_group *vg,
|
||||
uint32_t new_pe_count);
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
int64_t label_sector);
|
||||
|
||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
|
||||
uint32_t extent_size, uint32_t max_pv,
|
||||
@@ -448,6 +465,8 @@ int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
||||
int pv_count, char **pv_names);
|
||||
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t new_extent_size);
|
||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||
struct volume_group *vg_to);
|
||||
|
||||
/* Manipulate LVs */
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
@@ -483,8 +502,7 @@ struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
|
||||
|
||||
/* Find a PV within a given VG */
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id);
|
||||
pv_t *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id);
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *vgid, const char *pvid,
|
||||
struct physical_volume *pv);
|
||||
@@ -561,6 +579,8 @@ int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
|
||||
int vg_remove_snapshot(struct logical_volume *cow);
|
||||
|
||||
int vg_check_status(struct volume_group *vg, uint32_t status_flags);
|
||||
|
||||
/*
|
||||
* Mirroring functions
|
||||
*/
|
||||
@@ -616,4 +636,19 @@ uint32_t find_free_lvnum(struct logical_volume *lv);
|
||||
char *generate_lv_name(struct volume_group *vg, const char *format,
|
||||
char *buffer, size_t len);
|
||||
|
||||
/*
|
||||
* Gets/Sets for external LVM library
|
||||
*/
|
||||
struct id get_pv_id(pv_t *pv);
|
||||
const struct format_type *get_pv_format_type(pv_t *pv);
|
||||
struct id get_pv_vgid(pv_t *pv);
|
||||
struct device *get_pv_dev(pv_t *pv);
|
||||
const char *get_pv_vg_name(pv_t *pv);
|
||||
uint64_t get_pv_size(pv_t *pv);
|
||||
uint32_t get_pv_status(pv_t *pv);
|
||||
uint32_t get_pv_pe_size(pv_t *pv);
|
||||
uint64_t get_pv_pe_start(pv_t *pv);
|
||||
uint32_t get_pv_pe_count(pv_t *pv);
|
||||
uint32_t get_pv_pe_alloc_count(pv_t *pv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "str_list.h"
|
||||
#include "locking.h" /* FIXME Should not be used in this file */
|
||||
|
||||
#include "defaults.h" /* FIXME: should this be defaults.h? */
|
||||
@@ -36,20 +37,20 @@ struct lv_segment *find_mirror_seg(struct lv_segment *seg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure region size is compatible with volume size.
|
||||
* Reduce the region size if necessary to ensure
|
||||
* the volume size is a multiple of the region size.
|
||||
*/
|
||||
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
|
||||
uint32_t region_size)
|
||||
{
|
||||
uint32_t region_max;
|
||||
uint64_t region_max;
|
||||
|
||||
region_max = (1 << (ffs((int)extents) - 1)) * extent_size;
|
||||
region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
|
||||
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
if (region_max < UINT32_MAX && region_size > region_max) {
|
||||
region_size = (uint32_t) region_max;
|
||||
log_print("Using reduced mirror region size of %" PRIu32
|
||||
" sectors", region_max);
|
||||
return region_max;
|
||||
" sectors", region_size);
|
||||
}
|
||||
|
||||
return region_size;
|
||||
@@ -77,6 +78,42 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
|
||||
lv_from->size = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete independent/orphan LV, it must acquire lock.
|
||||
*/
|
||||
static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv)
|
||||
{
|
||||
struct cmd_context *cmd = mirrored_seg->lv->vg->cmd;
|
||||
struct str_list *sl;
|
||||
|
||||
/* Inherit tags - maybe needed for activation */
|
||||
if (!str_list_match_list(&mirrored_seg->lv->tags, &lv->tags)) {
|
||||
list_iterate_items(sl, &mirrored_seg->lv->tags)
|
||||
if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
|
||||
log_error("Aborting. Unable to tag.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_write(mirrored_seg->lv->vg) ||
|
||||
!vg_commit(mirrored_seg->lv->vg)) {
|
||||
log_error("Intermediate VG commit for orphan volume failed.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce mirrored_seg to num_mirrors images.
|
||||
*/
|
||||
@@ -84,6 +121,7 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct list *removable_pvs, int remove_log)
|
||||
{
|
||||
uint32_t m;
|
||||
uint32_t extents;
|
||||
uint32_t s, s1;
|
||||
struct logical_volume *sub_lv;
|
||||
struct logical_volume *log_lv = NULL;
|
||||
@@ -95,6 +133,7 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct pv_list *pvl;
|
||||
uint32_t old_area_count = mirrored_seg->area_count;
|
||||
uint32_t new_area_count = mirrored_seg->area_count;
|
||||
struct segment_type *segtype;
|
||||
|
||||
log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
|
||||
PRIu32 " image(s)%s.",
|
||||
@@ -156,9 +195,14 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
/* If no more mirrors, remove mirror layer */
|
||||
if (num_mirrors == 1) {
|
||||
lv1 = seg_lv(mirrored_seg, 0);
|
||||
extents = lv1->le_count;
|
||||
_move_lv_segments(mirrored_seg->lv, lv1);
|
||||
mirrored_seg->lv->status &= ~MIRRORED;
|
||||
remove_log = 1;
|
||||
/* Replace mirror with error segment */
|
||||
segtype = get_segtype_from_string(mirrored_seg->lv->vg->cmd, "error");
|
||||
if (!lv_add_virtual_segment(lv1, 0, extents, segtype))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (remove_log && mirrored_seg->log_lv) {
|
||||
@@ -174,8 +218,6 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
* then deactivate and remove them fully.
|
||||
*/
|
||||
|
||||
/* FIXME lv1 has no segments here so shouldn't be written to disk! */
|
||||
|
||||
if (!vg_write(mirrored_seg->lv->vg)) {
|
||||
log_error("intermediate VG write failed.");
|
||||
return 0;
|
||||
@@ -200,57 +242,15 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
}
|
||||
|
||||
/* Delete the 'orphan' LVs */
|
||||
for (m = num_mirrors; m < old_area_count; m++) {
|
||||
/* LV is now independent of the mirror so must acquire lock. */
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
for (m = num_mirrors; m < old_area_count; m++)
|
||||
if (!_delete_lv(mirrored_seg, seg_lv(mirrored_seg, m)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (lv1 && !_delete_lv(mirrored_seg, lv1))
|
||||
return 0;
|
||||
|
||||
if (!lv_remove(seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv1) {
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_lv) {
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (log_lv && !_delete_lv(mirrored_seg, log_lv))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -562,7 +562,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (activation() && segtype->ops->target_present &&
|
||||
!segtype->ops->target_present()) {
|
||||
!segtype->ops->target_present(NULL)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel", segtype->name);
|
||||
return 0;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
/*
|
||||
* Areas are maintained in size order, largest first.
|
||||
*
|
||||
* FIXME Cope with overlap.
|
||||
*/
|
||||
static void _insert_area(struct list *head, struct pv_area *a)
|
||||
{
|
||||
@@ -30,6 +32,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
|
||||
}
|
||||
|
||||
list_add(&pva->list, &a->list);
|
||||
a->map->pe_count += a->count;
|
||||
}
|
||||
|
||||
static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
|
||||
@@ -126,23 +129,32 @@ static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
|
||||
|
||||
static int _create_maps(struct dm_pool *mem, struct list *pvs, struct list *pvms)
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
struct pv_map *pvm, *pvm2;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate_items(pvl, pvs) {
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV))
|
||||
continue;
|
||||
|
||||
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
|
||||
stack;
|
||||
return 0;
|
||||
pvm = NULL;
|
||||
|
||||
list_iterate_items(pvm2, pvms)
|
||||
if (pvm2->pv->dev == pvl->pv->dev) {
|
||||
pvm = pvm2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pvm) {
|
||||
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvm->pv = pvl->pv;
|
||||
list_init(&pvm->areas);
|
||||
list_add(pvms, &pvm->list);
|
||||
}
|
||||
|
||||
pvm->pv = pvl->pv;
|
||||
|
||||
list_init(&pvm->areas);
|
||||
list_add(pvms, &pvm->list);
|
||||
|
||||
if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -180,6 +192,7 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
|
||||
void consume_pv_area(struct pv_area *pva, uint32_t to_go)
|
||||
{
|
||||
list_del(&pva->list);
|
||||
pva->map->pe_count -= pva->count;
|
||||
|
||||
assert(to_go <= pva->count);
|
||||
|
||||
@@ -190,3 +203,14 @@ void consume_pv_area(struct pv_area *pva, uint32_t to_go)
|
||||
_insert_area(&pva->map->areas, pva);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pv_maps_size(struct list *pvms)
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
uint32_t pe_count = 0;
|
||||
|
||||
list_iterate_items(pvm, pvms)
|
||||
pe_count += pvm->pe_count;
|
||||
|
||||
return pe_count;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ struct pv_area {
|
||||
struct pv_map {
|
||||
struct physical_volume *pv;
|
||||
struct list areas; /* struct pv_areas */
|
||||
uint32_t pe_count; /* Total number of PEs */
|
||||
|
||||
struct list list;
|
||||
};
|
||||
@@ -49,4 +50,6 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
|
||||
|
||||
void consume_pv_area(struct pv_area *area, uint32_t to_go);
|
||||
|
||||
uint32_t pv_maps_size(struct list *pvms);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@ struct dev_manager;
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010U
|
||||
#define SEG_VIRTUAL 0x00000020U
|
||||
#define SEG_CANNOT_BE_ZEROED 0x00000040U
|
||||
#define SEG_MONITORED 0x00000080U
|
||||
|
||||
#define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
@@ -39,6 +40,7 @@ struct dev_manager;
|
||||
#define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
||||
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
|
||||
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
@@ -76,13 +78,14 @@ struct segtype_handler {
|
||||
struct lv_segment *seg, char *params,
|
||||
uint64_t *total_numerator,
|
||||
uint64_t *total_denominator, float *percent);
|
||||
int (*target_present) (void);
|
||||
int (*target_present) (const struct lv_segment *seg);
|
||||
int (*modules_needed) (struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
void (*destroy) (const struct segment_type * segtype);
|
||||
int (*target_register_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unregister_events) (struct lv_segment *seg, int events);
|
||||
int (*target_monitored) (struct lv_segment *seg, int *pending);
|
||||
int (*target_monitor_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unmonitor_events) (struct lv_segment *seg, int events);
|
||||
};
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
|
||||
@@ -336,7 +336,7 @@ static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem
|
||||
return add_areas_line(dm, seg, node, start_area, area_count);
|
||||
}
|
||||
|
||||
static int _mirrored_target_present(void)
|
||||
static int _mirrored_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _mirrored_checked = 0;
|
||||
static int _mirrored_present = 0;
|
||||
@@ -368,13 +368,12 @@ static int _mirrored_target_present(void)
|
||||
}
|
||||
|
||||
#ifdef DMEVENTD
|
||||
static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
char **dso)
|
||||
static int _get_mirror_dso_path(struct cmd_context *cmd, char **dso)
|
||||
{
|
||||
char *path;
|
||||
const char *libpath;
|
||||
|
||||
if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
|
||||
if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Failed to allocate dmeventd library path.");
|
||||
return 0;
|
||||
}
|
||||
@@ -389,60 +388,105 @@ static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
/* FIXME Merge these two functions */
|
||||
static int _target_register_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
|
||||
const char *dso,
|
||||
enum dm_event_mask mask)
|
||||
{
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
if (!(dmevh = dm_event_handler_create()))
|
||||
return_0;
|
||||
|
||||
if (dm_event_handler_set_dso(dmevh, dso))
|
||||
goto fail;
|
||||
|
||||
if (dm_event_handler_set_dev_name(dmevh, dmname))
|
||||
goto fail;
|
||||
|
||||
dm_event_handler_set_event_mask(dmevh, mask);
|
||||
return dmevh;
|
||||
|
||||
fail:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _target_monitored(struct lv_segment *seg, int *pending)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
enum dm_event_mask evmask = 0;
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
*pending = 0;
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
/* FIXME Save a returned handle here so we can unregister it later */
|
||||
if (!dm_event_register(dso, name, DM_EVENT_ALL_ERRORS))
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
log_info("Registered %s for events", name);
|
||||
if (dm_event_get_registered_device(dmevh, 0)) {
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
evmask = dm_event_handler_get_event_mask(dmevh);
|
||||
if (evmask & DM_EVENT_REGISTRATION_PENDING) {
|
||||
*pending = 1;
|
||||
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
|
||||
}
|
||||
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return evmask;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
static int _target_set_events(struct lv_segment *seg, int evmask, int set)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *dmevh;
|
||||
int r;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
|
||||
dm_event_handler_destroy(dmevh);
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _target_unregister_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static int _target_monitor_events(struct lv_segment *seg, int events)
|
||||
{
|
||||
char *dso;
|
||||
char *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
return _target_set_events(seg, events, 1);
|
||||
}
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
/* FIXME Remove this and use handle to avoid config file race */
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
/* FIXME Use handle returned by registration function instead of dso */
|
||||
if (!dm_event_unregister(dso, name, DM_EVENT_ALL_ERRORS))
|
||||
return_0;
|
||||
|
||||
log_info("Unregistered %s for events", name);
|
||||
|
||||
return 1;
|
||||
static int _target_unmonitor_events(struct lv_segment *seg, int events)
|
||||
{
|
||||
return _target_set_events(seg, events, 0);
|
||||
}
|
||||
|
||||
#endif /* DMEVENTD */
|
||||
@@ -486,8 +530,9 @@ static struct segtype_handler _mirrored_ops = {
|
||||
.target_percent = _mirrored_target_percent,
|
||||
.target_present = _mirrored_target_present,
|
||||
#ifdef DMEVENTD
|
||||
.target_register_events = _target_register_events,
|
||||
.target_unregister_events = _target_unregister_events,
|
||||
.target_monitored = _target_monitored,
|
||||
.target_monitor_events = _target_monitor_events,
|
||||
.target_unmonitor_events = _target_unmonitor_events,
|
||||
#endif
|
||||
#endif
|
||||
.modules_needed = _mirrored_modules_needed,
|
||||
@@ -512,7 +557,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->ops = &_mirrored_ops;
|
||||
segtype->name = "mirror";
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_AREAS_MIRRORED;
|
||||
segtype->flags = SEG_AREAS_MIRRORED | SEG_MONITORED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef _LVM_LIB_H
|
||||
#define _LVM_LIB_H
|
||||
|
||||
#include <configure.h>
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
|
||||
@@ -66,7 +66,8 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd)
|
||||
if (!fcntl(*fd, F_SETLK, &lock))
|
||||
return 1;
|
||||
|
||||
close(*fd);
|
||||
if (close(*fd))
|
||||
log_sys_error("close", buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -239,8 +240,84 @@ void sync_dir(const char *file)
|
||||
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL))
|
||||
log_sys_error("fsync", dir);
|
||||
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", dir);
|
||||
|
||||
out:
|
||||
dm_free(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to obtain fcntl lock on a file, if necessary creating file first
|
||||
* or waiting.
|
||||
* Returns file descriptor on success, else -1.
|
||||
* mode is F_WRLCK or F_RDLCK
|
||||
*/
|
||||
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
|
||||
{
|
||||
int lockfd;
|
||||
char *dir;
|
||||
char *c;
|
||||
struct flock lock = {
|
||||
.l_type = lock_type,
|
||||
.l_whence = 0,
|
||||
.l_start = 0,
|
||||
.l_len = 0
|
||||
};
|
||||
|
||||
if (!(dir = dm_strdup(file))) {
|
||||
log_error("fcntl_lock_file failed in strdup.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((c = strrchr(dir, '/')))
|
||||
*c = '\0';
|
||||
|
||||
if (!create_dir(dir)) {
|
||||
dm_free(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dm_free(dir);
|
||||
|
||||
log_very_verbose("Locking %s (%s, %hd)", file,
|
||||
(lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
|
||||
lock_type);
|
||||
if ((lockfd = open(file, O_RDWR | O_CREAT, 0777)) < 0) {
|
||||
/* EACCES has been reported on NFS */
|
||||
if (warn_if_read_only || (errno != EROFS && errno != EACCES))
|
||||
log_sys_error("open", file);
|
||||
else
|
||||
stack;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(lockfd, F_SETLKW, &lock)) {
|
||||
log_sys_error("fcntl", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return lockfd;
|
||||
}
|
||||
|
||||
void fcntl_unlock_file(int lockfd)
|
||||
{
|
||||
struct flock lock = {
|
||||
.l_type = F_UNLCK,
|
||||
.l_whence = 0,
|
||||
.l_start = 0,
|
||||
.l_len = 0
|
||||
};
|
||||
|
||||
log_very_verbose("Unlocking fd %d", lockfd);
|
||||
|
||||
if (fcntl(lockfd, F_SETLK, &lock) == -1)
|
||||
log_error("fcntl unlock failed on fd %d: %s", lockfd,
|
||||
strerror(errno));
|
||||
|
||||
if (close(lockfd))
|
||||
log_error("lock file close failed on fd %d: %s", lockfd,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
@@ -48,4 +48,8 @@ int create_dir(const char *dir);
|
||||
/* Sync directory changes */
|
||||
void sync_dir(const char *file);
|
||||
|
||||
/* fcntl locking wrappers */
|
||||
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only);
|
||||
void fcntl_unlock_file(int lockfd);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,18 +36,38 @@ int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
* Count occurences of 'c' in 'str' until we reach a null char.
|
||||
*
|
||||
* Returns:
|
||||
* len - incremented for each char we encounter, whether 'c' or not.
|
||||
* count - number of occurences of 'c'
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
void count_chars(const char *str, size_t *len, int *count,
|
||||
const char c)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
if (*ptr == c)
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurences of 'c' in 'str' of length 'size'.
|
||||
*
|
||||
* Returns:
|
||||
* # of occurences of 'c'
|
||||
*/
|
||||
unsigned count_chars_len(const char *str, size_t size, const char c)
|
||||
{
|
||||
int i;
|
||||
unsigned count=0;
|
||||
|
||||
for (i=0; i < size; i++)
|
||||
if (str[i] == c)
|
||||
count++;
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -73,11 +93,11 @@ char *build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
int hyphens = 1;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vgname, &len, &hyphens);
|
||||
_count_hyphens(lvname, &len, &hyphens);
|
||||
count_chars(vgname, &len, &hyphens, '-');
|
||||
count_chars(lvname, &len, &hyphens, '-');
|
||||
|
||||
if (layer && *layer) {
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
count_chars(layer, &len, &hyphens, '-');
|
||||
hyphens++;
|
||||
}
|
||||
|
||||
@@ -105,6 +125,12 @@ char *build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
int validate_name(const char *n)
|
||||
{
|
||||
register char c;
|
||||
|
||||
@@ -30,4 +30,8 @@ char *build_dm_name(struct dm_pool *mem, const char *vg,
|
||||
|
||||
int validate_name(const char *n);
|
||||
|
||||
void count_chars(const char *str, size_t *len, int *count,
|
||||
char c);
|
||||
unsigned count_chars_len(const char *str, size_t size, char c);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _LVM_MATCHER_H
|
||||
#define _LVM_MATCHER_H
|
||||
|
||||
struct matcher;
|
||||
struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num);
|
||||
|
||||
int matcher_run(struct matcher *m, const char *begin);
|
||||
|
||||
#endif
|
||||
@@ -18,67 +18,67 @@
|
||||
* Display Fn, Unique format identifier */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid", "Unique identifier")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name", "Name. LVs created for internal use are enclosed in brackets.")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr", "Various attributes - see man page.")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major", "Persistent major number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor", "Persistent minor number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major", "Currently assigned major number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor", "Currently assigned minor number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size", "Size of LV in current units.")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count", "Number of segments in LV.")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent", "For snapshots, the percentage full if LV is active.")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent", "For mirrors and pvmove, current percentage in-sync.")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
|
||||
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
|
||||
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt", "Type of metadata.")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid", "Unique identifier.")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size", "Size of PV in current units.")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size", "Size of underlying device in current units.")
|
||||
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start", "Offset to the start of data on the underlying device.")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free", "Total amount of unallocated space in current units.")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used", "Total amount of allocated space in current units.")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name", "Name.")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr", "Various attributes - see man page.")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count", "Total number of Physical Extents.")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count", "Total number of allocated Physical Extents.")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags", "Tags, if any.")
|
||||
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
|
||||
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
|
||||
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
|
||||
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
|
||||
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
|
||||
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
|
||||
FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt", "Type of metadata.")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid", "Unique identifier.")
|
||||
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name", "Name.")
|
||||
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr", "Various attributes - see man page.")
|
||||
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size", "Total size of VG in current units.")
|
||||
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free", "Total amount of free space in current units.")
|
||||
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid", "System ID indicating when and where it was created.")
|
||||
FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size", "Size of Physical Extents in current units.")
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count", "Total number of Physical Extents.")
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count", "Total number of unallocated Physical Extents.")
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv", "Maximum number of LVs allowed in VG or 0 if unlimited.")
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv", "Maximum number of PVs allowed in VG or 0 if unlimited.")
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count", "Number of PVs.")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count", "Number of LVs.")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count", "Number of snapshots.")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno", "Revision number of internal metadata. Incremented whenever it changes.")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags", "Tags, if any.")
|
||||
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype", "Type of LV segment")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes", "Number of stripes or mirror legs.")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize", "For stripes, amount of data placed on one device before switching to the next.")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size", "For stripes, amount of data placed on one device before switching to the next.")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize", "For mirrors, the unit of data copied when synchronising devices.")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size", "For mirrors, the unit of data copied when synchronising devices.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start", "Offset within the LV to the start of the segment in current units.")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size", "Size of segment in current units.")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags", "Tags, if any.")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices", "Underlying devices used with starting extent numbers.")
|
||||
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start", "Physical Extent number of start of segment.")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size", "Number of extents in segment.")
|
||||
/* *INDENT-ON* */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user