1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-12-25 20:23:49 +03:00

Compare commits

...

133 Commits

Author SHA1 Message Date
Alasdair Kergon
e366b68ad3 pre-release 2007-04-27 20:47:14 +00:00
Alasdair Kergon
fb94fb980a Fix get_config_uint64() to read a 64-bit value not a 32-bit one. 2007-04-27 20:41:50 +00:00
Alasdair Kergon
b10cc18f53 Add -Wformat-security and change one fprintf() to fputs(). 2007-04-27 19:26:57 +00:00
Alasdair Kergon
a249de3b72 Standardise protective include file #defines. 2007-04-27 19:07:43 +00:00
Alasdair Kergon
d04e972d65 Move regex functions into libdevmapper. 2007-04-27 18:52:05 +00:00
Alasdair Kergon
b9f5a18a76 Add regex functions to library. 2007-04-27 18:40:23 +00:00
Alasdair Kergon
d3f157f08a configure.h isn't a system header 2007-04-27 18:01:45 +00:00
Alasdair Kergon
2294fdb496 Change some #include lines to search only standard system directories. 2007-04-27 17:46:16 +00:00
Alasdair Kergon
d7ba0e01a5 Avoid trailing separator in reports when there are hidden sort fields. 2007-04-27 15:22:27 +00:00
Alasdair Kergon
b6172b53fd Fix segfault in 'dmsetup status' without --showkeys against crypt target. [nec] 2007-04-27 15:12:26 +00:00
Alasdair Kergon
477ec611d5 Deal with some more compiler warnings. Hope this doesn't break anything... 2007-04-27 14:52:41 +00:00
Alasdair Kergon
b6194edd67 add preferred_names to man page. 2007-04-26 17:14:57 +00:00
Alasdair Kergon
dcdbbb3ecb 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.
2007-04-26 16:44:59 +00:00
Dave Wysochanski
7ef99ee4e6 Fix warnings on x86_64 involving ptrdiff_t:
config/config.c:493: warning: format '%d' expects type 'int', but argument 5 has type 'long int'

Modified original patch from Jim Meyering <jim@meyering.net>
2007-04-26 16:40:46 +00:00
Dave Wysochanski
1ac1418286 Update pvck to include text metadata area and record detection.
--
2007-04-25 21:10:55 +00:00
Dave Wysochanski
8fc854f38e Add support functions for analysis of config sections,
and hence, on-disk LVM2 metadata.

--
2007-04-25 20:38:39 +00:00
Dave Wysochanski
1c2360b335 Update pvck to read labels on disk, with flexible --labelsector
parameter.

--
2007-04-25 20:03:16 +00:00
Dave Wysochanski
dd4477406b Add count_chars and count_chars_len functions, two
generic string utility functions.

--
2007-04-25 18:24:19 +00:00
Bryn M. Reeves
9d67bbb104 Make lvm_dump.sh capture a listing of /sys/block entries. 2007-04-25 14:49:27 +00:00
Patrick Caulfield
d6c8e1df61 Fix thread race in clvmd. 2007-04-24 15:13:13 +00:00
Petr Rockai
5ec7c8fece Fix the regression introduced by dmeventd leak fixes. 2007-04-24 13:29:02 +00:00
Dave Wysochanski
86b21eaf83 Add 'scan_sector' parameter to label_read and _find_labeller to add
flexibility in searching for disk labels.
2007-04-23 18:21:01 +00:00
Petr Rockai
228486a971 Fix some memory leaks in dmeventd. 2007-04-23 15:06:03 +00:00
Patrick Caulfield
88c0caab26 Make clvmd cope with quorum devices in RHEL5
bz#237386
2007-04-23 14:55:28 +00:00
Bryn M. Reeves
5cd4679419 re-commit lvm_dump.sh change 2007-04-19 23:06:05 +00:00
Bryn M. Reeves
eeed5e0d19 Make lvm_dump.sh list /dev recursively to aid identifying devices. 2007-04-19 22:56:16 +00:00
Alasdair Kergon
369ab1e0b2 Introduce _add_field() and _is_same_field() to libdm-report.c. 2007-04-19 20:24:00 +00:00
Milan Broz
2e21519a10 Fix libdevmapper-event memory leaks 2007-04-19 19:10:19 +00:00
Dave Wysochanski
ecc001ed08 Add dev_read_circular, read 2 regions on same device. 2007-04-19 02:10:42 +00:00
Dave Wysochanski
cd96852696 Add stub for pvck, a command to check physical volume consistency. 2007-03-30 21:00:26 +00:00
Patrick Caulfield
b9f7f30158 Add some extra error checking & robustness.
Thanks to the Crosswalk engineering team:
    Leonard Maiorani
    Henry Harris
    Scott Cannata
2007-03-29 13:59:33 +00:00
Alasdair Kergon
ca5e423331 Update lists of attribute characters in man pages.
Change cling alloc policy attribute character from 'C' to l'.
2007-03-27 13:35:33 +00:00
Milan Broz
fa9407089c Fix creation and conversion of mirrors with tags. 2007-03-26 16:10:10 +00:00
Milan Broz
66f28e193a Fix vgsplit for lvm1 format (set and validate VG name in PVs metadata).
Split metadata areas in vgsplit properly.
2007-03-23 12:43:17 +00:00
Alasdair Kergon
0d93f89f5c post-release 2007-03-19 21:16:49 +00:00
Alasdair Kergon
154e9a2c47 pre-release 2007-03-19 21:12:54 +00:00
Milan Broz
84574a1257 Fix processing of exit status in init scripts 2007-03-16 17:15:36 +00:00
Alasdair Kergon
bf83527b64 Remove unnecessary memset() return value checks. [Jim Meyering] 2007-03-16 14:36:14 +00:00
Milan Broz
12c53622a0 Fix vgremove to require at least one vg argument. 2007-03-15 14:00:30 +00:00
Alasdair Kergon
d8f54cf891 Try to fix reading in of lvm1 striped LVs.
There are two fixes other than improving variable names and updating code
layout etc.
The loop counter is incremented by area_len instead of area_len * stripes;
the 3rd _check_stripe parameter is no longer multiplied by number of stripes.
2007-03-15 13:38:28 +00:00
Patrick Caulfield
625a671189 Flag nolocking as a clustered locking module as we need to be able
to look at clustered LVs at clvmd startup
2007-03-13 14:59:21 +00:00
Alasdair Kergon
6ebdad3102 Add a few missing pieces of vgname command line validation. 2007-03-09 21:25:33 +00:00
Alasdair Kergon
9a8f21aa03 Support the /dev/mapper prefix on most command lines. 2007-03-09 20:47:41 +00:00
Alasdair Kergon
291dd8edc2 post-release 2007-03-08 21:37:48 +00:00
Alasdair Kergon
de4c1daf29 pre-release 2007-03-08 21:28:13 +00:00
Alasdair Kergon
0b55d7d0d8 Fix vgrename active LV check to ignore differing vgids. 2007-03-08 21:08:25 +00:00
Alasdair Kergon
5d86fd8fdb Remove no-longer-used uuid_out parameter from activation info functions. 2007-03-08 19:58:04 +00:00
Alasdair Kergon
1b76eb1f59 Fix two more segfaults if an empty config file section encountered. 2007-03-08 19:22:52 +00:00
Alasdair Kergon
b05678d8bf 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.
2007-02-28 18:27:13 +00:00
Alasdair Kergon
781f4971c6 Exclude readline support from lvm.static 2007-02-14 16:51:48 +00:00
Alasdair Kergon
d02ac7b99a Fix a leak in a reporting error path. 2007-02-14 15:18:31 +00:00
Alasdair Kergon
b1b6c97f7c Fix a few leaks in reporting error paths. 2007-02-14 15:12:16 +00:00
Alasdair Kergon
baee28ab5c post-release 2007-02-13 16:16:15 +00:00
Alasdair Kergon
83edf68ff9 pre-release 2007-02-13 16:12:24 +00:00
Alasdair Kergon
c7588f91dd Correct -b and -P on a couple of man pages.
Add global/units to example.conf.
2007-02-13 16:04:01 +00:00
Alasdair Kergon
30b432adc5 Fix loading of segment_libraries. [gentoo] 2007-02-08 17:31:02 +00:00
Alasdair Kergon
7c9733eb5d If a PV reappears after it was removed from its VG, make it an orphan. 2007-02-07 13:29:52 +00:00
Alasdair Kergon
a223c3fea3 Improve dmeventd messaging protocol: drain pipe and tag messages. 2007-02-02 17:08:51 +00:00
Alasdair Kergon
d5250f4901 Fix some &->&& vgreduce cmdline validation. [Andre Noll] 2007-01-31 16:26:23 +00:00
Alasdair Kergon
25f29f4712 post-release 2007-01-30 21:37:18 +00:00
Alasdair Kergon
382af5563d pre-release 2007-01-30 18:08:17 +00:00
Alasdair Kergon
8cf3d165d3 Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring. 2007-01-30 18:02:15 +00:00
Alasdair Kergon
0fd6ce546f Fix vgsplit to handle mirrors.
Reorder fields in reporting field definitions.
2007-01-29 23:01:18 +00:00
Alasdair Kergon
b881c372bc post-release 2007-01-29 20:25:19 +00:00
Alasdair Kergon
94c5e7deb0 pre-release 2007-01-29 19:57:24 +00:00
Alasdair Kergon
c344766f3c Add recent reporting options to dmsetup man page.
Revise some report fields names.
2007-01-29 19:35:24 +00:00
Alasdair Kergon
67895de0bc help on help 2007-01-29 18:45:08 +00:00
Alasdair Kergon
ff00cb6990 help unused attr 2007-01-29 18:43:27 +00:00
Alasdair Kergon
2cc75c11ed add help -c for field list 2007-01-29 18:37:57 +00:00
Alasdair Kergon
cd79e58eda Add dmsetup 'help' command and update usage text. 2007-01-29 18:18:41 +00:00
Alasdair Kergon
6fa801f3d8 reorder report field definitions 2007-01-29 17:45:32 +00:00
Alasdair Kergon
684eecba1d Use fixed-size fields in report interface. 2007-01-29 17:23:54 +00:00
Alasdair Kergon
da9cf7e5de fix pvsegs report too 2007-01-27 02:32:31 +00:00
Alasdair Kergon
f57e7445fd Fix vgs to treat args as VGs even when PV fields are displayed. 2007-01-27 02:09:06 +00:00
Alasdair Kergon
fba1388719 Fix md signature check to handle both endiannesses. 2007-01-26 17:15:16 +00:00
Alasdair Kergon
80ed029c17 post-release 2007-01-25 23:40:33 +00:00
Alasdair Kergon
34a74e81e3 pre-release 2007-01-25 23:36:59 +00:00
Alasdair Kergon
cb120ddb15 dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors. 2007-01-25 23:32:29 +00:00
Alasdair Kergon
f9ee4395b0 also ignore mirrors 2007-01-25 23:03:48 +00:00
Alasdair Kergon
71f06d51ed Add devices/ignore_suspended_devices to ignore suspended dm devices. 2007-01-25 21:22:30 +00:00
Alasdair Kergon
217f70952f don't remove libdm-common.h any more 2007-01-25 15:45:10 +00:00
Alasdair Kergon
f813d41a76 Add some missing close() and fclose() return code checks.
Fix exit statuses of reporting tools (2.02.19).
2007-01-25 14:37:48 +00:00
Alasdair Kergon
d851289d8a Add some missing close() and fclose() return value checks. 2007-01-25 14:16:20 +00:00
Alasdair Kergon
b115b8a2ea Add init script for dmeventd monitoring. 2007-01-24 23:44:43 +00:00
Alasdair Kergon
d0f7067471 lvm.static no longer interacts with dmeventd unless explicitly asked to. 2007-01-24 23:43:27 +00:00
Alasdair Kergon
be5b4c38a7 fix earlier checkin 2007-01-24 22:06:11 +00:00
Alasdair Kergon
d6d597e3dd Migrate dmsetup column-based output over to new libdevmapper report framework. 2007-01-24 18:09:07 +00:00
Alasdair Kergon
84e348fade Add field definitions to report help text.
Remove unnecessary cmd arg from target_*monitor_events().
2007-01-24 16:51:24 +00:00
Alasdair Kergon
910054657e Adjust report field help description layout. 2007-01-24 16:41:33 +00:00
Alasdair Kergon
8357a11249 fix earlier checkin 2007-01-23 23:58:55 +00:00
Alasdair Kergon
9b021ba057 Add descriptions to reporting field definitions. 2007-01-23 19:18:52 +00:00
Alasdair Kergon
317e588efd Add private variable to dmeventd shared library interface. 2007-01-23 17:40:40 +00:00
Alasdair Kergon
b1d32a03c7 add a dso-private variable to dmeventd interface
more inline docn
2007-01-23 17:38:39 +00:00
Alasdair Kergon
ee6e6529ee Long-lived processes write out persistent dev cache in refresh_toolcontext(). 2007-01-23 16:03:54 +00:00
Alasdair Kergon
9d944d6cf9 Fix refresh_toolcontext() always to wipe persistent device filter cache.
Add is_long_lived to toolcontext.
2007-01-23 15:58:06 +00:00
Alasdair Kergon
13635d281a Add --clustered to man pages. 2007-01-23 13:08:34 +00:00
Alasdair Kergon
2493c46970 Streamline dm_report_field_* interface. 2007-01-22 15:07:21 +00:00
Alasdair Kergon
63e4217271 Add dm_event_handler_[gs]et_timeout functions.
Streamline dm_report_field_* interface.
2007-01-22 15:03:57 +00:00
Alasdair Kergon
f4bd12e8e9 register->monitor etc. 2007-01-19 22:21:45 +00:00
Alasdair Kergon
df15f46900 var dev_name->device_name (lvm2 has dev_name()) 2007-01-19 20:42:09 +00:00
Alasdair Kergon
fb3a732361 fix exit status; always print message on child failure 2007-01-19 18:08:36 +00:00
Alasdair Kergon
2d74110feb Add cmdline debug & version options to dmeventd.
Fix oom_adj handling.
2007-01-19 17:22:17 +00:00
Alasdair Kergon
19d102082d Add DM_LIB_VERSION definition to configure.h. 2007-01-19 15:53:01 +00:00
Alasdair Kergon
d2af2c9487 Update reporting man pages. 2007-01-18 22:33:24 +00:00
Alasdair Kergon
82980149fa Suppress 'Unrecognised field' error if report field is 'help'. 2007-01-18 22:15:04 +00:00
Alasdair Kergon
a19bb7b909 fix last checkin 2007-01-18 21:59:02 +00:00
Alasdair Kergon
9d98c3278d No longer necessary to specify alignment for report fields. 2007-01-18 17:48:29 +00:00
Alasdair Kergon
26376ac1c9 Some internal renaming.
Add --separator and --sort to dmsetup (unused as yet).
Make alignment flag optional when specifying report fields.
2007-01-18 17:47:58 +00:00
Alasdair Kergon
8459f99341 post-release 2007-01-17 17:56:15 +00:00
Alasdair Kergon
e5bdb0e0b5 pre-release 2007-01-17 17:51:51 +00:00
Alasdair Kergon
1106b7775a Fix a segfault if an empty config file section encountered. 2007-01-17 16:22:59 +00:00
Alasdair Kergon
ae2852156d merge _target_*register_events
introduce _create_dm_event_handler()
2007-01-17 15:00:57 +00:00
Alasdair Kergon
44c6c36c43 stat oom_adj and stay silent if it doesn't exist
dm_event_handler now keeps private copies of strings
2007-01-17 14:45:10 +00:00
Alasdair Kergon
a81926503d use updated dm_event_get_registered_device interface 2007-01-16 23:05:13 +00:00
Alasdair Kergon
af13ccddda more fixes 2007-01-16 23:03:13 +00:00
Alasdair Kergon
392e1bc2e8 more little fixes 2007-01-16 21:13:07 +00:00
Alasdair Kergon
9268d92c70 clean up global mutex usage and fix a race in thread finalisation code
properly clean up thread status when thread terminates from within
2007-01-16 20:27:07 +00:00
Alasdair Kergon
bb3366c07d dmeventd oom_adj + reduce thread stack size 2007-01-16 20:13:04 +00:00
Alasdair Kergon
d24d563ebc Move basic reporting functions into libdevmapper. 2007-01-16 18:06:12 +00:00
Alasdair Kergon
954bd9257b Add basic reporting functions to libdevmapper. 2007-01-16 18:04:15 +00:00
Alasdair Kergon
5d51a56c02 reduce some if/else complexity 2007-01-15 22:37:40 +00:00
Alasdair Kergon
f48648552e Fix a malloc error path in dmsetup message. 2007-01-15 22:05:50 +00:00
Alasdair Kergon
edb9c3cc9f Fix partition table processing after sparc changes (introduced in 2.02.16).
Fix cmdline PE range processing segfault (introduced in 2.02.13).
2007-01-15 21:55:11 +00:00
Alasdair Kergon
01dc83b936 fix recent checkins 2007-01-15 19:47:49 +00:00
Alasdair Kergon
3a8dff3a62 fail registration if timeout thread cannot be started 2007-01-15 19:19:31 +00:00
Alasdair Kergon
13b234ccba use DMEVENTD_PATH 2007-01-15 19:11:58 +00:00
Alasdair Kergon
e451e93664 static naming 2007-01-15 18:58:40 +00:00
Alasdair Kergon
b4f9531475 Some libdevmapper-event interface changes. 2007-01-15 18:22:02 +00:00
Alasdair Kergon
3184ff75c4 More libdevmapper-event interface changes and fixes.
Rename dm_saprintf() to dm_asprintf().
2007-01-15 18:21:01 +00:00
Alasdair Kergon
43243f4d30 Report error if NULL pointer supplied to dm_strdup_aux(). 2007-01-15 14:39:12 +00:00
Alasdair Kergon
c975a100b1 Report dmeventd mirror monitoring status. 2007-01-12 20:38:30 +00:00
Alasdair Kergon
02bf389425 Reinstate dm_event_get_registered_device 2007-01-12 20:22:11 +00:00
Alasdair Kergon
bcb9a3dd04 post-release 2007-01-11 23:19:08 +00:00
131 changed files with 8260 additions and 5101 deletions

View File

@@ -1 +1 @@
2.02.18-cvs (2007-01-11)
2.02.25-cvs (2007-04 27)

View File

@@ -1,3 +1,99 @@
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
===================================
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.

View File

@@ -1,3 +1,49 @@
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().

View File

@@ -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"
@@ -121,7 +121,7 @@ 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;
@@ -159,7 +159,7 @@ static int _cluster_do_node_callback(struct local_client *client,
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 +168,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];

View File

@@ -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;

View File

@@ -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;

View File

@@ -37,6 +37,7 @@
#include <getopt.h>
#include <syslog.h>
#include <errno.h>
#include <libdlm.h>
#include "clvmd-comms.h"
#include "lvm-functions.h"
@@ -44,7 +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"
@@ -56,6 +56,8 @@
#define FALSE 0
#endif
#define MAX_RETRIES 4
/* 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))
@@ -325,7 +327,7 @@ 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,
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
(void *)(long)using_gulm);
/* Tell the rest of the cluster our version number */
@@ -375,6 +377,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) {
@@ -412,6 +417,8 @@ 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));
if (len == -1 && errno == EINTR)
return 1;
if (len == sizeof(int)) {
memcpy(&status, buffer, sizeof(int));
@@ -786,6 +793,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);
@@ -901,8 +910,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;
@@ -927,9 +940,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;
@@ -1215,7 +1227,7 @@ static 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[3];
int version_nums[3];
char node[256];
memcpy(version_nums, msg->args, sizeof(version_nums));
@@ -1395,6 +1407,7 @@ 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;
@@ -1424,8 +1437,19 @@ static __attribute__ ((noreturn)) 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 */
@@ -1446,7 +1470,16 @@ static __attribute__ ((noreturn)) 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");
@@ -1650,6 +1683,11 @@ static int send_message(void *buf, int msglen, 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)) {
@@ -1660,14 +1698,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(errtext);
errno = saved_errno;
break;
}
len = write(fd, buf + ptr, msglen - ptr);
if (len <= 0) {
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(errtext);
break;
}
ptr += len;
} while (len < msglen);
} while (ptr < msglen);
}
return len;
}

View File

@@ -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 {
@@ -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;
}

View File

@@ -36,8 +36,11 @@
#include <dirent.h>
#include <errno.h>
#include <mntent.h>
#include <libdlm.h>
#ifdef HAVE_CCS
#include <ccs.h>
#endif
#include "libdlm.h"
#include "log.h"
#include "list.h"
#include "locking.h"
@@ -45,9 +48,6 @@
#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"

View File

@@ -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"

View File

@@ -1,16 +1,19 @@
dm_event_handler_create
dm_event_handler_destroy
dm_event_handler_set_dso
dm_event_handler_set_name
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_events
dm_event_handler_set_event_mask
dm_event_handler_get_dso
dm_event_handler_get_name
dm_event_handler_get_devname
dm_event_handler_get_uuid
dm_event_handler_get_major
dm_event_handler_get_minor
dm_event_handler_get_events
dm_event_register
dm_event_unregister
dm_event_handler_get_event_mask
dm_event_register_handler
dm_event_unregister_handler
dm_event_get_registered_device
dm_event_handler_set_timeout
dm_event_handler_get_timeout

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,7 @@ enum dm_event_command {
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. */

View File

@@ -30,110 +30,173 @@
#include <sys/wait.h>
#include <arpa/inet.h> /* for htonl, ntohl */
static int _sequence_nr = 0;
struct dm_event_handler {
const char *dso;
const char *device;
const char *uuid;
char *dso;
char *dev_name;
char *uuid;
int major;
int minor;
enum dm_event_type events;
uint32_t timeout;
enum dm_event_mask mask;
};
static void dm_event_handler_clear_device(struct dm_event_handler *h)
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
{
h->device = h->uuid = NULL;
h->major = h->minor = 0;
if (dmevh->dev_name)
dm_free(dmevh->dev_name);
if (dmevh->uuid)
dm_free(dmevh->uuid);
dmevh->dev_name = dmevh->uuid = NULL;
dmevh->major = dmevh->minor = 0;
}
struct dm_event_handler *dm_event_handler_create(void)
{
struct dm_event_handler *ret = 0;
struct dm_event_handler *dmevh = NULL;
if (!(ret = dm_malloc(sizeof(*ret))))
if (!(dmevh = dm_malloc(sizeof(*dmevh))))
return NULL;
ret->dso = ret->device = ret->uuid = NULL;
ret->major = ret->minor = 0;
ret->events = 0;
dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
dmevh->major = dmevh->minor = 0;
dmevh->mask = 0;
dmevh->timeout = 0;
return ret;
return dmevh;
}
void dm_event_handler_destroy(struct dm_event_handler *h)
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
{
dm_free(h);
_dm_event_handler_clear_dev_info(dmevh);
if (dmevh->dso)
dm_free(dmevh->dso);
dm_free(dmevh);
}
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path)
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
{
h->dso = path;
if (!path) /* noop */
return 0;
if (dmevh->dso)
dm_free(dmevh->dso);
dmevh->dso = dm_strdup(path);
if (!dmevh->dso)
return -ENOMEM;
return 0;
}
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name)
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name)
{
dm_event_handler_clear_device(h);
h->device = name;
if (!dev_name)
return 0;
_dm_event_handler_clear_dev_info(dmevh);
dmevh->dev_name = dm_strdup(dev_name);
if (!dmevh->dev_name)
return -ENOMEM;
return 0;
}
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid)
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
{
dm_event_handler_clear_device(h);
h->uuid = uuid;
if (!uuid)
return 0;
_dm_event_handler_clear_dev_info(dmevh);
dmevh->uuid = dm_strdup(uuid);
if (!dmevh->dev_name)
return -ENOMEM;
return 0;
}
void dm_event_handler_set_major(struct dm_event_handler *h, int major)
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major)
{
int minor = h->minor;
int minor = dmevh->minor;
dm_event_handler_clear_device(h);
h->major = major;
h->minor = minor;
_dm_event_handler_clear_dev_info(dmevh);
dmevh->major = major;
dmevh->minor = minor;
}
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor)
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
{
int major = h->major;
int major = dmevh->major;
dm_event_handler_clear_device(h);
_dm_event_handler_clear_dev_info(dmevh);
h->major = major;
h->minor = minor;
dmevh->major = major;
dmevh->minor = minor;
}
void dm_event_handler_set_events(struct dm_event_handler *h,
enum dm_event_type event)
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
enum dm_event_mask evmask)
{
h->events = event;
dmevh->mask = evmask;
}
const char *dm_event_handler_get_dso(const struct dm_event_handler *h)
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
{
return h->dso;
dmevh->timeout = timeout;
}
const char *dm_event_handler_get_name(const struct dm_event_handler *h)
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
{
return h->device;
return dmevh->dso;
}
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h)
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
{
return h->uuid;
return dmevh->dev_name;
}
int dm_event_handler_get_major(const struct dm_event_handler *h)
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
{
return h->major;
return dmevh->uuid;
}
int dm_event_handler_get_minor(const struct dm_event_handler *h)
int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
{
return h->minor;
return dmevh->major;
}
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
{
return h->events;
return dmevh->minor;
}
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
{
return dmevh->timeout;
}
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
{
return dmevh->mask;
}
static int _check_message_id(struct dm_event_daemon_message *msg)
{
int pid, seq_nr;
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
log_error("Ignoring out-of-sequence reply from dmeventd. "
"Expected %d:%d but received %s", getpid(),
_sequence_nr, msg->data);
return 0;
}
return 1;
}
/*
@@ -145,8 +208,8 @@ enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
*
* Returns: 0 on failure, 1 on success
*/
static int daemon_read(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg)
static int _daemon_read(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret, i;
@@ -205,8 +268,8 @@ static int daemon_read(struct dm_event_fifos *fifos,
}
/* Write message to daemon. */
static int daemon_write(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg)
static int _daemon_write(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
@@ -214,11 +277,28 @@ static int daemon_write(struct dm_event_fifos *fifos,
size_t size = 2 * sizeof(uint32_t) + msg->size;
char *buf = alloca(size);
char drainbuf[128];
struct timeval tval = { 0, 0 };
*((uint32_t *)buf) = htonl(msg->cmd);
*((uint32_t *)buf + 1) = htonl(msg->size);
memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
/* drain the answer fifo */
while (1) {
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
tval.tv_usec = 100;
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
if ((ret < 0) && (errno != EINTR)) {
log_error("Unable to talk to event daemon");
return 0;
}
if (ret == 0)
break;
read(fifos->server, drainbuf, 127);
}
while (bytes < size) {
do {
/* Watch daemon write FIFO to be ready for output. */
@@ -248,14 +328,15 @@ static int daemon_write(struct dm_event_fifos *fifos,
return bytes == size;
}
static int daemon_talk(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg, int cmd,
const char *dso_name, const char *device,
enum dm_event_type events, uint32_t timeout)
static int _daemon_talk(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg, int cmd,
const char *dso_name, const char *dev_name,
enum dm_event_mask evmask, uint32_t timeout)
{
const char *dso = dso_name ? dso_name : "";
const char *dev = device ? device : "";
const char *fmt = "%s %s %u %" PRIu32;
const char *dev = dev_name ? dev_name : "";
const char *fmt = "%d:%d %s %s %u %" PRIu32;
int msg_size;
memset(msg, 0, sizeof(*msg));
/*
@@ -263,21 +344,39 @@ static int daemon_talk(struct dm_event_fifos *fifos,
* into ASCII message string.
*/
msg->cmd = cmd;
msg->size = dm_saprintf(&(msg->data), fmt, dso, dev, events, timeout);
if (cmd == DM_EVENT_CMD_HELLO)
fmt = "%d:%d HELLO";
if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr,
dso, dev, evmask, timeout)) < 0) {
log_error("_daemon_talk: message allocation failed");
return -ENOMEM;
}
msg->size = msg_size;
/*
* Write command and message to and
* read status return code from daemon.
*/
if (!daemon_write(fifos, msg)) {
if (!_daemon_write(fifos, msg)) {
stack;
dm_free(msg->data);
msg->data = 0;
return -EIO;
}
if (!daemon_read(fifos, msg)) {
stack;
return -EIO;
}
do {
if (msg->data)
dm_free(msg->data);
msg->data = 0;
if (!_daemon_read(fifos, msg)) {
stack;
return -EIO;
}
} while (!_check_message_id(msg));
_sequence_nr++;
return (int32_t) msg->cmd;
}
@@ -294,7 +393,7 @@ static int daemon_talk(struct dm_event_fifos *fifos,
*
* Returns: 1 on success, 0 otherwise
*/
static int start_daemon(struct dm_event_fifos *fifos)
static int _start_daemon(struct dm_event_fifos *fifos)
{
int pid, ret = 0;
int status;
@@ -332,8 +431,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
log_error("Unable to fork.");
else if (!pid) {
/* FIXME configure path (cf. lvm2 modprobe) */
execvp("dmeventd", NULL);
execvp(DMEVENTD_PATH, NULL);
exit(EXIT_FAILURE);
} else {
if (waitpid(pid, &status, 0) < 0)
@@ -349,7 +447,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
}
/* Initialize client. */
static int init_client(struct dm_event_fifos *fifos)
static int _init_client(struct dm_event_fifos *fifos)
{
/* FIXME? Is fifo the most suitable method? Why not share
comms/daemon code with something else e.g. multipath? */
@@ -359,7 +457,7 @@ static int init_client(struct dm_event_fifos *fifos)
fifos->client_path = DM_EVENT_FIFO_CLIENT;
fifos->server_path = DM_EVENT_FIFO_SERVER;
if (!start_daemon(fifos)) {
if (!_start_daemon(fifos)) {
stack;
return 0;
}
@@ -391,7 +489,7 @@ static int init_client(struct dm_event_fifos *fifos)
return 1;
}
static void dtr_client(struct dm_event_fifos *fifos)
static void _dtr_client(struct dm_event_fifos *fifos)
{
if (flock(fifos->server, LOCK_UN))
log_error("flock unlock %s", fifos->server_path);
@@ -400,76 +498,99 @@ static void dtr_client(struct dm_event_fifos *fifos)
close(fifos->server);
}
/* Get uuid of a device, if it exists (otherwise NULL). */
static struct dm_task *get_device_info(const struct dm_event_handler *h)
/* Get uuid of a device */
static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
{
struct dm_task *dmt = dm_task_create(DM_DEVICE_INFO);
struct dm_task *ret;
struct dm_task *dmt;
struct dm_info info;
if (!dmt)
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
log_error("_get_device_info: dm_task creation for info failed");
return NULL;
if (h->uuid)
dm_task_set_uuid(dmt, h->uuid);
else if (h->device)
dm_task_set_name(dmt, h->device);
else if (h->major && h->minor) {
dm_task_set_major(dmt, h->major);
dm_task_set_minor(dmt, h->minor);
}
if (!dm_task_run(dmt))
ret = NULL;
else
ret = dmt;
if (dmevh->uuid)
dm_task_set_uuid(dmt, dmevh->uuid);
else if (dmevh->dev_name)
dm_task_set_name(dmt, dmevh->dev_name);
else if (dmevh->major && dmevh->minor) {
dm_task_set_major(dmt, dmevh->major);
dm_task_set_minor(dmt, dmevh->minor);
}
return ret;
/* FIXME Add name or uuid or devno to messages */
if (!dm_task_run(dmt)) {
log_error("_get_device_info: dm_task_run() failed");
goto failed;
}
if (!dm_task_get_info(dmt, &info)) {
log_error("_get_device_info: failed to get info for device");
goto failed;
}
if (!info.exists) {
log_error("_get_device_info: device not found");
goto failed;
}
return dmt;
failed:
dm_task_destroy(dmt);
return NULL;
}
/* Handle the event (de)registration call and return negative error codes. */
static int do_event(int cmd, struct dm_event_daemon_message *msg,
const char *dso_name, const char *device,
enum dm_event_type events, uint32_t timeout)
static int _do_event(int cmd, struct dm_event_daemon_message *msg,
const char *dso_name, const char *dev_name,
enum dm_event_mask evmask, uint32_t timeout)
{
int ret;
struct dm_event_fifos fifos;
if (!init_client(&fifos)) {
if (!_init_client(&fifos)) {
stack;
return -ESRCH;
}
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
if (msg->data)
dm_free(msg->data);
msg->data = 0;
if (!ret)
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
/* what is the opposite of init? */
dtr_client(&fifos);
_dtr_client(&fifos);
return ret;
}
/* External library interface. */
int dm_event_register(const struct dm_event_handler *h)
int dm_event_register_handler(const struct dm_event_handler *dmevh)
{
int ret, err;
int ret = 1, err;
const char *uuid;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!(dmt = get_device_info(h))) {
log_error("%s: device not found", h->device);
if (!(dmt = _get_device_info(dmevh))) {
stack;
return 0;
}
uuid = dm_task_get_uuid(dmt);
if ((err = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
h->dso, uuid, h->events, 0)) < 0) {
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
log_error("%s: event registration failed: %s",
dm_task_get_name(dmt),
msg.data ? msg.data : strerror(-err));
ret = 0;
} else
ret = 1;
}
if (msg.data)
dm_free(msg.data);
@@ -479,28 +600,27 @@ int dm_event_register(const struct dm_event_handler *h)
return ret;
}
int dm_event_unregister(const struct dm_event_handler *h)
int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
{
int ret, err;
int ret = 1, err;
const char *uuid;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!(dmt = get_device_info(h))) {
log_error("%s: device not found", dm_task_get_name(dmt));
if (!(dmt = _get_device_info(dmevh))) {
stack;
return 0;
}
uuid = dm_task_get_uuid(dmt);
if ((err = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
h->dso, uuid, h->events, 0)) < 0) {
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
log_error("%s: event deregistration failed: %s",
dm_task_get_name(dmt),
msg.data ? msg.data : strerror(-err));
ret = 0;
} else
ret = 1;
}
if (msg.data)
dm_free(msg.data);
@@ -510,12 +630,9 @@ int dm_event_unregister(const struct dm_event_handler *h)
return ret;
}
#if 0 /* left out for now */
/* Fetch a string off src and duplicate it into *dest. */
/* FIXME: move to seperate module to share with the daemon. */
static const char delimiter = ' ';
static char *fetch_string(char **src)
/* FIXME: move to separate module to share with the daemon. */
static char *_fetch_string(char **src, const int delimiter)
{
char *p, *ret;
@@ -532,17 +649,23 @@ static char *fetch_string(char **src)
}
/* Parse a device message from the daemon. */
static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
char **device, enum dm_event_type *events)
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
char **uuid, enum dm_event_mask *evmask)
{
char *id = NULL;
char *p = msg->data;
if ((*dso_name = fetch_string(&p)) && (*device = fetch_string(&p))) {
*events = atoi(p);
if ((id = _fetch_string(&p, ' ')) &&
(*dso_name = _fetch_string(&p, ' ')) &&
(*uuid = _fetch_string(&p, ' '))) {
*evmask = atoi(p);
dm_free(id);
return 0;
}
if (id)
dm_free(id);
return -ENOMEM;
}
@@ -550,68 +673,134 @@ static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
* dm_event_get_registered_device
* @dso_name
* @device_path
* @events
* @mask
* @next
*
* FIXME: This function sucks.
*
* Returns: 1 if device found, 0 otherwise (even on error)
* Returns: 0 if handler found, error (-ENOMEM, -ENOENT) otherwise
*/
int dm_event_get_registered_device(char **dso_name, char **device_path,
enum dm_event_type *events, int next)
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
{
int ret;
char *dso_name_arg = NULL, *device_path_arg = NULL;
struct dm_event_daemon_message msg;
int ret = 0;
const char *uuid = NULL;
char *reply_dso = NULL, *reply_uuid = NULL;
enum dm_event_mask reply_mask = 0;
struct dm_task *dmt = NULL;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
&msg, *dso_name, *device_path, *events, 0))) {
ret = !parse_message(&msg, &dso_name_arg, &device_path_arg,
events);
} else /* FIXME: Make sure this is ENOENT */
ret = 0;
if (msg.data)
dm_free(msg.data);
if (next) {
if (*dso_name)
dm_free(*dso_name);
if (*device_path)
dm_free(*device_path);
*dso_name = dso_name_arg;
*device_path = device_path_arg;
} else {
if (!(*dso_name))
*dso_name = dso_name_arg;
if (!(*device_path))
*device_path = device_path_arg;
if (!(dmt = _get_device_info(dmevh))) {
stack;
return 0;
}
uuid = dm_task_get_uuid(dmt);
if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
&msg, dmevh->dso, uuid, dmevh->mask, 0))) {
/* FIXME this will probably horribly break if we get
ill-formatted reply */
ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
} else {
ret = -ENOENT;
goto fail;
}
dm_task_destroy(dmt);
if (msg.data) {
dm_free(msg.data);
msg.data = NULL;
}
_dm_event_handler_clear_dev_info(dmevh);
dmevh->uuid = dm_strdup(reply_uuid);
if (!dmevh->uuid) {
ret = -ENOMEM;
goto fail;
}
if (!(dmt = _get_device_info(dmevh))) {
ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
goto fail;
}
dm_event_handler_set_dso(dmevh, reply_dso);
dm_event_handler_set_event_mask(dmevh, reply_mask);
if (reply_dso)
dm_free(reply_dso);
if (reply_uuid)
dm_free(reply_uuid);
dmevh->dev_name = dm_strdup(dm_task_get_name(dmt));
if (!dmevh->dev_name) {
ret = -ENOMEM;
goto fail;
}
struct dm_info info;
if (!dm_task_get_info(dmt, &info)) {
ret = -1;
goto fail;
}
dmevh->major = info.major;
dmevh->minor = info.minor;
dm_task_destroy(dmt);
return ret;
fail:
if (msg.data)
dm_free(msg.data);
if (reply_dso)
dm_free(reply_dso);
if (reply_uuid)
dm_free(reply_uuid);
_dm_event_handler_clear_dev_info(dmevh);
dm_task_destroy(dmt);
return ret;
}
#if 0 /* left out for now */
static char *_skip_string(char *src, const int delimiter)
{
src = srtchr(src, delimiter);
if (src && *(src + 1))
return src + 1;
return NULL;
}
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
{
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!device_exists(device_path))
return -ENODEV;
return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
NULL, device_path, 0, timeout);
return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
NULL, device_path, 0, timeout);
}
int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
{
int ret;
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!device_exists(device_path))
return -ENODEV;
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
0, 0)))
*timeout = atoi(msg.data);
if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
0, 0))) {
char *p = _skip_string(msg.data, ' ');
if (!p) {
log_error("malformed reply from dmeventd '%s'\n",
msg.data);
return -EIO;
}
*timeout = atoi(p);
}
if (msg.data)
dm_free(msg.data);
return ret;

View File

@@ -23,8 +23,11 @@
#include <stdint.h>
/* Event type definitions. */
enum dm_event_type {
/*
* Event library interface.
*/
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. */
@@ -33,7 +36,7 @@ enum dm_event_type {
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 off a host adaptor. */
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
DM_EVENT_STATUS_MASK = 0xFF0000,
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
@@ -44,50 +47,60 @@ enum dm_event_type {
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
/* Prototypes for event lib interface. */
struct dm_event_handler;
/* Create and destroy dm_event_handler struct, which is passed to
register/unregister functions below */
struct dm_event_handler *dm_event_handler_create(void);
void dm_event_handler_destroy(struct dm_event_handler *h);
void dm_event_handler_destroy(struct dm_event_handler *dmevh);
/* Set parameters of a handler:
- dso - shared library path to handle the events
(only one of the following three needs to be set)
- name - device name or path
- uuid - device uuid
- major and minor - device major/minor numbers
- events - a bitfield defining which events to handle (see
enum dm_event_type above)
*/
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path);
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name);
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid);
void dm_event_handler_set_major(struct dm_event_handler *h, int major);
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor);
void dm_event_handler_set_events(struct dm_event_handler *h,
enum dm_event_type event);
/*
* 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);
/* Get parameters of a handler, same as above */
const char *dm_event_handler_get_dso(const struct dm_event_handler *h);
const char *dm_event_handler_get_name(const struct dm_event_handler *h);
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h);
int dm_event_handler_get_major(const struct dm_event_handler *h);
int dm_event_handler_get_minor(const struct dm_event_handler *h);
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h);
/*
* 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);
/* Call out to dmeventd to register or unregister a handler. If
dmeventd is not running, it is spawned first. */
int dm_event_register(const struct dm_event_handler *h);
int dm_event_unregister(const struct dm_event_handler *h);
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
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);
/*
* Specify mask for events to monitor.
*/
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
enum dm_event_mask evmask);
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_type event);
int register_device(const char *device, const char *uuid, int major, int minor);
int unregister_device(const char *device, const char *uuid, int major,
int minor);
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

View File

@@ -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>
@@ -62,8 +61,12 @@ static int _get_mirror_event(char *params)
int log_argc, num_devs;
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
* 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 */
@@ -74,9 +77,9 @@ static int _get_mirror_event(char *params)
goto out_parse;
p += strlen(p) + 1;
/* devices names + max log parameters */
args = dm_malloc((num_devs + 8) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
/* 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];
@@ -148,7 +151,7 @@ static int _remove_failed_devices(const char *device)
}
/* 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 */
@@ -161,7 +164,8 @@ static int _remove_failed_devices(const char *device)
return (r == 1) ? 0 : -1;
}
void process_event(struct dm_task *dmt, enum dm_event_type event)
void process_event(struct dm_task *dmt, enum dm_event_mask event,
void **unused __attribute((unused)))
{
void *next = NULL;
uint64_t start, length;
@@ -218,7 +222,8 @@ void process_event(struct dm_task *dmt, enum dm_event_type event)
pthread_mutex_unlock(&_event_mutex);
}
int register_device(const char *device, const char *uuid, int major, int minor)
int register_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
int r = 0;
@@ -254,7 +259,8 @@ out:
return r;
}
int unregister_device(const char *device, const char *uuid, int major, int minor)
int unregister_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
pthread_mutex_lock(&_register_mutex);

View File

@@ -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>
@@ -62,8 +61,12 @@ static int _get_mirror_event(char *params)
int log_argc, num_devs;
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
* 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 */
@@ -74,9 +77,9 @@ static int _get_mirror_event(char *params)
goto out_parse;
p += strlen(p) + 1;
/* devices names + max log parameters */
args = dm_malloc((num_devs + 8) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
/* 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];
@@ -148,7 +151,7 @@ static int _remove_failed_devices(const char *device)
}
/* 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 */
@@ -161,7 +164,8 @@ static int _remove_failed_devices(const char *device)
return (r == 1) ? 0 : -1;
}
void process_event(struct dm_task *dmt, enum dm_event_type event)
void process_event(struct dm_task *dmt, enum dm_event_mask event,
void **unused __attribute((unused)))
{
void *next = NULL;
uint64_t start, length;
@@ -218,7 +222,8 @@ void process_event(struct dm_task *dmt, enum dm_event_type event)
pthread_mutex_unlock(&_event_mutex);
}
int register_device(const char *device, const char *uuid, int major, int minor)
int register_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
int r = 0;
@@ -254,7 +259,8 @@ out:
return r;
}
int unregister_device(const char *device, const char *uuid, int major, int minor)
int unregister_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
pthread_mutex_lock(&_register_mutex);

View File

@@ -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.

View File

@@ -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

View File

@@ -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 \

View File

@@ -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;
@@ -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)

View File

@@ -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

View File

@@ -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, &params);
/* Skip if target type doesn't match */
if (!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;
}

12
lib/cache/lvmcache.c vendored
View File

@@ -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);
}
@@ -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;

View File

@@ -59,8 +59,6 @@
# include <malloc.h>
#endif
static FILE *_log;
static int _get_env_vars(struct cmd_context *cmd)
{
const char *e;
@@ -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,8 +623,13 @@ static int _init_filters(struct cmd_context *cmd)
if (!*cmd->sys_dir)
cmd->dump_filter = 0;
if (!stat(dev_cache, &st) &&
(st.st_ctime != config_file_timestamp(cmd->cft)) &&
/*
* 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);
}

View File

@@ -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);

View File

@@ -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,
@@ -79,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);
@@ -210,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;
}
@@ -360,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:
@@ -435,13 +432,13 @@ int write_config_file(struct config_tree *cft, const char *file,
log_verbose("Dumping configuration to %s", file);
if (!argc) {
if (!_write_config(cft->root, 0, fp, 0)) {
log_error("Failure while writing configuration");
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 configuration");
log_error("Failure while writing to %s", file);
r = 0;
}
} else {
@@ -451,8 +448,10 @@ int write_config_file(struct config_tree *cft, const char *file,
argv++;
}
if (fp != stdout)
fclose(fp);
if ((fp != stdout) && fclose(fp)) {
log_sys_error("fclose", file);
r = 0;
}
return r;
}
@@ -480,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;
@@ -569,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;
@@ -592,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;
@@ -629,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;
@@ -714,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;
}
@@ -853,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;
}
@@ -870,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,
@@ -897,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;
}
@@ -930,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,
@@ -1022,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;
}
@@ -1152,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;
}

View File

@@ -31,7 +31,7 @@ enum {
struct config_value {
int type;
union {
int i;
int64_t i;
float r;
char *str;
} v;
@@ -108,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

View File

@@ -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"

View File

@@ -23,6 +23,7 @@
/* Define some portable printing types */
#define PRIsize_t "zu"
#define PRIptrdiff_t "td"
struct str_list {
struct list list;

View File

@@ -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;

View File

@@ -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.
*/

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -72,7 +72,7 @@ static int _has_partition_table(struct device *dev)
/* Check for msdos partition table */
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)) {

View File

@@ -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);

View File

@@ -239,7 +239,10 @@ int persistent_filter_dump(struct dev_filter *f)
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
fprintf(fp, "}\n");
fclose(fp);
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,
@@ -298,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;
@@ -310,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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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 ?

View File

@@ -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);
@@ -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;

View File

@@ -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;

View File

@@ -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.

View File

@@ -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);

View File

@@ -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)
{
@@ -710,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;
}
@@ -718,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;
}
@@ -1268,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;
}
@@ -1392,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 */

View File

@@ -660,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;

View File

@@ -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;
@@ -117,12 +118,13 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
int found = 0;
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;
}
@@ -256,7 +261,8 @@ 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] __attribute((aligned(8)));
struct labeller *l;
@@ -274,7 +280,7 @@ int label_read(struct device *dev, struct label **result)
return r;
}
if (!(l = _find_labeller(dev, buf, &sector)))
if (!(l = _find_labeller(dev, buf, &sector, scan_sector)))
goto_out;
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
@@ -354,7 +360,7 @@ int label_verify(struct device *dev)
return_0;
}
if (!(l = _find_labeller(dev, buf, &sector)))
if (!(l = _find_labeller(dev, buf, &sector, UINT64_C(0))))
goto_out;
r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;

View File

@@ -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);

View File

@@ -321,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

View File

@@ -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) {

View File

@@ -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 */
/*

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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

View File

@@ -280,10 +280,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;
@@ -320,7 +319,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;
@@ -505,6 +504,34 @@ 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;
}
/* Sizes in sectors */
struct physical_volume *pv_create(const struct format_type *fmt,
struct device *dev,
@@ -533,10 +560,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;
@@ -759,6 +784,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)) {
@@ -963,6 +994,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.
@@ -982,9 +1037,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) {
@@ -1069,6 +1127,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;
@@ -1104,13 +1164,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;
}
}
}
@@ -1143,17 +1215,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()) {
@@ -1303,7 +1400,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);
@@ -1433,3 +1530,66 @@ 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;
}
/*
* 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;
}

View File

@@ -178,6 +178,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 {
@@ -423,6 +434,7 @@ 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);
/* pe_start and pe_end relate to any existing data so that new metadata
* areas can avoid overlap */
@@ -437,6 +449,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
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,
@@ -449,6 +463,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,

View File

@@ -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? */
@@ -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.
*/
@@ -205,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;
}

View File

@@ -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)
@@ -81,8 +83,9 @@ struct segtype_handler {
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,

View File

@@ -368,13 +368,12 @@ static int _mirrored_target_present(const struct lv_segment *seg __attribute((un
}
#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,78 +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;
struct dm_event_handler *handler;
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;
if (!(handler = dm_event_handler_create()))
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
return_0;
dm_event_handler_set_dso(handler, dso);
dm_event_handler_set_name(handler, name);
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
if (!dm_event_register(handler)) {
dm_event_handler_destroy(handler);
return_0;
if (dm_event_get_registered_device(dmevh, 0)) {
dm_event_handler_destroy(dmevh);
return 0;
}
dm_event_handler_destroy(handler);
log_info("Registered %s for events", name);
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;
struct dm_event_handler *handler;
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;
if (!(handler = dm_event_handler_create()))
return_0;
dm_event_handler_set_dso(handler, dso);
dm_event_handler_set_name(handler, name);
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
if (!dm_event_unregister(handler)) {
dm_event_handler_destroy(handler);
return_0;
}
dm_event_handler_destroy(handler);
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 */
@@ -504,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,
@@ -530,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);

View File

@@ -19,7 +19,7 @@
#ifndef _LVM_LIB_H
#define _LVM_LIB_H
#include <configure.h>
#include "configure.h"
#define _REENTRANT
#define _GNU_SOURCE

View File

@@ -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,7 +240,8 @@ 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);
@@ -254,6 +256,8 @@ void sync_dir(const char *file)
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,
@@ -261,6 +265,21 @@ int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
.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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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* */

File diff suppressed because it is too large Load Diff

View File

@@ -115,4 +115,17 @@ dm_split_lvm_name
dm_split_words
dm_snprintf
dm_basename
dm_saprintf
dm_asprintf
dm_report_init
dm_report_object
dm_report_output
dm_report_free
dm_report_get_private
dm_report_field_string
dm_report_field_int
dm_report_field_int32
dm_report_field_uint32
dm_report_field_uint64
dm_report_field_set_value
dm_regex_create
dm_regex_match

View File

@@ -24,8 +24,12 @@ SOURCES =\
libdm-file.c \
libdm-deptree.c \
libdm-string.c \
libdm-report.c \
mm/dbg_malloc.c \
mm/pool.c \
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
$(interface)/libdm-iface.c
INCLUDES = -I$(interface)
@@ -89,7 +93,7 @@ install_ioctl_static: ioctl/libdevmapper.a
.PHONY: distclean_lib distclean
distclean_lib:
$(RM) libdm-common.h libdevmapper.pc
$(RM) libdevmapper.pc
distclean: distclean_lib

View File

@@ -13,8 +13,8 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_BITSET_H
#define _LVM_BITSET_H
#ifndef _DM_BITSET_H
#define _DM_BITSET_H
#include "pool.h"

View File

@@ -68,14 +68,14 @@ static struct dm_hash_node *_create_node(const char *str, unsigned len)
return n;
}
static unsigned long _hash(const unsigned char *str, unsigned len)
static unsigned long _hash(const char *str, unsigned len)
{
unsigned long h = 0, g;
unsigned i;
for (i = 0; i < len; i++) {
h <<= 4;
h += _nums[*str++];
h += _nums[(unsigned char) *str++];
g = h & ((unsigned long) 0xf << 16u);
if (g) {
h ^= g >> 16u;
@@ -230,12 +230,14 @@ void dm_hash_wipe(struct dm_hash_table *t)
t->num_nodes = 0u;
}
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n)
char *dm_hash_get_key(struct dm_hash_table *t __attribute((unused)),
struct dm_hash_node *n)
{
return n->key;
}
void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n)
void *dm_hash_get_data(struct dm_hash_table *t __attribute((unused)),
struct dm_hash_node *n)
{
return n->data;
}

View File

@@ -13,8 +13,8 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_HASH_H
#define _LVM_HASH_H
#ifndef _DM_HASH_H
#define _DM_HASH_H
struct hash_table;
struct hash_node;

View File

@@ -149,7 +149,8 @@ static int _get_proc_number(const char *file, const char *name,
if (!strcmp(name, nm)) {
if (number) {
*number = num;
fclose(fl);
if (fclose(fl))
log_error("%s: fclose failed: %s", file, strerror(errno));
return 1;
}
dm_bit_set(_dm_bitset, num);
@@ -158,7 +159,8 @@ static int _get_proc_number(const char *file, const char *name,
c = fgetc(fl);
} while (c != EOF && c != '\n');
}
fclose(fl);
if (fclose(fl))
log_error("%s: fclose failed: %s", file, strerror(errno));
if (number) {
log_error("%s: No entry for %s found", file, name);
@@ -431,12 +433,12 @@ static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
return 1;
}
static const char *_dm_task_get_name_v1(struct dm_task *dmt)
static const char *_dm_task_get_name_v1(const struct dm_task *dmt)
{
return (dmt->dmi.v1->name);
}
static const char *_dm_task_get_uuid_v1(struct dm_task *dmt)
static const char *_dm_task_get_uuid_v1(const struct dm_task *dmt)
{
return (dmt->dmi.v1->uuid);
}
@@ -922,7 +924,7 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
return 1;
}
const char *dm_task_get_name(struct dm_task *dmt)
const char *dm_task_get_name(const struct dm_task *dmt)
{
#ifdef DM_COMPAT
if (_dm_version == 1)
@@ -932,7 +934,7 @@ const char *dm_task_get_name(struct dm_task *dmt)
return (dmt->dmi.v4->name);
}
const char *dm_task_get_uuid(struct dm_task *dmt)
const char *dm_task_get_uuid(const struct dm_task *dmt)
{
#ifdef DM_COMPAT
if (_dm_version == 1)
@@ -1322,7 +1324,7 @@ static int _process_mapper_dir(struct dm_task *dmt)
dir = dm_dir();
if (!(d = opendir(dir))) {
fprintf(stderr, "opendir %s: %s", dir, strerror(errno));
log_error("opendir %s: %s", dir, strerror(errno));
return 0;
}
@@ -1335,9 +1337,8 @@ static int _process_mapper_dir(struct dm_task *dmt)
dm_task_run(dmt);
}
if (closedir(d)) {
fprintf(stderr, "closedir %s: %s", dir, strerror(errno));
}
if (closedir(d))
log_error("closedir %s: %s", dir, strerror(errno));
return r;
}
@@ -1554,7 +1555,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmi->flags |= DM_SKIP_BDGET_FLAG;
log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
"%s%c%c%s %.0llu %s [%u]",
"%s%c%c%s %.0" PRIu64 " %s [%u]",
_cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? " " : "",
dmt->newname ? dmt->newname : "",

View File

@@ -124,17 +124,17 @@ struct dm_names {
};
struct dm_versions {
uint32_t next; /* Offset to next struct from start of this struct */
uint32_t version[3];
uint32_t next; /* Offset to next struct from start of this struct */
uint32_t version[3];
char name[0];
char name[0];
};
int dm_get_library_version(char *version, size_t size);
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
const char *dm_task_get_name(struct dm_task *dmt);
const char *dm_task_get_uuid(struct dm_task *dmt);
const char *dm_task_get_name(const struct dm_task *dmt);
const char *dm_task_get_uuid(const struct dm_task *dmt);
struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
struct dm_names *dm_task_get_names(struct dm_task *dmt);
@@ -236,12 +236,12 @@ int dm_tree_add_dev(struct dm_tree *tree, uint32_t major, uint32_t minor);
* Add a new node to the tree if it doesn't already exist.
*/
struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *tree,
const char *name,
const char *uuid,
uint32_t major, uint32_t minor,
int read_only,
int clear_inactive,
void *context);
const char *name,
const char *uuid,
uint32_t major, uint32_t minor,
int read_only,
int clear_inactive,
void *context);
/*
* Search for a node in the tree.
@@ -289,16 +289,16 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
* Ignores devices that don't have a uuid starting with uuid_prefix.
*/
int dm_tree_preload_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len);
const char *uuid_prefix,
size_t uuid_prefix_len);
/*
* Resume a device plus all dependencies.
* Ignores devices that don't have a uuid starting with uuid_prefix.
*/
int dm_tree_activate_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len);
const char *uuid_prefix,
size_t uuid_prefix_len);
/*
* Suspend a device plus all dependencies.
@@ -626,7 +626,108 @@ char *dm_basename(const char *path);
/*
* Returns size of a buffer which is allocated with dm_malloc.
* Pointer to the buffer is stored in *buf.
* Returns -1 on failure leaving buf undefined.
*/
int dm_saprintf(char **buf, const char *format, ...);
int dm_asprintf(char **buf, const char *format, ...);
/*********************
* regular expressions
*********************/
struct dm_regex;
/*
* Initialise an array of num patterns for matching.
* Uses memory from mem.
*/
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
unsigned num_patterns);
/*
* Match string s against the patterns.
* Returns the index of the highest pattern in the array that matches,
* or -1 if none match.
*/
int dm_regex_match(struct dm_regex *regex, const char *s);
/*********************
* reporting functions
*********************/
struct dm_report_object_type {
uint32_t id; /* Powers of 2 */
const char *desc;
const char *prefix; /* field id string prefix (optional) */
void *(*data_fn)(void *object); /* callback from report_object() */
};
struct dm_report_field;
/*
* dm_report_field_type flags
*/
#define DM_REPORT_FIELD_MASK 0x000000FF
#define DM_REPORT_FIELD_ALIGN_MASK 0x0000000F
#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
#define DM_REPORT_FIELD_TYPE_MASK 0x000000F0
#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
struct dm_report;
struct dm_report_field_type {
uint32_t type; /* object type id */
uint32_t flags; /* DM_REPORT_FIELD_* */
uint32_t offset; /* byte offset in the object */
int32_t width; /* default width */
const char id[32]; /* string used to specify the field */
const char heading[32]; /* string printed in header */
int (*report_fn)(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field, const void *data,
void *private);
const char *desc; /* description of the field */
};
/*
* dm_report_init output_flags
*/
#define DM_REPORT_OUTPUT_MASK 0x000000FF
#define DM_REPORT_OUTPUT_ALIGNED 0x00000001
#define DM_REPORT_OUTPUT_BUFFERED 0x00000002
#define DM_REPORT_OUTPUT_HEADINGS 0x00000004
struct dm_report *dm_report_init(uint32_t *report_types,
const struct dm_report_object_type *types,
const struct dm_report_field_type *fields,
const char *output_fields,
const char *output_separator,
uint32_t output_flags,
const char *sort_keys,
void *private);
int dm_report_object(struct dm_report *rh, void *object);
int dm_report_output(struct dm_report *rh);
void dm_report_free(struct dm_report *rh);
/*
* Report functions are provided for simple data types.
* They take care of allocating copies of the data.
*/
int dm_report_field_string(struct dm_report *rh, struct dm_report_field *field,
const char **data);
int dm_report_field_int32(struct dm_report *rh, struct dm_report_field *field,
const int32_t *data);
int dm_report_field_uint32(struct dm_report *rh, struct dm_report_field *field,
const uint32_t *data);
int dm_report_field_int(struct dm_report *rh, struct dm_report_field *field,
const int *data);
int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field,
const uint64_t *data);
/*
* For custom fields, allocate the data in 'mem' and use
* dm_report_field_set_value().
* 'sortvalue' may be NULL if it matches 'value'
*/
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
const void *sortvalue);
#endif /* LIB_DEVICE_MAPPER_H */

View File

@@ -38,8 +38,8 @@ static int _verbose = 0;
* Library users can provide their own logging
* function.
*/
static void _default_log(int level, const char *file, int line,
const char *f, ...)
static void _default_log(int level, const char *file __attribute((unused)),
int line __attribute((unused)), const char *f, ...)
{
va_list ap;

View File

@@ -28,6 +28,4 @@ int rm_dev_node(const char *dev_name);
int rename_dev_node(const char *old_name, const char *new_name);
void update_devs(void);
#define DM_LIB_VERSION @DM_LIB_VERSION@
#endif

View File

@@ -1212,7 +1212,9 @@ static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *
return 1;
}
static int _emit_areas_line(struct dm_task *dmt, struct load_segment *seg, char *params, size_t paramsize, int *pos)
static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
struct load_segment *seg, char *params,
size_t paramsize, int *pos)
{
struct seg_area *area;
char devbuf[10];

863
libdm/libdm-report.c Normal file
View File

@@ -0,0 +1,863 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of device-mapper userspace tools.
* The code is based on LVM2 report function.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "libdevmapper.h"
#include "list.h"
#include "log.h"
/*
* Internal flags
*/
#define RH_SORT_REQUIRED 0x00000100
#define RH_HEADINGS_PRINTED 0x00000200
struct dm_report {
struct dm_pool *mem;
uint32_t report_types;
const char *field_prefix;
uint32_t flags;
const char *separator;
uint32_t keys_count;
/* Ordered list of fields needed for this report */
struct list field_props;
/* Rows of report data */
struct list rows;
/* Array of field definitions */
const struct dm_report_field_type *fields;
const struct dm_report_object_type *types;
/* To store caller private data */
void *private;
};
/*
* Internal per-field flags
*/
#define FLD_HIDDEN 0x00000100
#define FLD_SORT_KEY 0x00000200
#define FLD_ASCENDING 0x00000400
#define FLD_DESCENDING 0x00000800
struct field_properties {
struct list list;
uint32_t field_num;
uint32_t sort_posn;
int32_t width;
const struct dm_report_object_type *type;
uint32_t flags;
};
/*
* Report data field
*/
struct dm_report_field {
struct list list;
struct field_properties *props;
const char *report_string; /* Formatted ready for display */
const void *sort_value; /* Raw value for sorting */
};
struct row {
struct list list;
struct dm_report *rh;
struct list fields; /* Fields in display order */
struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
};
static const struct dm_report_object_type *_find_type(struct dm_report *rh,
uint32_t report_type)
{
const struct dm_report_object_type *t;
for (t = rh->types; t->data_fn; t++)
if (t->id == report_type)
return t;
return NULL;
}
/*
* Data-munging functions to prepare each data type for display and sorting
*/
int dm_report_field_string(struct dm_report *rh,
struct dm_report_field *field, const char **data)
{
char *repstr;
if (!(repstr = dm_pool_strdup(rh->mem, *data))) {
log_error("dm_report_field_string: dm_pool_strdup failed");
return 0;
}
field->report_string = repstr;
field->sort_value = (const void *) field->report_string;
return 1;
}
int dm_report_field_int(struct dm_report *rh,
struct dm_report_field *field, const int *data)
{
const int value = *data;
uint64_t *sortval;
char *repstr;
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
log_error("dm_report_field_int: dm_pool_alloc failed");
return 0;
}
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
log_error("dm_report_field_int: dm_pool_alloc failed");
return 0;
}
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
log_error("dm_report_field_int: int too big: %d", value);
return 0;
}
*sortval = (const uint64_t) value;
field->sort_value = sortval;
field->report_string = repstr;
return 1;
}
int dm_report_field_uint32(struct dm_report *rh,
struct dm_report_field *field, const uint32_t *data)
{
const uint32_t value = *data;
uint64_t *sortval;
char *repstr;
if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
log_error("dm_report_field_uint32: dm_pool_alloc failed");
return 0;
}
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
log_error("dm_report_field_uint32: dm_pool_alloc failed");
return 0;
}
if (dm_snprintf(repstr, 11, "%u", value) < 0) {
log_error("dm_report_field_uint32: uint32 too big: %u", value);
return 0;
}
*sortval = (const uint64_t) value;
field->sort_value = sortval;
field->report_string = repstr;
return 1;
}
int dm_report_field_int32(struct dm_report *rh,
struct dm_report_field *field, const int32_t *data)
{
const int32_t value = *data;
uint64_t *sortval;
char *repstr;
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
log_error("dm_report_field_int32: dm_pool_alloc failed");
return 0;
}
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
log_error("dm_report_field_int32: dm_pool_alloc failed");
return 0;
}
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
log_error("dm_report_field_int32: int32 too big: %d", value);
return 0;
}
*sortval = (const uint64_t) value;
field->sort_value = sortval;
field->report_string = repstr;
return 1;
}
int dm_report_field_uint64(struct dm_report *rh,
struct dm_report_field *field, const uint64_t *data)
{
const int value = *data;
uint64_t *sortval;
char *repstr;
if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
log_error("dm_report_field_uint64: dm_pool_alloc failed");
return 0;
}
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
log_error("dm_report_field_uint64: dm_pool_alloc failed");
return 0;
}
if (dm_snprintf(repstr, 21, "%d", value) < 0) {
log_error("dm_report_field_uint64: uint64 too big: %d", value);
return 0;
}
*sortval = (const uint64_t) value;
field->sort_value = sortval;
field->report_string = repstr;
return 1;
}
/*
* Helper functions for custom report functions
*/
void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
{
field->report_string = (const char *) value;
field->sort_value = sortvalue ? : value;
}
/*
* show help message
*/
static void _display_fields(struct dm_report *rh)
{
uint32_t f;
const struct dm_report_object_type *type;
const char *desc, *last_desc = "";
size_t id_len = 0;
for (f = 0; rh->fields[f].report_fn; f++)
if (strlen(rh->fields[f].id) > id_len)
id_len = strlen(rh->fields[f].id);
for (f = 0; rh->fields[f].report_fn; f++) {
if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
desc = type->desc;
else
desc = " ";
if (desc != last_desc) {
if (*last_desc)
log_print(" ");
log_print("%s Fields", desc);
log_print("%*.*s", (int) strlen(desc) + 7,
(int) strlen(desc) + 7,
"------------------------------------------");
}
/* FIXME Add line-wrapping at terminal width (or 80 cols) */
log_print(" %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
last_desc = desc;
}
}
/*
* Initialise report handle
*/
static int _copy_field(struct dm_report *rh, struct field_properties *dest,
uint32_t field_num)
{
dest->field_num = field_num;
dest->width = rh->fields[field_num].width;
dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
/* set object type method */
dest->type = _find_type(rh, rh->fields[field_num].type);
if (!dest->type) {
log_error("dm_report: field not match: %s",
rh->fields[field_num].id);
return 0;
}
return 1;
}
static struct field_properties * _add_field(struct dm_report *rh,
uint32_t field_num, uint32_t flags)
{
struct field_properties *fp;
rh->report_types |= rh->fields[field_num].type;
if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
log_error("dm_report: struct field_properties allocation "
"failed");
return NULL;
}
if (!_copy_field(rh, fp, field_num)) {
stack;
dm_pool_free(rh->mem, fp);
return NULL;
}
fp->flags |= flags;
/*
* Place hidden fields at the front so list_end() will
* tell us when we've reached the last visible field.
*/
if (fp->flags & FLD_HIDDEN)
list_add_h(&rh->field_props, &fp->list);
else
list_add(&rh->field_props, &fp->list);
return fp;
}
/*
* Compare name1 against name2 or prefix plus name2
* name2 is not necessarily null-terminated.
* len2 is the length of name2.
*/
static int _is_same_field(const char *name1, const char *name2,
size_t len2, const char *prefix)
{
size_t prefix_len;
/* Exact match? */
if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
return 1;
/* Match including prefix? */
prefix_len = strlen(prefix);
if (!strncasecmp(prefix, name1, prefix_len) &&
!strncasecmp(name1 + prefix_len, name2, len2) &&
strlen(name1) == prefix_len + len2)
return 1;
return 0;
}
static int _field_match(struct dm_report *rh, const char *field, size_t flen)
{
uint32_t f;
if (!flen)
return 0;
for (f = 0; rh->fields[f].report_fn; f++)
if (_is_same_field(rh->fields[f].id, field, flen,
rh->field_prefix))
return _add_field(rh, f, 0) ? 1 : 0;
return 0;
}
static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
uint32_t flags)
{
struct field_properties *fp, *found = NULL;
list_iterate_items(fp, &rh->field_props) {
if (fp->field_num == field_num) {
found = fp;
break;
}
}
if (!found && !(found = _add_field(rh, field_num, FLD_HIDDEN)))
return_0;
if (found->flags & FLD_SORT_KEY) {
log_error("dm_report: Ignoring duplicate sort field: %s",
rh->fields[field_num].id);
return 1;
}
found->flags |= FLD_SORT_KEY;
found->sort_posn = rh->keys_count++;
found->flags |= flags;
return 1;
}
static int _key_match(struct dm_report *rh, const char *key, size_t len)
{
uint32_t f;
uint32_t flags;
if (!len)
return 0;
if (*key == '+') {
key++;
len--;
flags = FLD_ASCENDING;
} else if (*key == '-') {
key++;
len--;
flags = FLD_DESCENDING;
} else
flags = FLD_ASCENDING;
if (!len) {
log_error("dm_report: Missing sort field name");
return 0;
}
for (f = 0; rh->fields[f].report_fn; f++)
if (_is_same_field(rh->fields[f].id, key, len,
rh->field_prefix))
return _add_sort_key(rh, f, flags);
return 0;
}
static int _parse_options(struct dm_report *rh, const char *format)
{
const char *ws; /* Word start */
const char *we = format; /* Word end */
while (*we) {
/* Allow consecutive commas */
while (*we && *we == ',')
we++;
/* start of the field name */
ws = we;
while (*we && *we != ',')
we++;
if (!_field_match(rh, ws, (size_t) (we - ws))) {
_display_fields(rh);
log_print(" ");
if (strcasecmp(ws, "help") && strcmp(ws, "?"))
log_error("Unrecognised field: %.*s",
(int) (we - ws), ws);
return 0;
}
}
return 1;
}
static int _parse_keys(struct dm_report *rh, const char *keys)
{
const char *ws; /* Word start */
const char *we = keys; /* Word end */
while (*we) {
/* Allow consecutive commas */
while (*we && *we == ',')
we++;
ws = we;
while (*we && *we != ',')
we++;
if (!_key_match(rh, ws, (size_t) (we - ws))) {
log_error("dm_report: Unrecognised field: %.*s",
(int) (we - ws), ws);
return 0;
}
}
return 1;
}
struct dm_report *dm_report_init(uint32_t *report_types,
const struct dm_report_object_type *types,
const struct dm_report_field_type *fields,
const char *output_fields,
const char *output_separator,
uint32_t output_flags,
const char *sort_keys,
void *private)
{
struct dm_report *rh;
const struct dm_report_object_type *type;
if (!(rh = dm_malloc(sizeof(*rh)))) {
log_error("dm_report_init: dm_malloc failed");
return 0;
}
memset(rh, 0, sizeof(*rh));
/*
* rh->report_types is updated in _parse_options() and _parse_keys()
* to contain all types corresponding to the fields specified by
* options or keys.
*/
if (report_types)
rh->report_types = *report_types;
rh->separator = output_separator;
rh->fields = fields;
rh->types = types;
rh->private = private;
rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
rh->flags |= RH_SORT_REQUIRED;
list_init(&rh->field_props);
list_init(&rh->rows);
if ((type = _find_type(rh, rh->report_types)) && type->prefix)
rh->field_prefix = type->prefix;
else
rh->field_prefix = "";
if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
log_error("dm_report_init: allocation of memory pool failed");
dm_free(rh);
return NULL;
}
/* Generate list of fields for output based on format string & flags */
if (!_parse_options(rh, output_fields)) {
dm_report_free(rh);
return NULL;
}
if (!_parse_keys(rh, sort_keys)) {
dm_report_free(rh);
return NULL;
}
/* Return updated types value for further compatility check by caller */
if (report_types)
*report_types = rh->report_types;
return rh;
}
void dm_report_free(struct dm_report *rh)
{
dm_pool_destroy(rh->mem);
dm_free(rh);
}
/*
* Create a row of data for an object
*/
static void * _report_get_field_data(struct dm_report *rh,
struct field_properties *fp, void *object)
{
void *ret = fp->type->data_fn(object);
if (!ret)
return NULL;
return ret + rh->fields[fp->field_num].offset;
}
int dm_report_object(struct dm_report *rh, void *object)
{
struct field_properties *fp;
struct row *row;
struct dm_report_field *field;
void *data = NULL;
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
log_error("dm_report_object: struct row allocation failed");
return 0;
}
row->rh = rh;
if ((rh->flags & RH_SORT_REQUIRED) &&
!(row->sort_fields =
dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
rh->keys_count))) {
log_error("dm_report_object: "
"row sort value structure allocation failed");
return 0;
}
list_init(&row->fields);
list_add(&rh->rows, &row->list);
/* For each field to be displayed, call its report_fn */
list_iterate_items(fp, &rh->field_props) {
if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
log_error("dm_report_object: "
"struct dm_report_field allocation failed");
return 0;
}
field->props = fp;
data = _report_get_field_data(rh, fp, object);
if (!data)
return 0;
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
field, data,
rh->private)) {
log_error("dm_report_object: "
"report function failed for field %s",
rh->fields[fp->field_num].id);
return 0;
}
if ((strlen(field->report_string) > field->props->width))
field->props->width = strlen(field->report_string);
if ((rh->flags & RH_SORT_REQUIRED) &&
(field->props->flags & FLD_SORT_KEY)) {
(*row->sort_fields)[field->props->sort_posn] = field;
}
list_add(&row->fields, &field->list);
}
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
return dm_report_output(rh);
return 1;
}
/*
* Print row of headings
*/
static int _report_headings(struct dm_report *rh)
{
struct field_properties *fp;
const char *heading;
char buf[1024];
if (rh->flags & RH_HEADINGS_PRINTED)
return 1;
rh->flags |= RH_HEADINGS_PRINTED;
if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
return 1;
if (!dm_pool_begin_object(rh->mem, 128)) {
log_error("dm_report: "
"dm_pool_begin_object failed for headings");
return 0;
}
/* First heading line */
list_iterate_items(fp, &rh->field_props) {
if (fp->flags & FLD_HIDDEN)
continue;
heading = rh->fields[fp->field_num].heading;
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
fp->width, fp->width, heading) < 0) {
log_error("dm_report: snprintf heading failed");
goto bad;
}
if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
log_error("dm_report: Failed to generate report headings for printing");
goto bad;
}
} else if (!dm_pool_grow_object(rh->mem, heading,
strlen(heading))) {
log_error("dm_report: Failed to generate report headings for printing");
goto bad;
}
if (!list_end(&rh->field_props, &fp->list))
if (!dm_pool_grow_object(rh->mem, rh->separator,
strlen(rh->separator))) {
log_error("dm_report: Failed to generate report headings for printing");
goto bad;
}
}
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
log_error("dm_report: Failed to generate report headings for printing");
goto bad;
}
log_print("%s", (char *) dm_pool_end_object(rh->mem));
return 1;
bad:
dm_pool_abandon_object(rh->mem);
return 0;
}
/*
* Sort rows of data
*/
static int _row_compare(const void *a, const void *b)
{
const struct row *rowa = *(const struct row **) a;
const struct row *rowb = *(const struct row **) b;
const struct dm_report_field *sfa, *sfb;
uint32_t cnt;
for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
sfa = (*rowa->sort_fields)[cnt];
sfb = (*rowb->sort_fields)[cnt];
if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
const uint64_t numa =
*(const uint64_t *) sfa->sort_value;
const uint64_t numb =
*(const uint64_t *) sfb->sort_value;
if (numa == numb)
continue;
if (sfa->props->flags & FLD_ASCENDING) {
return (numa > numb) ? 1 : -1;
} else { /* FLD_DESCENDING */
return (numa < numb) ? 1 : -1;
}
} else { /* DM_REPORT_FIELD_TYPE_STRING */
const char *stra = (const char *) sfa->sort_value;
const char *strb = (const char *) sfb->sort_value;
int cmp = strcmp(stra, strb);
if (!cmp)
continue;
if (sfa->props->flags & FLD_ASCENDING) {
return (cmp > 0) ? 1 : -1;
} else { /* FLD_DESCENDING */
return (cmp < 0) ? 1 : -1;
}
}
}
return 0; /* Identical */
}
static int _sort_rows(struct dm_report *rh)
{
struct row *(*rows)[];
uint32_t count = 0;
struct row *row;
if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
list_size(&rh->rows)))) {
log_error("dm_report: sort array allocation failed");
return 0;
}
list_iterate_items(row, &rh->rows)
(*rows)[count++] = row;
qsort(rows, count, sizeof(**rows), _row_compare);
list_init(&rh->rows);
while (count--)
list_add_h(&rh->rows, &(*rows)[count]->list);
return 1;
}
/*
* Produce report output
*/
int dm_report_output(struct dm_report *rh)
{
struct list *fh, *rowh, *ftmp, *rtmp;
struct row *row = NULL;
struct dm_report_field *field;
const char *repstr;
char buf[4096];
int32_t width;
uint32_t align;
if (list_empty(&rh->rows))
return 1;
/* Sort rows */
if ((rh->flags & RH_SORT_REQUIRED))
_sort_rows(rh);
/* If headings not printed yet, calculate field widths and print them */
if (!(rh->flags & RH_HEADINGS_PRINTED))
_report_headings(rh);
/* Print and clear buffer */
list_iterate_safe(rowh, rtmp, &rh->rows) {
if (!dm_pool_begin_object(rh->mem, 512)) {
log_error("dm_report: Unable to allocate output line");
return 0;
}
row = list_item(rowh, struct row);
list_iterate_safe(fh, ftmp, &row->fields) {
field = list_item(fh, struct dm_report_field);
if (field->props->flags & FLD_HIDDEN)
continue;
repstr = field->report_string;
width = field->props->width;
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
if (!dm_pool_grow_object(rh->mem, repstr,
strlen(repstr))) {
log_error("dm_report: Unable to extend output line");
goto bad;
}
} else {
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
width, width, repstr) < 0) {
log_error("dm_report: left-aligned snprintf() failed");
goto bad;
}
if (!dm_pool_grow_object(rh->mem, buf, width)) {
log_error("dm_report: Unable to extend output line");
goto bad;
}
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
if (dm_snprintf(buf, sizeof(buf), "%*.*s",
width, width, repstr) < 0) {
log_error("dm_report: right-aligned snprintf() failed");
goto bad;
}
if (!dm_pool_grow_object(rh->mem, buf, width)) {
log_error("dm_report: Unable to extend output line");
goto bad;
}
}
}
if (!list_end(&row->fields, fh))
if (!dm_pool_grow_object(rh->mem, rh->separator,
strlen(rh->separator))) {
log_error("dm_report: Unable to extend output line");
goto bad;
}
list_del(&field->list);
}
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
log_error("dm_report: Unable to terminate output line");
goto bad;
}
log_print("%s", (char *) dm_pool_end_object(rh->mem));
list_del(&row->list);
}
if (row)
dm_pool_free(rh->mem, row);
return 1;
bad:
dm_pool_abandon_object(rh->mem);
return 0;
}

View File

@@ -37,7 +37,8 @@ static int _isword(int c)
* Split buffer into NULL-separated words in argv.
* Returns number of words.
*/
int dm_split_words(char *buffer, unsigned max, unsigned ignore_comments,
int dm_split_words(char *buffer, unsigned max,
unsigned ignore_comments __attribute((unused)),
char **argv)
{
unsigned arg;
@@ -116,7 +117,7 @@ int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
n = vsnprintf(buf, bufsize, format, ap);
va_end(ap);
if (n < 0 || (n > bufsize - 1))
if (n < 0 || ((unsigned) n + 1 > bufsize))
return -1;
return n;
@@ -129,7 +130,7 @@ char *dm_basename(const char *path)
return p ? p + 1 : (char *) path;
}
int dm_saprintf(char **result, const char *format, ...)
int dm_asprintf(char **result, const char *format, ...)
{
int n, ok = 0, size = 32;
va_list ap;

View File

@@ -20,9 +20,14 @@
char *dm_strdup_aux(const char *str, const char *file, int line)
{
char *ret = dm_malloc_aux_debug(strlen(str) + 1, file, line);
char *ret;
if (ret)
if (!str) {
log_error("Internal error: dm_strdup called with NULL pointer");
return NULL;
}
if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
strcpy(ret, str);
return ret;
@@ -226,7 +231,8 @@ void dm_bounds_check_debug(void)
}
}
void *dm_malloc_aux(size_t s, const char *file, int line)
void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
int line __attribute((unused)))
{
if (s > 50000000) {
log_error("Huge memory allocation (size %" PRIsize_t

View File

@@ -13,8 +13,8 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_DBG_MALLOC_H
#define _LVM_DBG_MALLOC_H
#ifndef _DM_DBG_MALLOC_H
#define _DM_DBG_MALLOC_H
#include <stdlib.h>
#include <string.h>

View File

@@ -13,8 +13,8 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_POOL_H
#define _LVM_POOL_H
#ifndef _DM_POOL_H
#define _DM_POOL_H
#include <string.h>
#include <stdlib.h>

View File

@@ -1,8 +1,8 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
@@ -14,9 +14,9 @@
*/
#include "lib.h"
#include "matcher.h"
#include "parse_rx.h"
#include "ttree.h"
#include "assert.h"
struct dfa_state {
int final;
@@ -29,7 +29,7 @@ struct state_queue {
struct state_queue *next;
};
struct matcher { /* Instance variables for the lexer */
struct dm_regex { /* Instance variables for the lexer */
struct dfa_state *start;
unsigned num_nodes;
int nodes_entered;
@@ -52,7 +52,7 @@ static int _count_nodes(struct rx_node *rx)
return r;
}
static void _fill_table(struct matcher *m, struct rx_node *rx)
static void _fill_table(struct dm_regex *m, struct rx_node *rx)
{
assert((rx->type != OR) || (rx->left && rx->right));
@@ -65,7 +65,7 @@ static void _fill_table(struct matcher *m, struct rx_node *rx)
m->nodes[m->nodes_entered++] = rx;
}
static void _create_bitsets(struct matcher *m)
static void _create_bitsets(struct dm_regex *m)
{
int i;
@@ -77,7 +77,7 @@ static void _create_bitsets(struct matcher *m)
}
}
static void _calc_functions(struct matcher *m)
static void _calc_functions(struct dm_regex *m)
{
int i, j, final = 1;
struct rx_node *rx, *c1, *c2;
@@ -189,7 +189,7 @@ static struct state_queue *_create_state_queue(struct dm_pool *mem,
return r;
}
static int _calc_states(struct matcher *m, struct rx_node *rx)
static int _calc_states(struct dm_regex *m, struct rx_node *rx)
{
unsigned iwidth = (m->num_nodes / DM_BITS_PER_INT) + 1;
struct ttree *tt = ttree_create(m->scratch, iwidth);
@@ -263,43 +263,38 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
return 1;
}
struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
unsigned num)
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
unsigned num_patterns)
{
char *all, *ptr;
int i;
size_t len = 0;
struct rx_node *rx;
struct dm_pool *scratch = dm_pool_create("regex matcher", 10 * 1024);
struct matcher *m;
struct dm_regex *m;
if (!scratch) {
stack;
return NULL;
}
if (!scratch)
return_NULL;
if (!(m = dm_pool_alloc(mem, sizeof(*m)))) {
stack;
dm_pool_destroy(scratch);
return NULL;
return_NULL;
}
memset(m, 0, sizeof(*m));
/* join the regexps together, delimiting with zero */
for (i = 0; i < num; i++)
for (i = 0; i < num_patterns; i++)
len += strlen(patterns[i]) + 8;
ptr = all = dm_pool_alloc(scratch, len + 1);
if (!all) {
stack;
goto bad;
}
if (!all)
goto_bad;
for (i = 0; i < num; i++) {
for (i = 0; i < num_patterns; i++) {
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
if (i < (num - 1))
if (i < (num_patterns - 1))
*ptr++ = '|';
}
@@ -314,10 +309,8 @@ struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
m->num_nodes = _count_nodes(rx);
m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes);
if (!m->nodes) {
stack;
goto bad;
}
if (!m->nodes)
goto_bad;
_fill_table(m, rx);
_create_bitsets(m);
@@ -330,7 +323,7 @@ struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
bad:
dm_pool_destroy(scratch);
dm_pool_destroy(mem);
dm_pool_free(mem, m);
return NULL;
}
@@ -345,16 +338,16 @@ static struct dfa_state *_step_matcher(int c, struct dfa_state *cs, int *r)
return cs;
}
int matcher_run(struct matcher *m, const char *b)
int dm_regex_match(struct dm_regex *regex, const char *s)
{
struct dfa_state *cs = m->start;
struct dfa_state *cs = regex->start;
int r = 0;
if (!(cs = _step_matcher(HAT_CHAR, cs, &r)))
goto out;
for (; *b; b++)
if (!(cs = _step_matcher(*b, cs, &r)))
for (; *s; s++)
if (!(cs = _step_matcher(*s, cs, &r)))
goto out;
_step_matcher(DOLLAR_CHAR, cs, &r);

View File

@@ -1,8 +1,8 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions

View File

@@ -1,8 +1,8 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
@@ -13,8 +13,8 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_PARSE_REGEX_H
#define _LVM_PARSE_REGEX_H
#ifndef _DM_PARSE_REGEX_H
#define _DM_PARSE_REGEX_H
enum {
CAT,

View File

@@ -1,8 +1,8 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions

View File

@@ -1,8 +1,8 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
@@ -13,8 +13,8 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TTREE_H
#define _LVM_TTREE_H
#ifndef _DM_TTREE_H
#define _DM_TTREE_H
struct ttree;

View File

@@ -56,7 +56,7 @@ endif
.SUFFIXES: .c .d .o .so .a .po .pot .mo .dylib
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn -Wformat-security
#CFLAGS += -W -Wconversion -Wpointer-arith -Wredundant-decls -Wbad-function-cast -Wcast-qual
#CFLAGS += -pedantic -std=gnu99
@@ -94,7 +94,7 @@ STRIP=
LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
awk -F '.' '{printf "%s.%s",$$1,$$2}')
INCLUDES += -I. -I$(top_srcdir)/include
INCLUDES += -I$(top_srcdir)/include
ifneq ("@DMDIR@", "")
INCLUDES += -I@DMDIR@/include

View File

@@ -20,7 +20,7 @@ MAN5=lvm.conf.5
MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
lvmchange.8 lvmdiskscan.8 lvmdump.8 \
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
lvscan.8 pvchange.8 pvck.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
vgimport.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 vgrename.8 \

View File

@@ -3,6 +3,9 @@
dmsetup \- low level logical volume management
.SH SYNOPSIS
.ad l
.B dmsetup help
.I [-c|-C|--columns]
.br
.B dmsetup create
.I device_name [-u uuid] [--notable | --table <table> | table_file]
.br
@@ -33,21 +36,25 @@ dmsetup \- low level logical volume management
.B dmsetup message
.I device_name sector message
.br
.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
.B dmsetup ls
.I [--target target_type] [--exec command] [--tree [-o options]]
.br
.B dmsetup info
.I [device_name]
.br
.B dmsetup info -c|-C|--columns [--noheadings] [-o name]
.B dmsetup info -c|-C|--columns
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
.I [device_name]
.br
.B dmsetup deps
.I [device_name]
.br
.B dmsetup status [--target target_type]
.B dmsetup status
.I [--target target_type]
.I [device_name]
.br
.B dmsetup table [--target target_type]
.B dmsetup table
.I [--target target_type]
.I [device_name]
.br
.B dmsetup wait
@@ -103,7 +110,7 @@ Tell the kernel not to supply the open reference count for the device.
When creating a device, don't load any table.
.IP \fB-o|--options
.br
Specify which fields to display. Only \fB-o\ name\fP is supported.
Specify which fields to display.
.IP \fB-r|--readonly
.br
Set the table being loaded read-only.
@@ -136,6 +143,11 @@ See below for information on the table format.
.br
Outputs a list of (major, minor) pairs for devices referenced by the
live table for the specified device.
.IP \fBhelp
.I [-c|-C|--columns]
.br
Outputs a summary of the commands available, optionally including
the list of report fields.
.IP \fBinfo
.I [device_name]
.br
@@ -154,6 +166,17 @@ Outputs some brief information about the device in the form:
Number of targets in the live table
.br
UUID
.IP \fBinfo -c|-C|--columns
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
.I [device_name]
.br
Output you can customise.
Fields are comma-separated and chosen from the following list:
name, major, minor, attr, open, segments, events, uuid.
Attributes are: (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.
Precede the list with '+' to append
to the default selection of columns instead of replacing it.
Precede any sort_field with - for a reverse sort on that column.
.IP \fBls
.I [--target target_type]
.I [--exec command]

View File

@@ -12,7 +12,7 @@ lvchange \- change attributes of a logical volume
[\-\-ignorelockingfailure]
[\-\-monitor {y|n}]
[\-M/\-\-persistent y/n] [\-\-minor minor]
[\-P/\-\-partial y/n]
[\-P/\-\-partial]
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
[\-\-refresh]
[\-t/\-\-test]

View File

@@ -194,6 +194,7 @@ All tools return a status code of zero on success or non-zero on failure.
.BR lvs (8),
.BR lvscan (8),
.BR pvchange (8),
.BR pvck (8),
.BR pvcreate (8),
.BR pvdisplay (8),
.BR pvmove (8),

View File

@@ -81,6 +81,11 @@ LVM physical volumes.
Devices in directories outside this hierarchy will be ignored.
Defaults to "/dev".
.IP
\fBpreferred_names\fP \(em List of patterns compared in turn against
all the pathnames referencing the same device in in the scanned directories.
The pathname that matches the earliest pattern in the list is the
one used in any output.
.IP
\fBfilter\fP \(em List of patterns to apply to devices found by a scan.
Patterns are regular expressions delimited by any character and preceded
by \fBa\fP (for accept) or \fBr\fP (for reject). The list is traversed
@@ -95,8 +100,8 @@ pattern it is rejected; otherwise it is accepted.
As an example, to ignore /dev/cdrom you could use:
\fBdevices { filter=["r|cdrom|"] }\fP
.IP
\fBcache\fP \(em Persistent filter cache file.
Defaults to "/etc/lvm/.cache".
\fBcache_dir\fP \(em Persistent filter cache file directory.
Defaults to "/etc/lvm/cache".
.IP
\fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the
persistent filter cache file when \fBlvm\fP exits.
@@ -364,9 +369,9 @@ understand how things work: to make changes you should always use
the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore.
.SH FILES
.I /etc/lvm/lvm.conf
.I /etc/lvm/.cache
.I /etc/lvm/archive
.I /etc/lvm/backup
.I /etc/lvm/cache/.cache
.I /var/lock/lvm
.SH SEE ALSO
.BR lvm (8),

View File

@@ -35,11 +35,13 @@ lv_uuid, lv_name, lv_attr, lv_major, lv_minor, lv_kernel_major, lv_kernel_minor,
lv_size, seg_count, origin, snap_percent,
copy_percent, move_pv, lv_tags,
segtype, stripes,
stripesize, chunksize, seg_start, seg_size, seg_tags, devices.
stripesize, chunksize, seg_start, seg_size, seg_tags, devices,
regionsize, mirror_log, modules.
.IP
With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
prefixes are optional. Columns mentioned in \fBvgs (8)\fP
can also be chosen.
Use \fb-o help\fP to view the full list of fields available.
.IP
The lv_attr bits are:
.RS
@@ -49,7 +51,7 @@ invalid (S)napshot, (v)irtual
.IP 2 3
Permissions: (w)riteable, (r)ead-only
.IP 3 3
Allocation policy: (c)ontiguous, (n)ormal, (a)nywhere, (i)nherited
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
This is capitalised if the volume is currently locked against allocation
changes, for example during \fBpvmove\fP (8).
.IP 4 3

33
man/pvck.8 Normal file
View File

@@ -0,0 +1,33 @@
.TH PVCK 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
.SH NAME
pvck \- check physical volume metadata
.SH SYNOPSIS
.B pvck
.RB [ \-d | \-\-debug ]
.RB [ \-h | \-\-help ]
.RB [ \-v | \-\-verbose ]
.RB [ \-\-labelsector ]
.IR PhysicalVolume " [" PhysicalVolume ...]
.SH DESCRIPTION
pvck checks physical volume LVM metadata for consistency.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.BR \-\-labelsector " sector"
By default, 4 sectors of \fBPhysicalVolume\fP are scanned for an LVM label,
starting at sector 0. This parameter allows you to specify a different
starting sector for the scan and is useful for recovery situations. For
example, suppose the partition table is corrupted or lost on /dev/sda,
but you suspect there was an LVM partition at approximately 100 MB. This
area of the disk may be scanned by using the \fB--labelsector\fP parameter
with a value of 204800 (100 * 1024 * 1024 / 512 = 204800):
.sp
.BI "pvck --labelsector 204800 /dev/sda"
.sp
Note that a script can be used with \fB--labelsector\fP to automate the
process of finding LVM labels.
.SH SEE ALSO
.BR lvm (8),
.BR pvcreate (8),
.BR pvscan (8)
.BR vgck (8)

View File

@@ -5,7 +5,7 @@ pvmove \- move physical extents
.B pvmove
[\-\-abort]
[\-\-alloc AllocationPolicy]
[\-\-background]
[\-b/\-\-background]
[\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
[\-n/\-\-name LogicalVolume]
[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
@@ -73,7 +73,7 @@ type of on-disk metadata. Metadata can be converted using \fBvgconvert\fP(8).
.I \-\-abort
Abort any moves in progress.
.TP
.I \-\-background
.I \-b, \-\-background
Run the daemon in the background.
.TP
.I \-i, \-\-interval Seconds

View File

@@ -31,9 +31,16 @@ if processing the output.
Comma-separated ordered list of columns. Precede the list with '+' to append
to the default selection of columns. Column names are: pv_fmt, pv_uuid,
pv_size, dev_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count,
pv_pe_alloc_count, pv_tags.
The "pv_" prefix is optional. Columns mentioned in \fBvgs (8)\fP can also
pv_pe_alloc_count, pv_tags, pvseg_start, pvseg_size, pe_start.
With --segments, any "pvseg_" prefixes are optional; otherwise any
"pv_" prefixes are optional. Columns mentioned in \fBvgs (8)\fP can also
be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
Use \fb-o help\fP to view the full list of fields available.
.TP
.I \-\-segments
Produces one line of output for each contiguous allocation of space on each
Physical Volume, showing the start (pvseg_start) and length (pvseg_size) in
units of physical extents.
.TP
.I \-O, \-\-sort
Comma-separated ordered list of columns to sort by. Replaces the default

View File

@@ -10,6 +10,7 @@ vgchange \- change attributes of a volume group
.RB [ \-A | \-\-autobackup " {" y | n }]
.RB [ \-a | \-\-available " [e|l] {" y | n }]
.RB [ \-\-monitor " {" y | n }]
.RB [ \-c | \-\-clustered " {" y | n }]
.RB [ \-d | \-\-debug]
.RB [ \-\-deltag
.IR Tag ]
@@ -44,12 +45,12 @@ snapshots should be removed (see
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.BR \-A ", " \-\-autobackup { y | n }
.BR \-A ", " \-\-autobackup " " { y | n }
Controls automatic backup of metadata after the change. See
.B vgcfgbackup (8).
Default is yes.
.TP
.BR \-a ", " \-\-available [e|l] { y | n }
.BR \-a ", " \-\-available " " [e|l] { y | n }
Controls the availability of the logical volumes in the volume
group for input/output.
In other words, makes the logical volumes known/unknown to the kernel.
@@ -60,6 +61,14 @@ on the local node.
Logical volumes with single-host snapshots are always activated
exclusively because they can only be used on one node at once.
.TP
.BR \-c ", " \-\-clustered " " { y | n }
If clustered locking is enabled, this indicates whether this
Volume Group is shared with other nodes in the cluster or whether
it contains only local disks that are not visible on the other nodes.
If the cluster infrastructure is unavailable on a particular node at a
particular time, you may still be able to use Volume Groups that
are not marked as clustered.
.TP
.BR \-\-monitor " " { y | n }
Controls whether or not a mirrored logical volume is monitored by
dmeventd, if it is installed.
@@ -108,7 +117,7 @@ impact on I/O performance to the logical volume. The smallest PE is 1KB.
The 2.4 kernel has a limitation of 2TB per block device.
.TP
.BR \-x ", " \-\-resizeable { y | n }
.BR \-x ", " \-\-resizeable " " { y | n }
Enables or disables the extension/reduction of this volume group
with/by physical volumes.
.SH EXAMPLES

View File

@@ -8,6 +8,7 @@ vgcreate \- create a volume group
.RB [ \-\-alloc
.IR AllocationPolicy ]
.RB [ \-A | \-\-autobackup " {" y | n }]
.RB [ \-c | \-\-clustered " {" y | n }]
.RB [ \-d | \-\-debug ]
.RB [ \-h | \-\-help ]
.RB [ \-l | \-\-maxlogicalvolumes
@@ -33,6 +34,14 @@ previously configured for LVM with
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.BR \-c ", " \-\-clustered " " { y | n }
If clustered locking is enabled, this indicates whether this
Volume Group is shared with other nodes in the cluster or whether
it contains only local disks that are not visible on the other nodes.
If the cluster infrastructure is unavailable on a particular node at a
particular time, you may still be able to use Volume Groups that
are not marked as clustered.
.TP
.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
Sets the maximum number of logical volumes allowed in this
volume group.

View File

@@ -36,8 +36,24 @@ vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno,
vg_tags.
Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
resi(z)eable, e(x)ported, (p)artial and (c)lustered.
at the same time.
Use \fb-o help\fP to view the full list of fields available.
.IP
The vg_attr bits are:
.RS
.IP 1 3
Permissions: (w)riteable, (r)ead-only
.IP 2 3
Resi(z)eable
.IP 3 3
E(x)ported
.IP 4 3
(p)artial
.IP 5 3
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
.IP 6 3
(c)lustered
.RE
.TP
.I \-O, \-\-sort
Comma-separated ordered list of columns to sort by. Replaces the default

Some files were not shown because too many files have changed in this diff Show More