1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-12-24 16:23:50 +03:00

Compare commits

...

409 Commits

Author SHA1 Message Date
Alasdair Kergon
dd2a3f40e1 pre-release 2007-06-15 19:05:02 +00:00
Alasdair Kergon
78f76c1690 Fix default dmsetup report buffering and add --unbuffered.
Add tree-based and dependency fields to dmsetup reports.
2007-06-15 18:20:28 +00:00
Dave Wysochanski
4788066a5f Update vgcfgrestore man pg 2007-06-15 16:05:57 +00:00
Petr Rockai
10e4254e7d Allow keyboard interrupts in yes_no_prompt(). Add code to toollib.c
loops and to pvcreate.c, lvchange.c and lvresize.c to handle
interrupted prompts.
2007-06-15 10:11:14 +00:00
Dave Wysochanski
0106e4df9d Fix inverted logic on last checkin for pvremove 2007-06-14 15:51:36 +00:00
Dave Wysochanski
8ac718a3a2 convert pv->vg_name[0] to \!is_orphan(pv) 2007-06-14 15:48:05 +00:00
Dave Wysochanski
46d45273a1 Convert pv->vg_name to get_pv_vg_name 2007-06-14 15:25:36 +00:00
Patrick Caulfield
8da9ec3599 Remove system-lv.[ch] 2007-06-14 10:17:12 +00:00
Patrick Caulfield
01fdf84d69 Remove system LV code from clvmd. It's never been used and never should be
used! It's removal tidies a number of code paths inside clvmd.
2007-06-14 10:16:35 +00:00
Dave Wysochanski
cc78386e75 Update WHATS_NEW for get_pv* conversions 2007-06-13 23:57:15 +00:00
Dave Wysochanski
3755157c61 Convert pv->vg_name to get_pv_vg_name 2007-06-13 23:53:38 +00:00
Dave Wysochanski
80f8436f0a Convert pv->status to get_pv_status 2007-06-13 23:33:45 +00:00
Dave Wysochanski
f88a4b7760 Convert pv->dev to get_pv_dev 2007-06-13 23:29:33 +00:00
Dave Wysochanski
de229b8ab0 Convert pv->size to get_pv_size 2007-06-13 23:02:51 +00:00
Dave Wysochanski
a3ba37e45e Convert existing_pv dereferences to get_pv_* 2007-06-13 22:58:32 +00:00
Dave Wysochanski
50c779b3c6 Convert pv->pe_size to get_pv_pe_size 2007-06-13 22:30:26 +00:00
Dave Wysochanski
192372e1c3 Convert pv->pe_start to get_pv_pe_start 2007-06-13 22:16:27 +00:00
Dave Wysochanski
f88fd88c38 Convert pv->pe_count to get_pv_pe_count 2007-06-13 22:11:29 +00:00
Dave Wysochanski
6e15145af1 Convert pv->pe_alloc_count to get_pv_pe_alloc_count 2007-06-13 22:04:45 +00:00
Dave Wysochanski
4b5fad4e48 Remove casts in pv_create and find_pv_in_vg_by_uuid 2007-06-13 21:14:07 +00:00
Dave Wysochanski
7a13e71c80 Convert pv_handle_t to pv_t * and tidy up whitespace 2007-06-13 20:55:56 +00:00
Dave Wysochanski
3c10943900 Add typedef pv_handle_t 2007-06-13 19:52:48 +00:00
Dave Wysochanski
696b8811c2 Fix a couple benign warnings by adding variable initializations. 2007-06-13 15:11:19 +00:00
Dave Wysochanski
9fd2c8602a Convert find_pv_in_vg_by_uuid and pv_create to use PV handles 2007-06-12 22:41:27 +00:00
Dave Wysochanski
a3636a5af4 Change PV_HANDLE_DEREF to pv_field and add paren's 2007-06-12 21:39:49 +00:00
Dave Wysochanski
f2e5f07718 Add get_pv_* functions to return PV fields in prep for external LVM library 2007-06-12 21:20:20 +00:00
Dave Wysochanski
16c6fdde60 Add wrappers to functions related to pv commands in preparation for exported LVM lib 2007-06-11 18:29:30 +00:00
Alasdair Kergon
2155c93426 Add capability for tree-based fields to dmsetup reports. 2007-06-11 13:20:29 +00:00
Bryn M. Reeves
c394631e4c Allow vgcfgrestore to list metadata backup files using -f 2007-06-08 22:38:48 +00:00
Dave Wysochanski
8b370b7cc1 Add vg_check_status to consolidate vg status flags checks and error messages. 2007-06-06 19:40:28 +00:00
Dave Wysochanski
607db9971c make code consistent with pvresize code - good candidate for common code cleanup 2007-06-05 18:23:17 +00:00
Dave Wysochanski
6768f64e2f Fix pvdisplay --maps to not display segment header for orphan PVs. 2007-05-31 20:26:11 +00:00
Dave Wysochanski
f1813b1cc6 Fix redundant segment display when PV is given to 'pvdisplay --maps' cmdline. 2007-05-31 20:10:25 +00:00
Dave Wysochanski
fb665bd0dd Remove 'Type' from pvdisplay --maps as there is no 'Type' of a physical segment, only logical segments 2007-05-31 15:18:44 +00:00
Dave Wysochanski
65dda2ef3d Small fixes to pvdisplay --maps: 1) rename struct pv_segment vars from 'seg' to 'pvseg', 2) Change heading 2007-05-31 14:19:57 +00:00
Dave Wysochanski
b162b992af Add --maps to pvdisplay.
Modified original patch from David Robinson <zxvdr.au@gmail.com>.
2007-05-30 20:43:09 +00:00
Dave Wysochanski
67a3a3d130 Fix vgcfgrestore man pg to show mandatory VG name and remove LVM1 options. 2007-05-22 02:52:57 +00:00
Dave Wysochanski
92cd9bf7d2 Fix vgrename man page to include UUID and be more consistent with lvrename. 2007-05-22 02:51:33 +00:00
Patrick Caulfield
bf97034485 Add *Experimental* OpenAIS support to clvmd. 2007-05-21 10:52:01 +00:00
Milan Broz
1ded1fc509 Remove symlinks if parent volume is deactivated. 2007-05-15 14:42:01 +00:00
Milan Broz
e0592c58b3 Fix and clarify vgsplit error messages. 2007-05-15 13:01:41 +00:00
Milan Broz
5ead2706b4 Fix a segfault if a device has no target (no table) 2007-05-14 11:27:34 +00:00
Patrick Caulfield
52ada4853c Misc clvmd cleanups from Jim Meyering 2007-05-02 12:22:40 +00:00
Patrick Caulfield
c2b27a8298 Add some more debuglogs to clvmd startup. 2007-05-02 08:23:36 +00:00
Alasdair Kergon
3934c1d437 post-release 2007-04-27 20:58:45 +00:00
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
Alasdair Kergon
cce3baa275 pre-release 2007-01-11 22:49:43 +00:00
Alasdair Kergon
2b48fad426 updated dmeventd interface 2007-01-11 22:24:32 +00:00
Alasdair Kergon
d554b2bc94 Lots of dmeventd-related changes. 2007-01-11 21:54:53 +00:00
Alasdair Kergon
f66943de43 fail if status args are missing 2007-01-11 20:11:19 +00:00
Alasdair Kergon
9d1e9bc2fb Remove dmeventd mirror status line word limit 2007-01-11 19:52:06 +00:00
Alasdair Kergon
2d6a014920 Use CFLAGS when linking so mixed sparc builds can supply -m64 2007-01-11 17:12:27 +00:00
Alasdair Kergon
c1952bf257 Use CFLAGS when linking so mixed sparc builds can supply -m64. 2007-01-11 16:23:22 +00:00
Alasdair Kergon
a10227eb03 Prevent permission changes on active mirrors. 2007-01-10 19:56:39 +00:00
Milan Broz
475ae29b85 Print warning instead of error message if cannot zero volume
Update lvconvert man page (snapshot option)
2007-01-10 14:13:46 +00:00
Alasdair Kergon
0b9cfc278b dumpconfig accepts a list of configuration variables to display.
Change dumpconfig to use --file to redirect output to a file.
2007-01-09 23:22:31 +00:00
Alasdair Kergon
b57b6b4fba Avoid vgreduce error when mirror code removes the log LV. 2007-01-09 23:14:35 +00:00
Alasdair Kergon
7d948f7bc5 Remove 3 redundant AC_MSG_RESULTs from configure.in. 2007-01-09 22:07:20 +00:00
Alasdair Kergon
459023d171 Free memory in _raw_read_mda_header() error paths.
Fix ambiguous vgsplit error message for split LV.
Fix lvextend man page typo.
2007-01-09 21:12:41 +00:00
Alasdair Kergon
fd6570720a Add configure --with-dmdir to compile against a device-mapper source tree.
Use no flush suspending for mirrors.
2007-01-09 20:31:08 +00:00
Alasdair Kergon
7831665417 Add dm_tree_use_no_flush_suspend(). 2007-01-09 19:44:07 +00:00
Alasdair Kergon
7c9920d982 fix last checkin 2007-01-08 15:35:08 +00:00
Alasdair Kergon
cbdccf0a9c Lots of dmevent changes.
Export dm_basename().
Cope with a trailing space when comparing tables prior to possible reload.
2007-01-08 15:18:52 +00:00
Alasdair Kergon
64fa83ec3f Add dmeventd_mirror register_mutex, tidy initialisation & add memlock. 2007-01-08 14:24:20 +00:00
Milan Broz
faff865cfd Fix create mirror with name longer than 22 chars. 2007-01-05 15:53:40 +00:00
Alasdair Kergon
742ab55a9a Fix some activate.c prototypes when compiled without devmapper. 2006-12-20 16:19:01 +00:00
Alasdair Kergon
66e623fb2a Fix dmeventd mirror to cope if monitored device disappears. 2006-12-20 14:35:02 +00:00
Alasdair Kergon
4ab17ee965 post-release 2006-12-14 22:21:32 +00:00
Alasdair Kergon
7f48ca5132 pre-release 2006-12-14 20:05:08 +00:00
Alasdair Kergon
da983848b4 Add missing pvremove error message when device doesn't exist. 2006-12-13 18:40:23 +00:00
Alasdair Kergon
bc03f7bad3 When lvconvert allocates a mirror log, respect parallel area constraints.
Use loop to iterate through the now-ordered policy list in _allocate().
Check for failure to allocate just the mirror log.
Introduce calc_area_multiple().
Support mirror log allocation when there is only one PV: area_count now 0.

(See lvm-devel list archives for further details.)
2006-12-13 03:39:58 +00:00
Alasdair Kergon
a1c8bd3846 Fix detection of smallest area in _alloc_parallel_area() for cling policy. 2006-12-12 19:30:10 +00:00
Patrick Caulfield
404bc284e0 Add manpage reference for clvmd -T that got missed out when I
checked the code in (sorry).
2006-12-11 14:06:25 +00:00
Patrick Caulfield
9dee30ff0e Fix gulm operation of clvmd. including a hang when attempting to
exclusively lock an LV that is already locked no another node.
2006-12-11 14:00:26 +00:00
Patrick Caulfield
f91aadbea8 Fix hang in clvmd if a pre-command failed. The pre/post thread was getting
out of sync in this instance and would not quit.
2006-12-11 13:48:41 +00:00
Alasdair Kergon
aa15a10c91 post-release 2006-12-01 23:29:54 +00:00
Alasdair Kergon
5b03e36351 pre release 2006-12-01 23:15:59 +00:00
Alasdair Kergon
b9ba9ffad2 clvmd ia64 alignment fixes etc. (pjc) 2006-12-01 23:10:26 +00:00
Alasdair Kergon
642be5d16c Fix VG clustered read locks to use PR not CR.
VG metadata reads were not being locked out during metadata updates.
2006-12-01 22:48:47 +00:00
Alasdair Kergon
ee68d715bf Adjust some alignments for ia64 and sparc.
(Some of the changes are probably unnecessary.)
2006-11-30 23:11:42 +00:00
Alasdair Kergon
224084f056 Fix mirror segment removal to use temporary error segment. 2006-11-30 17:52:47 +00:00
Patrick Caulfield
1cd8c849b8 Always compile debug logging into clvmd as it's too useful to
restrict to just developers.
-d will switch it on and run the daemon in the foreground
2006-11-30 13:19:42 +00:00
Patrick Caulfield
169f68bfcd Add timeout to RHEL4 clvmd init script.
With the previous clvmd checkin this should address bz#187812
2006-11-30 10:16:48 +00:00
Patrick Caulfield
d2b7cfa2d1 Add -T (startup timeout) switch to clvmd 2006-11-30 09:44:07 +00:00
Alasdair Kergon
a40c7dff5d post-release 2006-11-28 22:51:01 +00:00
Alasdair Kergon
e8e00630d3 pre-release 2006-11-28 22:49:58 +00:00
Alasdair Kergon
e33720c854 Update dmsetup man page (setgeometry & message) 2006-11-23 20:34:16 +00:00
Alasdair Kergon
bd8a4e0d17 mention new env vars on man page 2006-11-23 17:44:15 +00:00
Alasdair Kergon
586a2aef76 Improve lvm_dump.sh robustness. 2006-11-23 17:23:14 +00:00
Alasdair Kergon
ce1d8f6754 Update lvm2create_initrd to support gentoo. 2006-11-21 22:41:56 +00:00
Alasdair Kergon
7b0f401065 . 2006-11-21 17:46:11 +00:00
Alasdair Kergon
8387016eef Fix clvmd_init_rhel4 line truncation (2.02.14). 2006-11-21 17:44:46 +00:00
Alasdair Kergon
4e1342b641 fix _find_config_node: null parameter is permitted 2006-11-21 15:13:36 +00:00
Alasdair Kergon
e45a184d90 post-release 2006-11-20 23:30:45 +00:00
Alasdair Kergon
979e1012d2 Install lvmdump by default. 2006-11-20 20:03:26 +00:00
Alasdair Kergon
fe10a50e23 pre-release 2006-11-20 19:33:03 +00:00
Alasdair Kergon
8ab6d72519 Fix check for snapshot module when activating snapshot. 2006-11-20 16:45:45 +00:00
Alasdair Kergon
3aada6dd1d Fix pvremove error path for case when PV is in use. 2006-11-17 02:45:51 +00:00
Alasdair Kergon
0933036366 Warn if certain duplicate config file entries are seen.
(not thoroughly tested)
2006-11-16 17:36:00 +00:00
Alasdair Kergon
05f5abdc06 Enhance lvm_dump.sh for sysreport integration and add man page. 2006-11-16 16:44:48 +00:00
Alasdair Kergon
fb875e0709 Fix --autobackup argument which could never disable backups. 2006-11-14 15:28:50 +00:00
Alasdair Kergon
9acdc2f6bf Fix a label_verify error path. 2006-11-14 15:03:07 +00:00
Alasdair Kergon
028ce4bff6 post-release 2006-11-10 21:27:51 +00:00
Alasdair Kergon
3f245ad6db pre-release 2006-11-10 21:22:34 +00:00
Alasdair Kergon
23115f4116 fix cast 2006-11-10 20:15:10 +00:00
Alasdair Kergon
cf5f48e6cc Fix adjusted_mirror_region_size() for 64-bit size. 2006-11-10 19:35:03 +00:00
Alasdair Kergon
997fa756ad Add some missing bounds checks on 32 bit extent counters.
Add Petabyte and Exabyte support.
Fix lvcreate error message when 0 extents requested.
2006-11-10 18:24:11 +00:00
Patrick Caulfield
e23f75b1cc Add note to lvremove man page: volumes must be inactive on
all cluster nodes before being removed.
2006-11-06 14:11:40 +00:00
Alasdair Kergon
6531e88761 Protect .cache manipulations with fcntl locking.
Change .cache timestamp comparisons to use ctime.
2006-11-04 03:34:10 +00:00
Alasdair Kergon
e76a9c2618 fix shift 2006-11-03 21:23:06 +00:00
Alasdair Kergon
45be8a836b fix last check-in: lv->size is in sectors 2006-11-03 21:07:15 +00:00
Alasdair Kergon
954b6032e7 Fix mirror log LV writing to set all bits in whole LV. 2006-11-02 23:33:20 +00:00
Alasdair Kergon
bd95416f27 Fix clustered VG detection and default runlevels in clvmd_init_rhel4. 2006-11-01 18:25:26 +00:00
Alasdair Kergon
df2577ace2 Fix high-level free space check for partial allocations. 2006-10-30 16:10:55 +00:00
Alasdair Kergon
720e6558c9 post-release 2006-10-27 15:37:02 +00:00
Alasdair Kergon
c239f15d8a pre-release 2006-10-27 15:21:07 +00:00
Alasdair Kergon
dfa1f80a57 dd couple of missing files to tools/Makefile CLEAN_TARGETS. 2006-10-26 20:37:13 +00:00
Alasdair Kergon
15dfb93b17 When adding snapshot leave cow LV mapped device active after zeroing. 2006-10-26 18:22:10 +00:00
Alasdair Kergon
0ec8488c2b . 2006-10-24 19:07:32 +00:00
Jonathan Earl Brassow
94b2e29cb1 - likely cut and paste error. Fix wrong function name in debug
output.
2006-10-24 18:49:31 +00:00
Alasdair Kergon
fefa8e9b4d Add dev_flush() to set_lv() 2006-10-24 18:25:30 +00:00
Alasdair Kergon
32c4c44812 resync alphabetical order 2006-10-24 17:19:48 +00:00
Alasdair Kergon
05195e2b1d try forcesync -> resync 2006-10-24 17:18:25 +00:00
Alasdair Kergon
4c2ff675b8 reword --resync desc a bit 2006-10-24 17:09:40 +00:00
Alasdair Kergon
e5692a4721 fix forcesync local active detection 2006-10-24 15:30:33 +00:00
Alasdair Kergon
312e6a0d31 Add lvchange --forcesync. 2006-10-23 23:03:55 +00:00
Alasdair Kergon
5bb8efa41f Perform high-level free space check before each allocation attempt. 2006-10-23 15:54:51 +00:00
Patrick Caulfield
949a835f4a Don't allow a node to remove an LV that's exclusively active on anther node. 2006-10-23 11:46:16 +00:00
Alasdair Kergon
85e6042941 Cope if same PV is included more than once in cmdline PE range list. 2006-10-21 23:18:43 +00:00
Alasdair Kergon
3cd2f28975 getline debug free 2006-10-19 16:50:05 +00:00
Alasdair Kergon
2179a72c3a Suppress encryption key in 'dmsetup table' output unless --showkeys supplied. 2006-10-19 15:34:50 +00:00
Alasdair Kergon
a5f282f156 Set PV size to current device size if it is found to be zero. 2006-10-19 12:53:47 +00:00
Alasdair Kergon
40e8631f63 Add segment parameter to target_present functions. 2006-10-18 18:01:53 +00:00
Alasdair Kergon
9ded05bb97 post-release 2006-10-16 17:18:08 +00:00
Alasdair Kergon
ec8efa35a1 revert 2006-10-16 16:47:56 +00:00
Alasdair Kergon
f72bf20482 pre-release 2006-10-16 16:44:28 +00:00
Alasdair Kergon
ebde2002e8 Fix pvdisplay to use vg_read() for non-orphans 2006-10-16 16:29:40 +00:00
Alasdair Kergon
352a66f46f Fall back to internal locking if external locking lib is missing or fails. 2006-10-14 16:37:54 +00:00
Alasdair Kergon
d84c5391f7 Retain activation state after changing LV minor number with --force. 2006-10-13 21:33:31 +00:00
Alasdair Kergon
f4c582472b post-release.
Note that I've dropped the 2.4 kernel files from the release tarballs now.
2006-10-13 19:01:30 +00:00
Alasdair Kergon
1485586f7e pre-release 2006-10-13 18:43:53 +00:00
Alasdair Kergon
d5c9024335 Avoid deptree attempting to suspend a device that's already suspended. 2006-10-13 14:03:35 +00:00
Alasdair Kergon
860cf80703 Propagate clustered flag in vgsplit and require resizeable flag. 2006-10-13 13:22:44 +00:00
Alasdair Kergon
897ff3161f post-release 2006-10-12 18:20:45 +00:00
Alasdair Kergon
b356b2e501 fix realtime msg alignment 2006-10-12 18:17:09 +00:00
Alasdair Kergon
1d2733c893 pre-release 2006-10-12 18:13:33 +00:00
Alasdair Kergon
32d9126094 . 2006-10-12 17:42:40 +00:00
Alasdair Kergon
db43314e50 missing mesg 2006-10-12 17:41:21 +00:00
Alasdair Kergon
68d2baeb65 pre-release 2006-10-12 17:37:42 +00:00
Alasdair Kergon
1fd5f562d3 noflush code fixes: missing debug log; non-standard variable name 2006-10-12 17:29:05 +00:00
Alasdair Kergon
48e02f2086 remove unused variable 2006-10-12 17:18:40 +00:00
Alasdair Kergon
eab7b2b581 fix dmsetup usage display (missing \n and --noflush wrong place) 2006-10-12 17:09:09 +00:00
Alasdair Kergon
45abade7fc Add suspend noflush support.
Add basic dmsetup loop support.
2006-10-12 15:42:25 +00:00
Alasdair Kergon
5372fc4b43 Test message to lvm-devel list. 2006-10-10 17:20:40 +00:00
Patrick Caulfield
4e2f240c98 Add clvmd call to return the cluster name. 2006-10-09 14:11:57 +00:00
Alasdair Kergon
bb3605518d add cling allocation policy 2006-10-08 12:01:13 +00:00
Alasdair Kergon
3ef6d37f27 . 2006-10-07 23:42:03 +00:00
Alasdair Kergon
88e9f2f7f4 check_contiguous to use for_each_pv 2006-10-07 23:40:36 +00:00
Alasdair Kergon
704a447df9 More work towards pv->size always holding the same value in internal metadata.
Store it in external text metadata as dev_size, and estimate it if not
present when metadata is read back in.
2006-10-07 23:17:17 +00:00
Alasdair Kergon
a5fcb26a33 rely on pv_setup functions to fix up pe_count 2006-10-07 23:06:18 +00:00
Alasdair Kergon
2491a61481 Accept regionsize with lvconvert. 2006-10-07 23:04:36 +00:00
Alasdair Kergon
91831d51ed more refactoring 2006-10-07 16:00:28 +00:00
Alasdair Kergon
174f0c19f7 Extend _for_each_pv() to allow termination without error. 2006-10-07 12:41:06 +00:00
Alasdair Kergon
de6fadfb4f abstract _is_contiguous() 2006-10-07 11:34:53 +00:00
Alasdair Kergon
f946db3e00 move _for_each_pv() 2006-10-07 11:23:22 +00:00
Alasdair Kergon
8d05e5bc31 Remove duplicated pv arg from _check_contiguous(). 2006-10-07 11:00:09 +00:00
Alasdair Kergon
cfb46820e4 Accept regionsize with lvconvert 2006-10-07 10:47:05 +00:00
Alasdair Kergon
081f1cbcc2 Correct regionsize default on lvcreate man page (MB). 2006-10-07 10:43:40 +00:00
Alasdair Kergon
7bc6da326f Add report columns with underscore before field names ending 'size'. 2006-10-07 10:42:27 +00:00
Patrick Caulfield
cd95a0df7b Use strncpy rather than strcpy 2006-10-06 10:06:37 +00:00
Patrick Caulfield
82fa497c16 Fix clvmd bug that could cause it to die when a node with a long name crashed. 2006-10-06 10:06:10 +00:00
Alasdair Kergon
44fd345206 Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
(This area of the code needs a lot more work.)
2006-10-05 22:02:52 +00:00
Alasdair Kergon
088e1c9db4 Fix _for_each_pv() for mirror with core log. 2006-10-05 21:24:48 +00:00
Alasdair Kergon
d4f16e666e Add lvm_dump.sh script to create a tarball of debugging info from a system. 2006-10-05 18:42:33 +00:00
Patrick Caulfield
8233cfd371 Vastly improve the errors returned to the user from clvmd.
It now captures the error messages that are generated and returns them
in the reply packet rather than just telling the user to check syslog.
2006-10-05 13:55:50 +00:00
Alasdair Kergon
ff05e2e30d Remove unused #defines from filter-md.c. 2006-10-04 16:03:17 +00:00
Patrick Caulfield
a8ea7dd3fb Make clvmd restart init script wait until clvmd has died before starting it. 2006-10-04 08:42:14 +00:00
Patrick Caulfield
96f70a5303 Update man page for clvmd -R 2006-10-04 08:28:17 +00:00
Patrick Caulfield
f1604c3e69 Add -R switch to clvmd.
This option will instruct all the clvmd daemons in the cluster to reload their device cache
2006-10-04 08:22:16 +00:00
Alasdair Kergon
c42c8c5192 Test. Future commit messages should now also go to the dm-devel list
(450 subscribers) for discussion as well as the read-only dm-cvs list
(just 15 subscribers).
2006-10-03 21:51:28 +00:00
Alasdair Kergon
5facb53a41 exclude targets that are always built-in 2006-10-03 18:02:06 +00:00
Alasdair Kergon
d039ce89af Add LV column to reports listing kernel modules needed for activation. 2006-10-03 17:55:20 +00:00
Alasdair Kergon
bc7605103f Show available fields if report given invalid field. (e.g. lvs -o list) 2006-10-02 16:46:27 +00:00
Alasdair Kergon
d305d655d4 Fix compiler warnings in percent arg. [pjc] 2006-10-02 16:15:03 +00:00
Alasdair Kergon
4ef1220b16 Add timestamp functions with --disable-realtime configure option. [AJ] 2006-09-30 20:02:02 +00:00
Alasdair Kergon
a4fef143cd Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
e.g. lvcreate -l 100%FREE to create an LV using all available space.
     lvextend -l 50%LV to increase an LV by 50% of its existing size.
     lvcreate -l 20%VG to create an LV using 20% of the total VG size.
2006-09-26 09:35:43 +00:00
Alasdair Kergon
74ecb724a9 Fix two potential NULL pointer derefs in error cases in vg_read(). 2006-09-21 20:25:54 +00:00
Alasdair Kergon
af235897ab Separate --enable-cluster from locking lib options in lvmconf.sh. 2006-09-20 17:36:47 +00:00
Alasdair Kergon
5ec4e458b5 Supply missing comma. [via Debian] 2006-09-19 20:20:40 +00:00
Alasdair Kergon
2dae63ce21 post-release 2006-09-19 19:36:59 +00:00
Alasdair Kergon
be748fe33b pre-release 2006-09-19 19:15:10 +00:00
Alasdair Kergon
7408340b6a Fix lvconvert mirror change case detection logic.
Fix mirror log detachment so it correctly becomes a standalone LV.
2006-09-19 19:13:41 +00:00
Alasdair Kergon
29eb92446e post-release 2006-09-19 17:50:58 +00:00
Alasdair Kergon
ae6918742e pre-release 2006-09-19 17:43:03 +00:00
Alasdair Kergon
863484bb65 Reorder mm bounds_check code to reduce window for a dmeventd race. (dm_free_aux) 2006-09-19 17:30:04 +00:00
Alasdair Kergon
1cd7ebce4c Extend _check_contiguous() to detect single-area LVs.
Include mirror log (untested) in _for_each_pv() processing.
Use MIRROR_LOG_SIZE constant.
Remove struct seg_pvs from _for_each_pv() for generalisation.
Avoid adding duplicates to list of parallel PVs to avoid.
2006-09-11 21:14:56 +00:00
Alasdair Kergon
eef8c7862e Fix several incorrect comparisons in parallel area avoidance code.
Fix segment lengths when flattening existing parallel areas.
Log existing parallel areas prior to allocation.
Fix mirror log creation when activation disabled.
2006-09-11 14:24:58 +00:00
Alasdair Kergon
b52375d446 fix vgreduce clustered check 2006-09-07 23:23:45 +00:00
Alasdair Kergon
6e2babc2ce When using local file locking, skip clustered VGs.
Add fallback_to_clustered_locking and fallback_to_local_locking parameters.
2006-09-02 01:18:17 +00:00
Alasdair Kergon
08e253bed1 lvm.static uses built-in cluster locking instead of external locking.
Don't attempt to load shared libraries if built statically.
2006-08-31 22:21:00 +00:00
Alasdair Kergon
c6661477a2 Change default locking_lib to liblvm2clusterlock.so. 2006-08-31 20:56:33 +00:00
Alasdair Kergon
415cfd99a0 Add skip_dev_dir() to process command line VGs. 2006-08-25 23:02:33 +00:00
Patrick Caulfield
8c2e37381a Stop clvmd complaining about nodes that have left the cluster 2006-08-24 12:45:05 +00:00
Alasdair Kergon
45df79feba stub.h shouldn't be here 2006-08-22 15:56:06 +00:00
Patrick Caulfield
5824f992b7 Add needed new parameter to create_toolcontext(). 2006-08-22 09:49:20 +00:00
Alasdair Kergon
b0b60fafd5 Move lvm_snprintf into libdevmapper. 2006-08-21 12:54:53 +00:00
Alasdair Kergon
8d98b02ba2 Add dm_snprintf 2006-08-21 12:52:39 +00:00
Alasdair Kergon
a93fe79bc4 Add dm_split_words() and dm_split_lvm_name() to libdevmapper. 2006-08-21 12:07:03 +00:00
Alasdair Kergon
4aebd7be37 fix lvm.conf (5) refs 2006-08-18 22:35:59 +00:00
Alasdair Kergon
3170a5db32 mirror man page tweaks 2006-08-18 22:27:01 +00:00
Alasdair Kergon
3605b9eef6 Add mirroring into man pages 2006-08-18 21:49:19 +00:00
Alasdair Kergon
a945f1fde2 reorder bounds check code 2006-08-18 21:38:58 +00:00
Alasdair Kergon
461a997b5b Prevent mirror renames. 2006-08-18 21:19:54 +00:00
Alasdair Kergon
a80afd7b4e Move CMDLIB code into separate file and record whether static build. 2006-08-18 21:17:18 +00:00
Alasdair Kergon
aad2b51d85 post 2006-08-17 20:04:38 +00:00
Alasdair Kergon
36a9a81ff1 wrappers files 2006-08-17 19:56:28 +00:00
Alasdair Kergon
42c88546ae pre-release 2006-08-17 19:55:50 +00:00
Alasdair Kergon
0f0e86ef9b Fix PE_ALIGN for pagesize over 32KB. 2006-08-17 19:53:36 +00:00
Alasdair Kergon
98efd9a857 wrap PE_ALIGN 2006-08-17 19:30:59 +00:00
Alasdair Kergon
a0c27d95b7 Separate out LVM1_PE_ALIGN. 2006-08-17 19:15:27 +00:00
Alasdair Kergon
984651d99d Add lvm_getpagesize wrapper. 2006-08-17 18:23:44 +00:00
Alasdair Kergon
c6f7370b30 Add --maxphysicalvolumes to vgchange. 2006-08-16 14:41:42 +00:00
Alasdair Kergon
3e4b8e8985 post-release 2006-08-15 19:13:06 +00:00
Alasdair Kergon
73f08b98d2 pre-release 2006-08-15 19:06:09 +00:00
Alasdair Kergon
8607a74206 post-release 2006-08-15 17:43:10 +00:00
Alasdair Kergon
8339f3ceb3 pre-release 2006-08-15 17:38:38 +00:00
Alasdair Kergon
c0c9f3cc19 fix getopt_long error check 2006-08-10 20:53:21 +00:00
Alasdair Kergon
81f4813c29 Add --table argument to dmsetup for a one-line table.
Abort if errors are found during cmdline option processing.
2006-08-10 14:11:03 +00:00
Alasdair Kergon
94f57745b9 Add checks for duplicate LV name, lvid and PV id before writing metadata.
Report all sanity check failures, not just the first.
2006-08-09 19:33:25 +00:00
Alasdair Kergon
54fb2ebbe0 Add lockfs indicator to debug output. 2006-08-08 21:22:31 +00:00
Alasdair Kergon
02d122b65b Fix missing lockfs on first snapshot creation. 2006-08-08 21:20:00 +00:00
Alasdair Kergon
df0a5561a1 Add --trustcache option to reporting commands in preparation for supporting
event-driven model.  Without changes to the way the cache gets updated, the
option is currently unreliable without a global lock to prevent any lvm2
commands from running concurrently.
2006-08-01 14:56:33 +00:00
Alasdair Kergon
f7c55da7d0 Fix locking for mimage removal. 2006-07-20 20:37:10 +00:00
Alasdair Kergon
b385f701ce Fix clvmd_init_rhel4 'status' exit code. 2006-07-19 18:55:58 +00:00
Alasdair Kergon
05dd42f443 post-release 2006-07-17 14:39:54 +00:00
Alasdair Kergon
36d816d5cb pre-release 2006-07-17 14:32:00 +00:00
Alasdair Kergon
92a6746e70 Fix activation logic in lvchange --persistent. 2006-07-10 19:39:14 +00:00
Alasdair Kergon
1728848a39 Don't ignore persistent minor numbers when activating. 2006-07-10 19:17:40 +00:00
Alasdair Kergon
f9eb4e7487 test 2006-07-05 21:07:35 +00:00
Alasdair Kergon
d0b9f33aeb test 2006-07-05 21:03:15 +00:00
Alasdair Kergon
718583b241 Append full patch to checkin emails. 2006-07-05 21:01:06 +00:00
Alasdair Kergon
6737127e9a Avoid duplicate dmeventd subdir with 'make distclean'. 2006-07-05 17:29:12 +00:00
Alasdair Kergon
19a7b4479b add dlerror to another error path 2006-07-05 17:26:36 +00:00
Alasdair Kergon
c340647502 Differentiate between the two 'log device failed' cases in vgreduce. 2006-07-04 19:52:47 +00:00
Alasdair Kergon
0f987d2982 Use RTLD_GLOBAL when loading shared libraries. 2006-07-04 19:40:27 +00:00
Alasdair Kergon
52bcaed169 Add some forgotten memlock checks to _vg_read to protect against full scans. 2006-07-04 19:36:49 +00:00
Alasdair Kergon
177bd565ac Add mutex to dmeventd_mirror to avoid concurrent execution. 2006-07-04 18:57:27 +00:00
Alasdair Kergon
c801c32fc5 If VG is already consistent with --removemissing, return success not failure. 2006-07-04 18:51:59 +00:00
Alasdair Kergon
d090cf3058 force remove fixes 2006-06-18 11:51:46 +00:00
Alasdair Kergon
1e4b82cc94 Add --force to dmsetup remove* to load error target. [Untested.]
Update dmsetup man page.
2006-06-18 11:35:04 +00:00
Alasdair Kergon
3426f31184 dmsetup remove_all also performs mknodes. 2006-06-17 16:12:41 +00:00
Alasdair Kergon
b4fb7af1df Don't suppress identical table reloads if permission changes. 2006-06-14 22:00:03 +00:00
Alasdair Kergon
b36647598b Fix return code if VG specified on command line is not found. 2006-06-14 20:27:15 +00:00
Alasdair Kergon
fd6b94f20e Fix PV tools to include orphaned PVs in default output again. 2006-06-14 20:11:22 +00:00
Alasdair Kergon
296dc0ed8a test checkin 2006-06-12 17:34:20 +00:00
Alasdair Kergon
4f869e14d6 test checkin 2006-06-12 17:32:43 +00:00
Alasdair Kergon
5704270e9d test checkin 2006-06-12 17:30:29 +00:00
Alasdair Kergon
505b381e85 checkin test 2006-06-12 17:18:31 +00:00
Patrick Caulfield
da6cb15393 Fix "Unaligned access" when using clvm
bz#194626
2006-06-12 09:46:35 +00:00
Alasdair Kergon
16843f6cc8 Fix an extra dev_close in a label_read error path. 2006-06-08 22:15:49 +00:00
Alasdair Kergon
64f3ad1fd4 change two files in different directories 2006-06-06 17:44:11 +00:00
Alasdair Kergon
ff4c4f99b3 test 2006-06-06 17:42:20 +00:00
Alasdair Kergon
f5d2e09569 test one change 2006-06-06 17:41:30 +00:00
Alasdair Kergon
f2bdbe0d4d Fix target_register_events args. 2006-05-25 13:32:26 +00:00
Alasdair Kergon
c51a13caa6 Prevent snapshots of mirrors. 2006-05-24 13:58:14 +00:00
Alasdair Kergon
7840c78a23 Add DISTCLEAN_TARGETS to make template for configure.h.
More fixes to error paths.
2006-05-16 20:53:13 +00:00
Alasdair Kergon
c706f3246b fix error path 2006-05-16 20:42:01 +00:00
Alasdair Kergon
608eedf88d Fix lvcreate corelog validation.
Add --config for overriding most config file settings from cmdline.
  Quote arguments when printing command line.
  Remove linefeed from 'initialising logging' message.
  Add 'Completed' debug message.
  Don't attempt library exit after reloading config files.
  Always compile with libdevmapper, even if device-mapper is disabled.
2006-05-16 16:48:31 +00:00
Alasdair Kergon
a564ca82be Fix corelog segment line.
Suppress some compiler warnings.
2006-05-16 16:20:29 +00:00
Patrick Caulfield
c868b1fee2 Add needed include. 2006-05-15 12:32:08 +00:00
Alasdair Kergon
22374f718f fix compile 2006-05-15 11:56:15 +00:00
Alasdair Kergon
abe3cfcf41 post-release 2006-05-12 20:32:39 +00:00
Alasdair Kergon
59db4b50cd fix dev->device 2006-05-12 19:47:40 +00:00
Alasdair Kergon
bdae38765d not reqd 2006-05-12 19:44:42 +00:00
Alasdair Kergon
66d3ceeb61 pre-release 2006-05-12 19:41:43 +00:00
Alasdair Kergon
445dd17db3 Add --monitor to vgcreate and lvcreate to control dmeventd registration.
Propagate --monitor around cluster.
Filter LCK_NONBLOCK in clvmd lock_vg.
2006-05-12 19:16:48 +00:00
Alasdair Kergon
cff78a2577 fix compile 2006-05-12 13:33:22 +00:00
218 changed files with 16495 additions and 8439 deletions

View File

@@ -16,7 +16,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SUBDIRS = doc include man
SUBDIRS = doc include man scripts
ifeq ("@INTL@", "yes")
SUBDIRS += po
@@ -38,6 +38,7 @@ ifeq ($(MAKECMDGOALS),distclean)
lib/snapshot \
po \
test/mm test/device test/format1 test/regex test/filters
DISTCLEAN_TARGETS += lib/misc/configure.h
endif
include make.tmpl

View File

@@ -1 +1 @@
2.02.06-cvs (2006-04-21)
2.02.26-cvs (2007-06-15)

309
WHATS_NEW
View File

@@ -1,5 +1,312 @@
Version 2.02.06 -
Version 2.02.26 - 15th June 2007
================================
Update vgcfgrestore man page.
Allow keyboard interrupt during user prompts when appropriate.
Remove unused clvmd system-lv code.
Replace many physical_volume struct dereferences with new get_pv_* functions.
Suppress a benign compile-time warning.
Convert find_pv_in_vg_by_uuid and pv_create to use PV handles.
Add wrappers to some functions in preparation for external LVM library.
Add -f to vgcfgrestore to list metadata backup files.
Add vg_check_status to consolidate vg status checks and error messages.
Add pvdisplay --maps implementation.
Remove unsupported LVM1 options from vgcfgrestore man page.
Update vgcfgrestore man page to show mandatory VG name.
Update vgrename man page to include UUID and be consistent with lvrename.
Add (experimental) OpenAIS support to clvmd.
Fix deactivation code to follow dependencies and remove symlinks.
Fix and clarify vgsplit error messages.
Fix a segfault in device_is_usable() if a device has no table.
Add some more debug messages to clvmd startup.
Misc clvmd cleanups.
Version 2.02.25 - 27th April 2007
=================================
Fix get_config_uint64() to read a 64-bit value not a 32-bit one.
Add -Wformat-security and change one fprintf() to fputs().
Move regex functions into libdevmapper.
Change some #include lines to search only standard system directories.
Add devices/preferred_names config regex list for displayed device names.
Free a temporary dir string in fcntl_lock_file() after use.
Fix a dm_pool_destroy() in matcher_create().
Introduce goto_bad macro.
Fix warnings on x86_64 involving ptrdiff_t in log_error messages.
Update pvck to include text metadata area and record detection.
Add support functions for token counting in config file extracts.
Update pvck to read labels on disk, with --labelsector parameter.
Add count_chars and count_chars_len functions.
Add /sys/block listings to lvm_dump.sh.
Make lvm_dump.sh list /dev recursively.
Fix thread race in clvmd.
Add scan_sector param to label_read and _find_labeller.
Make clvmd cope with quorum devices.
Add extra internal error checking to clvmd.
Add dev_read_circular.
Add pvck command stub.
Update lists of attribute characters in man pages.
Change cling alloc policy attribute character from 'C' to l'.
Fix creation and conversion of mirrors with tags.
Fix vgsplit for lvm1 format (set and validate VG name in PVs metadata).
Split metadata areas in vgsplit properly.
Version 2.02.24 - 19th March 2007
=================================
Fix processing of exit status in init scripts
Fix vgremove to require at least one vg argument.
Fix reading of striped LVs in LVM1 format.
Flag nolocking as clustered so clvmd startup sees clustered LVs. (2.02.10)
Add a few missing pieces of vgname command line validation.
Support the /dev/mapper prefix on most command lines.
Version 2.02.23 - 8th March 2007
================================
Fix vgrename active LV check to ignore differing vgids.
Remove no-longer-used uuid_out parameter from activation info functions.
Fix two more segfaults if an empty config file section encountered.
Move .cache file into a new /etc/lvm/cache directory by default.
Add devices/cache_dir & devices/cache_file_prefix, deprecating devices/cache.
Create directory in fcntl_lock_file() if required.
Exclude readline support from lvm.static.
Fix a leak in a reporting error path (2.02.19).
Version 2.02.22 - 13th February 2007
====================================
Correct -b and -P on a couple of man pages.
Add global/units to example.conf.
Fix loading of segment_libraries.
If a PV reappears after it was removed from its VG, make it an orphan.
Don't update metadata automatically if VGIDs don't match.
Fix some vgreduce --removemissing command line validation.
Version 2.02.21 - 30th January 2007
===================================
Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring.
Fix vgsplit to handle mirrors.
Reorder fields in reporting field definitions.
Fix vgs to treat args as VGs even when PV fields are displayed.
Fix md signature check to handle both endiannesses.
Version 2.02.20 - 25th January 2007
===================================
dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors.
Add devices/ignore_suspended_devices to ignore suspended dm devices.
Add some missing close() and fclose() return code checks.
Fix exit statuses of reporting tools (2.02.19).
Add init script for dmeventd monitoring.
lvm.static no longer interacts with dmeventd unless explicitly asked to.
Add field definitions to report help text.
Remove unnecessary cmd arg from target_*monitor_events().
Add private variable to dmeventd shared library interface.
Long-lived processes write out persistent dev cache in refresh_toolcontext().
Fix refresh_toolcontext() always to wipe persistent device filter cache.
Add is_long_lived to toolcontext.
Add --clustered to man pages.
Streamline dm_report_field_* interface.
Change remaining dmeventd terminology 'register' to 'monitor'.
Update reporting man pages.
No longer necessary to specify alignment type for report fields.
Version 2.02.19 - 17th January 2007
===================================
Fix a segfault if an empty config file section encountered.
Move basic reporting functions into libdevmapper.
Fix partition table processing after sparc changes (2.02.16).
Fix cmdline PE range processing segfault (2.02.13).
Some libdevmapper-event interface changes.
Report dmeventd mirror monitoring status.
Fix dmeventd mirror status line processing.
Version 2.02.18 - 11th January 2007
===================================
Revised libdevmapper-event interface for dmeventd.
Remove dmeventd mirror status line word limit.
Use CFLAGS when linking so mixed sparc builds can supply -m64.
Prevent permission changes on active mirrors.
Print warning instead of error message if lvconvert cannot zero volume.
Add snapshot options to lvconvert man page.
dumpconfig accepts a list of configuration variables to display.
Change dumpconfig to use --file to redirect output to a file.
Avoid vgreduce error when mirror code removes the log LV.
Remove 3 redundant AC_MSG_RESULTs from configure.in.
Free memory in _raw_read_mda_header() error paths.
Fix ambiguous vgsplit error message for split LV.
Fix lvextend man page typo.
Add configure --with-dmdir to compile against a device-mapper source tree.
Use no flush suspending for mirrors.
Add dmeventd_mirror register_mutex, tidy initialisation & add memlock.
Fix create mirror with name longer than 22 chars.
Fix some activate.c prototypes when compiled without devmapper.
Fix dmeventd mirror to cope if monitored device disappears.
Version 2.02.17 - 14th December 2006
====================================
Add missing pvremove error message when device doesn't exist.
When lvconvert allocates a mirror log, respect parallel area constraints.
Use loop to iterate through the now-ordered policy list in _allocate().
Check for failure to allocate just the mirror log.
Introduce calc_area_multiple().
Support mirror log allocation when there is only one PV: area_count now 0.
Fix detection of smallest area in _alloc_parallel_area() for cling policy.
Add manpage entry for clvmd -T
Fix gulm operation of clvmd, including a hang when doing lvchange -aey
Fix hang in clvmd if a pre-command failed.
Version 2.02.16 - 1st December 2006
===================================
Fix VG clustered read locks to use PR not CR.
Adjust some alignments for ia64/sparc.
Fix mirror segment removal to use temporary error segment.
Always compile debug logging into clvmd.
Add startup timeout to RHEL4 clvmd startup script.
Add -T (startup timeout) switch to clvmd.
Improve lvm_dump.sh robustness.
Update lvm2create_initrd to support gentoo.
Version 2.02.15 - 21st November 2006
====================================
Fix clvmd_init_rhel4 line truncation (2.02.14).
Install lvmdump by default.
Fix check for snapshot module when activating snapshot.
Fix pvremove error path for case when PV is in use.
Warn if certain duplicate config file entries are seen.
Enhance lvm_dump.sh for sysreport integration and add man page.
Fix --autobackup argument which could never disable backups.
Fix a label_verify error path.
Version 2.02.14 - 10th November 2006
====================================
Fix adjusted_mirror_region_size() to handle 64-bit size.
Add some missing bounds checks on 32-bit extent counters.
Add Petabyte and Exabyte support.
Fix lvcreate error message when 0 extents requested.
lvremove man page: volumes must be cluster inactive before being removed.
Protect .cache manipulations with fcntl locking.
Change .cache timestamp comparisons to use ctime.
Fix mirror log LV writing to set all bits in whole LV.
Fix clustered VG detection and default runlevels in clvmd_init_rhel4.
Fix high-level free space check for partial allocations.
Version 2.02.13 - 27th October 2006
===================================
Add couple of missing files to tools/Makefile CLEAN_TARGETS.
When adding snapshot leave cow LV mapped device active after zeroing.
Fix a clvmd debug message.
Add dev_flush() to set_lv().
Add lvchange --resync.
Perform high-level free space check before each allocation attempt.
Don't allow a node to remove an LV that's exclusively active on anther node.
Cope if same PV is included more than once in cmdline PE range list.
Set PV size to current device size if it is found to be zero.
Add segment parameter to target_present functions.
Version 2.02.12 - 16th October 2006
===================================
Fix pvdisplay to use vg_read() for non-orphans.
Fall back to internal locking if external locking lib is missing or fails.
Retain activation state after changing LV minor number with --force.
Propagate clustered flag in vgsplit and require resizeable flag.
Version 2.02.11 - 12th October 2006
===================================
Add clvmd function to return the cluster name. not used by LVM yet.
Add cling allocation policy.
Change _check_contiguous() to use _for_each_pv().
Extend _for_each_pv() to allow termination without error.
Abstract _is_contiguous().
Remove duplicated pv arg from _check_contiguous().
Accept regionsize with lvconvert.
Add report columns with underscore before field names ending 'size'.
Correct regionsize default on lvcreate man page (MB).
Fix clvmd bug that could cause it to die when a node with a long name crashed.
Add device size to text metadata.
Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
Fix _for_each_pv() for mirror with core log.
Add lvm_dump.sh script to create a tarball of debugging info from a system.
Capture error messages in clvmd and pass them back to the user.
Remove unused #defines from filter-md.c.
Make clvmd restart init script wait until clvmd has died before starting it.
Add -R to clvmd which tells running clvmds to reload their device cache.
Add LV column to reports listing kernel modules needed for activation.
Show available fields if report given invalid field. (e.g. lvs -o list)
Add timestamp functions with --disable-realtime configure option.
Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
Fix two potential NULL pointer derefs in error cases in vg_read().
Separate --enable-cluster from locking lib options in lvmconf.sh.
Add a missing comma in lvcreate man page.
Version 2.02.10 - 19th September 2006
=====================================
Fix lvconvert mirror change case detection logic.
Fix mirror log detachment so it correctly becomes a standalone LV.
Extend _check_contiguous() to detect single-area LVs.
Include mirror log (untested) in _for_each_pv() processing.
Use MIRROR_LOG_SIZE constant.
Remove struct seg_pvs from _for_each_pv() to generalise.
Avoid adding duplicates to list of parallel PVs to avoid.
Fix several incorrect comparisons in parallel area avoidance code.
Fix segment lengths when flattening existing parallel areas.
Log existing parallel areas prior to allocation.
Fix mirror log creation when activation disabled.
Don't attempt automatic recovery without proper locking.
When using local file locking, skip clustered VGs.
Add fallback_to_clustered_locking and fallback_to_local_locking parameters.
lvm.static uses built-in cluster locking instead of external locking.
Don't attempt to load shared libraries if built statically.
Change default locking_lib to liblvm2clusterlock.so.
Add skip_dev_dir() to process command line VGs.
Stop clvmd complaining about nodes that have left the cluster.
Move lvm_snprintf(), split_words() and split_dm_name() into libdevmapper.
Add lvconvert man page.
Add mirror options to man pages.
Prevent mirror renames.
Move CMDLIB code into separate file and record whether static build.
Version 2.02.09 - 17th August 2006
==================================
Fix PE_ALIGN for pagesize over 32KB.
Separate out LVM1_PE_ALIGN and pe_align().
Add lvm_getpagesize wrapper.
Add --maxphysicalvolumes to vgchange.
Version 2.02.08 - 15th August 2006
==================================
Add checks for duplicate LV name, lvid and PV id before writing metadata.
Report all sanity check failures, not just the first.
Fix missing lockfs on first snapshot creation.
Add unreliable --trustcache option to reporting commands.
Fix locking for mimage removal.
Fix clvmd_init_rhel4 'status' exit code.
Version 2.02.07 - 17th July 2006
================================
Fix activation logic in lvchange --persistent.
Don't ignore persistent minor numbers when activating.
Use RTLD_GLOBAL when loading shared libraries.
Add some forgotten memlock checks to _vg_read to protect against full scans.
Add mutex to dmeventd_mirror to avoid concurrent execution.
Fix vgreduce --removemissing to return success if VG is already consistent.
Fix return code if VG specified on command line is not found.
Fix PV tools to include orphaned PVs in default output again.
Fixed unaligned access when using clvm.
Fix an extra dev_close in a label_read error path.
Append patches to commit emails.
Fix target_register_events args.
Prevent snapshots of mirrors.
Add DISTCLEAN_TARGETS to make template for configure.h.
More fixes to error paths.
Fix lvcreate corelog validation.
Add --config for overriding most config file settings from cmdline.
Quote arguments when printing command line.
Remove linefeed from 'initialising logging' message.
Add 'Completed' debug message.
Don't attempt library exit after reloading config files.
Always compile with libdevmapper, even if device-mapper is disabled.
Version 2.02.06 - 12th May 2006
===============================
Propagate --monitor around cluster.
Add --monitor to vgcreate and lvcreate to control dmeventd registration.
Filter LCK_NONBLOCK in clvmd lock_vg.
Add --nosync to lvcreate with LV flag NOTSYNCED.
Use mirror's uuid for a core log.
Add mirror log fault-handling policy.

View File

@@ -1,3 +1,102 @@
Version 1.02.20 - 15th June 2007
================================
Fix default dmsetup report buffering and add --unbuffered.
Add tree-based and dependency fields to dmsetup reports.
Version 1.02.19 - 27th April 2007
=================================
Standardise protective include file #defines.
Add regex functions to library.
Avoid trailing separator in reports when there are hidden sort fields.
Fix segfault in 'dmsetup status' without --showkeys against crypt target.
Deal with some more compiler warnings.
Introduce _add_field() and _is_same_field() to libdm-report.c.
Fix some libdevmapper-event and dmeventd memory leaks.
Remove unnecessary memset() return value checks.
Fix a few leaks in reporting error paths. [1.02.15+]
Version 1.02.18 - 13th February 2007
====================================
Improve dmeventd messaging protocol: drain pipe and tag messages.
Version 1.02.17 - 29th January 2007
===================================
Add recent reporting options to dmsetup man page.
Revise some report fields names.
Add dmsetup 'help' command and update usage text.
Use fixed-size fields in report interface and reorder.
Version 1.02.16 - 25th January 2007
===================================
Add some missing close() and fclose() return value checks.
Migrate dmsetup column-based output over to new libdevmapper report framework.
Add descriptions to reporting field definitions.
Add a dso-private variable to dmeventd dso interface.
Add dm_event_handler_[gs]et_timeout functions.
Streamline dm_report_field_* interface.
Add cmdline debug & version options to dmeventd.
Add DM_LIB_VERSION definition to configure.h.
Suppress 'Unrecognised field' error if report field is 'help'.
Add --separator and --sort to dmsetup (unused).
Make alignment flag optional when specifying report fields.
Version 1.02.15 - 17th January 2007
===================================
Add basic reporting functions to libdevmapper.
Fix a malloc error path in dmsetup message.
More libdevmapper-event interface changes and fixes.
Rename dm_saprintf() to dm_asprintf().
Report error if NULL pointer is supplied to dm_strdup_aux().
Reinstate dm_event_get_registered_device.
Version 1.02.14 - 11th January 2007
===================================
Add dm_saprintf().
Use CFLAGS when linking so mixed sparc builds can supply -m64.
Add dm_tree_use_no_flush_suspend().
Lots of dmevent changes including revised interface.
Export dm_basename().
Cope with a trailing space when comparing tables prior to possible reload.
Fix dmeventd to cope if monitored device disappears.
Version 1.02.13 - 28 Nov 2006
=============================
Update dmsetup man page (setgeometry & message).
Fix dmsetup free after getline with debug.
Suppress encryption key in 'dmsetup table' output unless --showkeys supplied.
Version 1.02.12 - 13 Oct 2006
=============================
Avoid deptree attempting to suspend a device that's already suspended.
Version 1.02.11 - 12 Oct 2006
==============================
Add suspend noflush support.
Add basic dmsetup loop support.
Switch dmsetup to use dm_malloc and dm_free.
Version 1.02.10 - 19 Sep 2006
=============================
Add dm_snprintf(), dm_split_words() and dm_split_lvm_name() to libdevmapper.
Reorder mm bounds_check code to reduce window for a dmeventd race.
Version 1.02.09 - 15 Aug 2006
=============================
Add --table argument to dmsetup for a one-line table.
Abort if errors are found during cmdline option processing.
Add lockfs indicator to debug output.
Version 1.02.08 - 17 July 2006
==============================
Append full patch to check in emails.
Avoid duplicate dmeventd subdir with 'make distclean'.
Update dmsetup man page.
Add --force to dmsetup remove* to load error target.
dmsetup remove_all also performs mknodes.
Don't suppress identical table reloads if permission changes.
Fix corelog segment line.
Suppress some compiler warnings.
Version 1.02.07 - 11 May 2006
=============================
Add DM_CORELOG flag to dm_tree_node_add_mirror_target().

176
configure vendored
View File

@@ -310,7 +310,7 @@ ac_includes_default="\
#endif"
ac_default_prefix=/usr
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR DMDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -853,6 +853,7 @@ Optional Features:
statically. Default is dynamic linking
--enable-readline Enable readline support
--disable-selinux Disable selinux support
--disable-realtime Disable realtime clock support
--enable-debug Enable debugging
--disable-devmapper Disable device-mapper interaction
--disable-o_direct Disable O_DIRECT
@@ -882,6 +883,7 @@ Optional Packages:
--with-localedir=DIR Translation files in DIR PREFIX/share/locale
--with-confdir=DIR Configuration files in DIR /etc
--with-staticdir=DIR Static binary in DIR EXEC_PREFIX/sbin
--with-dmdir=DIR Build against device-mapper source tree in DIR
Some influential environment variables:
CC C compiler command
@@ -1459,6 +1461,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=yes
SELINUX=yes
REALTIME=yes
CLUSTER=internal
FSADM=no ;;
darwin*)
@@ -1473,6 +1476,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=no
SELINUX=no
REALTIME=no
CLUSTER=none
FSADM=no ;;
esac
@@ -7431,6 +7435,17 @@ fi;
echo "$as_me:$LINENO: result: $SELINUX" >&5
echo "${ECHO_T}$SELINUX" >&6
################################################################################
echo "$as_me:$LINENO: checking whether to enable realtime support" >&5
echo $ECHO_N "checking whether to enable realtime support... $ECHO_C" >&6
# Check whether --enable-realtime or --disable-realtime was given.
if test "${enable_realtime+set}" = set; then
enableval="$enable_realtime"
REALTIME=$enableval
fi;
echo "$as_me:$LINENO: result: $REALTIME" >&5
echo "${ECHO_T}$REALTIME" >&6
################################################################################
echo "$as_me:$LINENO: checking whether to build cluster LVM daemon" >&5
echo $ECHO_N "checking whether to build cluster LVM daemon... $ECHO_C" >&6
@@ -7534,14 +7549,6 @@ fi;
echo "$as_me:$LINENO: result: $CMDLIB" >&5
echo "${ECHO_T}$CMDLIB" >&6
if test x$CMDLIB = xyes; then
cat >>confdefs.h <<\_ACEOF
#define CMDLIB 1
_ACEOF
fi
################################################################################
echo "$as_me:$LINENO: checking whether to build fsadm" >&5
echo $ECHO_N "checking whether to build fsadm... $ECHO_C" >&6
@@ -8261,8 +8268,6 @@ fi
################################################################################
if test x$SELINUX = xyes; then
echo "$as_me:$LINENO: checking for sepol_check_context function" >&5
echo $ECHO_N "checking for sepol_check_context function... $ECHO_C" >&6
echo "$as_me:$LINENO: checking for sepol_check_context in -lsepol" >&5
echo $ECHO_N "checking for sepol_check_context in -lsepol... $ECHO_C" >&6
if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then
@@ -8333,15 +8338,11 @@ else
HAVE_SEPOL=no
fi
echo "$as_me:$LINENO: result: $HAVE_SEPOL" >&5
echo "${ECHO_T}$HAVE_SEPOL" >&6
if test x$HAVE_SEPOL = xyes; then
LIBS="-lsepol $LIBS"
fi
echo "$as_me:$LINENO: checking for is_selinux_enabled function" >&5
echo $ECHO_N "checking for is_selinux_enabled function... $ECHO_C" >&6
echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5
echo $ECHO_N "checking for is_selinux_enabled in -lselinux... $ECHO_C" >&6
if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then
@@ -8412,8 +8413,6 @@ else
HAVE_SELINUX=no
fi
echo "$as_me:$LINENO: result: $HAVE_SELINUX" >&5
echo "${ECHO_T}$HAVE_SELINUX" >&6
if test x$HAVE_SELINUX = xyes; then
@@ -8428,6 +8427,92 @@ echo "$as_me: WARNING: Disabling selinux" >&2;}
fi
fi
################################################################################
if test x$REALTIME = xyes; then
echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char clock_gettime ();
int
main ()
{
clock_gettime ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_lib_rt_clock_gettime=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_rt_clock_gettime=no
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
echo "${ECHO_T}$ac_cv_lib_rt_clock_gettime" >&6
if test $ac_cv_lib_rt_clock_gettime = yes; then
HAVE_REALTIME=yes
else
HAVE_REALTIME=no
fi
if test x$HAVE_REALTIME = xyes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_REALTIME 1
_ACEOF
LIBS="-lrt $LIBS"
else
{ echo "$as_me:$LINENO: WARNING: Disabling realtime clock" >&5
echo "$as_me: WARNING: Disabling realtime clock" >&2;}
fi
fi
################################################################################
for ac_header in getopt.h
@@ -8868,6 +8953,15 @@ else
STATICDIR='${exec_prefix}/sbin'
fi;
# Check whether --with-dmdir or --without-dmdir was given.
if test "${with_dmdir+set}" = set; then
withval="$with_dmdir"
DMDIR="$withval"
else
DMDIR=
fi;
################################################################################
if test x$READLINE = xyes; then
@@ -10699,7 +10793,6 @@ done
fi
if test x$DEVMAPPER = xyes; then
for ac_header in libdevmapper.h
do
@@ -10854,7 +10947,6 @@ fi
done
fi
if test x$HAVE_SELINUX = xyes; then
@@ -11053,45 +11145,6 @@ else
echo "${ECHO_T}no" >&6
fi
# Extract the first word of "ifconfig", so it can be a program name with args.
set dummy ifconfig; ac_word=$2
echo "$as_me:$LINENO: checking for $ac_word" >&5
echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
if test "${ac_cv_path_MODPROBE_CMD+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
case $MODPROBE_CMD in
[\\/]* | ?:[\\/]*)
ac_cv_path_MODPROBE_CMD="$MODPROBE_CMD" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_MODPROBE_CMD="$as_dir/$ac_word$ac_exec_ext"
echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
;;
esac
fi
MODPROBE_CMD=$ac_cv_path_MODPROBE_CMD
if test -n "$MODPROBE_CMD"; then
echo "$as_me:$LINENO: result: $MODPROBE_CMD" >&5
echo "${ECHO_T}$MODPROBE_CMD" >&6
else
echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
fi
if test x$MODPROBE_CMD != x; then
@@ -11143,11 +11196,13 @@ fi
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile scripts/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -11689,6 +11744,7 @@ do
"lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
"man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
"po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
"scripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
"tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
"tools/version.h" ) CONFIG_FILES="$CONFIG_FILES tools/version.h" ;;
"tools/fsadm/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/fsadm/Makefile" ;;
@@ -11838,10 +11894,12 @@ s,@DEBUG@,$DEBUG,;t t
s,@DEVMAPPER@,$DEVMAPPER,;t t
s,@HAVE_LIBDL@,$HAVE_LIBDL,;t t
s,@HAVE_SELINUX@,$HAVE_SELINUX,;t t
s,@HAVE_REALTIME@,$HAVE_REALTIME,;t t
s,@CMDLIB@,$CMDLIB,;t t
s,@LOCALEDIR@,$LOCALEDIR,;t t
s,@CONFDIR@,$CONFDIR,;t t
s,@STATICDIR@,$STATICDIR,;t t
s,@DMDIR@,$DMDIR,;t t
s,@INTL_PACKAGE@,$INTL_PACKAGE,;t t
s,@INTL@,$INTL,;t t
s,@CLVMD@,$CLVMD,;t t

View File

@@ -42,6 +42,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=yes
SELINUX=yes
REALTIME=yes
CLUSTER=internal
FSADM=no ;;
darwin*)
@@ -56,6 +57,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=no
SELINUX=no
REALTIME=no
CLUSTER=none
FSADM=no ;;
esac
@@ -282,6 +284,13 @@ AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
SELINUX=$enableval)
AC_MSG_RESULT($SELINUX)
################################################################################
dnl -- Disable realtime clock support
AC_MSG_CHECKING(whether to enable realtime support)
AC_ARG_ENABLE(realtime, [ --disable-realtime Disable realtime clock support],
REALTIME=$enableval)
AC_MSG_RESULT($REALTIME)
################################################################################
dnl -- Build cluster LVM daemon
AC_MSG_CHECKING(whether to build cluster LVM daemon)
@@ -351,10 +360,6 @@ AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library],
CMDLIB=$enableval, CMDLIB=no)
AC_MSG_RESULT($CMDLIB)
if test x$CMDLIB = xyes; then
AC_DEFINE([CMDLIB], 1, [Define to 1 to build the shared command library.])
fi
################################################################################
dnl -- Enable fsadm
AC_MSG_CHECKING(whether to build fsadm)
@@ -433,17 +438,13 @@ fi
################################################################################
dnl -- Check for selinux
if test x$SELINUX = xyes; then
AC_MSG_CHECKING(for sepol_check_context function)
AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no)
AC_MSG_RESULT($HAVE_SEPOL)
if test x$HAVE_SEPOL = xyes; then
LIBS="-lsepol $LIBS"
fi
AC_MSG_CHECKING(for is_selinux_enabled function)
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
AC_MSG_RESULT($HAVE_SELINUX)
if test x$HAVE_SELINUX = xyes; then
AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.])
@@ -453,6 +454,19 @@ if test x$SELINUX = xyes; then
fi
fi
################################################################################
dnl -- Check for realtime clock support
if test x$REALTIME = xyes; then
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
if test x$HAVE_REALTIME = xyes; then
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
LIBS="-lrt $LIBS"
else
AC_MSG_WARN(Disabling realtime clock)
fi
fi
################################################################################
dnl -- Check for getopt
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 to if getopt_long is available.]))
@@ -506,6 +520,11 @@ AC_ARG_WITH(staticdir,
[ STATICDIR="$withval" ],
[ STATICDIR='${exec_prefix}/sbin' ])
AC_ARG_WITH(dmdir,
[ --with-dmdir=DIR Build against device-mapper source tree in DIR],
[ DMDIR="$withval" ],
[ DMDIR= ])
################################################################################
dnl -- Ensure additional headers required
if test x$READLINE = xyes; then
@@ -538,9 +557,7 @@ if test x$INTL = xyes; then
AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out))
fi
if test x$DEVMAPPER = xyes; then
AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out))
fi
AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out))
if test x$HAVE_SELINUX = xyes; then
AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out))
@@ -584,11 +601,13 @@ AC_SUBST(DEBUG)
AC_SUBST(DEVMAPPER)
AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_SELINUX)
AC_SUBST(HAVE_REALTIME)
AC_SUBST(CMDLIB)
AC_SUBST(MSGFMT)
AC_SUBST(LOCALEDIR)
AC_SUBST(CONFDIR)
AC_SUBST(STATICDIR)
AC_SUBST(DMDIR)
AC_SUBST(INTL_PACKAGE)
AC_SUBST(INTL)
AC_SUBST(CLVMD)
@@ -618,6 +637,7 @@ lib/mirror/Makefile \
lib/snapshot/Makefile \
man/Makefile \
po/Makefile \
scripts/Makefile \
tools/Makefile \
tools/version.h \
tools/fsadm/Makefile \

View File

@@ -19,7 +19,7 @@ SOURCES = \
clvmd-command.c \
clvmd.c \
lvm-functions.c \
system-lv.c
refresh_clvmd.c
ifeq ("@CLVMD@", "gulm")
GULM = yes
@@ -29,9 +29,16 @@ ifeq ("@CLVMD@", "cman")
CMAN = yes
endif
ifeq ("@CLVMD@", "openais")
OPENAIS = yes
GULM = no
CMAN = no
endif
ifeq ("@CLVMD@", "all")
GULM = yes
CMAN = yes
OPENAIS = no
endif
ifeq ("@DEBUG@", "yes")
@@ -50,6 +57,12 @@ ifeq ("$(CMAN)", "yes")
DEFS += -DUSE_CMAN
endif
ifeq ("$(OPENAIS)", "yes")
SOURCES += clvmd-openais.c
LMLIBS += -lSaLck -lSaClm -lcpg
DEFS += -DUSE_OPENAIS
endif
TARGETS = \
clvmd
@@ -59,9 +72,7 @@ ifeq ("@DMEVENTD@", "yes")
LVMLIBS += -ldevmapper-event
endif
ifeq ("@DEVMAPPER@", "yes")
LVMLIBS += -ldevmapper
endif
LVMLIBS += -ldevmapper
DEFS += -D_REENTRANT
CFLAGS += -fno-strict-aliasing
@@ -72,7 +83,8 @@ INSTALL_TARGETS = \
install_clvmd
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS)
$(CC) -o clvmd $(OBJECTS) $(CFLAGS) $(LDFLAGS) \
$(LVMLIBS) $(LMLIBS) $(LIBS)
.PHONY: install_clvmd

View File

@@ -63,4 +63,8 @@ static const char CLVMD_SOCKNAME[] = "\0clvmd";
#define CLVMD_CMD_LOCK_LV 50
#define CLVMD_CMD_LOCK_VG 51
/* Misc functions */
#define CLVMD_CMD_REFRESH 40
#define CLVMD_CMD_GET_CLUSTERNAME 41
#endif

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"
@@ -58,7 +58,7 @@ static cman_handle_t c_handle;
static void count_clvmds_running(void);
static void get_members(void);
static int nodeid_from_csid(char *csid);
static int nodeid_from_csid(const char *csid);
static int name_from_nodeid(int nodeid, char *name);
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
static void data_callback(cman_handle_t handle, void *private,
@@ -78,6 +78,7 @@ static int _init_cluster(void)
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
return -1;
}
DEBUGLOG("Connected to CMAN\n");
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
syslog(LOG_ERR, "Can't bind cluster socket: %m");
@@ -93,6 +94,8 @@ static int _init_cluster(void)
get_members();
count_clvmds_running();
DEBUGLOG("CMAN initialisation complete\n");
/* Create a lockspace for LV & VG locks to live in */
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
if (!lockspace) {
@@ -100,7 +103,7 @@ static int _init_cluster(void)
return -1;
}
dlm_ls_pthread_init(lockspace);
DEBUGLOG("DLM initialisation complete\n");
return 0;
}
@@ -121,14 +124,15 @@ static int _get_num_nodes()
/* return number of ACTIVE nodes */
for (i=0; i<num_nodes; i++) {
if (nodes[i].cn_member)
if (nodes[i].cn_member && nodes[i].cn_nodeid)
nnodes++;
}
return nnodes;
}
/* send_message with the fd check removed */
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
const char *errtext)
{
int nodeid = 0;
@@ -137,7 +141,7 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
{
log_error(errtext);
log_error("%s", errtext);
}
return msglen;
}
@@ -152,25 +156,27 @@ static void _get_our_csid(char *csid)
/* Call a callback routine for each node is that known (down means not running a clvmd) */
static int _cluster_do_node_callback(struct local_client *client,
void (*callback) (struct local_client *, char *,
int))
void (*callback) (struct local_client *,
const char *,
int))
{
int i;
int somedown = 0;
for (i = 0; i < _get_num_nodes(); i++) {
callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
if (!node_updown[nodes[i].cn_nodeid])
somedown = -1;
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;
}
}
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_NAME_LEN];
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
switch (reason) {
case CMAN_REASON_PORTCLOSED:
@@ -204,8 +210,9 @@ static void event_callback(cman_handle_t handle, void *private, int reason, int
}
static struct local_client *cman_client;
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
struct local_client **new_client)
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
const char *csid,
struct local_client **new_client)
{
/* Save this for data_callback */
@@ -227,7 +234,7 @@ static void data_callback(cman_handle_t handle, void *private,
process_message(cman_client, buf, len, (char *)&nodeid);
}
static void _add_up_node(char *csid)
static void _add_up_node(const char *csid)
{
/* It's up ! */
int nodeid = nodeid_from_csid(csid);
@@ -243,7 +250,7 @@ static void _add_up_node(char *csid)
max_updown_nodes);
} else {
log_error
("Realloc failed. Node status for clvmd will be wrong. quitting\n");
("Realloc failed. Node status for clvmd will be wrong. quitting\n");
exit(999);
}
}
@@ -297,38 +304,38 @@ static void get_members()
return;
}
/* Not enough room for new nodes list ? */
if (num_nodes > count_nodes && nodes) {
free(nodes);
nodes = NULL;
}
/* Not enough room for new nodes list ? */
if (num_nodes > count_nodes && nodes) {
free(nodes);
nodes = NULL;
}
if (nodes == NULL) {
count_nodes = num_nodes + 10; /* Overallocate a little */
if (nodes == NULL) {
count_nodes = num_nodes + 10; /* Overallocate a little */
nodes = malloc(count_nodes * sizeof(struct cman_node));
if (!nodes) {
log_error("Unable to allocate nodes array\n");
exit(5);
}
}
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
if (status < 0) {
log_error("Unable to get node details");
exit(6);
}
if (node_updown == NULL) {
node_updown =
(int *) malloc(sizeof(int) *
max(num_nodes, max_updown_nodes));
memset(node_updown, 0,
sizeof(int) * max(num_nodes, max_updown_nodes));
if (!nodes) {
log_error("Unable to allocate nodes array\n");
exit(5);
}
}
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
if (status < 0) {
log_error("Unable to get node details");
exit(6);
}
if (node_updown == NULL) {
size_t buf_len = sizeof(int) * max(num_nodes, max_updown_nodes);
node_updown = malloc(buf_len);
if (node_updown)
memset(node_updown, 0, buf_len);
}
}
/* Convert a node name to a CSID */
static int _csid_from_name(char *csid, char *name)
static int _csid_from_name(char *csid, const char *name)
{
int i;
@@ -342,7 +349,7 @@ static int _csid_from_name(char *csid, char *name)
}
/* Convert a CSID to a node name */
static int _name_from_csid(char *csid, char *name)
static int _name_from_csid(const char *csid, char *name)
{
int i;
@@ -374,7 +381,7 @@ static int name_from_nodeid(int nodeid, char *name)
}
/* Convert a CSID to a node ID */
static int nodeid_from_csid(char *csid)
static int nodeid_from_csid(const char *csid)
{
int nodeid;
@@ -468,6 +475,18 @@ static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
}
static int _get_cluster_name(char *buf, int buflen)
{
cman_cluster_t cluster_info;
int status;
status = cman_get_cluster(c_handle, &cluster_info);
if (!status) {
strncpy(buf, cluster_info.ci_name, buflen);
}
return status;
}
static struct cluster_ops _cluster_cman_ops = {
.cluster_init_completed = _cluster_init_completed,
.cluster_send_message = _cluster_send_message,
@@ -481,6 +500,7 @@ static struct cluster_ops _cluster_cman_ops = {
.get_our_csid = _get_our_csid,
.add_up_node = _add_up_node,
.cluster_closedown = _cluster_closedown,
.get_cluster_name = _get_cluster_name,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};

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,8 @@
#include "clvmd-comms.h"
#include "clvm.h"
#include "clvmd.h"
#include "libdlm.h"
extern struct cluster_ops *clops;
/* This is where all the real work happens:
NOTE: client will be NULL when this is executed on a remote node */
@@ -93,13 +95,22 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
/* Just a test message */
case CLVMD_CMD_TEST:
if (arglen > buflen) {
char *new_buf;
buflen = arglen + 200;
*buf = realloc(*buf, buflen);
new_buf = realloc(*buf, buflen);
if (new_buf == NULL) {
status = errno;
free (*buf);
}
*buf = new_buf;
}
if (*buf) {
uname(&nodeinfo);
*retlen = 1 + snprintf(*buf, buflen,
"TEST from %s: %s v%s",
nodeinfo.nodename, args,
nodeinfo.release);
}
uname(&nodeinfo);
*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s",
nodeinfo.nodename, args,
nodeinfo.release);
break;
case CLVMD_CMD_LOCK_VG:
@@ -116,12 +127,22 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
/* Replace EIO with something less scary */
if (status == EIO) {
*retlen =
1 + snprintf(*buf, buflen,
"Internal lvm error, check syslog");
1 + snprintf(*buf, buflen, "%s",
get_last_lvm_error());
return EIO;
}
break;
case CLVMD_CMD_REFRESH:
do_refresh_cache();
break;
case CLVMD_CMD_GET_CLUSTERNAME:
status = clops->get_cluster_name(*buf, buflen);
if (!status)
*retlen = strlen(*buf)+1;
break;
default:
/* Won't get here because command is validated in pre_command */
break;
@@ -129,7 +150,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
/* Check the status of the command and return the error text */
if (status) {
*retlen = 1 + snprintf(*buf, buflen, strerror(status));
*retlen = 1 + snprintf(*buf, buflen, "%s", strerror(status));
}
return status;
@@ -179,12 +200,16 @@ static int lock_vg(struct local_client *client)
dm_hash_remove(lock_hash, lockname);
}
else {
status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid);
/* Read locks need to be PR; other modes get passed through */
if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) {
lock_cmd &= ~LCK_TYPE_MASK;
lock_cmd |= LCK_PREAD;
}
status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid);
if (status)
status = errno;
else
dm_hash_insert(lock_hash, lockname, (void *)lkid);
dm_hash_insert(lock_hash, lockname, (void *)(long)lkid);
}
return status;
@@ -208,7 +233,7 @@ int do_pre_command(struct local_client *client)
switch (header->cmd) {
case CLVMD_CMD_TEST:
status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
client->bits.localsock.private = (void *) lockid;
client->bits.localsock.private = (void *)(long)lockid;
break;
case CLVMD_CMD_LOCK_VG:
@@ -222,6 +247,10 @@ int do_pre_command(struct local_client *client)
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
break;
case CLVMD_CMD_REFRESH:
case CLVMD_CMD_GET_CLUSTERNAME:
break;
default:
log_error("Unknown command %d received\n", header->cmd);
status = EINVAL;

View File

@@ -25,25 +25,31 @@ struct local_client;
struct cluster_ops {
void (*cluster_init_completed) (void);
int (*cluster_send_message) (void *buf, int msglen, char *csid,
const char *errtext);
int (*name_from_csid) (char *csid, char *name);
int (*csid_from_name) (char *csid, char *name);
int (*cluster_send_message) (const void *buf, int msglen,
const char *csid,
const char *errtext);
int (*name_from_csid) (const char *csid, char *name);
int (*csid_from_name) (char *csid, const char *name);
int (*get_num_nodes) (void);
int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
char *csid, struct local_client **new_client);
const char *csid,
struct local_client **new_client);
int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */
int (*cluster_do_node_callback) (struct local_client *client,
void (*callback) (struct local_client *,
char *csid, int node_up));
void (*callback) (struct local_client *,
const char *csid,
int node_up));
int (*is_quorate) (void);
void (*get_our_csid) (char *csid);
void (*add_up_node) (char *csid);
void (*add_up_node) (const char *csid);
void (*reread_config) (void);
void (*cluster_closedown) (void);
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
int (*get_cluster_name)(char *buf, int buflen);
int (*sync_lock) (const char *resource, int mode,
int flags, int *lockid);
int (*sync_unlock) (const char *resource, int lockid);
};
@@ -69,6 +75,23 @@ struct cluster_ops *init_gulm_cluster(void);
struct cluster_ops *init_cman_cluster(void);
#endif
#ifdef USE_OPENAIS
# include <openais/saAis.h>
# include <openais/totem/totem.h>
# define OPENAIS_CSID_LEN (sizeof(int))
# define OPENAIS_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
# define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
# define MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
# endif
# ifndef CMAN_MAX_CLUSTER_MESSAGE
# define CMAN_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
# endif
# ifndef MAX_CSID_LEN
# define MAX_CSID_LEN sizeof(int)
# endif
struct cluster_ops *init_openais_cluster(void);
#endif
#endif

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;
@@ -730,7 +730,7 @@ static int _lock_resource(char *resource, int mode, int flags, int *lockid)
pthread_mutex_lock(&lwait.mutex);
/* This needs to be converted from DLM/LVM2 value for GULM */
if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try;
if (flags & LKF_NOQUEUE) flags = lg_lock_flag_Try;
dm_hash_insert(lock_hash, resource, &lwait);
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
@@ -828,6 +828,7 @@ static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
}
break;
case LCK_PREAD:
case LCK_READ:
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
if (status)
@@ -864,6 +865,7 @@ static int _sync_unlock(const char *resource, int lockid)
/* The held lock mode is in the lock id */
assert(lockid == LCK_EXCL ||
lockid == LCK_READ ||
lockid == LCK_PREAD ||
lockid == LCK_WRITE);
status = _unlock_resource(lock1, lockid);
@@ -973,6 +975,12 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
return gulm_cluster_send_message(buf, msglen, csid, errtext);
}
static int _get_cluster_name(char *buf, int buflen)
{
strncpy(buf, cluster_name, buflen);
return 0;
}
static struct cluster_ops _cluster_gulm_ops = {
.cluster_init_completed = NULL,
.cluster_send_message = _cluster_send_message,
@@ -987,6 +995,7 @@ static struct cluster_ops _cluster_gulm_ops = {
.add_up_node = gulm_add_up_node,
.reread_config = _reread_config,
.cluster_closedown = _cluster_closedown,
.get_cluster_name = _get_cluster_name,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};

View File

@@ -1,5 +1,6 @@
/* DLM constant that clvmd uses as a generic NONBLOCK lock flag */
#define LKF_NOQUEUE 1
extern int get_next_node_csid(void **context, char *csid);
extern void add_down_node(char *csid);

View File

@@ -0,0 +1,756 @@
/******************************************************************************
*******************************************************************************
**
** Copyright (C) 2007 Red Hat, Inc. All rights reserved.
**
*******************************************************************************
******************************************************************************/
/* This provides the interface between clvmd and OpenAIS as the cluster
* and lock manager.
*
*/
#include <pthread.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <utmpx.h>
#include <syslog.h>
#include <assert.h>
#include <libdevmapper.h>
#include <openais/saAis.h>
#include <openais/saLck.h>
#include <openais/saClm.h>
#include <openais/cpg.h>
#include "list.h"
#include "locking.h"
#include "log.h"
#include "clvm.h"
#include "clvmd-comms.h"
#include "lvm-functions.h"
#include "clvmd.h"
/* Timeout value for several openais calls */
#define TIMEOUT 10
static void lck_lock_callback(SaInvocationT invocation,
SaLckLockStatusT lockStatus,
SaAisErrorT error);
static void lck_unlock_callback(SaInvocationT invocation,
SaAisErrorT error);
static void cpg_deliver_callback (cpg_handle_t handle,
struct cpg_name *groupName,
uint32_t nodeid,
uint32_t pid,
void *msg,
int msg_len);
static void cpg_confchg_callback(cpg_handle_t handle,
struct cpg_name *groupName,
struct cpg_address *member_list, int member_list_entries,
struct cpg_address *left_list, int left_list_entries,
struct cpg_address *joined_list, int joined_list_entries);
static void _cluster_closedown(void);
/* Hash list of nodes in the cluster */
static struct dm_hash_table *node_hash;
/* For associating lock IDs & resource handles */
static struct dm_hash_table *lock_hash;
/* Number of active nodes */
static int num_nodes;
static unsigned int our_nodeid;
static struct local_client *cluster_client;
/* OpenAIS handles */
static cpg_handle_t cpg_handle;
static SaLckHandleT lck_handle;
static struct cpg_name cpg_group_name;
/* Openais callback structs */
cpg_callbacks_t cpg_callbacks = {
.cpg_deliver_fn = cpg_deliver_callback,
.cpg_confchg_fn = cpg_confchg_callback,
};
SaLckCallbacksT lck_callbacks = {
.saLckLockGrantCallback = lck_lock_callback,
.saLckResourceUnlockCallback = lck_unlock_callback
};
/* We only call Clm to get our node id */
SaClmCallbacksT clm_callbacks;
struct node_info
{
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
int nodeid;
};
struct lock_info
{
SaLckResourceHandleT res_handle;
SaLckLockIdT lock_id;
SaNameT lock_name;
};
struct lock_wait
{
pthread_cond_t cond;
pthread_mutex_t mutex;
int status;
};
/* Set errno to something approximating the right value and return 0 or -1 */
static int ais_to_errno(SaAisErrorT err)
{
switch(err)
{
case SA_AIS_OK:
return 0;
case SA_AIS_ERR_LIBRARY:
errno = EINVAL;
break;
case SA_AIS_ERR_VERSION:
errno = EINVAL;
break;
case SA_AIS_ERR_INIT:
errno = EINVAL;
break;
case SA_AIS_ERR_TIMEOUT:
errno = ETIME;
break;
case SA_AIS_ERR_TRY_AGAIN:
errno = EAGAIN;
break;
case SA_AIS_ERR_INVALID_PARAM:
errno = EINVAL;
break;
case SA_AIS_ERR_NO_MEMORY:
errno = ENOMEM;
break;
case SA_AIS_ERR_BAD_HANDLE:
errno = EINVAL;
break;
case SA_AIS_ERR_BUSY:
errno = EBUSY;
break;
case SA_AIS_ERR_ACCESS:
errno = EPERM;
break;
case SA_AIS_ERR_NOT_EXIST:
errno = ENOENT;
break;
case SA_AIS_ERR_NAME_TOO_LONG:
errno = ENAMETOOLONG;
break;
case SA_AIS_ERR_EXIST:
errno = EEXIST;
break;
case SA_AIS_ERR_NO_SPACE:
errno = ENOSPC;
break;
case SA_AIS_ERR_INTERRUPT:
errno = EINTR;
break;
case SA_AIS_ERR_NAME_NOT_FOUND:
errno = ENOENT;
break;
case SA_AIS_ERR_NO_RESOURCES:
errno = ENOMEM;
break;
case SA_AIS_ERR_NOT_SUPPORTED:
errno = EOPNOTSUPP;
break;
case SA_AIS_ERR_BAD_OPERATION:
errno = EINVAL;
break;
case SA_AIS_ERR_FAILED_OPERATION:
errno = EIO;
break;
case SA_AIS_ERR_MESSAGE_ERROR:
errno = EIO;
break;
case SA_AIS_ERR_QUEUE_FULL:
errno = EXFULL;
break;
case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
errno = EINVAL;
break;
case SA_AIS_ERR_BAD_FLAGS:
errno = EINVAL;
break;
case SA_AIS_ERR_TOO_BIG:
errno = E2BIG;
break;
case SA_AIS_ERR_NO_SECTIONS:
errno = ENOMEM;
break;
default:
errno = EINVAL;
break;
}
return -1;
}
static char *print_csid(const char *csid)
{
static char buf[128];
int id;
memcpy(&id, csid, sizeof(int));
sprintf(buf, "%d", id);
return buf;
}
static int add_internal_client(int fd, fd_callback_t callback)
{
struct local_client *client;
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
client = malloc(sizeof(struct local_client));
if (!client)
{
DEBUGLOG("malloc failed\n");
return -1;
}
memset(client, 0, sizeof(struct local_client));
client->fd = fd;
client->type = CLUSTER_INTERNAL;
client->callback = callback;
add_client(client);
/* Set Close-on-exec */
fcntl(fd, F_SETFD, 1);
return 0;
}
static void cpg_deliver_callback (cpg_handle_t handle,
struct cpg_name *groupName,
uint32_t nodeid,
uint32_t pid,
void *msg,
int msg_len)
{
int target_nodeid;
memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
DEBUGLOG("Got message from nodeid %d for %d. len %d\n",
nodeid, target_nodeid, msg_len-4);
if (target_nodeid == our_nodeid)
process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
}
static void cpg_confchg_callback(cpg_handle_t handle,
struct cpg_name *groupName,
struct cpg_address *member_list, int member_list_entries,
struct cpg_address *left_list, int left_list_entries,
struct cpg_address *joined_list, int joined_list_entries)
{
int i;
struct node_info *ninfo;
DEBUGLOG("confchg callback. %d joined, %d left, %d members\n",
joined_list_entries, left_list_entries, member_list_entries);
for (i=0; i<joined_list_entries; i++) {
ninfo = dm_hash_lookup_binary(node_hash,
(char *)&joined_list[i].nodeid,
OPENAIS_CSID_LEN);
if (!ninfo) {
ninfo = malloc(sizeof(struct node_info));
if (!ninfo) {
break;
}
else {
ninfo->nodeid = joined_list[i].nodeid;
dm_hash_insert_binary(node_hash,
(char *)&ninfo->nodeid,
OPENAIS_CSID_LEN, ninfo);
}
}
ninfo->state = NODE_CLVMD;
}
for (i=0; i<left_list_entries; i++) {
ninfo = dm_hash_lookup_binary(node_hash,
(char *)&left_list[i].nodeid,
OPENAIS_CSID_LEN);
if (ninfo)
ninfo->state = NODE_DOWN;
}
num_nodes = joined_list_entries;
}
static void lck_lock_callback(SaInvocationT invocation,
SaLckLockStatusT lockStatus,
SaAisErrorT error)
{
struct lock_wait *lwait = (struct lock_wait *)(long)invocation;
DEBUGLOG("lck_lock_callback, error = %d\n", error);
lwait->status = error;
pthread_mutex_lock(&lwait->mutex);
pthread_cond_signal(&lwait->cond);
pthread_mutex_unlock(&lwait->mutex);
}
static void lck_unlock_callback(SaInvocationT invocation,
SaAisErrorT error)
{
struct lock_wait *lwait = (struct lock_wait *)(long)invocation;
DEBUGLOG("lck_unlock_callback\n");
lwait->status = SA_AIS_OK;
pthread_mutex_lock(&lwait->mutex);
pthread_cond_signal(&lwait->cond);
pthread_mutex_unlock(&lwait->mutex);
}
static int lck_dispatch(struct local_client *client, char *buf, int len,
const char *csid, struct local_client **new_client)
{
*new_client = NULL;
saLckDispatch(lck_handle, SA_DISPATCH_ONE);
return 1;
}
static int _init_cluster(void)
{
SaAisErrorT err;
SaVersionT ver = { 'B', 1, 1 };
SaClmHandleT clm_handle;
int select_fd;
SaClmClusterNodeT cluster_node;
node_hash = dm_hash_create(100);
lock_hash = dm_hash_create(10);
err = cpg_initialize(&cpg_handle,
&cpg_callbacks);
if (err != SA_AIS_OK) {
syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
err);
DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
return ais_to_errno(err);
}
err = saLckInitialize(&lck_handle,
&lck_callbacks,
&ver);
if (err != SA_AIS_OK) {
cpg_initialize(&cpg_handle, &cpg_callbacks);
syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
err);
DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
return ais_to_errno(err);
}
/* Connect to the clvmd group */
strcpy((char *)cpg_group_name.value, "clvmd");
cpg_group_name.length = strlen((char *)cpg_group_name.value);
err = cpg_join(cpg_handle, &cpg_group_name);
if (err != SA_AIS_OK) {
cpg_finalize(cpg_handle);
saLckFinalize(lck_handle);
syslog(LOG_ERR, "Cannot join clvmd process group");
DEBUGLOG("Cannot join clvmd process group\n");
return ais_to_errno(err);
}
/* A brief foray into Clm to get our node id */
err = saClmInitialize(&clm_handle, &clm_callbacks, &ver);
if (err != SA_AIS_OK) {
syslog(LOG_ERR, "Could not initialize OpenAIS membership service %d\n", err);
DEBUGLOG("Could not initialize OpenAIS Membership service %d\n", err);
return ais_to_errno(err);
}
err = saClmClusterNodeGet(clm_handle,
SA_CLM_LOCAL_NODE_ID,
TIMEOUT,
&cluster_node);
if (err != SA_AIS_OK) {
cpg_finalize(cpg_handle);
saLckFinalize(lck_handle);
saClmFinalize(clm_handle);
syslog(LOG_ERR, "Cannot get local node id\n");
return ais_to_errno(err);
}
saClmFinalize(clm_handle);
our_nodeid = cluster_node.nodeId;
DEBUGLOG("Our local node id is %d\n", our_nodeid);
saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
add_internal_client(select_fd, lck_dispatch);
DEBUGLOG("Connected to OpenAIS\n");
return 0;
}
static void _cluster_closedown(void)
{
DEBUGLOG("cluster_closedown\n");
unlock_all();
saLckFinalize(lck_handle);
cpg_inalize(cpg_handle);
}
static void _get_our_csid(char *csid)
{
memcpy(csid, &our_nodeid, sizeof(int));
}
/* OpenAIS doesn't really have nmode names so we
just use the node ID in hex instead */
static int _csid_from_name(char *csid, const char *name)
{
int nodeid;
struct node_info *ninfo;
if (sscanf(name, "%x", &nodeid) == 1) {
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
if (ninfo)
return nodeid;
}
return -1;
}
static int _name_from_csid(const char *csid, char *name)
{
struct node_info *ninfo;
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
if (!ninfo)
{
sprintf(name, "UNKNOWN %s", print_csid(csid));
return -1;
}
sprintf(name, "%x", ninfo->nodeid);
return 0;
}
static int _get_num_nodes()
{
DEBUGLOG("num_nodes = %d\n", num_nodes);
return num_nodes;
}
/* Node is now known to be running a clvmd */
static void _add_up_node(const char *csid)
{
struct node_info *ninfo;
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
if (!ninfo) {
DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
print_csid(csid));
return;
}
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
ninfo->state = NODE_CLVMD;
return;
}
/* Call a callback for each node, so the caller knows whether it's up or down */
static int _cluster_do_node_callback(struct local_client *master_client,
void (*callback)(struct local_client *,
const char *csid, int node_up))
{
struct dm_hash_node *hn;
struct node_info *ninfo;
dm_hash_iterate(hn, node_hash)
{
char csid[OPENAIS_CSID_LEN];
ninfo = dm_hash_get_data(node_hash, hn);
memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
ninfo->state);
if (ninfo->state != NODE_DOWN)
callback(master_client, csid, ninfo->state == NODE_CLVMD);
}
return 0;
}
/* Real locking */
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
{
struct lock_wait lwait;
struct lock_info *linfo;
SaLckResourceHandleT res_handle;
SaAisErrorT err;
SaLckLockIdT lock_id;
pthread_cond_init(&lwait.cond, NULL);
pthread_mutex_init(&lwait.mutex, NULL);
pthread_mutex_lock(&lwait.mutex);
/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
linfo = malloc(sizeof(struct lock_info));
if (!linfo)
return -1;
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
linfo->lock_name.length = strlen(resource)+1;
strcpy((char *)linfo->lock_name.value, resource);
err = saLckResourceOpen(lck_handle, &linfo->lock_name,
SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
if (err != SA_AIS_OK)
{
DEBUGLOG("ResourceOpen returned %d\n", err);
free(linfo);
return ais_to_errno(err);
}
err = saLckResourceLockAsync(res_handle,
(SaInvocationT)(long)&lwait,
&lock_id,
mode,
flags,
0);
if (err != SA_AIS_OK)
{
free(linfo);
saLckResourceClose(res_handle);
return ais_to_errno(err);
}
/* Wait for it to complete */
pthread_cond_wait(&lwait.cond, &lwait.mutex);
pthread_mutex_unlock(&lwait.mutex);
DEBUGLOG("lock_resource returning %d, lock_id=%llx\n", lwait.status,
lock_id);
linfo->lock_id = lock_id;
linfo->res_handle = res_handle;
dm_hash_insert(lock_hash, resource, linfo);
return ais_to_errno(lwait.status);
}
static int _unlock_resource(char *resource, int lockid)
{
struct lock_wait lwait;
SaAisErrorT err;
struct lock_info *linfo;
pthread_cond_init(&lwait.cond, NULL);
pthread_mutex_init(&lwait.mutex, NULL);
pthread_mutex_lock(&lwait.mutex);
DEBUGLOG("unlock_resource %s\n", resource);
linfo = dm_hash_lookup(lock_hash, resource);
if (!linfo)
return 0;
DEBUGLOG("unlock_resource: lockid: %llx\n", linfo->lock_id);
err = saLckResourceUnlockAsync((SaInvocationT)(long)&lwait, linfo->lock_id);
if (err != SA_AIS_OK)
{
DEBUGLOG("Unlock returned %d\n", err);
return ais_to_errno(err);
}
/* Wait for it to complete */
pthread_cond_wait(&lwait.cond, &lwait.mutex);
pthread_mutex_unlock(&lwait.mutex);
/* Release the resource */
dm_hash_remove(lock_hash, resource);
saLckResourceClose(linfo->res_handle);
free(linfo);
return ais_to_errno(lwait.status);
}
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
{
int status;
char lock1[strlen(resource)+3];
char lock2[strlen(resource)+3];
snprintf(lock1, sizeof(lock1), "%s-1", resource);
snprintf(lock2, sizeof(lock2), "%s-2", resource);
switch (mode)
{
case LCK_EXCL:
status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
if (status)
goto out;
/* If we can't get this lock too then bail out */
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
lockid);
if (status == SA_LCK_LOCK_NOT_QUEUED)
{
_unlock_resource(lock1, *lockid);
status = -1;
errno = EAGAIN;
}
break;
case LCK_PREAD:
case LCK_READ:
status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
if (status)
goto out;
_unlock_resource(lock2, *lockid);
break;
case LCK_WRITE:
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
if (status)
goto out;
_unlock_resource(lock1, *lockid);
break;
default:
status = -1;
errno = EINVAL;
break;
}
out:
*lockid = mode;
return status;
}
static int _sync_unlock(const char *resource, int lockid)
{
int status = 0;
char lock1[strlen(resource)+3];
char lock2[strlen(resource)+3];
snprintf(lock1, sizeof(lock1), "%s-1", resource);
snprintf(lock2, sizeof(lock2), "%s-2", resource);
_unlock_resource(lock1, lockid);
_unlock_resource(lock2, lockid);
return status;
}
/* We are always quorate ! */
static int _is_quorate()
{
return 1;
}
static int _get_main_cluster_fd(void)
{
int select_fd;
cpg_fd_get(cpg_handle, &select_fd);
return select_fd;
}
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
const char *csid,
struct local_client **new_client)
{
cluster_client = fd;
*new_client = NULL;
cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
return 1;
}
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
const char *errtext)
{
struct iovec iov[2];
SaAisErrorT err;
int target_node;
if (csid)
memcpy(&target_node, csid, OPENAIS_CSID_LEN);
else
target_node = 0;
iov[0].iov_base = &target_node;
iov[0].iov_len = sizeof(int);
iov[1].iov_base = (char *)buf;
iov[1].iov_len = msglen;
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
return ais_to_errno(err);
}
/* We don't have a cluster name to report here */
static int _get_cluster_name(char *buf, int buflen)
{
strncpy(buf, "OpenAIS", buflen);
return 0;
}
static struct cluster_ops _cluster_openais_ops = {
.cluster_init_completed = NULL,
.cluster_send_message = _cluster_send_message,
.name_from_csid = _name_from_csid,
.csid_from_name = _csid_from_name,
.get_num_nodes = _get_num_nodes,
.cluster_fd_callback = _cluster_fd_callback,
.get_main_cluster_fd = _get_main_cluster_fd,
.cluster_do_node_callback = _cluster_do_node_callback,
.is_quorate = _is_quorate,
.get_our_csid = _get_our_csid,
.add_up_node = _add_up_node,
.reread_config = NULL,
.cluster_closedown = _cluster_closedown,
.get_cluster_name = _get_cluster_name,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};
struct cluster_ops *init_openais_cluster(void)
{
if (!_init_cluster())
return &_cluster_openais_ops;
else
return NULL;
}

View File

@@ -30,20 +30,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <syslog.h>
#include <errno.h>
#include <libdlm.h>
#include "clvmd-comms.h"
#include "lvm-functions.h"
#include "clvm.h"
#include "version.h"
#include "clvmd.h"
#include "libdlm.h"
#include "system-lv.h"
#include "refresh_clvmd.h"
#include "list.h"
#include "log.h"
@@ -54,9 +55,7 @@
#define FALSE 0
#endif
/* The maximum size of a message that will fit into a packet. Anything bigger
than this is sent via the system LV */
#define MAX_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
#define MAX_RETRIES 4
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
@@ -66,7 +65,7 @@ static struct local_client local_client_head;
static unsigned short global_xid = 0; /* Last transaction ID issued */
static struct cluster_ops *clops = NULL;
struct cluster_ops *clops = NULL;
static char our_csid[MAX_CSID_LEN];
static unsigned max_csid_len;
@@ -84,6 +83,7 @@ struct lvm_thread_cmd {
int msglen;
unsigned short xid;
};
static int debug = 0;
static pthread_t lvm_thread;
static pthread_mutex_t lvm_thread_mutex;
static pthread_cond_t lvm_thread_cond;
@@ -98,6 +98,7 @@ static int child_pipe[2];
#define DFAIL_LOCAL_SOCK 2
#define DFAIL_CLUSTER_IF 3
#define DFAIL_MALLOC 4
#define DFAIL_TIMEOUT 5
#define SUCCESS 0
/* Prototypes for code further down */
@@ -109,31 +110,32 @@ static void send_local_reply(struct local_client *client, int status,
static void free_reply(struct local_client *client);
static void send_version_message(void);
static void *pre_and_post_thread(void *arg);
static int send_message(void *buf, int msglen, char *csid, int fd,
static int send_message(void *buf, int msglen, const char *csid, int fd,
const char *errtext);
static int read_from_local_sock(struct local_client *thisfd);
static int process_local_command(struct clvm_header *msg, int msglen,
struct local_client *client,
unsigned short xid);
static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
char *csid);
static int process_reply(struct clvm_header *msg, int msglen, char *csid);
const char *csid);
static int process_reply(const struct clvm_header *msg, int msglen,
const char *csid);
static int open_local_sock(void);
static struct local_client *find_client(int clientid);
static void main_loop(int local_sock, int cmd_timeout);
static void be_daemon(void);
static void be_daemon(int start_timeout);
static int check_all_clvmds_running(struct local_client *client);
static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
int len, char *csid,
int len, const char *csid,
struct local_client **new_client);
static void *lvm_thread_fn(void *);
static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
int msglen, char *csid);
int msglen, const char *csid);
static int distribute_command(struct local_client *thisfd);
static void hton_clvm(struct clvm_header *hdr);
static void ntoh_clvm(struct clvm_header *hdr);
static void add_reply_to_list(struct local_client *client, int status,
char *csid, const char *buf, int len);
const char *csid, const char *buf, int len);
static void usage(char *prog, FILE *file)
{
@@ -143,7 +145,9 @@ static void usage(char *prog, FILE *file)
fprintf(file, " -V Show version of clvmd\n");
fprintf(file, " -h Show this help information\n");
fprintf(file, " -d Don't fork, run in the foreground\n");
fprintf(file, " -R Tell all running clvmds in the cluster to reload their device cache\n");
fprintf(file, " -t<secs> Command timeout (default 60 seconds)\n");
fprintf(file, " -T<secs> Startup timeout (default none)\n");
fprintf(file, "\n");
}
@@ -159,21 +163,36 @@ static void child_init_signal(int status)
}
void debuglog(const char *fmt, ...)
{
time_t P;
va_list ap;
if (!debug)
return;
va_start(ap,fmt);
time(&P);
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 );
vfprintf(stderr, fmt, ap);
va_end(ap);
}
int main(int argc, char *argv[])
{
int local_sock;
struct local_client *newfd;
struct utsname nodeinfo;
signed char opt;
int debug = 0;
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
int start_timeout = 0;
sigset_t ss;
int using_gulm = 0;
/* Deal with command-line arguments */
opterr = 0;
optind = 0;
while ((opt = getopt(argc, argv, "?vVhdt:")) != EOF) {
while ((opt = getopt(argc, argv, "?vVhdt:RT:")) != EOF) {
switch (opt) {
case 'h':
usage(argv[0], stdout);
@@ -183,6 +202,9 @@ int main(int argc, char *argv[])
usage(argv[0], stderr);
exit(0);
case 'R':
return refresh_clvmd();
case 'd':
debug++;
break;
@@ -195,6 +217,14 @@ int main(int argc, char *argv[])
exit(1);
}
break;
case 'T':
start_timeout = atoi(optarg);
if (start_timeout <= 0) {
fprintf(stderr, "startup timeout is invalid\n");
usage(argv[0], stderr);
exit(1);
}
break;
case 'V':
printf("Cluster LVM daemon version: %s\n", LVM_VERSION);
@@ -209,7 +239,7 @@ int main(int argc, char *argv[])
/* Fork into the background (unless requested not to) */
if (!debug) {
be_daemon();
be_daemon(start_timeout);
}
DEBUGLOG("CLVMD started\n");
@@ -261,6 +291,15 @@ int main(int argc, char *argv[])
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
}
#endif
#ifdef USE_OPENAIS
if (!clops)
if ((clops = init_openais_cluster())) {
max_csid_len = OPENAIS_CSID_LEN;
max_cluster_message = OPENAIS_MAX_CLUSTER_MESSAGE;
max_cluster_member_name_len = OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN;
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to OpenAIS");
}
#endif
if (!clops) {
DEBUGLOG("Can't initialise cluster interface\n");
@@ -293,7 +332,8 @@ int main(int argc, char *argv[])
/* This needs to be started after cluster initialisation
as it may need to take out locks */
DEBUGLOG("starting LVM thread\n");
pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
(void *)(long)using_gulm);
/* Tell the rest of the cluster our version number */
/* CMAN can do this immediately, gulm needs to wait until
@@ -324,7 +364,8 @@ void clvmd_cluster_init_completed()
/* Data on a connected socket */
static int local_sock_callback(struct local_client *thisfd, char *buf, int len,
char *csid, struct local_client **new_client)
const char *csid,
struct local_client **new_client)
{
*new_client = NULL;
return read_from_local_sock(thisfd);
@@ -332,7 +373,7 @@ static int local_sock_callback(struct local_client *thisfd, char *buf, int len,
/* Data on a connected socket */
static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
int len, char *csid,
int len, const char *csid,
struct local_client **new_client)
{
/* Someone connected to our local socket, accept it. */
@@ -342,6 +383,9 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
socklen_t sl = sizeof(socka);
int client_fd = accept(thisfd->fd, (struct sockaddr *) &socka, &sl);
if (client_fd == -1 && errno == EINTR)
return 1;
if (client_fd >= 0) {
newfd = malloc(sizeof(struct local_client));
if (!newfd) {
@@ -370,7 +414,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
}
static int local_pipe_callback(struct local_client *thisfd, char *buf,
int maxlen, char *csid,
int maxlen, const char *csid,
struct local_client **new_client)
{
int len;
@@ -379,17 +423,20 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
int status = -1; /* in error by default */
len = read(thisfd->fd, buffer, sizeof(int));
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
thisfd->fd, len, *(int *) buffer);
if (len == -1 && errno == EINTR)
return 1;
if (len == sizeof(int)) {
status = *(int *) buffer;
memcpy(&status, buffer, sizeof(int));
}
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
thisfd->fd, len, status);
/* EOF on pipe or an error, close it */
if (len <= 0) {
int jstat;
void *ret = &status;
close(thisfd->fd);
/* Clear out the cross-link */
@@ -399,9 +446,7 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
/* Reap child thread */
if (thisfd->bits.pipe.threadid) {
jstat =
pthread_join(thisfd->bits.pipe.threadid,
(void **) &status);
jstat = pthread_join(thisfd->bits.pipe.threadid, &ret);
thisfd->bits.pipe.threadid = 0;
if (thisfd->bits.pipe.client != NULL)
thisfd->bits.pipe.client->bits.localsock.
@@ -445,7 +490,7 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
add one with "ETIMEDOUT".
NOTE: This won't race with real replies because they happen in the same thread.
*/
static void timedout_callback(struct local_client *client, char *csid,
static void timedout_callback(struct local_client *client, const char *csid,
int node_up)
{
if (node_up) {
@@ -642,16 +687,66 @@ static void main_loop(int local_sock, int cmd_timeout)
close(local_sock);
}
static __attribute__ ((noreturn)) void wait_for_child(int c_pipe, int timeout)
{
int child_status;
int sstat;
fd_set fds;
struct timeval tv = {timeout, 0};
FD_ZERO(&fds);
FD_SET(c_pipe, &fds);
sstat = select(c_pipe+1, &fds, NULL, NULL, timeout? &tv: NULL);
if (sstat == 0) {
fprintf(stderr, "clvmd startup timed out\n");
exit(DFAIL_TIMEOUT);
}
if (sstat == 1) {
if (read(c_pipe, &child_status, sizeof(child_status)) !=
sizeof(child_status)) {
fprintf(stderr, "clvmd failed in initialisation\n");
exit(DFAIL_INIT);
}
else {
switch (child_status) {
case SUCCESS:
break;
case DFAIL_INIT:
fprintf(stderr, "clvmd failed in initialisation\n");
break;
case DFAIL_LOCAL_SOCK:
fprintf(stderr, "clvmd could not create local socket\n");
fprintf(stderr, "Another clvmd is probably already running\n");
break;
case DFAIL_CLUSTER_IF:
fprintf(stderr, "clvmd could not connect to cluster manager\n");
fprintf(stderr, "Consult syslog for more information\n");
break;
case DFAIL_MALLOC:
fprintf(stderr, "clvmd failed, not enough memory\n");
break;
default:
fprintf(stderr, "clvmd failed, error was %d\n", child_status);
break;
}
exit(child_status);
}
}
fprintf(stderr, "clvmd startup, select failed: %s\n", strerror(errno));
exit(DFAIL_INIT);
}
/*
* Fork into the background and detach from our parent process.
* In the interests of user-friendliness we wait for the daemon
* to complete initialisation before returning its status
* the the user.
*/
static void be_daemon()
static void be_daemon(int timeout)
{
pid_t pid;
int child_status;
int devnull = open("/dev/null", O_RDWR);
if (devnull == -1) {
perror("Can't open /dev/null");
@@ -671,36 +766,7 @@ static void be_daemon()
default: /* Parent */
close(child_pipe[1]);
if (read(child_pipe[0], &child_status, sizeof(child_status)) !=
sizeof(child_status)) {
fprintf(stderr, "clvmd failed in initialisation\n");
exit(DFAIL_INIT);
}
else {
switch (child_status) {
case SUCCESS:
break;
case DFAIL_INIT:
fprintf(stderr, "clvmd failed in initialisation\n");
break;
case DFAIL_LOCAL_SOCK:
fprintf(stderr, "clvmd could not create local socket\n");
fprintf(stderr, "Another clvmd is probably already running\n");
break;
case DFAIL_CLUSTER_IF:
fprintf(stderr, "clvmd could not connect to cluster manager\n");
fprintf(stderr, "Consult syslog for more information\n");
break;
case DFAIL_MALLOC:
fprintf(stderr, "clvmd failed, not enough memory\n");
break;
default:
fprintf(stderr, "clvmd failed, error was %d\n", child_status);
break;
}
exit(child_status);
}
wait_for_child(child_pipe[0], timeout);
}
/* Detach ourself from the calling environment */
@@ -733,6 +799,8 @@ static int read_from_local_sock(struct local_client *thisfd)
char buffer[PIPE_BUF];
len = read(thisfd->fd, buffer, sizeof(buffer));
if (len == -1 && errno == EINTR)
return 1;
DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len);
@@ -848,8 +916,12 @@ static int read_from_local_sock(struct local_client *thisfd)
len - strlen(inheader->node) - sizeof(struct clvm_header);
missing_len = inheader->arglen - argslen;
if (missing_len < 0)
missing_len = 0;
/* Save the message */
thisfd->bits.localsock.cmd = malloc(len + missing_len);
if (!thisfd->bits.localsock.cmd) {
struct clvm_header reply;
reply.cmd = CLVMD_CMD_REPLY;
@@ -874,9 +946,8 @@ static int read_from_local_sock(struct local_client *thisfd)
DEBUGLOG
("got %d bytes, need another %d (total %d)\n",
argslen, missing_len, inheader->arglen);
len =
read(thisfd->fd, argptr + argslen,
missing_len);
len = read(thisfd->fd, argptr + argslen,
missing_len);
if (len >= 0) {
missing_len -= len;
argslen += len;
@@ -986,31 +1057,6 @@ int add_client(struct local_client *new_client)
return 0;
}
/*
* Send a long message using the System LV
*/
static int send_long_message(struct local_client *thisfd, struct clvm_header *inheader, int len)
{
struct clvm_header new_header;
int status;
DEBUGLOG("Long message: being sent via system LV:\n");
/* Use System LV */
status = system_lv_write_data((char *)inheader, len);
if (status < 0)
return errno;
/* Send message indicating System-LV is being used */
memcpy(&new_header, inheader, sizeof(new_header));
new_header.flags |= CLVMD_FLAG_SYSTEMLV;
new_header.xid = thisfd->xid;
return send_message(&new_header, sizeof(new_header), NULL, -1,
"Error forwarding long message to cluster");
}
/* Called when the pre-command has completed successfully - we
now execute the real command on all the requested nodes */
static int distribute_command(struct local_client *thisfd)
@@ -1037,13 +1083,9 @@ static int distribute_command(struct local_client *thisfd)
add_to_lvmqueue(thisfd, inheader, len, NULL);
DEBUGLOG("Sending message to all cluster nodes\n");
if (len > MAX_INLINE_MESSAGE) {
send_long_message(thisfd, inheader, len );
} else {
inheader->xid = thisfd->xid;
send_message(inheader, len, NULL, -1,
"Error forwarding message to cluster");
}
inheader->xid = thisfd->xid;
send_message(inheader, len, NULL, -1,
"Error forwarding message to cluster");
} else {
/* Do it on a single node */
char csid[MAX_CSID_LEN];
@@ -1064,14 +1106,10 @@ static int distribute_command(struct local_client *thisfd)
} else {
DEBUGLOG("Sending message to single node: %s\n",
inheader->node);
if (len > MAX_INLINE_MESSAGE) {
send_long_message(thisfd, inheader, len );
} else {
inheader->xid = thisfd->xid;
send_message(inheader, len,
csid, -1,
"Error forwarding message to cluster node");
}
inheader->xid = thisfd->xid;
send_message(inheader, len,
csid, -1,
"Error forwarding message to cluster node");
}
}
}
@@ -1086,8 +1124,8 @@ static int distribute_command(struct local_client *thisfd)
}
/* Process a command from a remote node and return the result */
void process_remote_command(struct clvm_header *msg, int msglen, int fd,
char *csid)
static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
const char *csid)
{
char *replyargs;
char nodename[max_cluster_member_name_len];
@@ -1102,54 +1140,6 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
DEBUGLOG("process_remote_command %d for clientid 0x%x XID %d on node %s\n",
msg->cmd, msg->clientid, msg->xid, nodename);
/* Is the data to be found in the system LV ? */
if (msg->flags & CLVMD_FLAG_SYSTEMLV) {
struct clvm_header *newmsg;
DEBUGLOG("Reading message from system LV\n");
newmsg =
(struct clvm_header *) malloc(msg->arglen +
sizeof(struct clvm_header));
if (newmsg) {
if (system_lv_read_data
(nodename, (char *) newmsg,
(size_t *) &msglen) == 0) {
msg = newmsg;
msg_malloced = 1;
} else {
struct clvm_header head;
DEBUGLOG("System LV read failed\n");
/* Return a failure response */
head.cmd = CLVMD_CMD_REPLY;
head.status = EFBIG;
head.flags = 0;
head.clientid = msg->clientid;
head.arglen = 0;
head.node[0] = '\0';
send_message(&head, sizeof(struct clvm_header),
csid, fd,
"Error sending ENOMEM command reply");
return;
}
} else {
struct clvm_header head;
DEBUGLOG
("Error attempting to malloc %d bytes for system LV read\n",
msg->arglen);
/* Return a failure response */
head.cmd = CLVMD_CMD_REPLY;
head.status = ENOMEM;
head.flags = 0;
head.clientid = msg->clientid;
head.arglen = 0;
head.node[0] = '\0';
send_message(&head, sizeof(struct clvm_header), csid,
fd, "Error sending ENOMEM command reply");
return;
}
}
/* Check for GOAWAY and sulk */
if (msg->cmd == CLVMD_CMD_GOAWAY) {
@@ -1161,8 +1151,11 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
/* Version check is internal - don't bother exposing it in
clvmd-command.c */
if (msg->cmd == CLVMD_CMD_VERSION) {
int *version_nums = (int *) msg->args;
int version_nums[3];
char node[256];
memcpy(version_nums, msg->args, sizeof(version_nums));
clops->name_from_csid(csid, node);
DEBUGLOG("Remote node %s is version %d.%d.%d\n",
node,
@@ -1221,40 +1214,16 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
replyargs, replylen);
agghead->xid = msg->xid;
/* Use the system LV ? */
if (replylen > MAX_INLINE_MESSAGE) {
agghead->cmd = CLVMD_CMD_REPLY;
agghead->status = status;
agghead->flags = CLVMD_FLAG_SYSTEMLV;
agghead->clientid = msg->clientid;
agghead->arglen = replylen;
agghead->node[0] = '\0';
/* If System LV operation failed then report it as EFBIG but only do it
if the data buffer has something in it. */
if (system_lv_write_data(aggreply,
replylen + sizeof(struct clvm_header)) < 0
&& replylen > 0)
agghead->status = EFBIG;
send_message(agghead,
sizeof(struct clvm_header), csid,
fd,
"Error sending long command reply");
} else {
agghead->cmd = CLVMD_CMD_REPLY;
agghead->status = status;
agghead->flags = 0;
agghead->clientid = msg->clientid;
agghead->arglen = replylen;
agghead->node[0] = '\0';
send_message(aggreply,
sizeof(struct clvm_header) +
replylen, csid, fd,
"Error sending command reply");
}
agghead->cmd = CLVMD_CMD_REPLY;
agghead->status = status;
agghead->flags = 0;
agghead->clientid = msg->clientid;
agghead->arglen = replylen;
agghead->node[0] = '\0';
send_message(aggreply,
sizeof(struct clvm_header) +
replylen, csid, fd,
"Error sending command reply");
} else {
struct clvm_header head;
@@ -1283,7 +1252,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
If we have got a full set then send them to the waiting client down the local
socket */
static void add_reply_to_list(struct local_client *client, int status,
char *csid, const char *buf, int len)
const char *csid, const char *buf, int len)
{
struct node_reply *reply;
@@ -1334,10 +1303,11 @@ static void add_reply_to_list(struct local_client *client, int status,
}
/* This is the thread that runs the PRE and post commands for a particular connection */
static void *pre_and_post_thread(void *arg)
static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
{
struct local_client *client = (struct local_client *) arg;
int status;
int write_status;
sigset_t ss;
int pipe_fd = client->bits.localsock.pipe;
@@ -1367,8 +1337,21 @@ static void *pre_and_post_thread(void *arg)
client->bits.localsock.all_success = 0;
DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd);
/* Tell the parent process we have finished this bit */
write(pipe_fd, &status, sizeof(int));
do {
write_status = write(pipe_fd, &status, sizeof(int));
if (write_status == sizeof(int))
break;
if (write_status < 0 &&
(errno == EINTR || errno == EAGAIN))
continue;
log_error("Error sending to pipe: %m\n");
break;
} while(1);
if (status)
continue; /* Wait for another PRE command */
/* We may need to wait for the condition variable before running the post command */
pthread_mutex_lock(&client->bits.localsock.mutex);
@@ -1387,7 +1370,16 @@ static void *pre_and_post_thread(void *arg)
status = 0;
do_post_command(client);
write(pipe_fd, &status, sizeof(int));
do {
write_status = write(pipe_fd, &status, sizeof(int));
if (write_status == sizeof(int))
break;
if (write_status < 0 &&
(errno == EINTR || errno == EAGAIN))
continue;
log_error("Error sending to pipe: %m\n");
break;
} while(1);
DEBUGLOG("Waiting for next pre command\n");
@@ -1402,7 +1394,6 @@ static void *pre_and_post_thread(void *arg)
}
DEBUGLOG("Subthread finished\n");
pthread_exit((void *) 0);
return 0;
}
/* Process a command on the local node and store the result */
@@ -1438,7 +1429,7 @@ static int process_local_command(struct clvm_header *msg, int msglen,
return status;
}
static int process_reply(struct clvm_header *msg, int msglen, char *csid)
static int process_reply(const struct clvm_header *msg, int msglen, const char *csid)
{
struct local_client *client = NULL;
@@ -1511,7 +1502,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
if (thisreply->status)
clientreply->flags |= CLVMD_FLAG_NODEERRS;
*(int *) ptr = thisreply->status;
memcpy(ptr, &thisreply->status, sizeof(int));
ptr += sizeof(int);
if (thisreply->replymsg) {
@@ -1567,28 +1558,36 @@ static void send_version_message()
{
char message[sizeof(struct clvm_header) + sizeof(int) * 3];
struct clvm_header *msg = (struct clvm_header *) message;
int *version_nums = (int *) msg->args;
int version_nums[3];
msg->cmd = CLVMD_CMD_VERSION;
msg->status = 0;
msg->flags = 0;
msg->clientid = 0;
msg->arglen = sizeof(int) * 3;
msg->arglen = sizeof(version_nums);
version_nums[0] = htonl(CLVMD_MAJOR_VERSION);
version_nums[1] = htonl(CLVMD_MINOR_VERSION);
version_nums[2] = htonl(CLVMD_PATCH_VERSION);
memcpy(&msg->args, version_nums, sizeof(version_nums));
hton_clvm(msg);
clops->cluster_send_message(message, sizeof(message), NULL,
"Error Sending version number");
}
/* Send a message to either a local client or another server */
static int send_message(void *buf, int msglen, char *csid, int fd,
static int send_message(void *buf, int msglen, const char *csid, int fd,
const char *errtext)
{
int len;
int saved_errno = 0;
struct timespec delay;
struct timespec remtime;
int retry_cnt = 0;
/* Send remote messages down the cluster socket */
if (csid == NULL || !ISLOCAL_CSID(csid)) {
@@ -1599,14 +1598,38 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
/* Make sure it all goes */
do {
if (retry_cnt > MAX_RETRIES)
{
errno = saved_errno;
log_error("%s", errtext);
errno = saved_errno;
break;
}
len = write(fd, buf + ptr, msglen - ptr);
if (len <= 0) {
log_error(errtext);
if (errno == EINTR)
continue;
if (errno == EAGAIN ||
errno == EIO ||
errno == ENOSPC) {
saved_errno = errno;
retry_cnt++;
delay.tv_sec = 0;
delay.tv_nsec = 100000;
remtime.tv_sec = 0;
remtime.tv_nsec = 0;
(void) nanosleep (&delay, &remtime);
continue;
}
log_error("%s", errtext);
break;
}
ptr += len;
} while (len < msglen);
} while (ptr < msglen);
}
return len;
}
@@ -1636,11 +1659,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
/*
* Routine that runs in the "LVM thread".
*/
static void *lvm_thread_fn(void *arg)
static __attribute__ ((noreturn)) void *lvm_thread_fn(void *arg)
{
struct list *cmdl, *tmp;
sigset_t ss;
int using_gulm = (int)arg;
int using_gulm = (int)(long)arg;
/* Don't let anyone else to do work until we are started */
pthread_mutex_lock(&lvm_start_mutex);
@@ -1688,7 +1711,7 @@ static void *lvm_thread_fn(void *arg)
/* Pass down some work to the LVM thread */
static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
int msglen, char *csid)
int msglen, const char *csid)
{
struct lvm_thread_cmd *cmd;
@@ -1766,7 +1789,8 @@ static int open_local_sock()
return local_socket;
}
void process_message(struct local_client *client, char *buf, int len, char *csid)
void process_message(struct local_client *client, const char *buf, int len,
const char *csid)
{
struct clvm_header *inheader;
@@ -1779,7 +1803,7 @@ void process_message(struct local_client *client, char *buf, int len, char *csid
}
static void check_all_callback(struct local_client *client, char *csid,
static void check_all_callback(struct local_client *client, const char *csid,
int node_up)
{
if (!node_up)

View File

@@ -76,7 +76,8 @@ struct netsock_bits {
};
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
char *csid, struct local_client ** new_client);
const char *csid,
struct local_client ** new_client);
/* One of these for each fd we are listening on */
struct local_client {
@@ -95,11 +96,7 @@ struct local_client {
} bits;
};
#ifdef DEBUG
#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
#else
#define DEBUGLOG(fmt, args...)
#endif
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args);
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
@@ -116,7 +113,9 @@ extern void cmd_client_cleanup(struct local_client *client);
extern int add_client(struct local_client *new_client);
extern void clvmd_cluster_init_completed(void);
extern void process_message(struct local_client *client, char *buf, int len, char *csid);
extern void process_message(struct local_client *client, const char *buf,
int len, const char *csid);
extern void debuglog(const char *fmt, ... );
int sync_lock(const char *resource, int mode, int flags, int *lockid);
int sync_unlock(const char *resource, int lockid);

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"
@@ -45,16 +45,24 @@
#include "log.h"
#include "activate.h"
#include "locking.h"
#include "defaults.h"
static struct cmd_context *cmd = NULL;
static struct dm_hash_table *lv_hash = NULL;
static pthread_mutex_t lv_hash_lock;
static pthread_mutex_t lvm_lock;
static char last_error[1024];
struct lv_info {
int lock_id;
int lock_mode;
};
char *get_last_lvm_error()
{
return last_error;
}
/* Return the mode a lock is currently held at (or -1 if not held) */
static int get_current_lock(char *resource)
{
@@ -200,8 +208,17 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
/* Try to get the lock if it's a clustered volume group */
if (lock_flags & LCK_CLUSTER_VG) {
status = hold_lock(resource, mode, LKF_NOQUEUE);
if (status)
if (status) {
/* Return an LVM-sensible error for this.
* Forcing EIO makes the upper level return this text
* rather than the strerror text for EAGAIN.
*/
if (errno == EAGAIN) {
sprintf(last_error, "Volume is busy on another node");
errno = EIO;
}
return errno;
}
}
/* If it's suspended then resume it */
@@ -227,7 +244,7 @@ static int do_resume_lv(char *resource)
/* Is it open ? */
oldmode = get_current_lock(resource);
if (oldmode == -1) {
DEBUGLOG("do_deactivate_lock, lock not already held\n");
DEBUGLOG("do_resume_lv, lock not already held\n");
return 0; /* We don't need to do anything */
}
@@ -295,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;
}
}
@@ -309,6 +328,9 @@ 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_MONITOR_MODE))
init_dmeventd_monitor(0);
switch (command) {
case LCK_LV_EXCLUSIVE:
status = do_activate_lv(resource, lock_flags, LKM_EXMODE);
@@ -340,8 +362,15 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
if (lock_flags & LCK_PARTIAL_MODE)
init_partial(0);
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
init_mirror_in_sync(0);
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
/* clean the pool for another command */
dm_pool_empty(cmd->mem);
pthread_mutex_unlock(&lvm_lock);
DEBUGLOG("Command return is %d\n", status);
return status;
@@ -368,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;
@@ -381,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) {
@@ -406,6 +440,13 @@ int do_check_lvm1(char *vgname)
return status == 1 ? 0 : EBUSY;
}
int do_refresh_cache()
{
DEBUGLOG("Refreshing context\n");
log_notice("Refreshing context");
return refresh_toolcontext(cmd)==1?0:-1;
}
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
that might be hanging around if we died for any reason
@@ -441,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));
}
/*
@@ -491,16 +533,31 @@ static void *get_initial_state()
}
}
}
fclose(lvs);
if (fclose(lvs))
DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
return NULL;
}
static void lvm2_log_fn(int level, const char *file, int line,
const char *message)
{
/*
* Ignore non-error messages, but store the latest one for returning
* to the user.
*/
if (level != _LOG_ERR && level != _LOG_FATAL)
return;
strncpy(last_error, message, sizeof(last_error));
last_error[sizeof(last_error)-1] = '\0';
}
/* This checks some basic cluster-LVM configuration stuff */
static void check_config()
{
int locking_type;
locking_type = find_config_int(cmd->cft->root, "global/locking_type", 1);
locking_type = find_config_tree_int(cmd, "global/locking_type", 1);
if (locking_type == 3) /* compiled-in cluster support */
return;
@@ -508,7 +565,7 @@ static void check_config()
if (locking_type == 2) { /* External library, check name */
const char *libname;
libname = find_config_str(cmd->cft->root, "global/locking_library",
libname = find_config_tree_str(cmd, "global/locking_library",
"");
if (strstr(libname, "liblvm2clusterlock.so"))
return;
@@ -524,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))) {
if (!(cmd = create_toolcontext(NULL, 0, 1))) {
log_error("Failed to allocate command context");
return 0;
}
@@ -547,5 +605,8 @@ int init_lvm(int using_gulm)
get_initial_state();
/* Trap log messages so we can pass them back to the user */
init_log_fn(lvm2_log_fn);
return 1;
}

View File

@@ -25,11 +25,13 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
char *resource);
extern int do_check_lvm1(char *vgname);
extern int do_refresh_cache(void);
extern int init_lvm(int using_gulm);
extern void init_lvhash(void);
extern int hold_unlock(char *resource);
extern int hold_lock(char *resource, int mode, int flags);
extern void unlock_all(void);
extern char *get_last_lvm_error(void);
#endif

View File

@@ -0,0 +1,320 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Tell all clvmds in a cluster to refresh their toolcontext
*
*/
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <libdevmapper.h>
#include <stdint.h>
#include <stdio.h>
#include "clvm.h"
#include "refresh_clvmd.h"
typedef struct lvm_response {
char node[255];
char *response;
int status;
int len;
} lvm_response_t;
/*
* This gets stuck at the start of memory we allocate so we
* can sanity-check it at deallocation time
*/
#define LVM_SIGNATURE 0x434C564D
static int _clvmd_sock = -1;
/* Open connection to the Cluster Manager daemon */
static int _open_local_sock(void)
{
int local_socket;
struct sockaddr_un sockaddr;
/* Open local socket */
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
return -1;
}
memset(&sockaddr, 0, sizeof(sockaddr));
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
sockaddr.sun_family = AF_UNIX;
if (connect(local_socket,(struct sockaddr *) &sockaddr,
sizeof(sockaddr))) {
int saved_errno = errno;
fprintf(stderr, "connect() failed on local socket: %s\n",
strerror(errno));
if (close(local_socket))
return -1;
errno = saved_errno;
return -1;
}
return local_socket;
}
/* Send a request and return the status */
static int _send_request(char *inbuf, int inlen, char **retbuf)
{
char outbuf[PIPE_BUF];
struct clvm_header *outheader = (struct clvm_header *) outbuf;
int len;
int off;
int buflen;
int err;
/* Send it to CLVMD */
rewrite:
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
if (err == -1 && errno == EINTR)
goto rewrite;
fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
return 0;
}
/* Get the response */
reread:
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
if (errno == EINTR)
goto reread;
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
return 0;
}
if (len == 0) {
fprintf(stderr, "EOF reading CLVMD");
errno = ENOTCONN;
return 0;
}
/* Allocate buffer */
buflen = len + outheader->arglen;
*retbuf = dm_malloc(buflen);
if (!*retbuf) {
errno = ENOMEM;
return 0;
}
/* Copy the header */
memcpy(*retbuf, outbuf, len);
outheader = (struct clvm_header *) *retbuf;
/* Read the returned values */
off = 1; /* we've already read the first byte */
while (off <= outheader->arglen && len > 0) {
len = read(_clvmd_sock, outheader->args + off,
buflen - off - offsetof(struct clvm_header, args));
if (len > 0)
off += len;
}
/* Was it an error ? */
if (outheader->status != 0) {
errno = outheader->status;
/* Only return an error here if there are no node-specific
errors present in the message that might have more detail */
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
return 0;
}
}
return 1;
}
/* Build the structure header and parse-out wildcard node names */
static void _build_header(struct clvm_header *head, int cmd, const char *node,
int len)
{
head->cmd = cmd;
head->status = 0;
head->flags = 0;
head->clientid = 0;
head->arglen = len;
if (node) {
/*
* Allow a couple of special node names:
* "*" for all nodes,
* "." for the local node only
*/
if (strcmp(node, "*") == 0) {
head->node[0] = '\0';
} else if (strcmp(node, ".") == 0) {
head->node[0] = '\0';
head->flags = CLVMD_FLAG_LOCAL;
} else
strcpy(head->node, node);
} else
head->node[0] = '\0';
}
/*
* Send a message to a(or all) node(s) in the cluster and wait for replies
*/
static int _cluster_request(char cmd, const char *node, void *data, int len,
lvm_response_t ** response, int *num)
{
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
char *inptr;
char *retbuf = NULL;
int status;
int i;
int num_responses = 0;
struct clvm_header *head = (struct clvm_header *) outbuf;
lvm_response_t *rarray;
*num = 0;
if (_clvmd_sock == -1)
_clvmd_sock = _open_local_sock();
if (_clvmd_sock == -1)
return 0;
_build_header(head, cmd, node, len);
memcpy(head->node + strlen(head->node) + 1, data, len);
status = _send_request(outbuf, sizeof(struct clvm_header) +
strlen(head->node) + len, &retbuf);
if (!status)
goto out;
/* Count the number of responses we got */
head = (struct clvm_header *) retbuf;
inptr = head->args;
while (inptr[0]) {
num_responses++;
inptr += strlen(inptr) + 1;
inptr += sizeof(int);
inptr += strlen(inptr) + 1;
}
/*
* Allocate response array.
* With an extra pair of INTs on the front to sanity
* check the pointer when we are given it back to free
*/
*response = dm_malloc(sizeof(lvm_response_t) * num_responses +
sizeof(int) * 2);
if (!*response) {
errno = ENOMEM;
status = 0;
goto out;
}
rarray = *response;
/* Unpack the response into an lvm_response_t array */
inptr = head->args;
i = 0;
while (inptr[0]) {
strcpy(rarray[i].node, inptr);
inptr += strlen(inptr) + 1;
memcpy(&rarray[i].status, inptr, sizeof(int));
inptr += sizeof(int);
rarray[i].response = dm_malloc(strlen(inptr) + 1);
if (rarray[i].response == NULL) {
/* Free up everything else and return error */
int j;
for (j = 0; j < i; j++)
dm_free(rarray[i].response);
free(*response);
errno = ENOMEM;
status = -1;
goto out;
}
strcpy(rarray[i].response, inptr);
rarray[i].len = strlen(inptr);
inptr += strlen(inptr) + 1;
i++;
}
*num = num_responses;
*response = rarray;
out:
if (retbuf)
dm_free(retbuf);
return status;
}
/* Free reply array */
static int _cluster_free_request(lvm_response_t * response, int num)
{
int i;
for (i = 0; i < num; i++) {
dm_free(response[i].response);
}
dm_free(response);
return 1;
}
int refresh_clvmd()
{
int num_responses;
char args[1]; // No args really.
lvm_response_t *response;
int saved_errno;
int status;
int i;
status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses);
/* If any nodes were down then display them and return an error */
for (i = 0; i < num_responses; i++) {
if (response[i].status == EHOSTDOWN) {
fprintf(stderr, "clvmd not running on node %s",
response[i].node);
status = 0;
errno = response[i].status;
} else if (response[i].status) {
fprintf(stderr, "Error resetting node %s: %s",
response[i].node,
response[i].response[0] ?
response[i].response :
strerror(response[i].status));
status = 0;
errno = response[i].status;
}
}
saved_errno = errno;
_cluster_free_request(response, num_responses);
errno = saved_errno;
return status;
}

View File

@@ -0,0 +1,2 @@
int refresh_clvmd(void);

View File

@@ -1,371 +0,0 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Routines dealing with the System LV */
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#include <syslog.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <mntent.h>
#include "libdlm.h"
#include "log.h"
#include "list.h"
#include "locking.h"
#include "system-lv.h"
#include "clvm.h"
#include "clvmd-comms.h"
#include "clvmd.h"
#ifdef HAVE_CCS
#include "ccs.h"
#endif
#define SYSTEM_LV_FILESYSTEM "ext2"
#define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX"
extern char *config_filename(void);
static char system_lv_name[PATH_MAX] = { '\0' };
static char mount_point[PATH_MAX] = { '\0' };
static int mounted = 0;
static int mounted_rw = 0;
static int lockid;
static const char *lock_name = "CLVM_SYSTEM_LV";
/* Look in /proc/mounts or (as a last resort) /etc/mtab to
see if the system-lv is mounted. If it is mounted and we
think it's not then abort because we don't have the right
lock status and we don't know what other processes are doing with it.
Returns 1 for mounted, 0 for not mounted so it matches the condition
of the "mounted" static variable above.
*/
static int is_really_mounted(void)
{
FILE *mountfile;
struct mntent *ment;
mountfile = setmntent("/proc/mounts", "r");
if (!mountfile) {
mountfile = setmntent("/etc/mtab", "r");
if (!mountfile) {
log_error("Unable to open /proc/mounts or /etc/mtab");
return -1;
}
}
/* Look for system LV name in the file */
do {
ment = getmntent(mountfile);
if (ment) {
if (strcmp(ment->mnt_fsname, system_lv_name) == 0) {
endmntent(mountfile);
return 1;
}
}
}
while (ment);
endmntent(mountfile);
return 0;
}
/* Get the system LV name from the config file */
static int find_system_lv(void)
{
if (system_lv_name[0] == '\0') {
#ifdef HAVE_CCS
int error;
ccs_node_t *ctree;
/* Read the cluster config file */
/* Open the config file */
error = open_ccs_file(&ctree, "clvm.ccs");
if (error) {
perror("reading config file");
return -1;
}
strcpy(system_lv_name, find_ccs_str(ctree,
"cluster/systemlv", '/',
"/dev/vg/system_lv"));
/* Finished with config file */
close_ccs_file(ctree);
#else
if (getenv("CLVMD_SYSTEM_LV"))
strcpy(system_lv_name, getenv("CLVMD_SYSTEM_LV"));
else
return -1;
#endif
}
/* See if it has been mounted outside our control */
if (is_really_mounted() != mounted) {
log_error
("The system LV state has been mounted/umounted outside the control of clvmd\n"
"it cannot not be used for cluster communications until this is fixed.\n");
return -1;
}
return 0;
}
/* No prizes */
int system_lv_umount(void)
{
if (!mounted)
return 0;
if (umount(mount_point) < 0) {
log_error("umount of system LV (%s) failed: %m\n",
system_lv_name);
return -1;
}
sync_unlock(lock_name, lockid);
mounted = 0;
/* Remove the mount point */
rmdir(mount_point);
return 0;
}
int system_lv_mount(int readwrite)
{
int status;
int saved_errno;
int fd;
if (find_system_lv()) {
errno = EBUSY;
return -1;
}
/* Is it already mounted suitably? */
if (mounted) {
if (!readwrite || (readwrite && mounted_rw)) {
return 0;
} else {
/* Mounted RO and we need RW */
if (system_lv_umount() < 0)
return -1;
}
}
/* Randomize the mount point */
strcpy(mount_point, SYSTEM_LV_MOUNTPOINT);
fd = mkstemp(mount_point);
if (fd < 0) {
log_error("mkstemp for system LV mount point failed: %m\n");
return -1;
}
/* Race condition here but there's no mkstemp for directories */
close(fd);
unlink(mount_point);
mkdir(mount_point, 0600);
/* Make sure we have a system-lv lock */
status =
sync_lock(lock_name, (readwrite) ? LKM_EXMODE : LKM_CRMODE, 0,
&lockid);
if (status < 0)
return -1;
/* Mount it */
if (mount(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_SYNCHRONOUS
| (readwrite ? 0 : MS_RDONLY), NULL) < 0) {
/* mount(2) returns EINVAL if the volume has no FS on it. So, if we want to
write to it we try to make a filesystem in it and retry the mount */
if (errno == EINVAL && readwrite) {
char cmd[256];
log_error("Attempting mkfs on system LV device %s\n",
system_lv_name);
snprintf(cmd, sizeof(cmd), "/sbin/mkfs -t %s %s",
SYSTEM_LV_FILESYSTEM, system_lv_name);
system(cmd);
if (mount
(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC |
MS_SYNCHRONOUS | (readwrite ? 0 : MS_RDONLY),
NULL) == 0)
goto mounted;
}
saved_errno = errno;
log_error("mount of system LV (%s, %s, %s) failed: %m\n",
system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM);
sync_unlock(lock_name, lockid);
errno = saved_errno;
return -1;
}
mounted:
/* Set the internal flags */
mounted = 1;
mounted_rw = readwrite;
return 0;
}
/* Erase *all* files in the root directory of the system LV.
This *MUST* be called with an appropriate lock held!
The LV is left mounted RW because it is assumed that the
caller wants to write something here after clearing some space */
int system_lv_eraseall(void)
{
DIR *dir;
struct dirent *ent;
char fname[PATH_MAX];
/* Must be mounted R/W */
system_lv_mount(1);
dir = opendir(mount_point);
if (!dir)
return -1;
while ((ent = readdir(dir))) {
struct stat st;
snprintf(fname, sizeof(fname), "%s/%s", mount_point,
ent->d_name);
if (stat(fname, &st)) {
if (S_ISREG(st.st_mode))
unlink(fname);
}
}
closedir(dir);
return 0;
}
/* This is a "high-level" routine - it mounts the system LV, writes
the data into a file named after this node and then umounts the LV
again */
int system_lv_write_data(char *data, ssize_t len)
{
struct utsname nodeinfo;
char fname[PATH_MAX];
int outfile;
ssize_t thiswrite;
ssize_t written;
if (system_lv_mount(1))
return -1;
/* Build the file name we are goingto use. */
uname(&nodeinfo);
snprintf(fname, sizeof(fname), "%s/%s", mount_point, nodeinfo.nodename);
/* Open the file for output */
outfile = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600);
if (outfile < 0) {
int saved_errno = errno;
system_lv_umount();
errno = saved_errno;
return -1;
}
written = 0;
do {
thiswrite = write(outfile, data + written, len - written);
if (thiswrite > 0)
written += thiswrite;
} while (written < len && thiswrite > 0);
close(outfile);
system_lv_umount();
return (thiswrite < 0) ? -1 : 0;
}
/* This is a "high-level" routine - it mounts the system LV, reads
the data from a named file and then umounts the LV
again */
int system_lv_read_data(char *fname_base, char *data, ssize_t *len)
{
char fname[PATH_MAX];
int outfile;
struct stat st;
ssize_t filesize;
ssize_t thisread;
ssize_t readbytes;
if (system_lv_mount(0))
return -1;
/* Build the file name we are going to use. */
snprintf(fname, sizeof(fname), "%s/%s", mount_point, fname_base);
/* Get the file size and stuff. Actually we only need the file size but
this will also check that the file exists */
if (stat(fname, &st) < 0) {
int saved_errno = errno;
log_error("stat of file %s on system LV failed: %m\n", fname);
system_lv_umount();
errno = saved_errno;
return -1;
}
filesize = st.st_size;
outfile = open(fname, O_RDONLY);
if (outfile < 0) {
int saved_errno = errno;
log_error("open of file %s on system LV failed: %m\n", fname);
system_lv_umount();
errno = saved_errno;
return -1;
}
readbytes = 0;
do {
thisread =
read(outfile, data + readbytes, filesize - readbytes);
if (thisread > 0)
readbytes += thisread;
} while (readbytes < filesize && thisread > 0);
close(outfile);
system_lv_umount();
*len = readbytes;
return (thisread < 0) ? -1 : 0;
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CLVM_SYSTEM_LV_H
#define _CLVM_SYSTEM_LV_H
/* Prototypes for System-LV functions */
/* "low-level" functions */
extern int system_lv_umount(void);
extern int system_lv_mount(int readwrite);
extern int system_lv_eraseall(void);
/* "high-level" functions */
extern int system_lv_write_data(char *data, ssize_t len);
extern int system_lv_read_data(char *fname_base, char *data, ssize_t *len);
#endif

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"
@@ -92,41 +92,37 @@ int init_comms(unsigned short port)
return 0;
}
void tcp_remove_client(char *csid)
{
void tcp_remove_client(const char *c_csid)
{
struct local_client *client;
char csid[GULM_MAX_CSID_LEN];
unsigned int i;
memcpy(csid, c_csid, sizeof csid);
DEBUGLOG("tcp_remove_client\n");
/* Don't actually close the socket here - that's the
job of clvmd.c whch will do the job when it notices the
other end has gone. We just need to remove the client(s) from
the hash table so we don't try to use it for sending any more */
client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
for (i = 0; i < 2; i++)
{
dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
close(client->fd);
client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
{
dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
close(client->fd);
}
/* Look for a mangled one too, on the 2nd iteration. */
csid[0] ^= 0x80;
}
/* Look for a mangled one too */
csid[0] ^= 0x80;
client = dm_hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
{
dm_hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
close(client->fd);
}
/* Put it back as we found it */
csid[0] ^= 0x80;
}
int alloc_client(int fd, char *csid, struct local_client **new_client)
int alloc_client(int fd, const char *c_csid, struct local_client **new_client)
{
struct local_client *client;
char csid[GULM_MAX_CSID_LEN];
memcpy(csid, c_csid, sizeof csid);
DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid));
@@ -315,7 +311,7 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
return status;
}
int gulm_connect_csid(char *csid, struct local_client **newclient)
int gulm_connect_csid(const char *csid, struct local_client **newclient)
{
int fd;
struct sockaddr_in6 addr;
@@ -366,7 +362,7 @@ int gulm_connect_csid(char *csid, struct local_client **newclient)
}
/* Send a message to a known CSID */
static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const char *errtext)
static int tcp_send_message(void *buf, int msglen, const char *csid, const char *errtext)
{
int status;
struct local_client *client;
@@ -465,7 +461,7 @@ static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6)
}
/* Get someone else's IP address from DNS */
int get_ip_address(char *node, char *addr)
int get_ip_address(const char *node, char *addr)
{
struct hostent *he;
@@ -493,7 +489,7 @@ int get_ip_address(char *node, char *addr)
return 0;
}
char *print_csid(char *csid)
char *print_csid(const char *csid)
{
static char buf[128];
int *icsid = (int *)csid;

View File

@@ -5,9 +5,9 @@
#define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128
extern int init_comms(unsigned short);
extern char *print_csid(char *);
extern char *print_csid(const char *);
int get_main_gulm_cluster_fd(void);
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client);
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext);
void get_our_gulm_csid(char *csid);
int gulm_connect_csid(char *csid, struct local_client **newclient);
int gulm_connect_csid(const char *csid, struct local_client **newclient);

View File

@@ -1,5 +1,19 @@
dm_event_register
dm_event_unregister
dm_event_handler_create
dm_event_handler_destroy
dm_event_handler_set_dso
dm_event_handler_set_dev_name
dm_event_handler_set_uuid
dm_event_handler_set_major
dm_event_handler_set_minor
dm_event_handler_set_event_mask
dm_event_handler_get_dso
dm_event_handler_get_devname
dm_event_handler_get_uuid
dm_event_handler_get_major
dm_event_handler_get_minor
dm_event_handler_get_event_mask
dm_event_register_handler
dm_event_unregister_handler
dm_event_get_registered_device
dm_event_set_timeout
dm_event_get_timeout
dm_event_handler_set_timeout
dm_event_handler_get_timeout

View File

@@ -15,8 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES = libdevmapper-event.c \
dmeventd.c
SOURCES = libdevmapper-event.c
LIB_STATIC = libdevmapper-event.a
@@ -26,12 +25,20 @@ else
LIB_SHARED = libdevmapper-event.so
endif
TARGETS = dmeventd
CLEAN_TARGETS = dmeventd.o
include ../make.tmpl
LDFLAGS += -ldl -ldevmapper -lpthread
CLDFLAGS += -ldl -ldevmapper -lpthread
dmeventd: $(LIB_SHARED) dmeventd.o
$(CC) -o $@ dmeventd.o $(CFLAGS) $(LDFLAGS) \
-L. -ldevmapper-event $(LIBS) -rdynamic
.PHONY: install_dynamic install_static install_include \
install_pkgconfig
install_pkgconfig install_dmeventd
INSTALL_TYPE = install_dynamic
@@ -43,7 +50,7 @@ ifeq ("@PKGCONFIG@", "yes")
INSTALL_TYPE += install_pkgconfig
endif
install: $(INSTALL_TYPE) install_include
install: $(INSTALL_TYPE) install_include install_dmeventd
install_include:
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
@@ -55,6 +62,9 @@ install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
install_dmeventd: dmeventd
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< $(sbindir)/$<
install_pkgconfig:
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.pc \
$(usrlibdir)/pkgconfig/devmapper-event.pc

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,52 @@
#ifndef __DMEVENTD_DOT_H__
#define __DMEVENTD_DOT_H__
/* FIXME This stuff must be configurable. */
#define DM_EVENT_DAEMON "/sbin/dmeventd"
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
#define DM_EVENT_DEFAULT_TIMEOUT 10
/* Commands for the daemon passed in the message below. */
enum dm_event_command {
DM_EVENT_CMD_ACTIVE = 1,
DM_EVENT_CMD_REGISTER_FOR_EVENT,
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
DM_EVENT_CMD_SET_TIMEOUT,
DM_EVENT_CMD_GET_TIMEOUT,
DM_EVENT_CMD_HELLO,
};
/* Message passed between client and daemon. */
struct dm_event_daemon_message {
uint32_t cmd;
uint32_t size;
char *data;
};
/* FIXME Is this meant to be exported? I can't see where the
interface uses it. */
/* Fifos for client/daemon communication. */
struct dm_event_fifos {
int client;
int server;
const char *client_path;
const char *server_path;
};
/* EXIT_SUCCESS 0 -- stdlib.h */
/* EXIT_FAILURE 1 -- stdlib.h */
#define EXIT_LOCKFILE_INUSE 2
#define EXIT_DESC_CLOSE_FAILURE 3
#define EXIT_OPEN_PID_FAILURE 4
#define EXIT_FIFO_FAILURE 5
#define EXIT_CHDIR_FAILURE 6
void dmeventd(void)
__attribute((noreturn));
#define EXIT_DESC_OPEN_FAILURE 4
#define EXIT_OPEN_PID_FAILURE 5
#define EXIT_FIFO_FAILURE 6
#define EXIT_CHDIR_FAILURE 7
#endif /* __DMEVENTD_DOT_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -23,86 +23,84 @@
#include <stdint.h>
/* FIXME This stuff must be configurable. */
/*
* Event library interface.
*/
#define DM_EVENT_DAEMON "/sbin/dmeventd"
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
enum dm_event_mask {
DM_EVENT_SETTINGS_MASK = 0x0000FF,
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
#define DM_EVENT_DEFAULT_TIMEOUT 10
DM_EVENT_ERROR_MASK = 0x00FF00,
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
/* Commands for the daemon passed in the message below. */
enum dm_event_command {
DM_EVENT_CMD_ACTIVE = 1,
DM_EVENT_CMD_REGISTER_FOR_EVENT,
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
DM_EVENT_CMD_SET_TIMEOUT,
DM_EVENT_CMD_GET_TIMEOUT,
DM_EVENT_STATUS_MASK = 0xFF0000,
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
};
/* Message passed between client and daemon. */
struct dm_event_daemon_message {
union {
unsigned int cmd; /* FIXME Use fixed size. */
int status; /* FIXME Use fixed size. */
} opcode;
char msg[252]; /* FIXME Why is this 252 ? */
} __attribute__((packed)); /* FIXME Do this properly! */
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
/* Fifos for client/daemon communication. */
struct dm_event_fifos {
int client;
int server;
const char *client_path;
const char *server_path;
};
struct dm_event_handler;
/* Event type definitions. */
/* FIXME Use masks to separate the types and provide for extension. */
enum dm_event_type {
DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x02, /* Report all of them. */
struct dm_event_handler *dm_event_handler_create(void);
void dm_event_handler_destroy(struct dm_event_handler *dmevh);
DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
/*
* Path of shared library to handle events.
*
* All of dso, device_name and uuid strings are duplicated, you do not
* need to keep the pointers valid after the call succeeds. Thes may
* return -ENOMEM though.
*/
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
};
/*
* Identify the device to monitor by exactly one of device_name, uuid or
* device number. String arguments are duplicated, see above.
*/
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
/* FIXME Use a mask. */
#define DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
/* Prototypes for event lib interface. */
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major);
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor);
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout);
/* FIXME Replace device with standard name/uuid/devno choice */
/* Interface changes:
First register a handler, passing in a unique ref for the device. */
// int dm_event_register_handler(const char *dso_name, const char *device);
// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
/* Or (better?) add to task structure and use existing functions - run a task to register/unregister events - we may need to run task withe that with the new event mechanism anyway, then the dso calls just hook in.
*/
/* FIXME Missing consts? */
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
int dm_event_unregister(char *dso_name, char *device,
enum dm_event_type events);
int dm_event_get_registered_device(char **dso_name, char **device,
enum dm_event_type *events, int next);
int dm_event_set_timeout(char *device, uint32_t timeout);
int dm_event_get_timeout(char *device, uint32_t *timeout);
/*
* Specify mask for events to monitor.
*/
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
enum dm_event_mask evmask);
/* Prototypes for DSO interface. */
void process_event(const char *device, enum dm_event_type event);
int register_device(const char *device);
int unregister_device(const char *device);
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh);
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh);
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh);
int dm_event_handler_get_major(const struct dm_event_handler *dmevh);
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh);
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh);
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh);
/* FIXME Review interface (what about this next thing?) */
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
/*
* Initiate monitoring using dmeventd.
*/
int dm_event_register_handler(const struct dm_event_handler *dmevh);
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
detailed descriptions. */
void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user);
int register_device(const char *device_name, const char *uuid, int major, int minor, void **user);
int unregister_device(const char *device_name, const char *uuid, int major,
int minor, void **user);
#endif

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>
@@ -26,77 +25,104 @@
#include <unistd.h>
#include <syslog.h> /* FIXME Replace syslog with multilog */
/* FIXME Missing openlog? */
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
/* FIXME: We may need to lock around operations to these */
static int register_count = 0;
static struct dm_pool *mem_pool = NULL;
/*
* register_device() is called first and performs initialisation.
* Only one device may be registered or unregistered at a time.
*/
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* Number of active registrations.
*/
static int _register_count = 0;
static struct dm_pool *_mem_pool = NULL;
static void *_lvm_handle = NULL;
/*
* Currently only one event can be processed at a time.
*/
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
static int _get_mirror_event(char *params)
{
int i, rtn = ME_INSYNC;
int max_args = 30; /* should support at least 8-way mirrors */
char *args[max_args];
int i, r = ME_INSYNC;
char **args = NULL;
char *dev_status_str;
char *log_status_str;
char *sync_str;
char *p;
int log_argc, num_devs, num_failures=0;
if (max_args <= split_words(params, max_args, args)) {
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
return -E2BIG;
}
char *p = NULL;
int log_argc, num_devs;
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
*/
num_devs = atoi(args[0]);
dev_status_str = args[3 + num_devs];
log_argc = atoi(args[4 + num_devs]);
log_status_str = args[4 + num_devs + log_argc];
sync_str = args[1 + num_devs];
* dm core parms: 0 409600 mirror
* Mirror core parms: 2 253:4 253:5 400/400
* New-style failure params: 1 AA
* New-style log params: 3 cluster 253:3 A
* or 3 disk 253:3 A
* or 1 core
*/
/* number of devices */
if (!dm_split_words(params, 1, 0, &p))
goto out_parse;
if (!(num_devs = atoi(p)))
goto out_parse;
p += strlen(p) + 1;
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
args = dm_malloc((num_devs + 7) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
goto out_parse;
dev_status_str = args[2 + num_devs];
log_argc = atoi(args[3 + num_devs]);
log_status_str = args[3 + num_devs + log_argc];
sync_str = args[num_devs];
/* Check for bad mirror devices */
for (i = 0; i < num_devs; i++) {
for (i = 0; i < num_devs; i++)
if (dev_status_str[i] == 'D') {
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
num_failures++;
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
r = ME_FAILURE;
}
}
/* Check for bad log device */
if (log_status_str[0] == 'D') {
/* Check for bad disk log device */
if (log_argc > 1 && log_status_str[0] == 'D') {
syslog(LOG_ERR, "Log device, %s, has failed.\n",
args[3 + num_devs + log_argc]);
num_failures++;
args[2 + num_devs + log_argc]);
r = ME_FAILURE;
}
if (num_failures) {
rtn = ME_FAILURE;
if (r == ME_FAILURE)
goto out;
}
p = strstr(sync_str, "/");
if (p) {
p[0] = '\0';
if (strcmp(sync_str, p+1))
rtn = ME_IGNORE;
r = ME_IGNORE;
p[0] = '/';
} else {
/*
* How the hell did we get this?
* Might mean all our parameters are screwed.
*/
syslog(LOG_ERR, "Unable to parse sync string.");
rtn = ME_IGNORE;
}
out:
return rtn;
} else
goto out_parse;
out:
if (args)
dm_free(args);
return r;
out_parse:
if (args)
dm_free(args);
syslog(LOG_ERR, "Unable to parse mirror status string.");
return ME_IGNORE;
}
static void _temporary_log_fn(int level, const char *file,
@@ -111,65 +137,55 @@ static void _temporary_log_fn(int level, const char *file,
static int _remove_failed_devices(const char *device)
{
int r;
void *handle;
int cmd_size = 256; /* FIXME Use system restriction */
char cmd_str[cmd_size];
#define CMD_SIZE 256 /* FIXME Use system restriction */
char cmd_str[CMD_SIZE];
char *vg = NULL, *lv = NULL, *layer = NULL;
if (strlen(device) > 200)
return -ENAMETOOLONG;
if (strlen(device) > 200) /* FIXME Use real restriction */
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
syslog(LOG_ERR, "Unable to determine VG name from %s",
device);
return -ENOMEM;
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
}
/* FIXME Is any sanity-checking required on %s? */
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
/* this error should be caught above, but doesn't hurt to check again */
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG;
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
}
lvm2_log_fn(_temporary_log_fn);
handle = lvm2_init();
lvm2_log_level(handle, 1);
r = lvm2_run(handle, cmd_str);
r = lvm2_run(_lvm_handle, cmd_str);
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1)? 0: -1;
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1) ? 0 : -1;
}
void process_event(const char *device, enum dm_event_type event)
void process_event(struct dm_task *dmt, enum dm_event_mask event,
void **unused __attribute((unused)))
{
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
const char *device = dm_task_get_name(dmt);
/* FIXME Move inside libdevmapper */
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
syslog(LOG_ERR, "Unable to create dm_task.\n");
goto fail;
if (pthread_mutex_trylock(&_event_mutex)) {
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
pthread_mutex_lock(&_event_mutex);
}
if (!dm_task_set_name(dmt, device)) {
syslog(LOG_ERR, "Unable to set device name.\n");
goto fail;
}
if (!dm_task_run(dmt)) {
syslog(LOG_ERR, "Unable to run task.\n");
goto fail;
}
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (!target_type) {
syslog(LOG_INFO, "%s mapping lost.\n", device);
continue;
}
if (strcmp(target_type, "mirror")) {
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
continue;
@@ -186,6 +202,7 @@ void process_event(const char *device, enum dm_event_type event)
case ME_FAILURE:
syslog(LOG_ERR, "Device failure in %s\n", device);
if (_remove_failed_devices(device))
/* FIXME Why are all the error return codes unused? Get rid of them? */
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
device);
/* Should check before warning user that device is now linear
@@ -197,51 +214,68 @@ void process_event(const char *device, enum dm_event_type event)
case ME_IGNORE:
break;
default:
/* FIXME Provide value then! */
syslog(LOG_INFO, "Unknown event received.\n");
}
} while (next);
fail:
if (dmt)
dm_task_destroy(dmt);
pthread_mutex_unlock(&_event_mutex);
}
int register_device(const char *device)
int register_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
syslog(LOG_INFO, "Monitoring mirror device, %s for events\n", device);
int r = 0;
pthread_mutex_lock(&_register_mutex);
syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
/*
* Need some space for allocations. 1024 should be more
* than enough for what we need (device mapper name splitting)
*/
if (!mem_pool)
mem_pool = dm_pool_create("mirror_dso", 1024);
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
goto out;
if (!mem_pool)
return 0;
register_count++;
return 1;
}
int unregister_device(const char *device)
{
if (!(--register_count)) {
dm_pool_destroy(mem_pool);
mem_pool = NULL;
if (!_lvm_handle) {
lvm2_log_fn(_temporary_log_fn);
if (!(_lvm_handle = lvm2_init())) {
dm_pool_destroy(_mem_pool);
_mem_pool = NULL;
goto out;
}
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
/* FIXME Temporary: move to dmeventd core */
lvm2_run(_lvm_handle, "_memlock_inc");
}
return 1;
_register_count++;
r = 1;
out:
pthread_mutex_unlock(&_register_mutex);
return r;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
int unregister_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
pthread_mutex_lock(&_register_mutex);
syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
device);
if (!--_register_count) {
dm_pool_destroy(_mem_pool);
_mem_pool = NULL;
lvm2_run(_lvm_handle, "_memlock_dec");
lvm2_exit(_lvm_handle);
_lvm_handle = NULL;
}
pthread_mutex_unlock(&_register_mutex);
return 1;
}

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>
@@ -26,77 +25,104 @@
#include <unistd.h>
#include <syslog.h> /* FIXME Replace syslog with multilog */
/* FIXME Missing openlog? */
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
/* FIXME: We may need to lock around operations to these */
static int register_count = 0;
static struct dm_pool *mem_pool = NULL;
/*
* register_device() is called first and performs initialisation.
* Only one device may be registered or unregistered at a time.
*/
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* Number of active registrations.
*/
static int _register_count = 0;
static struct dm_pool *_mem_pool = NULL;
static void *_lvm_handle = NULL;
/*
* Currently only one event can be processed at a time.
*/
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
static int _get_mirror_event(char *params)
{
int i, rtn = ME_INSYNC;
int max_args = 30; /* should support at least 8-way mirrors */
char *args[max_args];
int i, r = ME_INSYNC;
char **args = NULL;
char *dev_status_str;
char *log_status_str;
char *sync_str;
char *p;
int log_argc, num_devs, num_failures=0;
if (max_args <= split_words(params, max_args, args)) {
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
return -E2BIG;
}
char *p = NULL;
int log_argc, num_devs;
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
*/
num_devs = atoi(args[0]);
dev_status_str = args[3 + num_devs];
log_argc = atoi(args[4 + num_devs]);
log_status_str = args[4 + num_devs + log_argc];
sync_str = args[1 + num_devs];
* dm core parms: 0 409600 mirror
* Mirror core parms: 2 253:4 253:5 400/400
* New-style failure params: 1 AA
* New-style log params: 3 cluster 253:3 A
* or 3 disk 253:3 A
* or 1 core
*/
/* number of devices */
if (!dm_split_words(params, 1, 0, &p))
goto out_parse;
if (!(num_devs = atoi(p)))
goto out_parse;
p += strlen(p) + 1;
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
args = dm_malloc((num_devs + 7) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
goto out_parse;
dev_status_str = args[2 + num_devs];
log_argc = atoi(args[3 + num_devs]);
log_status_str = args[3 + num_devs + log_argc];
sync_str = args[num_devs];
/* Check for bad mirror devices */
for (i = 0; i < num_devs; i++) {
for (i = 0; i < num_devs; i++)
if (dev_status_str[i] == 'D') {
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
num_failures++;
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
r = ME_FAILURE;
}
}
/* Check for bad log device */
if (log_status_str[0] == 'D') {
/* Check for bad disk log device */
if (log_argc > 1 && log_status_str[0] == 'D') {
syslog(LOG_ERR, "Log device, %s, has failed.\n",
args[3 + num_devs + log_argc]);
num_failures++;
args[2 + num_devs + log_argc]);
r = ME_FAILURE;
}
if (num_failures) {
rtn = ME_FAILURE;
if (r == ME_FAILURE)
goto out;
}
p = strstr(sync_str, "/");
if (p) {
p[0] = '\0';
if (strcmp(sync_str, p+1))
rtn = ME_IGNORE;
r = ME_IGNORE;
p[0] = '/';
} else {
/*
* How the hell did we get this?
* Might mean all our parameters are screwed.
*/
syslog(LOG_ERR, "Unable to parse sync string.");
rtn = ME_IGNORE;
}
out:
return rtn;
} else
goto out_parse;
out:
if (args)
dm_free(args);
return r;
out_parse:
if (args)
dm_free(args);
syslog(LOG_ERR, "Unable to parse mirror status string.");
return ME_IGNORE;
}
static void _temporary_log_fn(int level, const char *file,
@@ -111,65 +137,55 @@ static void _temporary_log_fn(int level, const char *file,
static int _remove_failed_devices(const char *device)
{
int r;
void *handle;
int cmd_size = 256; /* FIXME Use system restriction */
char cmd_str[cmd_size];
#define CMD_SIZE 256 /* FIXME Use system restriction */
char cmd_str[CMD_SIZE];
char *vg = NULL, *lv = NULL, *layer = NULL;
if (strlen(device) > 200)
return -ENAMETOOLONG;
if (strlen(device) > 200) /* FIXME Use real restriction */
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
syslog(LOG_ERR, "Unable to determine VG name from %s",
device);
return -ENOMEM;
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
}
/* FIXME Is any sanity-checking required on %s? */
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
/* this error should be caught above, but doesn't hurt to check again */
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG;
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
}
lvm2_log_fn(_temporary_log_fn);
handle = lvm2_init();
lvm2_log_level(handle, 1);
r = lvm2_run(handle, cmd_str);
r = lvm2_run(_lvm_handle, cmd_str);
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1)? 0: -1;
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1) ? 0 : -1;
}
void process_event(const char *device, enum dm_event_type event)
void process_event(struct dm_task *dmt, enum dm_event_mask event,
void **unused __attribute((unused)))
{
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
const char *device = dm_task_get_name(dmt);
/* FIXME Move inside libdevmapper */
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
syslog(LOG_ERR, "Unable to create dm_task.\n");
goto fail;
if (pthread_mutex_trylock(&_event_mutex)) {
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
pthread_mutex_lock(&_event_mutex);
}
if (!dm_task_set_name(dmt, device)) {
syslog(LOG_ERR, "Unable to set device name.\n");
goto fail;
}
if (!dm_task_run(dmt)) {
syslog(LOG_ERR, "Unable to run task.\n");
goto fail;
}
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (!target_type) {
syslog(LOG_INFO, "%s mapping lost.\n", device);
continue;
}
if (strcmp(target_type, "mirror")) {
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
continue;
@@ -186,6 +202,7 @@ void process_event(const char *device, enum dm_event_type event)
case ME_FAILURE:
syslog(LOG_ERR, "Device failure in %s\n", device);
if (_remove_failed_devices(device))
/* FIXME Why are all the error return codes unused? Get rid of them? */
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
device);
/* Should check before warning user that device is now linear
@@ -197,51 +214,68 @@ void process_event(const char *device, enum dm_event_type event)
case ME_IGNORE:
break;
default:
/* FIXME Provide value then! */
syslog(LOG_INFO, "Unknown event received.\n");
}
} while (next);
fail:
if (dmt)
dm_task_destroy(dmt);
pthread_mutex_unlock(&_event_mutex);
}
int register_device(const char *device)
int register_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
syslog(LOG_INFO, "Monitoring mirror device, %s for events\n", device);
int r = 0;
pthread_mutex_lock(&_register_mutex);
syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
/*
* Need some space for allocations. 1024 should be more
* than enough for what we need (device mapper name splitting)
*/
if (!mem_pool)
mem_pool = dm_pool_create("mirror_dso", 1024);
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
goto out;
if (!mem_pool)
return 0;
register_count++;
return 1;
}
int unregister_device(const char *device)
{
if (!(--register_count)) {
dm_pool_destroy(mem_pool);
mem_pool = NULL;
if (!_lvm_handle) {
lvm2_log_fn(_temporary_log_fn);
if (!(_lvm_handle = lvm2_init())) {
dm_pool_destroy(_mem_pool);
_mem_pool = NULL;
goto out;
}
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
/* FIXME Temporary: move to dmeventd core */
lvm2_run(_lvm_handle, "_memlock_inc");
}
return 1;
_register_count++;
r = 1;
out:
pthread_mutex_unlock(&_register_mutex);
return r;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
int unregister_device(const char *device, const char *uuid, int major, int minor,
void **unused __attribute((unused)))
{
pthread_mutex_lock(&_register_mutex);
syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
device);
if (!--_register_count) {
dm_pool_destroy(_mem_pool);
_mem_pool = NULL;
lvm2_run(_lvm_handle, "_memlock_dec");
lvm2_exit(_lvm_handle);
_lvm_handle = NULL;
}
pthread_mutex_unlock(&_register_mutex);
return 1;
}

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.
@@ -207,11 +228,26 @@ global {
# Location of proc filesystem
proc = "/proc"
# Type of locking to use. Defaults to file-based locking (1).
# Type of locking to use. Defaults to local file-based locking (1).
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
# if LVM2 commands get run concurrently).
# Type 2 uses the external shared library locking_library.
# Type 3 uses built-in clustered locking.
locking_type = 1
# If using external locking (type 2) and initialisation fails,
# with this set to 1 an attempt will be made to use the built-in
# clustered locking.
# If you are using a customised locking_library you should set this to 0.
fallback_to_clustered_locking = 1
# If an attempt to initialise type 2 or type 3 locking failed, perhaps
# because cluster components such as clvmd are not running, with this set
# to 1 an attempt will be made to use local file-based locking (type 1).
# If this succeeds, only commands against local volume groups will proceed.
# Volume Groups marked as clustered will be ignored.
fallback_to_local_locking = 1
# Local non-LV directory that holds file-based locks while commands are
# in progress. A directory like /tmp that may get wiped on reboot is OK.
locking_dir = "/var/lock/lvm"
@@ -223,6 +259,9 @@ global {
# Search this directory first for shared libraries.
# library_dir = "/lib"
# The external locking library to load if locking_type is set to 2.
# locking_library = "liblvm2clusterlock.so"
}
activation {
@@ -295,7 +334,7 @@ activation {
# device and space can be allocated for the replacement.
mirror_log_fault_policy = "allocate"
mirror_dev_fault_policy = "remove"
mirror_device_fault_policy = "remove"
}

View File

@@ -41,8 +41,8 @@
../lib/misc/lvm-exec.h
../lib/misc/lvm-file.h
../lib/misc/lvm-string.h
../lib/misc/lvm-wrappers.h
../lib/misc/sharedlib.h
../lib/regex/matcher.h
../lib/report/report.h
../lib/uuid/uuid.h
../po/pogen.h

View File

@@ -78,10 +78,9 @@ SOURCES =\
misc/lvm-exec.c \
misc/lvm-file.c \
misc/lvm-string.c \
misc/lvm-wrappers.c \
misc/timestamp.c \
mm/memlock.c \
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
report/report.c \
striped/striped.c \
uuid/uuid.c \

View File

@@ -39,7 +39,7 @@ int lvm1_present(struct cmd_context *cmd)
{
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
< 0) {
log_error("LVM1 proc global snprintf failed");
return 0;
@@ -51,6 +51,66 @@ int lvm1_present(struct cmd_context *cmd)
return 0;
}
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct list *modules)
{
unsigned int s;
struct lv_segment *seg2, *snap_seg;
struct list *snh;
if (seg->segtype->ops->modules_needed &&
!seg->segtype->ops->modules_needed(mem, seg, modules)) {
log_error("module string allocation failed");
return 0;
}
if (lv_is_origin(seg->lv))
list_iterate(snh, &seg->lv->snapshot_segs)
if (!list_lv_modules(mem,
list_struct_base(snh,
struct lv_segment,
origin_list)->cow,
modules))
return_0;
if (lv_is_cow(seg->lv)) {
snap_seg = find_cow(seg->lv);
if (snap_seg->segtype->ops->modules_needed &&
!snap_seg->segtype->ops->modules_needed(mem, snap_seg,
modules)) {
log_error("snap_seg module string allocation failed");
return 0;
}
}
for (s = 0; s < seg->area_count; s++) {
switch (seg_type(seg, s)) {
case AREA_LV:
seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s));
if (seg2 && !list_segment_modules(mem, seg2, modules))
return_0;
break;
case AREA_PV:
case AREA_UNASSIGNED:
;
}
}
return 1;
}
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
struct list *modules)
{
struct lv_segment *seg;
list_iterate_items(seg, &lv->segments)
if (!list_segment_modules(mem, seg, modules))
return_0;
return 1;
}
#ifndef DEVMAPPER_SUPPORT
void set_activation(int act)
{
@@ -81,7 +141,7 @@ int target_version(const char *target_name, uint32_t *maj,
{
return 0;
}
int target_present(const char *target_name)
int target_present(const char *target_name, int use_modprobe)
{
return 0;
}
@@ -108,6 +168,10 @@ int lvs_in_vg_activated(struct volume_group *vg)
{
return 0;
}
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
{
return 0;
}
int lvs_in_vg_opened(struct volume_group *vg)
{
return 0;
@@ -151,12 +215,17 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return 1;
}
int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv,
struct volume_group *vg)
int pv_uses_vg(struct physical_volume *pv,
struct volume_group *vg)
{
return 0;
}
void activation_release(void)
{
return;
}
void activation_exit(void)
{
return;
@@ -193,7 +262,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
char *str;
char path[PATH_MAX];
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
if (!(cn = find_config_tree_node(cmd, "activation/volume_list"))) {
/* If no host tags defined, activate */
if (list_empty(&cmd->tags))
return 1;
@@ -252,9 +321,9 @@ static int _passes_activation_filter(struct cmd_context *cmd,
continue;
}
/* vgname/lvname */
if (lvm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
if (dm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
lv->name) < 0) {
log_error("lvm_snprintf error from %s/%s", lv->vg->name,
log_error("dm_snprintf error from %s/%s", lv->vg->name,
lv->name);
continue;
}
@@ -337,7 +406,7 @@ int target_present(const char *target_name, int use_modprobe)
if (target_version(target_name, &maj, &min, &patchlevel))
return 1;
if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name)
if (dm_snprintf(module, sizeof(module), "dm-%s", target_name)
< 0) {
log_error("target_present module name too long: %s",
target_name);
@@ -356,21 +425,23 @@ int target_present(const char *target_name, int use_modprobe)
* Returns 1 if info structure populated, else 0 on failure.
*/
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int with_mknodes,
struct lvinfo *info, int with_open_count)
struct lvinfo *info, int with_open_count, unsigned by_uuid_only)
{
struct dm_info dminfo;
char *name;
char *name = NULL;
if (!activation())
return 0;
if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
if (!by_uuid_only &&
!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
return_0;
log_debug("Getting device info for %s", name);
if (!dev_manager_info(lv->vg->cmd->mem, name, lv, with_mknodes,
with_open_count, &dminfo)) {
dm_pool_free(cmd->mem, name);
if (name)
dm_pool_free(cmd->mem, name);
return_0;
}
@@ -383,14 +454,16 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, in
info->live_table = dminfo.live_table;
info->inactive_table = dminfo.inactive_table;
dm_pool_free(cmd->mem, name);
if (name)
dm_pool_free(cmd->mem, name);
return 1;
}
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, struct lvinfo *info,
int with_open_count)
{
return _lv_info(cmd, lv, 0, info, with_open_count);
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
}
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
@@ -401,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);
}
/*
@@ -454,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;
}
@@ -523,7 +597,7 @@ static int _lv_deactivate(struct logical_volume *lv)
return r;
}
static int _lv_suspend_lv(struct logical_volume *lv)
static int _lv_suspend_lv(struct logical_volume *lv, int lockfs)
{
int r;
struct dev_manager *dm;
@@ -531,7 +605,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
return_0;
if (!(r = dev_manager_suspend(dm, lv)))
if (!(r = dev_manager_suspend(dm, lv, lockfs)))
stack;
dev_manager_destroy(dm);
@@ -542,7 +616,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
* These two functions return the number of visible LVs in the state,
* or -1 on error.
*/
int lvs_in_vg_activated(struct volume_group *vg)
static int _lvs_in_vg_activated(struct volume_group *vg, unsigned by_uuid_only)
{
struct lv_list *lvl;
int count = 0;
@@ -552,12 +626,22 @@ int lvs_in_vg_activated(struct volume_group *vg)
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & VISIBLE_LV)
count += (_lv_active(vg->cmd, lvl->lv) == 1);
count += (_lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1);
}
return count;
}
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
{
return _lvs_in_vg_activated(vg, 1);
}
int lvs_in_vg_activated(struct volume_group *vg)
{
return _lvs_in_vg_activated(vg, 0);
}
int lvs_in_vg_opened(struct volume_group *vg)
{
struct lv_list *lvl;
@@ -574,38 +658,96 @@ int lvs_in_vg_opened(struct volume_group *vg)
return count;
}
static int _register_dev_for_events(struct cmd_context *cmd,
struct logical_volume *lv, int do_reg)
/*
* Returns 0 if an attempt to (un)monitor the device failed.
* Returns 1 otherwise.
*/
int monitor_dev_for_events(struct cmd_context *cmd,
struct logical_volume *lv, int monitor)
{
#ifdef DMEVENTD
int i, pending = 0, monitored;
int r = 1;
struct list *tmp;
struct lv_segment *seg;
int (*reg) (struct dm_pool *mem, struct lv_segment *,
struct config_tree *cft, int events);
int (*monitor_fn) (struct lv_segment *s, int e);
/* skip dmeventd code altogether */
if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE)
return 1;
/*
* Nothing to do if dmeventd configured not to be used.
*/
if (monitor && !dmeventd_monitor_mode())
return 1;
list_iterate(tmp, &lv->segments) {
seg = list_item(tmp, struct lv_segment);
reg = NULL;
if (!seg_monitored(seg) || (seg->status & PVMOVE))
continue;
if (do_reg) {
if (seg->segtype->ops->target_register_events)
reg = seg->segtype->ops->target_register_events;
} else if (seg->segtype->ops->target_unregister_events)
reg = seg->segtype->ops->target_unregister_events;
monitor_fn = NULL;
if (!reg)
return_0;
/* Check monitoring status */
if (seg->segtype->ops->target_monitored)
monitored = seg->segtype->ops->target_monitored(seg, &pending);
else
continue; /* segtype doesn't support registration */
/* FIXME specify events */
if (!reg(cmd->mem, seg, cmd->cft, 0)) {
stack;
/*
* FIXME: We should really try again if pending
*/
monitored = (pending) ? 0 : monitored;
if (monitor) {
if (monitored)
log_verbose("%s/%s already monitored.", lv->vg->name, lv->name);
else if (seg->segtype->ops->target_monitor_events)
monitor_fn = seg->segtype->ops->target_monitor_events;
} else {
if (!monitored)
log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name);
else if (seg->segtype->ops->target_unmonitor_events)
monitor_fn = seg->segtype->ops->target_unmonitor_events;
}
/* Do [un]monitor */
if (!monitor_fn)
continue;
log_verbose("%sonitoring %s/%s", monitor ? "M" : "Not m", lv->vg->name, lv->name);
/* FIXME specify events */
if (!monitor_fn(seg, 0)) {
log_error("%s/%s: %s segment monitoring function failed.",
lv->vg->name, lv->name, seg->segtype->name);
return 0;
}
/* Check [un]monitor results */
/* Try a couple times if pending, but not forever... */
for (i = 0; i < 10; i++) {
pending = 0;
monitored = seg->segtype->ops->target_monitored(seg, &pending);
if (pending ||
(!monitored && monitor) ||
(monitored && !monitor))
log_very_verbose("%s/%s %smonitoring still pending: waiting...",
lv->vg->name, lv->name, monitor ? "" : "un");
else
break;
sleep(1);
}
r = (monitored && monitor) || (!monitored && !monitor);
}
#endif
return r;
#else
return 1;
#endif
}
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
@@ -613,6 +755,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
{
struct logical_volume *lv, *lv_pre;
struct lvinfo info;
int lockfs = 0;
if (!activation())
return 1;
@@ -643,12 +786,16 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
}
}
if (!_register_dev_for_events(cmd, lv, 0))
if (!monitor_dev_for_events(cmd, lv, 0))
/* FIXME Consider aborting here */
stack;
memlock_inc();
if (!_lv_suspend_lv(lv)) {
if (lv_is_origin(lv_pre) || lv_is_cow(lv_pre))
lockfs = 1;
if (!_lv_suspend_lv(lv, lockfs)) {
memlock_dec();
fs_unlock();
return 0;
@@ -697,7 +844,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
memlock_dec();
fs_unlock();
if (!_register_dev_for_events(cmd, lv, 1))
if (!monitor_dev_for_events(cmd, lv, 1))
stack;
return 1;
@@ -743,7 +890,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
return 0;
}
if (!_register_dev_for_events(cmd, lv, 0))
if (!monitor_dev_for_events(cmd, lv, 0))
stack;
memlock_inc();
@@ -816,7 +963,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
memlock_dec();
fs_unlock();
if (!_register_dev_for_events(cmd, lv, 1))
if (!monitor_dev_for_events(cmd, lv, 1))
stack;
return r;
@@ -845,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)
@@ -863,7 +1010,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
* Returns 1 on failure.
*/
int pv_uses_vg(struct physical_volume *pv,
struct volume_group *vg)
struct volume_group *vg)
{
if (!activation())
return 0;
@@ -874,6 +1021,11 @@ int pv_uses_vg(struct physical_volume *pv,
return dev_manager_device_uses_vg(pv->dev, vg);
}
void activation_release(void)
{
dev_manager_release();
}
void activation_exit(void)
{
dev_manager_exit();

View File

@@ -39,7 +39,12 @@ int lvm1_present(struct cmd_context *cmd);
int target_present(const char *target_name, int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct list *modules);
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
struct list *modules);
void activation_release(void);
void activation_exit(void);
int lv_suspend(struct cmd_context *cmd, const char *lvid_s);
@@ -78,12 +83,22 @@ 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 monitor_dev_for_events(struct cmd_context *cmd,
struct logical_volume *lv, int do_reg);
/*
* Returns 1 if PV has a dependency tree that uses anything in VG.
*/
int pv_uses_vg(struct 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>
@@ -37,6 +38,7 @@ typedef enum {
ACTIVATE,
DEACTIVATE,
SUSPEND,
SUSPEND_WITH_LOCKFS,
CLEAN
} action_t;
@@ -116,12 +118,10 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
}
static int _info_run(const char *name, const char *dlid, struct dm_info *info,
int mknodes, int with_open_count, struct dm_pool *mem,
char **uuid_out)
int mknodes, int with_open_count)
{
int r = 0;
struct dm_task *dmt;
const char *u;
int dmtask;
dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO;
@@ -141,11 +141,58 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
if (!dm_task_get_info(dmt, info))
goto_out;
if (info->exists && uuid_out) {
if (!(u = dm_task_get_uuid(dmt)))
goto_out;
*uuid_out = dm_pool_strdup(mem, u);
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
int device_is_usable(dev_t dev)
{
struct dm_task *dmt;
struct dm_info info;
const char *name;
uint64_t start, length;
char *target_type = NULL;
char *params;
void *next = NULL;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
log_error("Failed to allocate dm_task struct to check dev status");
return 0;
}
if (!dm_task_set_major(dmt, MAJOR(dev)) || !dm_task_set_minor(dmt, MINOR(dev)))
goto_out;
if (!dm_task_run(dmt)) {
log_error("Failed to get state of mapped device");
goto out;
}
if (!dm_task_get_info(dmt, &info))
goto_out;
if (!info.exists || info.suspended)
goto out;
name = dm_task_get_name(dmt);
/* FIXME Also check for mirror block_on_error and mpath no paths */
/* For now, we exclude all mirrors */
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
/* Skip if target type doesn't match */
if (target_type && !strcmp(target_type, "mirror"))
goto out;
} while (next);
/* FIXME Also check dependencies? */
r = 1;
out:
@@ -154,23 +201,20 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
}
static int _info(const char *name, const char *dlid, int mknodes,
int with_open_count, struct dm_info *info,
struct dm_pool *mem, char **uuid_out)
int with_open_count, struct dm_info *info)
{
if (!mknodes && dlid && *dlid) {
if (_info_run(NULL, dlid, info, 0, with_open_count, mem,
uuid_out) &&
if (_info_run(NULL, dlid, info, 0, with_open_count) &&
info->exists)
return 1;
else if (_info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
0, with_open_count, mem, uuid_out) &&
0, with_open_count) &&
info->exists)
return 1;
}
if (name)
return _info_run(name, NULL, info, mknodes, with_open_count,
mem, uuid_out);
return _info_run(name, NULL, info, mknodes, with_open_count);
return 0;
}
@@ -186,8 +230,7 @@ int dev_manager_info(struct dm_pool *mem, const char *name,
return 0;
}
return _info(name, dlid, with_mknodes, with_open_count, info,
NULL, NULL);
return _info(name, dlid, with_mknodes, with_open_count, info);
}
/* FIXME Interface must cope with multiple targets */
@@ -329,7 +372,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
if (segtype->ops->target_percent &&
!segtype->ops->target_percent(&dm->target_state, dm->mem,
dm->cmd->cft, seg, params,
dm->cmd, seg, params,
&total_numerator,
&total_denominator,
percent))
@@ -392,25 +435,21 @@ 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;
if (!stripe_filler) {
stripe_filler = find_config_str(cmd->cft->root,
stripe_filler = find_config_tree_str(cmd,
"activation/missing_stripe_filler",
DEFAULT_STRIPE_FILLER);
}
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;
@@ -426,6 +465,11 @@ void dev_manager_destroy(struct dev_manager *dm)
dm_pool_destroy(dm->mem);
}
void dev_manager_release(void)
{
dm_lib_release();
}
void dev_manager_exit(void)
{
dm_lib_exit();
@@ -587,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;
}
@@ -758,7 +802,7 @@ static int _add_target_to_dtree(struct dev_manager *dm,
return 0;
}
return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd->cft,
return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd,
&dm->target_state, seg,
dnode,
extent_size * seg->len,
@@ -776,12 +820,19 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
{
uint32_t s;
struct list *snh;
struct lv_segment *seg_present;
/* Ensure required device-mapper targets are loaded */
if (seg->segtype->ops->target_present &&
!seg->segtype->ops->target_present()) {
seg_present = find_cow(seg->lv) ? : seg;
log_debug("Checking kernel supports %s segment type for %s%s%s",
seg_present->segtype->name, seg->lv->name,
layer ? "-" : "", layer ? : "");
if (seg_present->segtype->ops->target_present &&
!seg_present->segtype->ops->target_present(seg_present)) {
log_error("Can't expand LV %s: %s target support missing "
"from kernel?", seg->lv->name, seg->segtype->name);
"from kernel?", seg->lv->name, seg_present->segtype->name);
return 0;
}
@@ -861,8 +912,8 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
* Major/minor settings only apply to the visible layer.
*/
if (!(dnode = dm_tree_add_new_dev(dtree, name, dlid,
layer ? (uint32_t) lv->major : UINT32_C(0),
layer ? (uint32_t) lv->minor : UINT32_C(0),
layer ? UINT32_C(0) : (uint32_t) lv->major,
layer ? UINT32_C(0) : (uint32_t) lv->minor,
_read_only_lv(lv),
(lv->vg->status & PRECOMMITTED) ? 1 : 0,
lvlayer)))
@@ -886,6 +937,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return 1;
}
/* FIXME: symlinks should be created/destroyed at the same time
* as the kernel devices but we can't do that from within libdevmapper
* at present so we must walk the tree twice instead. */
/*
* Create LV symlinks for children of supplied root node.
*/
@@ -906,7 +961,7 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
name = dm_tree_node_get_name(child);
if (name && lvlayer->old_name && *lvlayer->old_name && strcmp(name, lvlayer->old_name)) {
if (!split_dm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) {
if (!dm_split_lvm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) {
log_error("_create_lv_symlinks: Couldn't split up old device name %s", lvlayer->old_name);
return 0;
}
@@ -918,6 +973,32 @@ static int _create_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root
return r;
}
/*
* Remove LV symlinks for children of supplied root node.
*/
static int _remove_lv_symlinks(struct dev_manager *dm, struct dm_tree_node *root)
{
void *handle = NULL;
struct dm_tree_node *child;
char *vgname, *lvname, *layer;
int r = 1;
while ((child = dm_tree_next_child(&handle, root, 0))) {
if (!dm_split_lvm_name(dm->mem, dm_tree_node_get_name(child), &vgname, &lvname, &layer)) {
r = 0;
continue;
}
/* only top level layer has symlinks */
if (*layer)
continue;
fs_del_lv_byname(dm->cmd->dev_dir, vgname, lvname);
}
return r;
}
static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root)
{
void *handle = NULL;
@@ -932,7 +1013,7 @@ static int _clean_tree(struct dev_manager *dm, struct dm_tree_node *root)
if (!(uuid = dm_tree_node_get_uuid(child)))
continue;
if (!split_dm_name(dm->mem, name, &vgname, &lvname, &layer)) {
if (!dm_split_lvm_name(dm->mem, name, &vgname, &lvname, &layer)) {
log_error("_clean_tree: Couldn't split up device name %s.", name);
return 0;
}
@@ -977,10 +1058,14 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
/* Deactivate LV and all devices it references that nothing else has open. */
if (!dm_tree_deactivate_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
goto_out;
if (!_remove_lv_symlinks(dm, root))
log_error("Failed to remove all device symlinks associated with %s.", lv->name);
break;
case SUSPEND:
if (!lv_is_origin(lv) && !lv_is_cow(lv))
dm_tree_skip_lockfs(root);
dm_tree_skip_lockfs(root);
if ((lv->status & MIRRORED) && !(lv->status & PVMOVE))
dm_tree_use_no_flush_suspend(root);
case SUSPEND_WITH_LOCKFS:
if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
goto_out;
break;
@@ -1044,9 +1129,10 @@ int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv)
return r;
}
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv)
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
int lockfs)
{
return _tree_action(dm, lv, SUSPEND);
return _tree_action(dm, lv, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND);
}
/*
@@ -1058,7 +1144,7 @@ int dev_manager_device_uses_vg(struct device *dev,
{
struct dm_tree *dtree;
struct dm_tree_node *root;
char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1];
char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1] __attribute((aligned(8)));
int r = 1;
if (!(dtree = dm_tree_create())) {

View File

@@ -29,6 +29,7 @@ struct device;
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
const char *vg_name);
void dev_manager_destroy(struct dev_manager *dm);
void dev_manager_release(void);
void dev_manager_exit(void);
/*
@@ -46,7 +47,8 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
int dev_manager_mirror_percent(struct dev_manager *dm,
struct logical_volume *lv, int wait,
float *percent, uint32_t *event_nr);
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
int lockfs);
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);

View File

@@ -30,7 +30,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
{
char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
@@ -53,7 +53,7 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
{
char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
@@ -87,7 +87,7 @@ static void _rm_blks(const char *dir)
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
log_error("Couldn't create path for %s", name);
continue;
}
@@ -109,28 +109,28 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
char vg_path[PATH_MAX];
struct stat buf;
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
dev_dir, vg_name) == -1) {
log_error("Couldn't create path for volume group dir %s",
vg_name);
return 0;
}
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
lv_name) == -1) {
log_error("Couldn't create source pathname for "
"logical volume link %s", lv_name);
return 0;
}
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
if (dm_snprintf(link_path, sizeof(link_path), "%s/%s",
dm_dir(), dev) == -1) {
log_error("Couldn't create destination pathname for "
"logical volume link for %s", lv_name);
return 0;
}
if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
vg_path) == -1) {
log_error("Couldn't create pathname for LVM1 group file for %s",
vg_name);
@@ -190,7 +190,7 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
struct stat buf;
char lv_path[PATH_MAX];
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
dev_dir, vg_name, lv_name) == -1) {
log_error("Couldn't determine link pathname.");
return 0;
@@ -338,6 +338,11 @@ int fs_del_lv(const struct logical_volume *lv)
"", "");
}
int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name)
{
return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", "");
}
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name)
{

View File

@@ -25,6 +25,7 @@
*/
int fs_add_lv(const struct logical_volume *lv, const char *dev);
int fs_del_lv(const struct logical_volume *lv);
int fs_del_lv_byname(const char *dev_dir, const char *vg_name, const char *lv_name);
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name);
void fs_unlock(void);

43
lib/cache/lvmcache.c vendored
View File

@@ -114,7 +114,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
struct list *devh, *tmp;
struct list devs;
struct device_list *devl;
char vgid_found[ID_LEN + 1];
char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
return NULL;
@@ -135,7 +135,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
list_iterate_safe(devh, tmp, &devs) {
devl = list_item(devh, struct device_list);
label_read(devl->dev, &label);
label_read(devl->dev, &label, UINT64_C(0));
list_del(&devl->list);
dm_free(devl);
}
@@ -151,7 +151,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
{
struct lvmcache_vginfo *vginfo;
char id[ID_LEN + 1];
char id[ID_LEN + 1] __attribute((aligned(8)));
if (!_vgid_hash || !vgid)
return NULL;
@@ -169,20 +169,24 @@ struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
{
struct lvmcache_vginfo *vginfo;
const char *vgname = NULL;
if ((vginfo = vginfo_from_vgid(vgid))) {
if (mem)
return dm_pool_strdup(mem, vginfo->vgname);
return vginfo->vgname;
}
if (!*vgid)
vgname = ORPHAN;
return NULL;
if ((vginfo = vginfo_from_vgid(vgid)))
vgname = vginfo->vgname;
if (mem && vgname)
return dm_pool_strdup(mem, vgname);
return vgname;
}
struct lvmcache_info *info_from_pvid(const char *pvid)
{
struct lvmcache_info *info;
char id[ID_LEN + 1];
char id[ID_LEN + 1] __attribute((aligned(8)));
if (!_pvid_hash || !pvid)
return NULL;
@@ -201,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)
@@ -237,13 +241,13 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
goto out;
}
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
log_error("dev_iter creation failed");
goto out;
}
while ((dev = dev_iter_get(iter)))
label_read(dev, &label);
label_read(dev, &label, UINT64_C(0));
dev_iter_destroy(iter);
@@ -342,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;
@@ -353,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;
@@ -367,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;
@@ -472,7 +476,8 @@ static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
struct lvmcache_vginfo *primary_vginfo)
{
struct lvmcache_vginfo *last_vginfo = primary_vginfo;
char uuid_primary[64], uuid_new[64];
char uuid_primary[64] __attribute((aligned(8)));
char uuid_new[64] __attribute((aligned(8)));
int use_new = 0;
/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
@@ -705,7 +710,7 @@ int lvmcache_update_vg(struct volume_group *vg)
{
struct pv_list *pvl;
struct lvmcache_info *info;
char pvid_s[ID_LEN + 1];
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
pvid_s[sizeof(pvid_s) - 1] = '\0';
@@ -729,7 +734,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
{
struct label *label;
struct lvmcache_info *existing, *info;
char pvid_s[ID_LEN + 1];
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
if (!_vgname_hash && !lvmcache_init()) {
log_error("Internal cache initialisation failed");

View File

@@ -59,15 +59,13 @@
# include <malloc.h>
#endif
static FILE *_log;
static int _get_env_vars(struct cmd_context *cmd)
{
const char *e;
/* Set to "" to avoid using any system directory */
if ((e = getenv("LVM_SYSTEM_DIR"))) {
if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
if (dm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
"%s", e) < 0) {
log_error("LVM_SYSTEM_DIR environment variable "
"is too long.");
@@ -84,10 +82,11 @@ static void _init_logging(struct cmd_context *cmd)
time_t t;
const char *log_file;
char timebuf[26];
/* Syslog */
cmd->default_settings.syslog =
find_config_int(cmd->cft->root, "log/syslog", DEFAULT_SYSLOG);
find_config_tree_int(cmd, "log/syslog", DEFAULT_SYSLOG);
if (cmd->default_settings.syslog != 1)
fin_syslog();
@@ -96,37 +95,37 @@ static void _init_logging(struct cmd_context *cmd)
/* Debug level for log file output */
cmd->default_settings.debug =
find_config_int(cmd->cft->root, "log/level", DEFAULT_LOGLEVEL);
find_config_tree_int(cmd, "log/level", DEFAULT_LOGLEVEL);
init_debug(cmd->default_settings.debug);
/* Verbose level for tty output */
cmd->default_settings.verbose =
find_config_int(cmd->cft->root, "log/verbose", DEFAULT_VERBOSE);
find_config_tree_int(cmd, "log/verbose", DEFAULT_VERBOSE);
init_verbose(cmd->default_settings.verbose + VERBOSE_BASE_LEVEL);
/* Log message formatting */
init_indent(find_config_int(cmd->cft->root, "log/indent",
init_indent(find_config_tree_int(cmd, "log/indent",
DEFAULT_INDENT));
cmd->default_settings.msg_prefix = find_config_str(cmd->cft->root,
cmd->default_settings.msg_prefix = find_config_tree_str(cmd,
"log/prefix",
DEFAULT_MSG_PREFIX);
init_msg_prefix(cmd->default_settings.msg_prefix);
cmd->default_settings.cmd_name = find_config_int(cmd->cft->root,
cmd->default_settings.cmd_name = find_config_tree_int(cmd,
"log/command_names",
DEFAULT_CMD_NAME);
init_cmd_name(cmd->default_settings.cmd_name);
/* Test mode */
cmd->default_settings.test =
find_config_int(cmd->cft->root, "global/test", 0);
find_config_tree_int(cmd, "global/test", 0);
/* Settings for logging to file */
if (find_config_int(cmd->cft->root, "log/overwrite", DEFAULT_OVERWRITE))
if (find_config_tree_int(cmd, "log/overwrite", DEFAULT_OVERWRITE))
append = 0;
log_file = find_config_str(cmd->cft->root, "log/file", 0);
log_file = find_config_tree_str(cmd, "log/file", 0);
if (log_file) {
release_log_memory();
@@ -134,15 +133,17 @@ static void _init_logging(struct cmd_context *cmd)
init_log_file(log_file, append);
}
log_file = find_config_str(cmd->cft->root, "log/activate_file", 0);
log_file = find_config_tree_str(cmd, "log/activate_file", 0);
if (log_file)
init_log_direct(log_file, append);
init_log_while_suspended(find_config_int(cmd->cft->root,
init_log_while_suspended(find_config_tree_int(cmd,
"log/activation", 0));
t = time(NULL);
log_verbose("Logging initialised at %s", ctime(&t));
ctime_r(&t, &timebuf[0]);
timebuf[24] = '\0';
log_verbose("Logging initialised at %s", timebuf);
/* Tell device-mapper about our logging */
#ifdef DEVMAPPER_SUPPORT
@@ -155,7 +156,7 @@ static int _process_config(struct cmd_context *cmd)
mode_t old_umask;
/* umask */
cmd->default_settings.umask = find_config_int(cmd->cft->root,
cmd->default_settings.umask = find_config_tree_int(cmd,
"global/umask",
DEFAULT_UMASK);
@@ -164,8 +165,8 @@ static int _process_config(struct cmd_context *cmd)
log_verbose("Set umask to %04o", cmd->default_settings.umask);
/* dev dir */
if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
find_config_str(cmd->cft->root, "devices/dir",
if (dm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
find_config_tree_str(cmd, "devices/dir",
DEFAULT_DEV_DIR)) < 0) {
log_error("Device directory given in config file too long");
return 0;
@@ -175,8 +176,8 @@ static int _process_config(struct cmd_context *cmd)
#endif
/* proc dir */
if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
find_config_str(cmd->cft->root, "global/proc",
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
find_config_tree_str(cmd, "global/proc",
DEFAULT_PROC_DIR)) < 0) {
log_error("Device directory given in config file too long");
return 0;
@@ -189,17 +190,17 @@ static int _process_config(struct cmd_context *cmd)
}
/* activation? */
cmd->default_settings.activation = find_config_int(cmd->cft->root,
cmd->default_settings.activation = find_config_tree_int(cmd,
"global/activation",
DEFAULT_ACTIVATION);
set_activation(cmd->default_settings.activation);
cmd->default_settings.suffix = find_config_int(cmd->cft->root,
cmd->default_settings.suffix = find_config_tree_int(cmd,
"global/suffix",
DEFAULT_SUFFIX);
if (!(cmd->default_settings.unit_factor =
units_to_bytes(find_config_str(cmd->cft->root,
units_to_bytes(find_config_tree_str(cmd,
"global/units",
DEFAULT_UNITS),
&cmd->default_settings.unit_type))) {
@@ -316,7 +317,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
if (*tag)
filler = "_";
if (lvm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
cmd->sys_dir, filler, tag) < 0) {
log_error("LVM_SYSTEM_DIR or tag was too long");
return 0;
@@ -327,7 +328,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
return 0;
}
if (!(cfl->cft = create_config_tree(config_file))) {
if (!(cfl->cft = create_config_tree(config_file, 0))) {
log_error("config_tree allocation failed");
return 0;
}
@@ -367,7 +368,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
{
/* No config file if LVM_SYSTEM_DIR is empty */
if (!*cmd->sys_dir) {
if (!(cmd->cft = create_config_tree(NULL))) {
if (!(cmd->cft = create_config_tree(NULL, 0))) {
log_error("Failed to create config tree");
return 0;
}
@@ -405,7 +406,7 @@ static int _merge_config_files(struct cmd_context *cmd)
/* Replace temporary duplicate copy of lvm.conf */
if (cmd->cft->root) {
if (!(cmd->cft = create_config_tree(NULL))) {
if (!(cmd->cft = create_config_tree(NULL, 0))) {
log_error("Failed to create config tree");
return 0;
}
@@ -464,12 +465,10 @@ 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_node(cmd->cft->root, "devices/scan"))) {
if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
if (!dev_cache_add_dir("/dev")) {
log_error("Failed to add /dev to internal "
"device cache");
@@ -494,7 +493,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
}
}
if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
if (!(cn = find_config_tree_node(cmd, "devices/loopfiles")))
return 1;
for (cv = cn->v; cv; cv = cv->next) {
@@ -536,14 +535,14 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
* Listed first because it's very efficient at eliminating
* unavailable devices.
*/
if (find_config_bool(cmd->cft->root, "devices/sysfs_scan",
if (find_config_tree_bool(cmd, "devices/sysfs_scan",
DEFAULT_SYSFS_SCAN)) {
if ((filters[nr_filt] = sysfs_filter_create(cmd->proc_dir)))
nr_filt++;
}
/* regex filter. Optional. */
if (!(cn = find_config_node(cmd->cft->root, "devices/filter")))
if (!(cn = find_config_tree_node(cmd, "devices/filter")))
log_very_verbose("devices/filter not found in config file: "
"no regex filter installed");
@@ -553,14 +552,14 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
}
/* device type filter. Required. */
cn = find_config_node(cmd->cft->root, "devices/types");
cn = find_config_tree_node(cmd, "devices/types");
if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
log_error("Failed to create lvm type filter");
return NULL;
}
/* md component filter. Optional, non-critical. */
if (find_config_bool(cmd->cft->root, "devices/md_component_detection",
if (find_config_tree_bool(cmd, "devices/md_component_detection",
DEFAULT_MD_COMPONENT_DETECTION)) {
init_md_filtering(1);
if ((filters[nr_filt] = md_filter_create()))
@@ -572,9 +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];
@@ -584,30 +583,54 @@ static int _init_filters(struct cmd_context *cmd)
if (!(f3 = _init_filter_components(cmd)))
return 0;
if (lvm_snprintf(cache_file, sizeof(cache_file),
"%s/.cache", cmd->sys_dir) < 0) {
log_error("Persistent cache filename too long ('%s/.cache').",
cmd->sys_dir);
init_ignore_suspended_devices(find_config_tree_int(cmd,
"devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
/*
* If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'.
*/
cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL);
cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL);
if (cache_dir || cache_file_prefix) {
if (dm_snprintf(cache_file, sizeof(cache_file),
"%s%s%s/%s.cache",
cache_dir ? "" : cmd->sys_dir,
cache_dir ? "" : "/",
cache_dir ? : DEFAULT_CACHE_SUBDIR,
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
log_error("Persistent cache filename too long.");
return 0;
}
} else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
(dm_snprintf(cache_file, sizeof(cache_file),
"%s/%s/%s.cache",
cmd->sys_dir, DEFAULT_CACHE_SUBDIR,
DEFAULT_CACHE_FILE_PREFIX) < 0)) {
log_error("Persistent cache filename too long.");
return 0;
}
dev_cache = find_config_str(cmd->cft->root, "devices/cache",
cache_file);
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
if (!(f4 = persistent_filter_create(f3, dev_cache ? : cache_file))) {
log_error("Failed to create persistent device filter");
return 0;
}
/* Should we ever dump persistent filter state? */
if (find_config_int(cmd->cft->root, "devices/write_cache_state", 1))
if (find_config_tree_int(cmd, "devices/write_cache_state", 1))
cmd->dump_filter = 1;
if (!*cmd->sys_dir)
cmd->dump_filter = 0;
if (!stat(dev_cache, &st) &&
(st.st_mtime > config_file_timestamp(cmd->cft)) &&
!persistent_filter_load(f4))
/*
* Only load persistent filter device cache on startup if it is newer
* than the config file and this is not a long-lived process.
*/
if (load_persistent_cache && !cmd->is_long_lived &&
!stat(dev_cache, &st) &&
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
!persistent_filter_load(f4, NULL))
log_verbose("Failed to load existing device cache from %s",
dev_cache);
@@ -643,8 +666,9 @@ static int _init_formats(struct cmd_context *cmd)
#endif
#ifdef HAVE_LIBDL
/* Load any formats in shared libs */
if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) {
/* Load any formats in shared libs if not static */
if (!cmd->is_static &&
(cn = find_config_tree_node(cmd, "global/format_libraries"))) {
struct config_value *cv;
struct format_type *(*init_format_fn) (struct cmd_context *);
@@ -656,7 +680,7 @@ static int _init_formats(struct cmd_context *cmd)
"global/format_libraries");
return 0;
}
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
if (!(lib = load_shared_library(cmd, cv->v.str,
"format", 0))) {
stack;
return 0;
@@ -684,7 +708,7 @@ static int _init_formats(struct cmd_context *cmd)
cmd->fmt_backup = fmt;
format = find_config_str(cmd->cft->root, "global/format",
format = find_config_tree_str(cmd, "global/format",
DEFAULT_FORMAT);
list_iterate_items(fmt, &cmd->formats) {
@@ -737,13 +761,13 @@ static int _init_segtypes(struct cmd_context *cmd)
#endif
#ifdef HAVE_LIBDL
/* Load any formats in shared libs */
if ((cn = find_config_node(cmd->cft->root, "global/segment_libraries"))) {
/* Load any formats in shared libs unless static */
if (!cmd->is_static &&
(cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
struct config_value *cv;
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
void *lib;
struct list *sgtl, *tmp;
struct segment_type *segtype2;
for (cv = cn->v; cv; cv = cv->next) {
@@ -752,7 +776,7 @@ static int _init_segtypes(struct cmd_context *cmd)
"global/segment_libraries");
return 0;
}
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
if (!(lib = load_shared_library(cmd, cv->v.str,
"segment type", 0))) {
stack;
return 0;
@@ -770,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);
}
}
}
@@ -827,16 +849,16 @@ static int _init_backup(struct cmd_context *cmd)
/* set up archiving */
cmd->default_settings.archive =
find_config_bool(cmd->cft->root, "backup/archive",
find_config_tree_bool(cmd, "backup/archive",
DEFAULT_ARCHIVE_ENABLED);
days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
days = (uint32_t) find_config_tree_int(cmd, "backup/retain_days",
DEFAULT_ARCHIVE_DAYS);
min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
min = (uint32_t) find_config_tree_int(cmd, "backup/retain_min",
DEFAULT_ARCHIVE_NUMBER);
if (lvm_snprintf
if (dm_snprintf
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
DEFAULT_ARCHIVE_SUBDIR) == -1) {
log_err("Couldn't create default archive path '%s/%s'.",
@@ -844,7 +866,7 @@ static int _init_backup(struct cmd_context *cmd)
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/archive_dir",
dir = find_config_tree_str(cmd, "backup/archive_dir",
default_dir);
if (!archive_init(cmd, dir, days, min)) {
@@ -854,10 +876,10 @@ static int _init_backup(struct cmd_context *cmd)
/* set up the backup */
cmd->default_settings.backup =
find_config_bool(cmd->cft->root, "backup/backup",
find_config_tree_bool(cmd, "backup/backup",
DEFAULT_BACKUP_ENABLED);
if (lvm_snprintf
if (dm_snprintf
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
DEFAULT_BACKUP_SUBDIR) == -1) {
log_err("Couldn't create default backup path '%s/%s'.",
@@ -865,7 +887,7 @@ static int _init_backup(struct cmd_context *cmd)
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
dir = find_config_tree_str(cmd, "backup/backup_dir", default_dir);
if (!backup_init(cmd, dir)) {
log_debug("backup_init failed.");
@@ -876,7 +898,8 @@ static int _init_backup(struct cmd_context *cmd)
}
/* Entry point */
struct cmd_context *create_toolcontext(struct arg *the_args)
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
unsigned is_long_lived)
{
struct cmd_context *cmd;
@@ -899,6 +922,8 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
}
memset(cmd, 0, sizeof(*cmd));
cmd->args = the_args;
cmd->is_static = is_static;
cmd->is_long_lived = is_long_lived;
cmd->hosttags = 0;
list_init(&cmd->formats);
list_init(&cmd->segtypes);
@@ -921,7 +946,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!(cmd->libmem = dm_pool_create("library", 4 * 1024))) {
log_error("Library memory pool creation failed");
return 0;
goto error;
}
if (!_init_lvm_conf(cmd))
@@ -947,7 +972,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!_init_dev_cache(cmd))
goto error;
if (!_init_filters(cmd))
if (!_init_filters(cmd, 1))
goto error;
if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) {
@@ -1016,12 +1041,12 @@ int refresh_toolcontext(struct cmd_context *cmd)
{
log_verbose("Reloading config files");
if (cmd->config_valid) {
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
}
/*
* Don't update the persistent filter cache as we will
* perform a full rescan.
*/
activation_exit();
activation_release();
lvmcache_destroy();
label_exit();
_destroy_segtypes(&cmd->segtypes);
@@ -1058,7 +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))
@@ -1067,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;
}
@@ -1094,8 +1126,4 @@ void destroy_toolcontext(struct cmd_context *cmd)
activation_exit();
fin_log();
fin_syslog();
if (_log)
fclose(_log);
}

View File

@@ -64,6 +64,8 @@ struct cmd_context {
struct command *command;
struct arg *args;
char **argv;
unsigned is_static; /* Static binary? */
unsigned is_long_lived; /* Optimises persistent_filter handling */
struct dev_filter *filter;
int dump_filter; /* Dump filter when exiting? */
@@ -71,6 +73,7 @@ struct cmd_context {
struct list config_files;
int config_valid;
struct config_tree *cft;
struct config_tree *cft_override;
struct config_info default_settings;
struct config_info current_settings;
@@ -86,7 +89,7 @@ struct cmd_context {
char proc_dir[PATH_MAX];
};
struct cmd_context *create_toolcontext(struct arg *the_args);
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived);
void destroy_toolcontext(struct cmd_context *cmd);
int refresh_toolcontext(struct cmd_context *cmd);
int config_files_changed(struct cmd_context *cmd);

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,
@@ -41,10 +45,10 @@ enum {
};
struct parser {
char *fb, *fe; /* file limits */
const char *fb, *fe; /* file limits */
int t; /* token limits and type */
char *tb, *te;
const char *tb, *te;
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
@@ -58,6 +62,8 @@ struct cs {
time_t timestamp;
char *filename;
int exists;
int keep_open;
struct device *dev;
};
static void _get_token(struct parser *p, int tok_prev);
@@ -77,7 +83,8 @@ static const int sep = '/';
#define match(t) do {\
if (!_match_aux(p, (t))) {\
log_error("Parse error at line %d: unexpected token", p->line); \
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
p->tb - p->fb + 1, p->line); \
return 0;\
} \
} while(0);
@@ -95,18 +102,18 @@ static int _tok_match(const char *str, const char *b, const char *e)
/*
* public interface
*/
struct config_tree *create_config_tree(const char *filename)
struct config_tree *create_config_tree(const char *filename, int keep_open)
{
struct cs *c;
struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
if (!mem) {
stack;
log_error("Failed to allocate config pool.");
return 0;
}
if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) {
stack;
log_error("Failed to allocate config tree.");
dm_pool_destroy(mem);
return 0;
}
@@ -115,6 +122,8 @@ struct config_tree *create_config_tree(const char *filename)
c->cft.root = (struct config_node *) NULL;
c->timestamp = 0;
c->exists = 0;
c->keep_open = keep_open;
c->dev = 0;
if (filename)
c->filename = dm_pool_strdup(c->mem, filename);
return &c->cft;
@@ -122,7 +131,52 @@ struct config_tree *create_config_tree(const char *filename)
void destroy_config_tree(struct config_tree *cft)
{
dm_pool_destroy(((struct cs *) cft)->mem);
struct cs *c = (struct cs *) cft;
if (c->dev)
dev_close(c->dev);
dm_pool_destroy(c->mem);
}
static int _parse_config_file(struct parser *p, struct config_tree *cft)
{
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p, TOK_SECTION_E);
if (!(cft->root = _file(p)))
return_0;
return 1;
}
struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
const char *config_settings)
{
struct cs *c;
struct config_tree *cft;
struct parser *p;
if (!(cft = create_config_tree(NULL, 0)))
return_NULL;
c = (struct cs *) cft;
if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
log_error("Failed to allocate config tree parser.");
destroy_config_tree(cft);
return NULL;
}
p->mem = c->mem;
p->fb = config_settings;
p->fe = config_settings + strlen(config_settings);
if (!_parse_config_file(p, cft)) {
destroy_config_tree(cft);
return_NULL;
}
return cft;
}
int read_config_fd(struct config_tree *cft, struct device *dev,
@@ -134,6 +188,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
int r = 0;
int use_mmap = 1;
off_t mmap_offset = 0;
char *buf = NULL;
if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) {
stack;
@@ -146,7 +201,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
use_mmap = 0;
if (use_mmap) {
mmap_offset = offset % getpagesize();
mmap_offset = offset % lvm_getpagesize();
/* memory map the file */
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
@@ -156,22 +211,15 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
}
p->fb = p->fb + mmap_offset;
} else {
if (!(p->fb = dm_malloc(size + size2))) {
if (!(buf = dm_malloc(size + size2))) {
stack;
return 0;
}
if (!dev_read(dev, (uint64_t) offset, size, p->fb)) {
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,
p->fb + size)) {
log_error("Circular read from %s failed",
dev_name(dev));
goto out;
}
}
p->fb = buf;
}
if (checksum_fn && checksum !=
@@ -183,11 +231,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
p->fe = p->fb + size + size2;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p, TOK_SECTION_E);
if (!(cft->root = _file(p))) {
if (!_parse_config_file(p, cft)) {
stack;
goto out;
}
@@ -196,7 +240,7 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
out:
if (!use_mmap)
dm_free(p->fb);
dm_free(buf);
else {
/* unmap the file */
if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
@@ -212,7 +256,6 @@ int read_config_file(struct config_tree *cft)
{
struct cs *c = (struct cs *) cft;
struct stat info;
struct device *dev;
int r = 1;
if (stat(c->filename, &info)) {
@@ -234,22 +277,23 @@ int read_config_file(struct config_tree *cft)
return 1;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
stack;
return 0;
if (!c->dev) {
if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
return_0;
if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
return_0;
}
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0);
dev_close(dev);
if (!c->keep_open) {
dev_close(c->dev);
c->dev = 0;
}
c->timestamp = info.st_mtime;
c->timestamp = info.st_ctime;
return r;
}
@@ -293,7 +337,7 @@ int config_file_changed(struct config_tree *cft)
}
/* Unchanged? */
if (c->timestamp == info.st_mtime)
if (c->timestamp == info.st_ctime)
return 0;
reload:
@@ -313,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:
@@ -326,7 +370,8 @@ static void _write_value(FILE *fp, struct config_value *v)
}
}
static int _write_config(struct config_node *n, FILE *fp, int level)
static int _write_config(struct config_node *n, int only_one, FILE *fp,
int level)
{
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
@@ -339,12 +384,12 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
space[i] = '\t';
space[i] = '\0';
while (n) {
do {
fprintf(fp, "%s%s", space, n->key);
if (!n->v) {
/* it's a sub section */
fprintf(fp, " {\n");
_write_config(n->child, fp, level + 1);
_write_config(n->child, 0, fp, level + 1);
fprintf(fp, "%s}", space);
} else {
/* it's a value */
@@ -364,13 +409,15 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
}
fprintf(fp, "\n");
n = n->sib;
}
} while (n && !only_one);
/* FIXME: add error checking */
return 1;
}
int write_config_file(struct config_tree *cft, const char *file)
int write_config_file(struct config_tree *cft, const char *file,
int argc, char **argv)
{
struct config_node *cn;
int r = 1;
FILE *fp;
@@ -383,13 +430,28 @@ int write_config_file(struct config_tree *cft, const char *file)
}
log_verbose("Dumping configuration to %s", file);
if (!_write_config(cft->root, fp, 0)) {
log_error("Failure while writing configuration");
r = 0;
if (!argc) {
if (!_write_config(cft->root, 0, fp, 0)) {
log_error("Failure while writing to %s", file);
r = 0;
}
} else while (argc--) {
if ((cn = find_config_node(cft->root, *argv))) {
if (!_write_config(cn, 1, fp, 0)) {
log_error("Failure while writing to %s", file);
r = 0;
}
} else {
log_error("Configuration node %s not found", *argv);
r = 0;
}
argv++;
}
if (fp != stdout)
fclose(fp);
if ((fp != stdout) && fclose(fp)) {
log_sys_error("fclose", file);
r = 0;
}
return r;
}
@@ -417,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;
@@ -506,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;
@@ -529,7 +591,8 @@ static struct config_value *_type(struct parser *p)
break;
default:
log_error("Parse error at line %d: expected a value", p->line);
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
p->tb - p->fb + 1, p->line);
return 0;
}
return v;
@@ -566,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;
@@ -651,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;
}
@@ -721,10 +785,11 @@ static char *_dup_tok(struct parser *p)
/*
* utility functions
*/
struct config_node *find_config_node(const struct config_node *cn,
const char *path)
static struct config_node *_find_config_node(const struct config_node *cn,
const char *path)
{
const char *e;
const struct config_node *cn_found = NULL;
while (cn) {
/* trim any leading slashes */
@@ -735,31 +800,61 @@ struct config_node *find_config_node(const struct config_node *cn,
for (e = path; *e && (*e != sep); e++) ;
/* hunt for the node */
cn_found = NULL;
while (cn) {
if (_tok_match(cn->key, path, e))
break;
if (_tok_match(cn->key, path, e)) {
/* Inefficient */
if (!cn_found)
cn_found = cn;
else
log_error("WARNING: Ignoring duplicate"
" config node: %s ("
"seeking %s)", cn->key, path);
}
cn = cn->sib;
}
if (cn && *e)
cn = cn->child;
if (cn_found && *e)
cn = cn_found->child;
else
break; /* don't move into the last node */
path = e;
}
return (struct config_node *) cn;
return (struct config_node *) cn_found;
}
const char *find_config_str(const struct config_node *cn,
const char *path, const char *fail)
static struct config_node *_find_first_config_node(const struct config_node *cn1,
const struct config_node *cn2,
const char *path)
{
const struct config_node *n = find_config_node(cn, path);
struct config_node *cn;
if (cn1 && (cn = _find_config_node(cn1, path)))
return cn;
if (cn2 && (cn = _find_config_node(cn2, path)))
return cn;
return NULL;
}
struct config_node *find_config_node(const struct config_node *cn,
const char *path)
{
return _find_config_node(cn, path);
}
static const char *_find_config_str(const struct config_node *cn1,
const struct config_node *cn2,
const char *path, const char *fail)
{
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
/* Empty strings are ignored */
if ((n && n->v->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;
}
@@ -770,26 +865,41 @@ const char *find_config_str(const struct config_node *cn,
return fail;
}
int find_config_int(const struct config_node *cn, const char *path, int fail)
const char *find_config_str(const struct config_node *cn,
const char *path, const char *fail)
{
const struct config_node *n = find_config_node(cn, path);
return _find_config_str(cn, NULL, path, fail);
}
if (n && n->v->type == CFG_INT) {
log_very_verbose("Setting %s to %d", path, n->v->v.i);
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 && 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;
}
float find_config_float(const struct config_node *cn, const char *path,
float fail)
int find_config_int(const struct config_node *cn, const char *path, int fail)
{
const struct config_node *n = find_config_node(cn, path);
/* FIXME Add log_error message on overflow */
return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
}
if (n && n->v->type == CFG_FLOAT) {
static float _find_config_float(const struct config_node *cn1,
const struct config_node *cn2,
const char *path, float fail)
{
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
if (n && n->v && n->v->type == CFG_FLOAT) {
log_very_verbose("Setting %s to %f", path, n->v->v.r);
return n->v->v.r;
}
@@ -801,6 +911,37 @@ float find_config_float(const struct config_node *cn, const char *path,
}
float find_config_float(const struct config_node *cn, const char *path,
float fail)
{
return _find_config_float(cn, NULL, path, fail);
}
struct config_node *find_config_tree_node(struct cmd_context *cmd,
const char *path)
{
return _find_first_config_node(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path);
}
const char *find_config_tree_str(struct cmd_context *cmd,
const char *path, const char *fail)
{
return _find_config_str(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
}
int find_config_tree_int(struct cmd_context *cmd, const char *path,
int fail)
{
/* 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,
float fail)
{
return _find_config_float(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
}
static int _str_in_array(const char *str, const char *values[])
{
int i;
@@ -827,9 +968,11 @@ static int _str_to_bool(const char *str, int fail)
return fail;
}
int find_config_bool(const struct config_node *cn, const char *path, int fail)
static int _find_config_bool(const struct config_node *cn1,
const struct config_node *cn2,
const char *path, int fail)
{
const struct config_node *n = find_config_node(cn, path);
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
struct config_value *v;
if (!n)
@@ -848,6 +991,16 @@ int find_config_bool(const struct config_node *cn, const char *path, int fail)
return fail;
}
int find_config_bool(const struct config_node *cn, const char *path, int fail)
{
return _find_config_bool(cn, NULL, path, fail);
}
int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail)
{
return _find_config_bool(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
}
int get_config_uint32(const struct config_node *cn, const char *path,
uint32_t *result)
{
@@ -872,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;
}
@@ -1002,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;
@@ -53,17 +53,20 @@ struct config_tree_list {
struct config_tree *cft;
};
struct config_tree *create_config_tree(const char *filename);
struct config_tree *create_config_tree(const char *filename, int keep_open);
struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
const char *config_settings);
void destroy_config_tree(struct config_tree *cft);
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
typedef uint32_t (*checksum_fn_t) (uint32_t initial, const void *buf, uint32_t size);
int read_config_fd(struct config_tree *cft, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum);
int read_config_file(struct config_tree *cft);
int write_config_file(struct config_tree *cft, const char *file);
int write_config_file(struct config_tree *cft, const char *file,
int argc, char **argv);
time_t config_file_timestamp(struct config_tree *cft);
int config_file_changed(struct config_tree *cft);
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
@@ -71,20 +74,30 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
struct config_node *find_config_node(const struct config_node *cn,
const char *path);
const char *find_config_str(const struct config_node *cn, const char *path,
const char *fail);
int find_config_int(const struct config_node *cn, const char *path, int fail);
float find_config_float(const struct config_node *cn, const char *path,
float fail);
/*
* These versions check an override tree, if present, first.
*/
struct config_node *find_config_tree_node(struct cmd_context *cmd,
const char *path);
const char *find_config_tree_str(struct cmd_context *cmd,
const char *path, const char *fail);
int find_config_tree_int(struct cmd_context *cmd, const char *path,
int fail);
float find_config_tree_float(struct cmd_context *cmd, const char *path,
float fail);
/*
* Understands (0, ~0), (y, n), (yes, no), (on,
* off), (true, false).
*/
int find_config_bool(const struct config_node *cn, const char *path, int fail);
int find_config_tree_bool(struct cmd_context *cmd, const char *path, int fail);
int get_config_uint32(const struct config_node *cn, const char *path,
uint32_t *result);
@@ -95,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,13 +32,17 @@
#define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_SYSFS_SCAN 1
#define DEFAULT_MD_COMPONENT_DETECTION 1
#define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
#define DEFAULT_MIRROR_DEV_FAULT_POLICY "remove"
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
#define DEFAULT_DMEVENTD_MONITOR 1
#define DEFAULT_UMASK 0077

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;
@@ -645,8 +748,7 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
return NULL;
}
if (dev_scan) {
if (dev_scan && !trust_cache()) {
/* Flag gets reset between each command */
if (!full_scan_done())
persistent_filter_wipe(f); /* Calls _full_scan(1) */

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

@@ -176,7 +176,7 @@ static int _aligned_io(struct device_area *where, void *buffer,
}
if (!block_size)
block_size = getpagesize();
block_size = lvm_getpagesize();
_widen_region(block_size, where, &widened);
@@ -292,11 +292,14 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
if (ioctl(fd, BLKSSZGET, &s) < 0) {
log_sys_error("ioctl BLKSSZGET", name);
close(fd);
if (close(fd))
log_sys_error("close", name);
return 0;
}
close(fd);
if (close(fd))
log_sys_error("close", name);
*size = (uint32_t) s;
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
@@ -561,6 +564,35 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
return _aligned_io(&where, buffer, 0);
}
/*
* Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted
* by (offset,len) and (offset2,len2). Thus, the total size of
* 'buf' should be len+len2.
*/
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
uint64_t offset2, size_t len2, void *buf)
{
if (!dev_read(dev, offset, len, buf)) {
log_error("Read from %s failed", dev_name(dev));
return 0;
}
/*
* The second region is optional, and allows for
* a circular buffer on the device.
*/
if (!len2)
return 1;
if (!dev_read(dev, offset2, len2, buf + len)) {
log_error("Circular read from %s failed",
dev_name(dev));
return 0;
}
return 1;
}
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
* But fails if concurrent processes writing
*/
@@ -605,7 +637,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
{
size_t s;
char buffer[4096];
char buffer[4096] __attribute((aligned(8)));
if (!dev_open(dev)) {
stack;

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

@@ -53,7 +53,7 @@ static int _has_partition_table(struct device *dev)
{
int ret = 0;
unsigned p;
uint8_t buf[SECTOR_SIZE];
uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)];
uint16_t *part_magic;
struct partition *part;
@@ -70,9 +70,9 @@ static int _has_partition_table(struct device *dev)
/* FIXME Check for other types of partition table too */
/* Check for msdos partition table */
part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET);
part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
if ((*part_magic == xlate16(PART_MAGIC))) {
part = (struct partition *) (buf + PART_OFFSET);
part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
for (p = 0; p < 4; p++, part++) {
/* Table is invalid if boot indicator not 0 or 0x80 */
if ((part->boot_ind & 0x7f)) {

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

@@ -30,6 +30,7 @@ static struct {
} _policies[] = {
{
ALLOC_CONTIGUOUS, "contiguous"}, {
ALLOC_CLING, "cling"}, {
ALLOC_NORMAL, "normal"}, {
ALLOC_ANYWHERE, "anywhere"}, {
ALLOC_INHERIT, "inherit"}
@@ -81,6 +82,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
case 't':
v *= KILO * KILO * KILO * KILO;
break;
case 'p':
v *= KILO * KILO * KILO * KILO * KILO;
break;
case 'e':
v *= KILO * KILO * KILO * KILO * KILO * KILO;
break;
#undef KILO
#define KILO UINT64_C(1000)
case 'K':
@@ -95,6 +102,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
case 'T':
v *= KILO * KILO * KILO * KILO;
break;
case 'P':
v *= KILO * KILO * KILO * KILO * KILO;
break;
case 'E':
v *= KILO * KILO * KILO * KILO * KILO * KILO;
break;
#undef KILO
default:
return 0;
@@ -142,6 +155,8 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
const char *size_str[][3] = {
{" Exabyte", " EB", "E"},
{" Petabyte", " PB", "P"},
{" Terabyte", " TB", "T"},
{" Gigabyte", " GB", "G"},
{" Megabyte", " MB", "M"},
@@ -160,7 +175,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
suffix = cmd->current_settings.suffix;
for (s = 0; s < 8; s++)
for (s = 0; s < 10; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[s][2])
break;
@@ -170,7 +185,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
return size_buf;
}
if (s < 8) {
if (s < 10) {
byte = cmd->current_settings.unit_factor;
size *= UINT64_C(512);
} else {
@@ -180,7 +195,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
units = UINT64_C(1000);
else
units = UINT64_C(1024);
byte = units * units * units;
byte = units * units * units * units * units;
s = 0;
while (size_str[s] && size < byte)
s++, byte /= units;
@@ -219,7 +234,7 @@ const char *display_size(struct cmd_context *cmd, uint64_t size)
void pvdisplay_colons(struct physical_volume *pv)
{
char uuid[64];
char uuid[64] __attribute((aligned(8)));
if (!pv)
return;
@@ -243,11 +258,38 @@ void pvdisplay_colons(struct physical_volume *pv)
return;
}
void pvdisplay_segments(struct physical_volume *pv)
{
struct pv_segment *pvseg;
if (pv->pe_size)
log_print("--- Physical Segments ---");
list_iterate_items(pvseg, &pv->segments) {
log_print("Physical extent %u to %u:",
pvseg->pe, pvseg->pe + pvseg->len - 1);
if (pvseg->lvseg) {
log_print(" Logical volume\t%s%s/%s",
pvseg->lvseg->lv->vg->cmd->dev_dir,
pvseg->lvseg->lv->vg->name,
pvseg->lvseg->lv->name);
log_print(" Logical extents\t%d to %d",
pvseg->lvseg->le, pvseg->lvseg->le +
pvseg->lvseg->len - 1);
} else
log_print(" FREE");
}
log_print(" ");
return;
}
/* FIXME Include label fields */
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
void *handle __attribute((unused)))
{
char uuid[64];
char uuid[64] __attribute((aligned(8)));
const char *size;
uint32_t pe_free;
@@ -309,7 +351,7 @@ int pvdisplay_short(struct cmd_context *cmd __attribute((unused)),
struct physical_volume *pv,
void *handle __attribute((unused)))
{
char uuid[64];
char uuid[64] __attribute((aligned(8)));
if (!pv)
return 0;
@@ -356,7 +398,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
{
struct lvinfo info;
int inkernel, snap_active = 0;
char uuid[64];
char uuid[64] __attribute((aligned(8)));
struct lv_segment *snap_seg = NULL;
float snap_percent; /* fused, fsize; */
@@ -522,7 +564,7 @@ void vgdisplay_full(struct volume_group *vg)
{
uint32_t access;
uint32_t active_pvs;
char uuid[64];
char uuid[64] __attribute((aligned(8)));
if (vg->status & PARTIAL_VG)
active_pvs = list_size(&vg->pvs);
@@ -601,7 +643,7 @@ void vgdisplay_colons(struct volume_group *vg)
{
uint32_t active_pvs;
const char *access;
char uuid[64];
char uuid[64] __attribute((aligned(8)));
if (vg->status & PARTIAL_VG)
active_pvs = list_size(&vg->pvs);

View File

@@ -31,6 +31,7 @@ char *display_uuid(char *uuidstr);
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre);
void pvdisplay_colons(struct physical_volume *pv);
void pvdisplay_segments(struct physical_volume *pv);
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
void *handle);
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,

View File

@@ -23,6 +23,7 @@
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
#include "str_list.h"
static const char *_errseg_name(const struct lv_segment *seg)
{
@@ -40,7 +41,7 @@ static int _errseg_merge_segments(struct lv_segment *seg1, struct lv_segment *se
#ifdef DEVMAPPER_SUPPORT
static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)),
struct dm_pool *mem __attribute((unused)),
struct config_tree *cft __attribute((unused)),
struct cmd_context *cmd __attribute((unused)),
void **target_state __attribute((unused)),
struct lv_segment *seg __attribute((unused)),
struct dm_tree_node *node, uint64_t len,
@@ -49,7 +50,7 @@ static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)),
return dm_tree_node_add_error_target(node, len);
}
static int _errseg_target_present(void)
static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)))
{
static int _errseg_checked = 0;
static int _errseg_present = 0;
@@ -64,6 +65,18 @@ static int _errseg_target_present(void)
}
#endif
static int _errseg_modules_needed(struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules)
{
if (!str_list_add(mem, modules, "error")) {
log_error("error module string list allocation failed");
return 0;
}
return 1;
}
static void _errseg_destroy(const struct segment_type *segtype)
{
dm_free((void *)segtype);
@@ -76,6 +89,7 @@ static struct segtype_handler _error_ops = {
.add_target_line = _errseg_add_target_line,
.target_present = _errseg_target_present,
#endif
.modules_needed = _errseg_modules_needed,
.destroy = _errseg_destroy,
};

View File

@@ -18,14 +18,6 @@
#ifdef linux
/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
#define MD_SB_MAGIC 0xa92b4efc
#define MD_RESERVED_BYTES (64 * 1024)
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
- MD_RESERVED_SECTORS)
static int _ignore_md(struct dev_filter *f, struct device *dev)
{
int ret;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -17,6 +17,7 @@
#include "config.h"
#include "dev-cache.h"
#include "filter-persistent.h"
#include "lvm-file.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -26,11 +27,12 @@ struct pfilter {
char *file;
struct dm_hash_table *devices;
struct dev_filter *real;
time_t ctime;
};
/*
* entries in the table can be in one of these
* states.
* The hash table holds one of these two states
* against each entry.
*/
#define PF_BAD_DEVICE ((void *) 1)
#define PF_GOOD_DEVICE ((void *) 2)
@@ -93,22 +95,26 @@ static int _read_array(struct pfilter *pf, struct config_tree *cft,
return 1;
}
int persistent_filter_load(struct dev_filter *f)
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
{
struct pfilter *pf = (struct pfilter *) f->private;
int r = 0;
struct config_tree *cft;
struct stat info;
int r = 0;
if (!(cft = create_config_tree(pf->file))) {
stack;
return 0;
if (!stat(pf->file, &info))
pf->ctime = info.st_ctime;
else {
log_very_verbose("%s: stat failed: %s", pf->file,
strerror(errno));
return_0;
}
if (!read_config_file(cft)) {
stack;
goto out;
}
if (!(cft = create_config_tree(pf->file, 1)))
return_0;
if (!read_config_file(cft))
goto_out;
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
PF_GOOD_DEVICE);
@@ -126,7 +132,10 @@ int persistent_filter_load(struct dev_filter *f)
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out:
destroy_config_tree(cft);
if (r && cft_out)
*cft_out = cft;
else
destroy_config_tree(cft);
return r;
}
@@ -163,8 +172,12 @@ static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
int persistent_filter_dump(struct dev_filter *f)
{
struct pfilter *pf = (struct pfilter *) f->private;
char *tmp_file;
struct stat info, info2;
struct config_tree *cft = NULL;
FILE *fp;
int lockfd;
int r = 0;
if (!dm_hash_get_num_entries(pf->devices)) {
log_very_verbose("Internal persistent device cache empty "
@@ -179,11 +192,43 @@ int persistent_filter_dump(struct dev_filter *f)
log_very_verbose("Dumping persistent device cache to %s", pf->file);
fp = fopen(pf->file, "w");
if (!fp) {
if (errno != EROFS)
log_sys_error("fopen", pf->file);
return 0;
while (1) {
if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0)
return_0;
/*
* Ensure we locked the file we expected
*/
if (fstat(lockfd, &info)) {
log_sys_error("fstat", pf->file);
goto out;
}
if (stat(pf->file, &info2)) {
log_sys_error("stat", pf->file);
goto out;
}
if (!memcmp(&info.st_ino, &info2.st_ino, sizeof(ino_t)))
break;
fcntl_unlock_file(lockfd);
}
/*
* If file contents changed since we loaded it, merge new contents
*/
if (info.st_ctime != pf->ctime)
/* Keep cft open to avoid losing lock */
persistent_filter_load(f, &cft);
tmp_file = alloca(strlen(pf->file) + 5);
sprintf(tmp_file, "%s.tmp", pf->file);
if (!(fp = fopen(tmp_file, "w"))) {
/* EACCES has been reported over NFS */
if (errno != EROFS && errno != EACCES)
log_sys_error("fopen", tmp_file);
goto out;
}
fprintf(fp, "# This file is automatically maintained by lvm.\n\n");
@@ -194,8 +239,24 @@ int persistent_filter_dump(struct dev_filter *f)
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
fprintf(fp, "}\n");
fclose(fp);
return 1;
if (fclose(fp)) {
log_sys_error("fclose", tmp_file);
goto out;
}
if (rename(tmp_file, pf->file))
log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
strerror(errno));
r = 1;
out:
fcntl_unlock_file(lockfd);
if (cft)
destroy_config_tree(cft);
return r;
}
static int _lookup_p(struct dev_filter *f, struct device *dev)
@@ -240,10 +301,9 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
}
memset(pf, 0, sizeof(*pf));
if (!(pf->file = dm_malloc(strlen(file) + 1))) {
stack;
goto bad;
}
if (!(pf->file = dm_malloc(strlen(file) + 1)))
goto_bad;
strcpy(pf->file, file);
pf->real = real;
@@ -252,10 +312,8 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
goto bad;
}
if (!(f = dm_malloc(sizeof(*f)))) {
stack;
goto bad;
}
if (!(f = dm_malloc(sizeof(*f))))
goto_bad;
f->passes_filter = _lookup_p;
f->destroy = _persistent_destroy;

View File

@@ -22,7 +22,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *f,
const char *file);
int persistent_filter_wipe(struct dev_filter *f);
int persistent_filter_load(struct dev_filter *f);
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
int persistent_filter_dump(struct dev_filter *f);
#endif

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

@@ -32,7 +32,7 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
return 0;
}
if (lvm_snprintf(proc_mounts, sizeof(proc_mounts),
if (dm_snprintf(proc_mounts, sizeof(proc_mounts),
"%s/mounts", proc) < 0) {
log_error("Failed to create /proc/mounts string");
return 0;
@@ -44,9 +44,9 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
}
while (fgets(buffer, sizeof(buffer), fp)) {
if (split_words(buffer, 4, split) == 4 &&
if (dm_split_words(buffer, 4, 0, split) == 4 &&
!strcmp(split[2], "sysfs")) {
if (lvm_snprintf(path, len, "%s/%s", split[1],
if (dm_snprintf(path, len, "%s/%s", split[1],
"block") >= 0) {
r = 1;
}
@@ -54,7 +54,9 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
}
}
fclose(fp);
if (fclose(fp))
log_sys_error("fclose", proc_mounts);
return r;
}
@@ -156,7 +158,9 @@ static int _read_dev(const char *file, dev_t *result)
}
r = _parse_dev(file, fp, result);
fclose(fp);
if (fclose(fp))
log_sys_error("fclose", file);
return r;
}
@@ -183,7 +187,7 @@ static int _read_devs(struct dev_set *ds, const char *dir)
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir,
if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
d->d_name) < 0) {
log_error("sysfs path name too long: %s in %s",
d->d_name, dir);
@@ -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);
@@ -145,7 +154,7 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
/* All types unrecognised initially */
memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
if (dm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return 0;
@@ -182,10 +191,14 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
_md_major = line_maj;
/* Look for device-mapper device */
/* FIXME Cope with multiple majors */
if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
_device_mapper_major = line_maj;
/* Go through the valid device names and if there is a
match store max number of partitions */
for (j = 0; device_info[j].name != NULL; j++) {
dev_len = strlen(device_info[j].name);
if (dev_len <= strlen(line + i) &&
!strncmp(device_info[j].name, line + i, dev_len) &&
@@ -204,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

@@ -248,7 +248,7 @@ static int _read_uuids(struct disk_list *data)
{
unsigned num_read = 0;
struct uuid_list *ul;
char buffer[NAME_LEN];
char buffer[NAME_LEN] __attribute((aligned(8)));
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
@@ -357,10 +357,8 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
list_init(&dl->uuids);
list_init(&dl->lvds);
if (!_read_pvd(dev, &dl->pvd)) {
stack;
goto bad;
}
if (!_read_pvd(dev, &dl->pvd))
goto_bad;
/*
* is it an orphan ?
@@ -458,7 +456,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
/*
* Build a list of pv_d's structures, allocated from mem.
* We keep track of the first object allocated form the pool
* We keep track of the first object allocated from the pool
* so we can free off all the memory if something goes wrong.
*/
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,

View File

@@ -148,7 +148,7 @@ struct pe_disk {
struct uuid_list {
struct list list;
char uuid[NAME_LEN];
char uuid[NAME_LEN] __attribute((aligned(8)));
};
struct lvd_list {
@@ -161,17 +161,18 @@ struct disk_list {
struct dm_pool *mem;
struct device *dev;
struct pv_disk pvd;
struct vg_disk vgd;
struct list uuids;
struct list lvds;
struct pe_disk *extents;
struct pv_disk pvd __attribute((aligned(8)));
struct vg_disk vgd __attribute((aligned(8)));
struct list uuids __attribute((aligned(8)));
struct list lvds __attribute((aligned(8)));
struct pe_disk *extents __attribute((aligned(8)));
};
/*
* Layout constants.
*/
#define METADATA_ALIGN 4096UL
#define LVM1_PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */
#define METADATA_BASE 0UL
#define PV_SIZE 1024UL
@@ -202,8 +203,8 @@ int write_disks(const struct format_type *fmt, struct list *pvds);
* Functions to translate to between disk and in
* core structures.
*/
int import_pv(struct dm_pool *mem, struct device *dev,
struct volume_group *vg,
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
struct device *dev, struct volume_group *vg,
struct physical_volume *pv, struct pv_disk *pvd,
struct vg_disk *vgd);
int export_pv(struct cmd_context *cmd, struct dm_pool *mem,

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);
@@ -312,7 +308,7 @@ static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
goto out;
}
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
stack;
goto out;
}
@@ -408,36 +404,31 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
/* Ensure any residual PE structure is gone */
pv->pe_size = pv->pe_count = 0;
pv->pe_start = PE_ALIGN;
pv->pe_start = LVM1_PE_ALIGN;
if (!(mem = dm_pool_create("lvm1 pv_write", 1024))) {
stack;
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 */
dl->pvd.pv_on_disk.base = METADATA_BASE;
dl->pvd.pv_on_disk.size = PV_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
list_add(&pvs, &dl->list);
if (!write_disks(fmt, &pvs)) {
stack;
goto bad;
}
if (!write_disks(fmt, &pvs))
goto_bad;
dm_pool_destroy(mem);
return 1;

View File

@@ -24,6 +24,7 @@
#include "toolcontext.h"
#include "segtype.h"
#include "pv_alloc.h"
#include "display.h"
#include <time.h>
@@ -47,11 +48,13 @@ static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
return dm_pool_strdup(mem, ptr);
}
int import_pv(struct dm_pool *mem, struct device *dev,
struct volume_group *vg,
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
struct device *dev, struct volume_group *vg,
struct physical_volume *pv, struct pv_disk *pvd,
struct vg_disk *vgd)
{
uint64_t size;
memset(pv, 0, sizeof(*pv));
memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
@@ -89,6 +92,25 @@ int import_pv(struct dm_pool *mem, struct device *dev,
pv->pe_count = pvd->pe_total;
pv->pe_alloc_count = 0;
/* Fix up pv size if missing */
if (!pv->size) {
if (!dev_get_size(dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return 0;
}
log_verbose("Fixing up missing format1 size (%s) "
"for PV %s", display_size(fmt->cmd, pv->size),
dev_name(pv->dev));
if (vg) {
size = pv->pe_count * (uint64_t) vg->extent_size +
pv->pe_start;
if (size > pv->size)
log_error("WARNING: Physical Volume %s is too "
"large for underlying device",
dev_name(pv->dev));
}
}
list_init(&pv->tags);
list_init(&pv->segments);
@@ -103,7 +125,7 @@ int import_pv(struct dm_pool *mem, struct device *dev,
static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
{
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
prefix, cmd->hostname, time(NULL)) < 0) {
log_error("Generated system_id too long");
return 0;
@@ -427,7 +449,7 @@ int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
return 0;
}
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
stack;
return 0;
}

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

@@ -153,7 +153,7 @@ int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
if (pe_start && end < pe_start)
end = pe_start;
pvd->pe_start = _round_up(end, PE_ALIGN);
pvd->pe_start = _round_up(end, LVM1_PE_ALIGN);
} while ((pvd->pe_start + (pvd->pe_total * extent_size))
> pv->size);

View File

@@ -30,7 +30,7 @@ static void _not_supported(const char *op)
op);
}
static int _lvm1_can_handle(struct labeller *l, char *buf, uint64_t sector)
static int _lvm1_can_handle(struct labeller *l, void *buf, uint64_t sector)
{
struct pv_disk *pvd = (struct pv_disk *) buf;
uint32_t version;
@@ -48,13 +48,13 @@ static int _lvm1_can_handle(struct labeller *l, char *buf, uint64_t sector)
return 0;
}
static int _lvm1_write(struct label *label, char *buf)
static int _lvm1_write(struct label *label, void *buf)
{
_not_supported("write");
return 0;
}
static int _lvm1_read(struct labeller *l, struct device *dev, char *buf,
static int _lvm1_read(struct labeller *l, struct device *dev, void *buf,
struct label **label)
{
struct pv_disk *pvd = (struct pv_disk *) buf;

View File

@@ -36,7 +36,7 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
struct dm_pool *mem, struct pool_list *pl,
const char *vg_name)
{
char buf[512];
char buf[512] __attribute((aligned(8)));
/* FIXME: Need to check the cache here first */
if (!dev_read(dev, UINT64_C(0), 512, buf)) {
@@ -59,7 +59,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data)
list_iterate_items(pl, head) {
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
char uuid[ID_LEN + 7];
char uuid[ID_LEN + 7] __attribute((aligned(8)));
id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
@@ -84,7 +84,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
struct lvmcache_info *info;
struct id pvid;
struct id vgid;
char uuid[ID_LEN + 7];
char uuid[ID_LEN + 7] __attribute((aligned(8)));
struct pool_disk *pd = &pl->pd;
pool_label_in(pd, buf);
@@ -128,7 +128,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
* be able to interpret ondisk labels correctly. Always use
* this function before writing to disk.
*/
void pool_label_out(struct pool_disk *pl, char *buf)
void pool_label_out(struct pool_disk *pl, void *buf)
{
struct pool_disk *bufpl = (struct pool_disk *) buf;
@@ -163,7 +163,7 @@ void pool_label_out(struct pool_disk *pl, char *buf)
* correctly. Always use this function before using labels that
* were read from disk.
*/
void pool_label_in(struct pool_disk *pl, char *buf)
void pool_label_in(struct pool_disk *pl, void *buf)
{
struct pool_disk *bufpl = (struct pool_disk *) buf;

View File

@@ -134,8 +134,8 @@ struct user_device {
int read_pool_label(struct pool_list *pl, struct labeller *l,
struct device *dev, char *buf, struct label **label);
void pool_label_out(struct pool_disk *pl, char *buf);
void pool_label_in(struct pool_disk *pl, char *buf);
void pool_label_out(struct pool_disk *pl, void *buf);
void pool_label_in(struct pool_disk *pl, void *buf);
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid);
int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct list *pls);
int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem,

View File

@@ -29,7 +29,7 @@ static void _pool_not_supported(const char *op)
op);
}
static int _pool_can_handle(struct labeller *l, char *buf, uint64_t sector)
static int _pool_can_handle(struct labeller *l, void *buf, uint64_t sector)
{
struct pool_disk pd;
@@ -50,13 +50,13 @@ static int _pool_can_handle(struct labeller *l, char *buf, uint64_t sector)
return 0;
}
static int _pool_write(struct label *label, char *buf)
static int _pool_write(struct label *label, void *buf)
{
_pool_not_supported("write");
return 0;
}
static int _pool_read(struct labeller *l, struct device *dev, char *buf,
static int _pool_read(struct labeller *l, struct device *dev, void *buf,
struct label **label)
{
struct pool_list pl;

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.
@@ -277,7 +283,7 @@ int archive_vg(struct volume_group *vg,
}
for (i = 0; i < 10; i++) {
if (lvm_snprintf(archive_name, sizeof(archive_name),
if (dm_snprintf(archive_name, sizeof(archive_name),
"%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
log_error("Archive file name too long.");
return 0;
@@ -356,6 +362,22 @@ int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
return 1;
}
int archive_list_file(struct cmd_context *cmd, const char *file)
{
struct archive_file af;
af.path = (char *)file;
if (!path_exists(af.path)) {
log_err("Archive file %s not found.", af.path);
return 0;
}
_display_archive(cmd, &af);
return 1;
}
int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname)
{
struct archive_file af;

View File

@@ -148,6 +148,17 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
return r1 && r2;
}
int archive_display_file(struct cmd_context *cmd, const char *file)
{
int r;
init_partial(1);
r = archive_list_file(cmd, file);
init_partial(0);
return r;
}
int backup_init(struct cmd_context *cmd, const char *dir)
{
if (!(cmd->backup_params = dm_pool_zalloc(cmd->libmem,
@@ -190,7 +201,7 @@ static int __backup(struct volume_group *vg)
return 0;
}
if (lvm_snprintf(name, sizeof(name), "%s/%s",
if (dm_snprintf(name, sizeof(name), "%s/%s",
vg->cmd->backup_params->dir, vg->name) < 0) {
log_error("Failed to generate volume group metadata backup "
"filename.");
@@ -233,7 +244,7 @@ int backup_remove(struct cmd_context *cmd, const char *vg_name)
{
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/%s",
if (dm_snprintf(path, sizeof(path), "%s/%s",
cmd->backup_params->dir, vg_name) < 0) {
log_err("Failed to generate backup filename (for removal).");
return 0;
@@ -342,7 +353,7 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
{
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/%s",
if (dm_snprintf(path, sizeof(path), "%s/%s",
cmd->backup_params->dir, vg_name) < 0) {
log_err("Failed to generate backup filename (for restore).");
return 0;
@@ -397,7 +408,7 @@ void check_current_backup(struct volume_group *vg)
if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
return;
if (lvm_snprintf(path, sizeof(path), "%s/%s",
if (dm_snprintf(path, sizeof(path), "%s/%s",
vg->cmd->backup_params->dir, vg->name) < 0) {
log_debug("Failed to generate backup filename.");
return;

View File

@@ -38,6 +38,7 @@ void archive_exit(struct cmd_context *cmd);
void archive_enable(struct cmd_context *cmd, int flag);
int archive(struct volume_group *vg);
int archive_display(struct cmd_context *cmd, const char *vg_name);
int archive_display_file(struct cmd_context *cmd, const char *file);
int backup_init(struct cmd_context *cmd, const char *dir);
void backup_exit(struct cmd_context *cmd);

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);
@@ -221,6 +221,8 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
"Megabytes",
"Gigabytes",
"Terabytes",
"Petabytes",
"Exabytes",
NULL
};
@@ -233,7 +235,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
for (i = 0; (d > 1024.0) && _units[i]; i++)
d /= 1024.0;
return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
}
/*
@@ -409,6 +411,11 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
outf(f, "tags = %s", buffer);
}
if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size)) {
stack;
return 0;
}
outf(f, "pe_start = %" PRIu64, pv->pe_start);
if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
"pe_count = %u", pv->pe_count)) {
@@ -613,46 +620,27 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
struct physical_volume *pv;
char buffer[32], *name;
if (!(f->mem = dm_pool_create("text pv_names", 512))) {
stack;
goto bad;
}
if (!(f->mem = dm_pool_create("text pv_names", 512)))
return_0;
if (!(f->pv_names = dm_hash_create(128))) {
stack;
goto bad;
}
if (!(f->pv_names = dm_hash_create(128)))
return_0;
list_iterate_items(pvl, &vg->pvs) {
pv = pvl->pv;
/* FIXME But skip if there's already an LV called pv%d ! */
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
stack;
goto bad;
}
if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
return_0;
if (!(name = dm_pool_strdup(f->mem, buffer))) {
stack;
goto bad;
}
if (!(name = dm_pool_strdup(f->mem, buffer)))
return_0;
if (!dm_hash_insert(f->pv_names, dev_name(pv->dev), name)) {
stack;
goto bad;
}
if (!dm_hash_insert(f->pv_names, dev_name(pv->dev), name))
return_0;
}
return 1;
bad:
if (f->mem)
dm_pool_destroy(f->mem);
if (f->pv_names)
dm_hash_destroy(f->pv_names);
return 0;
}
static int _text_vg_export(struct formatter *f,
@@ -664,35 +652,33 @@ static int _text_vg_export(struct formatter *f,
stack;
goto out;
}
#define fail do {stack; goto out;} while(0)
if (f->header && !_print_header(f, desc))
fail;
goto_out;
if (!out_text(f, "%s {", vg->name))
fail;
goto_out;
_inc_indent(f);
if (!_print_vg(f, vg))
fail;
goto_out;
outnl(f);
if (!_print_pvs(f, vg))
fail;
goto_out;
outnl(f);
if (!_print_lvs(f, vg))
fail;
goto_out;
_dec_indent(f);
if (!out_text(f, "}"))
fail;
goto_out;
if (!f->header && !_print_header(f, desc))
fail;
goto_out;
#undef fail
r = 1;
out:

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)
{
@@ -132,37 +293,40 @@ static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) {
stack;
dm_pool_free(fmt->cmd->mem, mdah);
return NULL;
goto error;
}
if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)))) {
log_error("Incorrect metadata area header checksum");
return NULL;
goto error;
}
_xlate_mdah(mdah);
if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
log_error("Wrong magic number in metadata area header");
return NULL;
goto error;
}
if (mdah->version != FMTT_VERSION) {
log_error("Incompatible metadata area header version: %d",
mdah->version);
return NULL;
goto error;
}
if (mdah->start != dev_area->start) {
log_error("Incorrect start sector in metadata area header: %"
PRIu64, mdah->start);
return NULL;
goto error;
}
return mdah;
error:
dm_pool_free(fmt->cmd->mem, mdah);
return NULL;
}
static int _raw_write_mda_header(const struct format_type *fmt,
@@ -193,7 +357,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
int *precommitted)
{
size_t len;
char vgnamebuf[NAME_LEN + 2];
char vgnamebuf[NAME_LEN + 2] __attribute((aligned(8)));
struct raw_locn *rlocn, *rlocn_precommitted;
struct lvmcache_info *info;
@@ -707,7 +871,8 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
if (!(fp = fdopen(fd, "w"))) {
log_sys_error("fdopen", temp_file);
close(fd);
if (close(fd))
log_sys_error("fclose", temp_file);
return 0;
}
@@ -715,13 +880,15 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
if (!text_vg_export_file(vg, tc->desc, fp)) {
log_error("Failed to write metadata to %s.", temp_file);
fclose(fp);
if (fclose(fp))
log_sys_error("fclose", temp_file);
return 0;
}
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
log_sys_error("fsync", tc->path_edit);
fclose(fp);
if (fclose(fp))
log_sys_error("fclose", tc->path_edit);
return 0;
}
@@ -853,7 +1020,7 @@ static int _scan_file(const struct format_type *fmt)
tmp != dirent->d_name + strlen(dirent->d_name)
- 4)) {
vgname = dirent->d_name;
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
if (dm_snprintf(path, PATH_MAX, "%s/%s",
dl->dir, vgname) < 0) {
log_error("Name too long %s/%s",
dl->dir, vgname);
@@ -885,8 +1052,8 @@ const char *vgname_from_mda(const struct format_type *fmt,
uint32_t wrap = 0;
const char *vgname = NULL;
unsigned int len = 0;
char buf[NAME_LEN + 1];
char uuid[64];
char buf[NAME_LEN + 1] __attribute((aligned(8)));
char uuid[64] __attribute((aligned(8)));
if (!dev_open(dev_area->dev)) {
stack;
@@ -994,7 +1161,7 @@ static int _text_scan(const struct format_type *fmt)
}
/* For orphan, creates new mdas according to policy.
Always have an mda between end-of-label and PE_ALIGN boundary */
Always have an mda between end-of-label and pe_align() boundary */
static int _mda_setup(const struct format_type *fmt,
uint64_t pe_start, uint64_t pe_end,
int pvmetadatacopies,
@@ -1005,15 +1172,12 @@ static int _mda_setup(const struct format_type *fmt,
uint64_t start1, mda_size1; /* First area - start of disk */
uint64_t start2, mda_size2; /* Second area - end of disk */
uint64_t wipe_size = 8 << SECTOR_SHIFT;
size_t pagesize = getpagesize();
size_t pagesize = lvm_getpagesize();
if (!pvmetadatacopies) {
/* Space available for PEs */
pv->size -= PE_ALIGN;
if (!pvmetadatacopies)
return 1;
}
alignment = PE_ALIGN << SECTOR_SHIFT;
alignment = pe_align() << SECTOR_SHIFT;
disk_size = pv->size << SECTOR_SHIFT;
pe_start <<= SECTOR_SHIFT;
pe_end <<= SECTOR_SHIFT;
@@ -1027,9 +1191,6 @@ static int _mda_setup(const struct format_type *fmt,
/* Requested metadatasize */
mda_size1 = pvmetadatasize << SECTOR_SHIFT;
/* Space available for PEs (before any mdas created) */
pv->size -= LABEL_SCAN_SECTORS;
/* Place mda straight after label area at start of disk */
start1 = LABEL_SCAN_SIZE;
@@ -1037,11 +1198,8 @@ static int _mda_setup(const struct format_type *fmt,
if ((!pe_start && !pe_end) ||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
mda_adjustment = start1 % pagesize;
if (mda_adjustment) {
if (mda_adjustment)
start1 += (pagesize - mda_adjustment);
pv->size -= ((pagesize - mda_adjustment) >>
SECTOR_SHIFT);
}
}
/* Ensure it's not going to be bigger than the disk! */
@@ -1055,7 +1213,7 @@ static int _mda_setup(const struct format_type *fmt,
pvmetadatacopies = 1;
}
/* Round up to PE_ALIGN boundary */
/* Round up to pe_align() boundary */
mda_adjustment = (mda_size1 + start1) % alignment;
if (mda_adjustment)
mda_size1 += (alignment - mda_adjustment);
@@ -1071,7 +1229,8 @@ static int _mda_setup(const struct format_type *fmt,
/* FIXME If creating new mdas, wipe them! */
if (mda_size1) {
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
mda_size1)) return 0;
mda_size1))
return 0;
if (!dev_set((struct device *) pv->dev, start1,
(size_t) (mda_size1 >
@@ -1080,7 +1239,6 @@ static int _mda_setup(const struct format_type *fmt,
return 0;
}
pv->size -= mda_size1 >> SECTOR_SHIFT;
if (pvmetadatacopies == 1)
return 1;
} else
@@ -1125,7 +1283,6 @@ static int _mda_setup(const struct format_type *fmt,
log_error("Failed to wipe new metadata area");
return 0;
}
pv->size -= mda_size2 >> SECTOR_SHIFT;
} else
return 0;
@@ -1141,7 +1298,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
struct lvmcache_info *info;
struct mda_context *mdac;
struct metadata_area *mda;
char buf[MDA_HEADER_SIZE];
char buf[MDA_HEADER_SIZE] __attribute((aligned(8)));
struct mda_header *mdah = (struct mda_header *) buf;
uint64_t adjustment;
@@ -1189,18 +1346,18 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
/* Set pe_start to first aligned sector after any metadata
* areas that begin before pe_start */
pv->pe_start = PE_ALIGN;
pv->pe_start = pe_align();
list_iterate_items(mda, &info->mdas) {
mdac = (struct mda_context *) mda->metadata_locn;
if (pv->dev == mdac->area.dev &&
(mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) &&
(mdac->area.start <= (pv->pe_start << SECTOR_SHIFT)) &&
(mdac->area.start + mdac->area.size >
(pv->pe_start << SECTOR_SHIFT))) {
pv->pe_start = (mdac->area.start + mdac->area.size)
>> SECTOR_SHIFT;
adjustment = pv->pe_start % PE_ALIGN;
adjustment = pv->pe_start % pe_align();
if (adjustment)
pv->pe_start += (PE_ALIGN - adjustment);
pv->pe_start += (pe_align() - adjustment);
}
}
if (!add_da
@@ -1275,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;
}
@@ -1399,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 */
@@ -1416,8 +1575,9 @@ static int _text_pv_setup(const struct format_type *fmt,
struct lvmcache_info *info;
int found;
uint64_t pe_end = 0;
/* FIXME if vg, adjust start/end of pe area to avoid mdas! */
unsigned mda_count = 0;
uint64_t mda_size2 = 0;
uint64_t pe_count;
/* FIXME Cope with pvchange */
/* FIXME Merge code with _text_create_text_instance */
@@ -1428,11 +1588,16 @@ static int _text_pv_setup(const struct format_type *fmt,
if ((info = info_from_pvid(pv->dev->pvid))) {
pvmdas = &info->mdas;
list_iterate_items(mda, pvmdas) {
mda_count++;
mdac =
(struct mda_context *) mda->metadata_locn;
/* FIXME Check it isn't already in use */
/* Reduce usable device size */
if (mda_count > 1)
mda_size2 = mdac->area.size >> SECTOR_SHIFT;
/* Ensure it isn't already on list */
found = 0;
list_iterate_items(mda2, mdas) {
@@ -1470,6 +1635,26 @@ static int _text_pv_setup(const struct format_type *fmt,
}
}
/* FIXME Cope with genuine pe_count 0 */
/* If missing, estimate pv->size from file-based metadata */
if (!pv->size && pv->pe_count)
pv->size = pv->pe_count * (uint64_t) vg->extent_size +
pv->pe_start + mda_size2;
/* Recalculate number of extents that will fit */
if (!pv->pe_count) {
pe_count = (pv->size - pv->pe_start - mda_size2) /
vg->extent_size;
if (pe_count > UINT32_MAX) {
log_error("PV %s too large for extent size %s.",
dev_name(pv->dev),
display_size(vg->cmd, (uint64_t) vg->extent_size));
return 0;
}
pv->pe_count = (uint32_t) pe_count;
}
/* Unlike LVM1, we don't store this outside a VG */
/* FIXME Default from config file? vgextend cmdline flag? */
pv->status |= ALLOCATABLE_PV;
@@ -1533,7 +1718,7 @@ static struct format_instance *_text_create_text_instance(const struct format_ty
dir_list = &((struct mda_lists *) fmt->private)->dirs;
list_iterate_items(dl, dir_list) {
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
if (dm_snprintf(path, PATH_MAX, "%s/%s",
dl->dir, vgname) < 0) {
log_error("Name too long %s/%s", dl->dir,
vgname);
@@ -1726,7 +1911,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
}
if (!(dev_area.dev = device_from_pvid(cmd, &id))) {
char buffer[64];
char buffer[64] __attribute((aligned(8)));
if (!id_write_format(&id, buffer, sizeof(buffer)))
log_err("Couldn't find device.");
@@ -1783,7 +1968,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
return NULL;
}
if ((cn = find_config_node(cmd->cft->root, "metadata/dirs"))) {
if ((cn = find_config_tree_node(cmd, "metadata/dirs"))) {
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
@@ -1799,7 +1984,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
}
}
if ((cn = find_config_node(cmd->cft->root, "metadata/disk_areas"))) {
if ((cn = find_config_tree_node(cmd, "metadata/disk_areas"))) {
for (cn = cn->child; cn; cn = cn->sib) {
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
goto err;

View File

@@ -33,6 +33,7 @@ int archive_vg(struct volume_group *vg,
* Displays a list of vg backups in a particular archive directory.
*/
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname);
int archive_list_file(struct cmd_context *cmd, const char *file);
int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname);
/*

View File

@@ -43,7 +43,7 @@ const char *text_vgname_import(const struct format_type *fmt,
_text_import_initialised = 1;
}
if (!(cft = create_config_tree(NULL)))
if (!(cft = create_config_tree(NULL, 0)))
return_NULL;
if ((!dev && !read_config_file(cft)) ||
@@ -94,7 +94,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
*desc = NULL;
*when = 0;
if (!(cft = create_config_tree(file)))
if (!(cft = create_config_tree(file, 0)))
return_NULL;
if ((!dev && !read_config_file(cft)) ||

View File

@@ -116,6 +116,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
struct physical_volume *pv;
struct pv_list *pvl;
struct config_node *cn;
uint64_t size;
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) {
@@ -148,7 +149,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
* Convert the uuid into a device.
*/
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
char buffer[64];
char buffer[64] __attribute((aligned(8)));
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_error("Couldn't find device.");
@@ -179,6 +180,9 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
return 0;
}
/* Late addition */
_read_int64(pvn, "dev_size", &pv->size);
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
log_error("Couldn't read extent size for volume group.");
return 0;
@@ -206,10 +210,29 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
vg->free_count += pv->pe_count;
pv->pe_size = vg->extent_size;
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;
/* Fix up pv size if missing */
if (!pv->size && pv->dev) {
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return 0;
}
log_verbose("Fixing up missing format1 size (%s) "
"for PV %s", display_size(fid->fmt->cmd, pv->size),
dev_name(pv->dev));
if (vg) {
size = pv->pe_count * (uint64_t) vg->extent_size +
pv->pe_start;
if (size > pv->size)
log_error("WARNING: Physical Volume %s is too "
"large for underlying device",
dev_name(pv->dev));
}
}
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
@@ -637,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

@@ -83,6 +83,6 @@ struct mda_context {
#define FMTT_VERSION 1
#define MDA_HEADER_SIZE 512
#define LVM2_LABEL "LVM2 001"
#define MDA_SIZE_MIN (8 * (unsigned) getpagesize())
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#endif

View File

@@ -24,7 +24,7 @@
#include <fcntl.h>
static int _text_can_handle(struct labeller *l __attribute((unused)),
char *buf,
void *buf,
uint64_t sector __attribute((unused)))
{
struct label_header *lh = (struct label_header *) buf;
@@ -35,7 +35,7 @@ static int _text_can_handle(struct labeller *l __attribute((unused)),
return 0;
}
static int _text_write(struct label *label, char *buf)
static int _text_write(struct label *label, void *buf)
{
struct label_header *lh = (struct label_header *) buf;
struct pv_header *pvhdr;
@@ -189,7 +189,7 @@ static int _text_initialise_label(struct labeller *l __attribute((unused)),
return 1;
}
static int _text_read(struct labeller *l, struct device *dev, char *buf,
static int _text_read(struct labeller *l, struct device *dev, void *buf,
struct label **label)
{
struct label_header *lh = (struct label_header *) buf;

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;
@@ -115,14 +116,15 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
struct lvmcache_info *info;
uint64_t sector;
int found = 0;
char readbuf[LABEL_SCAN_SIZE];
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
LABEL_SCAN_SIZE, readbuf)) {
log_debug("%s: Failed to read label area", dev_name(dev));
goto out;
}
/* Scan first few sectors for a valid label */
/* Scan a few sectors for a valid label */
for (sector = 0; sector < LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
lh = (struct label_header *) (readbuf +
@@ -132,13 +134,14 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
if (found) {
log_error("Ignoring additional label on %s at "
"sector %" PRIu64, dev_name(dev),
sector);
sector + scan_sector);
}
if (xlate64(lh->sector_xl) != sector) {
if (xlate64(lh->sector_xl) != sector + scan_sector) {
log_info("%s: Label for sector %" PRIu64
" found at sector %" PRIu64
" - ignoring", dev_name(dev),
xlate64(lh->sector_xl), sector);
xlate64(lh->sector_xl),
sector + scan_sector);
continue;
}
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
@@ -153,19 +156,21 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
}
list_iterate_items(li, &_labellers) {
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
if (li->l->ops->can_handle(li->l, (char *) lh,
sector + scan_sector)) {
log_very_verbose("%s: %s label detected",
dev_name(dev), li->name);
if (found) {
log_error("Ignoring additional label "
"on %s at sector %" PRIu64,
dev_name(dev), sector);
dev_name(dev),
sector + scan_sector);
continue;
}
r = li->l;
memcpy(buf, lh, LABEL_SIZE);
if (label_sector)
*label_sector = sector;
*label_sector = sector + scan_sector;
found = 1;
break;
}
@@ -186,8 +191,8 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
/* FIXME Also wipe associated metadata area headers? */
int label_remove(struct device *dev)
{
char buf[LABEL_SIZE];
char readbuf[LABEL_SCAN_SIZE];
char buf[LABEL_SIZE] __attribute((aligned(8)));
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
int r = 1;
uint64_t sector;
int wipe;
@@ -256,9 +261,10 @@ int label_remove(struct device *dev)
}
/* FIXME Avoid repeated re-reading if cache lock held */
int label_read(struct device *dev, struct label **result)
int label_read(struct device *dev, struct label **result,
uint64_t scan_sector)
{
char buf[LABEL_SIZE];
char buf[LABEL_SIZE] __attribute((aligned(8)));
struct labeller *l;
uint64_t sector;
struct lvmcache_info *info;
@@ -271,10 +277,10 @@ int label_read(struct device *dev, struct label **result)
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
0, NULL);
goto out;
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)
@@ -290,7 +296,7 @@ int label_read(struct device *dev, struct label **result)
/* Caller may need to use label_get_handler to create label struct! */
int label_write(struct device *dev, struct label *label)
{
char buf[LABEL_SIZE];
char buf[LABEL_SIZE] __attribute((aligned(8)));
struct label_header *lh = (struct label_header *) buf;
int r = 1;
@@ -341,22 +347,20 @@ int label_write(struct device *dev, struct label *label)
int label_verify(struct device *dev)
{
struct labeller *l;
char buf[LABEL_SIZE];
char buf[LABEL_SIZE] __attribute((aligned(8)));
uint64_t sector;
struct lvmcache_info *info;
int r = 0;
if (!dev_open(dev)) {
stack;
if ((info = info_from_pvid(dev->pvid)))
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
0, NULL);
goto out;
return_0;
}
if (!(l = _find_labeller(dev, buf, &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

@@ -49,23 +49,23 @@ struct label_ops {
/*
* Is the device labelled with this format ?
*/
int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
int (*can_handle) (struct labeller * l, void *buf, uint64_t sector);
/*
* Write a label to a volume.
*/
int (*write) (struct label * label, char *buf);
int (*write) (struct label * label, void *buf);
/*
* Read a label from a volume.
*/
int (*read) (struct labeller * l, struct device * dev,
char *buf, struct label ** label);
void *buf, struct label ** label);
/*
* Additional consistency checks for the paranoid.
*/
int (*verify) (struct labeller * l, char *buf, uint64_t sector);
int (*verify) (struct labeller * l, void *buf, uint64_t sector);
/*
* Populate label_type etc.
@@ -96,7 +96,8 @@ int label_register_handler(const char *name, struct labeller *handler);
struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev);
int label_read(struct device *dev, struct label **result);
int label_read(struct device *dev, struct label **result,
uint64_t scan_sector);
int label_write(struct device *dev, struct label *label);
int label_verify(struct device *dev);
struct label *label_create(struct labeller *labeller);

View File

@@ -94,7 +94,7 @@ static int _open_local_sock(void)
/* Send a request and return the status */
static int _send_request(char *inbuf, int inlen, char **retbuf)
{
char outbuf[PIPE_BUF];
char outbuf[PIPE_BUF] __attribute((aligned(8)));
struct clvm_header *outheader = (struct clvm_header *) outbuf;
int len;
int off;
@@ -195,8 +195,7 @@ static void _build_header(struct clvm_header *head, int cmd, const char *node,
static int _cluster_request(char cmd, const char *node, void *data, int len,
lvm_response_t ** response, int *num)
{
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
int *outptr;
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute((aligned(8)));
char *inptr;
char *retbuf = NULL;
int status;
@@ -236,17 +235,13 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
* With an extra pair of INTs on the front to sanity
* check the pointer when we are given it back to free
*/
outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
sizeof(int) * 2);
if (!outptr) {
*response = dm_malloc(sizeof(lvm_response_t) * num_responses);
if (!*response) {
errno = ENOMEM;
status = 0;
goto out;
}
*response = (lvm_response_t *) (outptr + 2);
outptr[0] = LVM_SIGNATURE;
outptr[1] = num_responses;
rarray = *response;
/* Unpack the response into an lvm_response_t array */
@@ -256,7 +251,7 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
strcpy(rarray[i].node, inptr);
inptr += strlen(inptr) + 1;
rarray[i].status = *(int *) inptr;
memcpy(&rarray[i].status, inptr, sizeof(int));
inptr += sizeof(int);
rarray[i].response = dm_malloc(strlen(inptr) + 1);
@@ -265,7 +260,7 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
int j;
for (j = 0; j < i; j++)
dm_free(rarray[i].response);
free(outptr);
free(*response);
errno = ENOMEM;
status = -1;
goto out;
@@ -287,25 +282,15 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
}
/* Free reply array */
static int _cluster_free_request(lvm_response_t * response)
static int _cluster_free_request(lvm_response_t * response, int num)
{
int *ptr = (int *) response - 2;
int i;
int num;
/* Check it's ours to free */
if (response == NULL || *ptr != LVM_SIGNATURE) {
errno = EINVAL;
return 0;
}
num = ptr[1];
for (i = 0; i < num; i++) {
dm_free(response[i].response);
}
dm_free(ptr);
dm_free(response);
return 1;
}
@@ -333,9 +318,12 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
if (partial_mode())
args[1] |= LCK_PARTIAL_MODE;
if (mirror_sync())
if (mirror_in_sync())
args[1] |= LCK_MIRROR_NOSYNC_MODE;
if (dmeventd_monitor_mode())
args[1] |= LCK_DMEVENTD_MONITOR_MODE;
/*
* VG locks are just that: locks, and have no side effects
* so we only need to do them on the local node because all
@@ -371,7 +359,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
}
saved_errno = errno;
_cluster_free_request(response);
_cluster_free_request(response, num_responses);
errno = saved_errno;
return status;
@@ -395,9 +383,9 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
case LCK_VG:
/* If the VG name is empty then lock the unused PVs */
if (!*resource)
lvm_snprintf(lockname, sizeof(lockname), "P_orphans");
dm_snprintf(lockname, sizeof(lockname), "P_orphans");
else
lvm_snprintf(lockname, sizeof(lockname), "V_%s",
dm_snprintf(lockname, sizeof(lockname), "V_%s",
resource);
cluster_cmd = CLVMD_CMD_LOCK_VG;
@@ -449,7 +437,7 @@ void reset_locking(void)
}
#ifdef CLUSTER_LOCKING_INTERNAL
int init_cluster_locking(struct locking_type *locking, struct config_tree *cft)
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
{
locking->lock_resource = _lock_resource;
locking->fin_locking = _locking_end;

View File

@@ -17,6 +17,7 @@
#include "locking_types.h"
#include "defaults.h"
#include "sharedlib.h"
#include "toolcontext.h"
static void *_locking_lib = NULL;
static void (*_reset_fn) (void) = NULL;
@@ -55,7 +56,7 @@ static void _reset_external_locking(void)
_reset_fn();
}
int init_external_locking(struct locking_type *locking, struct config_tree *cft)
int init_external_locking(struct locking_type *locking, struct cmd_context *cmd)
{
const char *libname;
@@ -69,10 +70,10 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
locking->reset_locking = _reset_external_locking;
locking->flags = 0;
libname = find_config_str(cft->root, "global/locking_library",
DEFAULT_LOCKING_LIB);
libname = find_config_tree_str(cmd, "global/locking_library",
DEFAULT_LOCKING_LIB);
if (!(_locking_lib = load_shared_library(cft, libname, "locking", 1))) {
if (!(_locking_lib = load_shared_library(cmd, libname, "locking", 1))) {
stack;
return 0;
}
@@ -90,5 +91,5 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
}
log_verbose("Loaded external locking library %s", libname);
return _init_fn(2, cft, &locking->flags);
return _init_fn(2, cmd->cft, &locking->flags);
}

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) {
@@ -212,10 +212,10 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG:
if (!*resource)
lvm_snprintf(lockfile, sizeof(lockfile),
dm_snprintf(lockfile, sizeof(lockfile),
"%s/P_orphans", _lock_dir);
else
lvm_snprintf(lockfile, sizeof(lockfile),
dm_snprintf(lockfile, sizeof(lockfile),
"%s/V_%s", _lock_dir, resource);
if (!_lock_file(lockfile, flags))
@@ -271,7 +271,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
return 1;
}
int init_file_locking(struct locking_type *locking, struct config_tree *cft)
int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
{
locking->lock_resource = _file_lock_resource;
locking->reset_locking = _reset_file_locking;
@@ -279,8 +279,8 @@ int init_file_locking(struct locking_type *locking, struct config_tree *cft)
locking->flags = 0;
/* Get lockfile directory from config file */
strncpy(_lock_dir, find_config_str(cft->root, "global/locking_dir",
DEFAULT_LOCK_DIR),
strncpy(_lock_dir, find_config_tree_str(cmd, "global/locking_dir",
DEFAULT_LOCK_DIR),
sizeof(_lock_dir));
if (!create_dir(_lock_dir))

View File

@@ -20,6 +20,7 @@
#include "activate.h"
#include "toolcontext.h"
#include "memlock.h"
#include "defaults.h"
#include <signal.h>
#include <sys/stat.h>
@@ -33,6 +34,87 @@ static int _vg_lock_count = 0; /* Number of locks held */
static int _vg_write_lock_held = 0; /* VG write lock held? */
static int _signals_blocked = 0;
static volatile sig_atomic_t _sigint_caught = 0;
static volatile sig_atomic_t _handler_installed;
static struct sigaction _oldhandler;
static int _oldmasked;
static void _catch_sigint(int unused __attribute__((unused)))
{
_sigint_caught = 1;
}
int sigint_caught() {
return _sigint_caught;
}
void sigint_clear()
{
_sigint_caught = 0;
}
/* Temporarily allow keyboard interrupts to be intercepted and noted;
saves interrupt handler state for sigint_restore(). Users should
use the sigint_caught() predicate to check whether interrupt was
requested and act appropriately. Interrupt flags are never
automatically cleared by this code, but lvm_run_command() clears
the flag before running any command. All other places where the
flag needs to be cleared need to call sigint_clear(). */
void sigint_allow()
{
struct sigaction handler;
sigset_t sigs;
/* do not overwrite the backed up handler data with our
override ones; we just increase nesting count */
if (_handler_installed) {
_handler_installed++;
return;
}
/* grab old sigaction for SIGINT; shall not fail */
sigaction(SIGINT, NULL, &handler);
handler.sa_flags &= ~SA_RESTART; /* clear restart flag */
handler.sa_handler = _catch_sigint;
_handler_installed = 1;
/* override the signal handler; shall not fail */
sigaction(SIGINT, &handler, &_oldhandler);
/* unmask SIGINT, remember to mask it again on restore */
sigprocmask(0, NULL, &sigs);
if ((_oldmasked = sigismember(&sigs, SIGINT))) {
sigdelset(&sigs, SIGINT);
sigprocmask(SIG_SETMASK, &sigs, NULL);
}
}
void sigint_restore()
{
/* extra call, ignore */
if (!_handler_installed)
return;
if (_handler_installed > 1) {
_handler_installed--;
return;
}
/* nesting count went down to 0 */
_handler_installed = 0;
if (_oldmasked) {
sigset_t sigs;
sigprocmask(0, NULL, &sigs);
sigaddset(&sigs, SIGINT);
sigprocmask(SIG_SETMASK, &sigs, NULL);
}
sigaction(SIGINT, &_oldhandler, NULL);
}
static void _block_signals(int flags __attribute((unused)))
{
sigset_t set;
@@ -122,36 +204,43 @@ static void _update_vg_lock_count(int flags)
/*
* Select a locking type
*/
int init_locking(int type, struct config_tree *cft)
int init_locking(int type, struct cmd_context *cmd)
{
init_lockingfailed(0);
switch (type) {
case 0:
init_no_locking(&_locking, cft);
init_no_locking(&_locking, cmd);
log_print("WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
return 1;
case 1:
if (!init_file_locking(&_locking, cft))
log_very_verbose("File-based locking selected.");
if (!init_file_locking(&_locking, cmd))
break;
log_very_verbose("File-based locking enabled.");
return 1;
#ifdef HAVE_LIBDL
case 2:
if (!init_external_locking(&_locking, cft))
if (!cmd->is_static) {
log_very_verbose("External locking selected.");
if (init_external_locking(&_locking, cmd))
return 1;
}
if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))
break;
log_very_verbose("External locking enabled.");
return 1;
#endif
#ifdef CLUSTER_LOCKING_INTERNAL
log_very_verbose("Falling back to internal clustered locking.");
/* Fall through */
case 3:
if (!init_cluster_locking(&_locking, cft))
log_very_verbose("Cluster locking selected.");
if (!init_cluster_locking(&_locking, cmd))
break;
log_very_verbose("Cluster locking enabled.");
return 1;
#endif
@@ -160,13 +249,23 @@ int init_locking(int type, struct config_tree *cft)
return 0;
}
if ((type == 2 || type == 3) &&
find_config_tree_int(cmd, "locking/fallback_to_local_locking",
DEFAULT_FALLBACK_TO_LOCAL_LOCKING)) {
log_print("WARNING: Falling back to local file-based locking.");
log_print("Volume Groups with the clustered attribute will "
"be inaccessible.");
if (init_file_locking(&_locking, cmd))
return 1;
}
if (!ignorelockingfailure())
return 0;
/* FIXME Ensure only read ops are permitted */
log_verbose("Locking disabled - only read operations permitted.");
init_no_locking(&_locking, cft);
init_no_locking(&_locking, cmd);
init_lockingfailed(1);
return 1;
@@ -189,7 +288,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
if (!*vgname)
return 1;
if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
if (dm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
vgname) < 0) {
log_error("LVM1 proc VG pathname too long for %s", vgname);
return 0;
@@ -231,7 +330,7 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
{
char resource[258];
char resource[258] __attribute((aligned(8)));
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG:

View File

@@ -19,7 +19,7 @@
#include "uuid.h"
#include "config.h"
int init_locking(int type, struct config_tree *cf);
int init_locking(int type, struct cmd_context *cmd);
void fin_locking(void);
void reset_locking(void);
int vg_write_lock_held(void);
@@ -50,7 +50,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */
/* LCK$_PRMODE */
#define LCK_PREAD 0x00000003 /* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000006 /* This is ours */
@@ -75,6 +75,8 @@ 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_MONITOR_MODE 0x00000004 /* Register with dmeventd */
/*
* Common combinations
@@ -113,4 +115,11 @@ int suspend_lvs(struct cmd_context *cmd, struct list *lvs);
int resume_lvs(struct cmd_context *cmd, struct list *lvs);
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs);
/* interrupt handling */
void sigint_clear();
void sigint_allow();
void sigint_restore();
int sigint_caught();
#endif

View File

@@ -36,10 +36,10 @@ struct locking_type {
/*
* Locking types
*/
int init_no_locking(struct locking_type *locking, struct config_tree *cf);
int init_no_locking(struct locking_type *locking, struct cmd_context *cmd);
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
int init_file_locking(struct locking_type *locking, struct cmd_context *cmd);
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
int init_external_locking(struct locking_type *locking, struct cmd_context *cmd);
int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd);

View File

@@ -76,12 +76,12 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
return 1;
}
int init_no_locking(struct locking_type *locking, struct config_tree *cft)
int init_no_locking(struct locking_type *locking, struct cmd_context *cmd)
{
locking->lock_resource = _no_lock_resource;
locking->reset_locking = _no_reset_locking;
locking->fin_locking = _no_fin_locking;
locking->flags = 0;
locking->flags = LCK_CLUSTERED;
return 1;
}

View File

@@ -17,6 +17,7 @@
#include "device.h"
#include "memlock.h"
#include "lvm-string.h"
#include "defaults.h"
#include <stdarg.h>
#include <syslog.h>
@@ -31,6 +32,7 @@ static int _partial = 0;
static int _md_filtering = 0;
static int _pvmove = 0;
static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */
static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
static int _debug_level = 0;
static int _syslog = 0;
static int _log_to_file = 0;
@@ -46,6 +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_monitor = DEFAULT_DMEVENTD_MONITOR;
static int _ignore_suspended_devices = 0;
static lvm2_log_fn_t _lvm2_log_fn = NULL;
@@ -117,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;
}
}
@@ -161,6 +166,11 @@ void init_full_scan_done(int level)
_full_scan_done = level;
}
void init_trust_cache(int trustcache)
{
_trust_cache = trustcache;
}
void init_ignorelockingfailure(int level)
{
_ignorelockingfailure = level;
@@ -181,6 +191,16 @@ void init_mirror_in_sync(int in_sync)
_mirror_in_sync = in_sync;
}
void init_dmeventd_monitor(int reg)
{
_dmeventd_monitor = reg;
}
void init_ignore_suspended_devices(int ignore)
{
_ignore_suspended_devices = ignore;
}
void init_cmd_name(int status)
{
_log_cmd_name = status;
@@ -230,6 +250,11 @@ int full_scan_done()
return _full_scan_done;
}
int trust_cache()
{
return _trust_cache;
}
int lockingfailed()
{
return _lockingfailed;
@@ -250,6 +275,16 @@ int mirror_in_sync(void)
return _mirror_in_sync;
}
int dmeventd_monitor_mode(void)
{
return _dmeventd_monitor;
}
int ignore_suspended_devices(void)
{
return _ignore_suspended_devices;
}
void init_debug(int level)
{
_debug_level = level;
@@ -295,7 +330,7 @@ void print_log(int level, const char *file, int line, const char *format, ...)
log_it:
if (!_log_suppress) {
if (_verbose_level > _LOG_DEBUG)
lvm_snprintf(locn, sizeof(locn), "#%s:%d ",
dm_snprintf(locn, sizeof(locn), "#%s:%d ",
file, line);
else
locn[0] = '\0';
@@ -390,7 +425,7 @@ void print_log(int level, const char *file, int line, const char *format, ...)
_already_logging = 1;
memset(&buf, ' ', sizeof(buf));
bufused = 0;
if ((n = lvm_snprintf(buf, sizeof(buf) - bufused - 1,
if ((n = dm_snprintf(buf, sizeof(buf) - bufused - 1,
"%s:%d %s%s", file, line, _cmd_name,
_msg_prefix)) == -1)
goto done;

View File

@@ -66,6 +66,7 @@ void init_partial(int level);
void init_md_filtering(int level);
void init_pvmove(int level);
void init_full_scan_done(int level);
void init_trust_cache(int trustcache);
void init_debug(int level);
void init_cmd_name(int status);
void init_msg_prefix(const char *prefix);
@@ -74,6 +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_monitor(int reg);
void init_ignore_suspended_devices(int ignore);
void set_cmd_name(const char *cmd_name);
@@ -82,11 +85,16 @@ int partial_mode(void);
int md_filtering(void);
int pvmove_mode(void);
int full_scan_done(void);
int trust_cache(void);
int debug_level(void);
int ignorelockingfailure(void);
int lockingfailed(void);
int security_level(void);
int mirror_in_sync(void);
int ignore_suspended_devices(void);
#define DMEVENTD_MONITOR_IGNORE -1
int dmeventd_monitor_mode(void);
/* Suppress messages to stdout/stderr (1) or everywhere (2) */
/* Returns previous setting */
@@ -130,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

@@ -158,7 +158,7 @@ void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
}
if (seg_lv(seg, s)->status & MIRROR_IMAGE) {
lv_reduce(seg_lv(seg, s), area_reduction);
lv_reduce(seg_lv(seg, s), area_reduction);
return;
}
@@ -398,6 +398,7 @@ struct alloced_area {
* Details of an allocation attempt
*/
struct alloc_handle {
struct cmd_context *cmd;
struct dm_pool *mem;
alloc_policy_t alloc; /* Overall policy */
@@ -414,10 +415,20 @@ struct alloc_handle {
struct list alloced_areas[0]; /* Lists of areas in each stripe */
};
static uint32_t calc_area_multiple(const struct segment_type *segtype,
const uint32_t area_count)
{
if (!segtype_is_striped(segtype) || !area_count)
return 1;
return area_count;
}
/*
* Preparation for a specific allocation attempt
*/
static struct alloc_handle *_alloc_init(struct dm_pool *mem,
static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
struct dm_pool *mem,
const struct segment_type *segtype,
alloc_policy_t alloc,
uint32_t mirrors,
@@ -464,6 +475,8 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
if (segtype_is_virtual(segtype))
return ah;
ah->cmd = cmd;
if (!(ah->mem = dm_pool_create("allocation", 1024))) {
log_error("allocation pool creation failed");
return NULL;
@@ -472,7 +485,7 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
ah->area_count = area_count;
ah->log_count = log_count;
ah->alloc = alloc;
ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1;
ah->area_multiple = calc_area_multiple(segtype, area_count);
for (s = 0; s < ah->area_count; s++)
list_init(&ah->alloced_areas[s]);
@@ -490,6 +503,49 @@ void alloc_destroy(struct alloc_handle *ah)
dm_pool_destroy(ah->mem);
}
static int _log_parallel_areas(struct dm_pool *mem, struct list *parallel_areas)
{
struct seg_pvs *spvs;
struct pv_list *pvl;
char *pvnames;
if (!parallel_areas)
return 1;
if (!dm_pool_begin_object(mem, 256)) {
log_error("dm_pool_begin_object failed");
return 0;
}
list_iterate_items(spvs, parallel_areas) {
list_iterate_items(pvl, &spvs->pvs) {
if (!dm_pool_grow_object(mem, dev_name(pvl->pv->dev), strlen(dev_name(pvl->pv->dev)))) {
log_error("dm_pool_grow_object failed");
dm_pool_abandon_object(mem);
return 0;
}
if (!dm_pool_grow_object(mem, " ", 1)) {
log_error("dm_pool_grow_object failed");
dm_pool_abandon_object(mem);
return 0;
}
}
if (!dm_pool_grow_object(mem, "\0", 1)) {
log_error("dm_pool_grow_object failed");
dm_pool_abandon_object(mem);
return 0;
}
pvnames = dm_pool_end_object(mem);
log_debug("Parallel PVs at LE %" PRIu32 " length %" PRIu32 ": %s",
spvs->le, spvs->len, pvnames);
dm_pool_free(mem, pvnames);
}
return 1;
}
static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
uint32_t area_count,
uint32_t stripe_size,
@@ -506,7 +562,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
if (mirrored_pv)
extra_areas = 1;
area_multiple = segtype_is_striped(segtype) ? area_count : 1;
area_multiple = calc_area_multiple(segtype, area_count);
/* log_lv gets set up elsehere */
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
@@ -581,17 +637,17 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
struct pv_area **areas,
uint32_t *ix, struct pv_area *log_area)
{
uint32_t area_len, smallest, remaining;
uint32_t area_len, remaining;
uint32_t s;
struct alloced_area *aa;
remaining = needed - *ix;
area_len = remaining / ah->area_multiple;
smallest = areas[ah->area_count - 1]->count;
if (area_len > smallest)
area_len = smallest;
/* Reduce area_len to the smallest of the areas */
for (s = 0; s < ah->area_count; s++)
if (area_len > areas[s]->count)
area_len = areas[s]->count;
if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) *
(ah->area_count + (log_area ? 1 : 0))))) {
@@ -614,7 +670,7 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
if (log_area) {
ah->log_area.pv = log_area->map->pv;
ah->log_area.pe = log_area->start;
ah->log_area.len = 1; /* FIXME Calculate & check this */
ah->log_area.len = MIRROR_LOG_SIZE; /* FIXME Calculate & check this */
consume_pv_area(log_area, ah->log_area.len);
}
@@ -623,6 +679,82 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
return 1;
}
/*
* Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
* If any constituent area contains more than one segment, max_seg_len is
* reduced to cover only the first.
* fn should return 0 on error, 1 to continue scanning or >1 to terminate without error.
* In the last case, this function passes on the return code.
*/
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t le, uint32_t len, uint32_t *max_seg_len,
uint32_t first_area, uint32_t max_areas,
int top_level_area_index,
int only_single_area_segments,
int (*fn)(struct cmd_context *cmd,
struct pv_segment *peg, uint32_t s,
void *data),
void *data)
{
struct lv_segment *seg;
uint32_t s;
uint32_t remaining_seg_len, area_len, area_multiple;
int r = 1;
if (!(seg = find_seg_by_le(lv, le))) {
log_error("Failed to find segment for %s extent %" PRIu32,
lv->name, le);
return 0;
}
/* Remaining logical length of segment */
remaining_seg_len = seg->len - (le - seg->le);
if (remaining_seg_len > len)
remaining_seg_len = len;
if (max_seg_len && *max_seg_len > remaining_seg_len)
*max_seg_len = remaining_seg_len;
area_multiple = calc_area_multiple(seg->segtype, seg->area_count);
area_len = remaining_seg_len / area_multiple ? : 1;
for (s = first_area;
s < seg->area_count && (!max_areas || s <= max_areas);
s++) {
if (seg_type(seg, s) == AREA_LV) {
if (!(r = _for_each_pv(cmd, seg_lv(seg, s),
seg_le(seg, s) +
(le - seg->le) / area_multiple,
area_len, max_seg_len,
only_single_area_segments ? 0 : 0,
only_single_area_segments ? 1 : 0,
top_level_area_index != -1 ? top_level_area_index : s,
only_single_area_segments, fn,
data)))
stack;
} else if (seg_type(seg, s) == AREA_PV)
if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? top_level_area_index : s, data)))
stack;
if (r != 1)
return r;
}
/* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */
if (!only_single_area_segments && seg_is_mirrored(seg) && seg->log_lv) {
if (!(r = _for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
NULL, 0, 0, 0, only_single_area_segments,
fn, data)))
stack;
if (r != 1)
return r;
}
/* FIXME Add snapshot cow LVs etc. */
return 1;
}
static int _comp_area(const void *l, const void *r)
{
const struct pv_area *lhs = *((const struct pv_area **) l);
@@ -637,33 +769,114 @@ static int _comp_area(const void *l, const void *r)
return 0;
}
/*
* Search for pvseg that matches condition
*/
struct pv_match {
int (*condition)(struct pv_segment *pvseg, struct pv_area *pva);
struct pv_area **areas;
struct pv_area *pva;
uint32_t areas_size;
int s; /* Area index of match */
};
/*
* Is PV area on the same PV?
*/
static int _is_same_pv(struct pv_segment *pvseg, struct pv_area *pva)
{
if (pvseg->pv != pva->map->pv)
return 0;
return 1;
}
/*
* Is PV area contiguous to PV segment?
*/
static int _is_contiguous(struct pv_segment *pvseg, struct pv_area *pva)
{
if (pvseg->pv != pva->map->pv)
return 0;
if (pvseg->pe + pvseg->len != pva->start)
return 0;
return 1;
}
static int _is_condition(struct cmd_context *cmd,
struct pv_segment *pvseg, uint32_t s,
void *data)
{
struct pv_match *pvmatch = data;
if (!pvmatch->condition(pvseg, pvmatch->pva))
return 1; /* Continue */
if (s >= pvmatch->areas_size)
return 1;
pvmatch->areas[s] = pvmatch->pva;
return 2; /* Finished */
}
/*
* Is pva on same PV as any existing areas?
*/
static int _check_cling(struct cmd_context *cmd,
struct lv_segment *prev_lvseg, struct pv_area *pva,
struct pv_area **areas, uint32_t areas_size)
{
struct pv_match pvmatch;
int r;
pvmatch.condition = _is_same_pv;
pvmatch.areas = areas;
pvmatch.areas_size = areas_size;
pvmatch.pva = pva;
/* FIXME Cope with stacks by flattening */
if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
0, 0, -1, 1,
_is_condition, &pvmatch)))
stack;
if (r != 2)
return 0;
return 1;
}
/*
* Is pva contiguous to any existing areas or on the same PV?
*/
static int _check_contiguous(struct lv_segment *prev_lvseg,
struct physical_volume *pv, struct pv_area *pva,
struct pv_area **areas)
static int _check_contiguous(struct cmd_context *cmd,
struct lv_segment *prev_lvseg, struct pv_area *pva,
struct pv_area **areas, uint32_t areas_size)
{
struct pv_segment *prev_pvseg;
uint32_t s;
struct pv_match pvmatch;
int r;
for (s = 0; s < prev_lvseg->area_count; s++) {
if (seg_type(prev_lvseg, s) != AREA_PV)
continue; /* FIXME Broken */
pvmatch.condition = _is_contiguous;
pvmatch.areas = areas;
pvmatch.areas_size = areas_size;
pvmatch.pva = pva;
if (!(prev_pvseg = seg_pvseg(prev_lvseg, s)))
continue; /* FIXME Broken */
/* FIXME Cope with stacks by flattening */
if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
0, 0, -1, 1,
_is_condition, &pvmatch)))
stack;
if ((prev_pvseg->pv != pv))
continue;
if (r != 2)
return 0;
if (prev_pvseg->pe + prev_pvseg->len == pva->start) {
areas[s] = pva;
return 1;
}
}
return 0;
return 1;
}
/*
@@ -679,21 +892,35 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
struct pv_area *pva;
struct pv_list *pvl;
unsigned already_found_one = 0;
unsigned contiguous = 0, contiguous_count = 0;
unsigned contiguous = 0, cling = 0, preferred_count = 0;
unsigned ix;
unsigned ix_offset = 0; /* Offset for non-contiguous allocations */
unsigned ix_offset = 0; /* Offset for non-preferred allocations */
uint32_t max_parallel; /* Maximum extents to allocate */
uint32_t next_le;
struct seg_pvs *spvs;
struct list *parallel_pvs;
uint32_t free_pes;
/* Is there enough total space? */
free_pes = pv_maps_size(pvms);
if (needed - *allocated > free_pes) {
log_error("Insufficient free space: %" PRIu32 " extents needed,"
" but only %" PRIu32 " available",
needed - *allocated, free_pes);
return 0;
}
/* FIXME Do calculations on free extent counts before selecting space */
/* FIXME Select log PV appropriately if there isn't one yet */
/* Are there any preceding segments we must follow on from? */
if ((alloc == ALLOC_CONTIGUOUS) && prev_lvseg) {
contiguous = 1;
if (prev_lvseg) {
ix_offset = prev_lvseg->area_count;
if ((alloc == ALLOC_CONTIGUOUS))
contiguous = 1;
else if ((alloc == ALLOC_CLING))
cling = 1;
else
ix_offset = 0;
}
/* FIXME This algorithm needs a lot of cleaning up! */
@@ -702,6 +929,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
/* ix holds the number of areas found on other PVs */
do {
ix = 0;
preferred_count = 0;
parallel_pvs = NULL;
max_parallel = needed;
@@ -711,14 +939,15 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
* the maximum we can allocate in one go accordingly.
*/
if (ah->parallel_areas) {
next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated / ah->area_multiple;
list_iterate_items(spvs, ah->parallel_areas) {
next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated;
if (next_le >= spvs->le) {
if (next_le + max_parallel > spvs->le + spvs->len)
max_parallel = (spvs->le + spvs->len - next_le) * ah->area_multiple;
parallel_pvs = &spvs->pvs;
break;
}
if (next_le >= spvs->le + spvs->len)
continue;
if (max_parallel > (spvs->le + spvs->len) * ah->area_multiple)
max_parallel = (spvs->le + spvs->len) * ah->area_multiple;
parallel_pvs = &spvs->pvs;
break;
}
}
@@ -750,17 +979,30 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
list_iterate_items(pva, &pvm->areas) {
if (contiguous) {
if (prev_lvseg &&
_check_contiguous(prev_lvseg,
pvm->pv,
pva, areas)) {
contiguous_count++;
_check_contiguous(ah->cmd,
prev_lvseg,
pva, areas,
areas_size)) {
preferred_count++;
goto next_pv;
}
continue;
}
if (cling) {
if (prev_lvseg &&
_check_cling(ah->cmd,
prev_lvseg,
pva, areas,
areas_size)) {
preferred_count++;
}
goto next_pv;
}
/* Is it big enough on its own? */
if ((pva->count < max_parallel - *allocated) &&
if (pva->count * ah->area_multiple <
max_parallel - *allocated &&
((!can_split && !ah->log_count) ||
(already_found_one &&
!(alloc == ALLOC_ANYWHERE))))
@@ -781,7 +1023,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
break;
}
if (contiguous && (contiguous_count < ix_offset))
if ((contiguous || cling) && (preferred_count < ix_offset))
break;
/* Only allocate log_area the first time around */
@@ -833,6 +1075,7 @@ static int _allocate(struct alloc_handle *ah,
int r = 0;
struct list *pvms;
uint32_t areas_size;
alloc_policy_t alloc;
if (allocated >= new_extents && !ah->log_count) {
log_error("_allocate called with no work to do!");
@@ -853,6 +1096,9 @@ static int _allocate(struct alloc_handle *ah,
return 0;
}
if (!_log_parallel_areas(ah->mem, ah->parallel_areas))
stack;
areas_size = list_size(pvms);
if (areas_size < ah->area_count + ah->log_count) {
if (ah->alloc != ALLOC_ANYWHERE) {
@@ -875,38 +1121,18 @@ static int _allocate(struct alloc_handle *ah,
return 0;
}
old_allocated = allocated;
if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas,
areas_size, can_split,
prev_lvseg, &allocated, new_extents)) {
stack;
goto out;
/* Attempt each defined allocation policy in turn */
for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
old_allocated = allocated;
if (!_find_parallel_space(ah, alloc, pvms, areas,
areas_size, can_split,
prev_lvseg, &allocated, new_extents))
goto_out;
if ((allocated == new_extents) || (ah->alloc == alloc) ||
(!can_split && (allocated != old_allocated)))
break;
}
if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
(!can_split && (allocated != old_allocated)))
goto finished;
old_allocated = allocated;
if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
areas_size, can_split,
prev_lvseg, &allocated, new_extents)) {
stack;
goto out;
}
if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) ||
(!can_split && (allocated != old_allocated)))
goto finished;
if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas,
areas_size, can_split,
prev_lvseg, &allocated, new_extents)) {
stack;
goto out;
}
finished:
if (allocated != new_extents) {
log_error("Insufficient suitable %sallocatable extents "
"for logical volume %s: %u more required",
@@ -917,6 +1143,13 @@ static int _allocate(struct alloc_handle *ah,
goto out;
}
if (ah->log_count && !ah->log_area.len) {
log_error("Insufficient extents for log allocation "
"for logical volume %s.",
lv ? lv->name : "");
goto out;
}
r = 1;
out:
@@ -982,7 +1215,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
if (alloc == ALLOC_INHERIT)
alloc = vg->alloc;
if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
stripes, log_count, mirrored_pv,
mirrored_pe, parallel_areas))) {
stack;
@@ -1213,7 +1446,7 @@ int lv_extend(struct logical_volume *lv,
log_error("Aborting. Failed to extend %s.",
seg_lv(seg, m)->name);
return 0;
}
}
}
seg->area_len += extents;
seg->len += extents;
@@ -1240,7 +1473,7 @@ char *generate_lv_name(struct volume_group *vg, const char *format,
high = i;
}
if (lvm_snprintf(buffer, len, format, high + 1) < 0)
if (dm_snprintf(buffer, len, format, high + 1) < 0)
return NULL;
return buffer;
@@ -1260,7 +1493,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
struct cmd_context *cmd = vg->cmd;
struct lv_list *ll = NULL;
struct logical_volume *lv;
char dname[32];
char dname[NAME_LEN];
if (vg->max_lv && (vg->max_lv == vg->lv_count)) {
log_error("Maximum number of logical volumes (%u) reached "
@@ -1326,58 +1559,16 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
return lv;
}
/* Recursively process each PV used by part of an LV */
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t le, uint32_t len,
int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs),
struct seg_pvs *spvs)
{
struct lv_segment *seg;
uint32_t s;
uint32_t remaining_seg_len, area_len, area_multiple;
if (!(seg = find_seg_by_le(lv, le))) {
log_error("Failed to find segment for %s extent %" PRIu32,
lv->name, le);
return 0;
}
/* Remaining logical length of segment */
remaining_seg_len = seg->len - (le - seg->le);
if (len > remaining_seg_len)
remaining_seg_len = len;
if (spvs->len > remaining_seg_len)
spvs->len = remaining_seg_len;
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
area_len = remaining_seg_len / area_multiple;
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_LV) {
if (!_for_each_pv(cmd, seg_lv(seg, s),
seg_le(seg, s) + (le - seg->le) / area_multiple,
area_len, fn, spvs)) {
stack;
return 0;
}
} else if (seg_type(seg, s) == AREA_PV) {
if (!fn(cmd, seg_pvseg(seg, s), spvs)) {
stack;
return 0;
}
}
}
return 1;
}
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs)
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg,
uint32_t s __attribute((unused)), void *data)
{
struct seg_pvs *spvs = (struct seg_pvs *) data;
struct pv_list *pvl;
/* FIXME Don't add again if it's already on the list! */
/* Don't add again if it's already on list. */
list_iterate_items(pvl, &spvs->pvs)
if (pvl->pv == peg->pv)
return 1;
if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
log_error("pv_list allocation failed");
@@ -1386,11 +1577,8 @@ static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_
pvl->pv = peg->pv;
/* FIXME Use ordered list to facilitate comparison */
list_add(&spvs->pvs, &pvl->list);
/* FIXME Add mirror logs, snapshot cow LVs etc. */
return 1;
}
@@ -1426,7 +1614,8 @@ struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
/* Find next segment end */
/* FIXME Unnecessary nesting! */
if (!_for_each_pv(cmd, lv, current_le, lv->le_count, _add_pvs, spvs)) {
if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len,
0, 0, -1, 0, _add_pvs, (void *) spvs)) {
stack;
return NULL;
}

View File

@@ -23,6 +23,48 @@
#include "str_list.h"
#include "pv_alloc.h"
#include "activate.h"
#include "display.h"
#include "locking.h"
#include <sys/param.h>
/*
* FIXME: Check for valid handle before dereferencing field or log error?
*/
#define pv_field(handle, field) \
(((struct physical_volume *)(handle))->field)
static struct physical_volume *_pv_read(struct cmd_context *cmd,
const char *pv_name,
struct list *mdas,
uint64_t *label_sector,
int warnings);
static struct physical_volume *_pv_create(const struct format_type *fmt,
struct device *dev,
struct id *id, uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas);
static int _pv_write(struct cmd_context *cmd __attribute((unused)),
struct physical_volume *pv,
struct list *mdas, int64_t label_sector);
static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
const char *pv_name);
static struct pv_list *_find_pv_in_vg(struct volume_group *vg, const char *pv_name);
static struct physical_volume *_find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id);
unsigned long pe_align(void)
{
return MAX(65536UL, lvm_getpagesize()) >> SECTOR_SHIFT;
}
static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
const char *pv_name)
@@ -41,7 +83,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
}
list_init(&mdas);
if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL, 1))) {
if (!(pv = _pv_read(fid->fmt->cmd, pv_name, &mdas, NULL, 1))) {
log_error("%s not identified as an existing physical volume",
pv_name);
return 0;
@@ -78,15 +120,12 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
/* FIXME Do proper rounding-up alignment? */
/* Reserved space for label; this holds 0 for PVs created by LVM1 */
if (pv->pe_start < PE_ALIGN)
pv->pe_start = PE_ALIGN;
if (pv->pe_start < pe_align())
pv->pe_start = pe_align();
/*
* The next two fields should be corrected
* by fid->pv_setup.
* pe_count must always be calculated by pv_setup
*/
pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
pv->pe_alloc_count = 0;
if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
@@ -97,7 +136,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
return 0;
}
if (find_pv_in_vg(vg, pv_name)) {
if (_find_pv_in_vg(vg, pv_name)) {
log_error("Physical volume '%s' listed more than once.",
pv_name);
return 0;
@@ -118,6 +157,15 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
pvl->pv = pv;
list_add(&vg->pvs, &pvl->list);
if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
log_error("Unable to add %s to %s: new extent count (%"
PRIu64 ") exceeds limit (%" PRIu32 ").",
pv_name, vg->name,
(uint64_t) vg->extent_count + pv->pe_count,
UINT32_MAX);
return 0;
}
vg->pv_count++;
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
@@ -266,10 +314,9 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
vg->seqno = 0;
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN))) {
stack;
goto bad;
}
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
goto_bad;
*vg->system_id = '\0';
vg->extent_size = extent_size;
@@ -306,7 +353,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
/* attach the pv's */
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
goto bad;
goto_bad;
return vg;
@@ -491,8 +538,72 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
return 1;
}
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
struct volume_group *vg_to)
{
struct metadata_area *mda, *mda2;
struct list *mdas_from, *mdas_to;
int common_mda = 0;
mdas_from = &vg_from->fid->metadata_areas;
mdas_to = &vg_to->fid->metadata_areas;
list_iterate_items_safe(mda, mda2, mdas_from) {
if (!mda->ops->mda_in_vg) {
common_mda = 1;
continue;
}
if (!mda->ops->mda_in_vg(vg_from->fid, vg_from, mda)) {
list_del(&mda->list);
list_add(mdas_to, &mda->list);
}
}
if (list_empty(mdas_from) || list_empty(mdas_to))
return common_mda;
return 1;
}
/**
* pv_create - initialize a physical volume for use with a volume group
* @fmt: format type
* @dev: PV device to initialize
* @id: PV UUID to use for initialization
* @size: size of the PV in sectors
* @pe_start: physical extent start
* @existing_extent_count
* @existing_extent_size
* @pvmetadatacopies
* @pvmetadatasize
* @mdas
*
* Returns:
* PV handle - physical volume initialized successfully
* NULL - invalid parameter or problem initializing the physical volume
*
* Note:
* FIXME - liblvm todo - tidy up arguments for external use (fmt, mdas, etc)
*/
pv_t *pv_create(const struct format_type *fmt,
struct device *dev,
struct id *id, uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas)
{
return _pv_create(fmt, dev, id, size, pe_start,
existing_extent_count,
existing_extent_size,
pvmetadatacopies,
pvmetadatasize, mdas);
}
/* Sizes in sectors */
struct physical_volume *pv_create(const struct format_type *fmt,
static struct physical_volume *_pv_create(const struct format_type *fmt,
struct device *dev,
struct id *id, uint64_t size,
uint64_t pe_start,
@@ -519,10 +630,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
pv->dev = dev;
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN))) {
stack;
goto bad;
}
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN)))
goto_bad;
pv->status = ALLOCATABLE_PV;
@@ -570,7 +679,13 @@ struct physical_volume *pv_create(const struct format_type *fmt,
return NULL;
}
/* FIXME: liblvm todo - make into function that returns handle */
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
{
return _find_pv_in_vg(vg, pv_name);
}
static struct pv_list *_find_pv_in_vg(struct volume_group *vg, const char *pv_name)
{
struct pv_list *pvl;
@@ -592,8 +707,26 @@ int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
return 0;
}
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id)
/**
* find_pv_in_vg_by_uuid - Find PV in VG by PV UUID
* @vg: volume group to search
* @id: UUID of the PV to match
*
* Returns:
* PV handle - if UUID of PV found in VG
* NULL - invalid parameter or UUID of PV not found in VG
*
* Note
* FIXME - liblvm todo - make into function that takes VG handle
*/
pv_t *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id)
{
return _find_pv_in_vg_by_uuid(vg, id);
}
static struct physical_volume *_find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id)
{
struct pv_list *pvl;
@@ -651,12 +784,20 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
return NULL;
}
/* FIXME: liblvm todo - make into function that returns handle */
struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
const char *pv_name)
{
return _find_pv_by_name(cmd, pv_name);
}
static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
const char *pv_name)
{
struct physical_volume *pv;
if (!(pv = pv_read(cmd, pv_name, NULL, NULL, 1))) {
if (!(pv = _pv_read(cmd, pv_name, NULL, NULL, 1))) {
log_error("Physical volume %s not found", pv_name);
return NULL;
}
@@ -722,23 +863,76 @@ int vg_remove(struct volume_group *vg)
int vg_validate(struct volume_group *vg)
{
struct lv_list *lvl;
struct pv_list *pvl, *pvl2;
struct lv_list *lvl, *lvl2;
char uuid[64] __attribute((aligned(8)));
int r = 1;
/* FIXME Also check there's no data/metadata overlap */
list_iterate_items(pvl, &vg->pvs) {
list_iterate_items(pvl2, &vg->pvs) {
if (pvl == pvl2)
break;
if (id_equal(&pvl->pv->id,
&pvl2->pv->id)) {
if (!id_write_format(&pvl->pv->id, uuid,
sizeof(uuid)))
stack;
log_error("Internal error: Duplicate PV id "
"%s detected for %s in %s.",
uuid, dev_name(pvl->pv->dev),
vg->name);
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)) {
log_error("Internal error: PV segments corrupted in %s.",
vg->name);
return 0;
r = 0;
}
list_iterate_items(lvl, &vg->lvs) {
list_iterate_items(lvl2, &vg->lvs) {
if (lvl == lvl2)
break;
if (!strcmp(lvl->lv->name, lvl2->lv->name)) {
log_error("Internal error: Duplicate LV name "
"%s detected in %s.", lvl->lv->name,
vg->name);
r = 0;
}
if (id_equal(&lvl->lv->lvid.id[1],
&lvl2->lv->lvid.id[1])) {
if (!id_write_format(&lvl->lv->lvid.id[1], uuid,
sizeof(uuid)))
stack;
log_error("Internal error: Duplicate LV id "
"%s detected for %s and %s in %s.",
uuid, lvl->lv->name, lvl2->lv->name,
vg->name);
r = 0;
}
}
}
list_iterate_items(lvl, &vg->lvs) {
if (!check_lv_segments(lvl->lv, 1)) {
log_error("Internal error: LV segments corrupted in %s.",
lvl->lv->name);
return 0;
r = 0;
}
}
return 1;
return r;
}
/*
@@ -887,7 +1081,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
}
list_iterate_items(info, &vginfo->infos) {
if (!(pv = pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
if (!(pv = _pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
continue;
}
if (!(pvl = dm_pool_zalloc(cmd->mem, sizeof(*pvl)))) {
@@ -902,6 +1096,30 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
return vg;
}
static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
{
struct pv_list *pvl, *pvl2;
list_iterate_items(pvl, &vg->pvs) {
list_iterate_items(pvl2, all_pvs) {
if (pvl->pv->dev == pvl2->pv->dev)
goto next_pv;
}
/* PV is not on list so add it. Note that we don't copy it. */
if (!(pvl2 = dm_pool_zalloc(vg->cmd->mem, sizeof(*pvl2)))) {
log_error("pv_list allocation for '%s' failed",
dev_name(pvl->pv->dev));
return 0;
}
pvl2->pv = pvl->pv;
list_add(all_pvs, &pvl2->list);
next_pv:
;
}
return 1;
}
/* Caller sets consistent to 1 if it's safe for vg_read to correct
* inconsistent metadata on disk (i.e. the VG write lock is held).
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
@@ -921,9 +1139,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
struct volume_group *vg, *correct_vg = NULL;
struct metadata_area *mda;
int inconsistent = 0;
int inconsistent_vgid = 0;
int use_precommitted = precommitted;
struct list *pvids;
struct pv_list *pvl;
struct pv_list *pvl, *pvl2;
struct list all_pvs;
char uuid[64] __attribute((aligned(8)));
if (!*vgname) {
if (use_precommitted) {
@@ -992,22 +1213,32 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if (correct_vg) {
if (list_size(&correct_vg->pvs) != list_size(pvids)) {
log_debug("Cached VG %s had incorrect PV list",
vg->name);
correct_vg = NULL;
vgname);
if (memlock())
inconsistent = 1;
else
correct_vg = NULL;
} else list_iterate_items(pvl, &correct_vg->pvs) {
if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
log_debug("Cached VG %s had incorrect PV list",
vg->name);
vgname);
correct_vg = NULL;
break;
}
}
}
list_init(&all_pvs);
/* Failed to find VG where we expected it - full scan and retry */
if (!correct_vg) {
inconsistent = 0;
if (memlock()) {
stack;
return NULL;
}
lvmcache_label_scan(cmd, 2);
if (!(fmt = fmt_from_vgname(vgname, vgid))) {
stack;
@@ -1035,13 +1266,25 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
if (!correct_vg) {
correct_vg = vg;
if (!_update_pv_list(&all_pvs, correct_vg))
return_NULL;
continue;
}
if (strncmp((char *)vg->id.uuid,
(char *)correct_vg->id.uuid, ID_LEN)) {
inconsistent = 1;
inconsistent_vgid = 1;
}
/* FIXME Also ensure contents same - checksums same? */
if (correct_vg->seqno != vg->seqno) {
inconsistent = 1;
if (vg->seqno > correct_vg->seqno)
if (vg->seqno > correct_vg->seqno) {
if (!_update_pv_list(&all_pvs, vg))
return_NULL;
correct_vg = vg;
}
}
}
@@ -1074,17 +1317,42 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return correct_vg;
}
log_print("Inconsistent metadata copies found - updating "
"to use version %u", correct_vg->seqno);
/* Don't touch if vgids didn't match */
if (inconsistent_vgid) {
log_error("Inconsistent metadata UUIDs found for "
"volume group %s", vgname);
*consistent = 0;
return correct_vg;
}
log_print("Inconsistent metadata found for VG %s - updating "
"to use version %u", vgname, correct_vg->seqno);
if (!vg_write(correct_vg)) {
log_error("Automatic metadata correction failed");
return NULL;
}
if (!vg_commit(correct_vg)) {
log_error("Automatic metadata correction commit "
"failed");
return NULL;
}
list_iterate_items(pvl, &all_pvs) {
list_iterate_items(pvl2, &correct_vg->pvs) {
if (pvl->pv->dev == pvl2->pv->dev)
goto next_pv;
}
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
return_NULL;
log_error("Removing PV %s (%s) that no longer belongs to VG %s",
dev_name(pvl->pv->dev), uuid, correct_vg->name);
if (!pv_write_orphan(cmd, pvl->pv))
return_NULL;
next_pv:
;
}
}
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
@@ -1149,7 +1417,8 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
if (!consistent) {
log_error("Volume group %s metadata is "
"inconsistent", vginfo->vgname);
return NULL;
if (!partial_mode())
return NULL;
}
return vg;
}
@@ -1218,10 +1487,34 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
return lvl->lv;
}
/* FIXME Use label functions instead of PV functions */
/**
* pv_read - read and return a handle to a physical volume
* @cmd: LVM command initiating the pv_read
* @pv_name: full device name of the PV, including the path
* @mdas: list of metadata areas of the PV
* @label_sector: sector number where the PV label is stored on @pv_name
* @warnings:
*
* Returns:
* PV handle - valid pv_name and successful read of the PV, or
* NULL - invalid parameter or error in reading the PV
*
* Note:
* FIXME - liblvm todo - make into function that returns handle
*/
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector,
int warnings)
{
return _pv_read(cmd, pv_name, mdas, label_sector, warnings);
}
/* FIXME Use label functions instead of PV functions */
static struct physical_volume *_pv_read(struct cmd_context *cmd,
const char *pv_name,
struct list *mdas,
uint64_t *label_sector,
int warnings)
{
struct physical_volume *pv;
struct label *label;
@@ -1233,7 +1526,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
return NULL;
}
if (!(label_read(dev, &label))) {
if (!(label_read(dev, &label, UINT64_C(0)))) {
if (warnings)
log_error("No physical volume label read from %s",
pv_name);
@@ -1342,8 +1635,17 @@ struct list *get_pvs(struct cmd_context *cmd)
return results;
}
int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volume *pv,
/* FIXME: liblvm todo - make into function that takes handle */
int pv_write(struct cmd_context *cmd __attribute((unused)),
struct physical_volume *pv,
struct list *mdas, int64_t label_sector)
{
return _pv_write(cmd, pv, mdas, label_sector);
}
static int _pv_write(struct cmd_context *cmd __attribute((unused)),
struct physical_volume *pv,
struct list *mdas, int64_t label_sector)
{
if (!pv->fmt->ops->pv_write) {
log_error("Format does not support writing physical volumes");
@@ -1363,3 +1665,176 @@ int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volu
return 1;
}
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
{
const char *old_vg_name = pv->vg_name;
pv->vg_name = ORPHAN;
pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return 0;
}
if (!_pv_write(cmd, pv, NULL, INT64_C(-1))) {
log_error("Failed to clear metadata from physical "
"volume \"%s\" after removal from \"%s\"",
dev_name(pv->dev), old_vg_name);
return 0;
}
return 1;
}
/**
* is_orphan - Determine whether a pv is an orphan based on its vg_name
* @pv: handle to the physical volume
*/
int is_orphan(pv_t *pv)
{
return (pv_field(pv, vg_name)[0] ? 0 : 1);
}
/*
* Returns:
* 0 - fail
* 1 - success
*/
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
int64_t label_sector)
{
struct label *label;
struct device *dev;
struct metadata_area *mda;
struct lvmcache_info *info;
dev = dev_cache_get(pv_name, cmd->filter);
if (!dev) {
log_error("Device %s not found (or ignored by filtering).",
pv_name);
return 0;
}
/*
* First, scan for LVM labels.
*/
if (!label_read(dev, &label, label_sector)) {
log_error("Could not find LVM label on %s",
pv_name);
return 0;
}
log_print("Found label on %s, sector %"PRIu64", type=%s",
pv_name, label->sector, label->type);
/*
* Next, loop through metadata areas
*/
info = label->info;
list_iterate_items(mda, &info->mdas)
mda->ops->pv_analyze_mda(info->fmt, mda);
return 1;
}
/**
* vg_check_status - check volume group status flags and log error
* @vg - volume group to check status flags
* @status_flags - specific status flags to check (e.g. EXPORTED_VG)
*
* Returns:
* 0 - fail
* 1 - success
*/
int vg_check_status(struct volume_group *vg, uint32_t status_flags)
{
if ((status_flags & CLUSTERED) &&
(vg->status & CLUSTERED) && !locking_is_clustered() &&
!lockingfailed()) {
log_error("Skipping clustered volume group %s", vg->name);
return 0;
}
if ((status_flags & EXPORTED_VG) &&
(vg->status & EXPORTED_VG)) {
log_error("Volume group %s is exported", vg->name);
return 0;
}
if ((status_flags & LVM_WRITE) &&
!(vg->status & LVM_WRITE)) {
log_error("Volume group %s is read-only", vg->name);
return 0;
}
if ((status_flags & RESIZEABLE_VG) &&
!(vg->status & RESIZEABLE_VG)) {
log_error("Volume group %s is not resizeable.", vg->name);
return 0;
}
return 1;
}
/*
* Gets/Sets for external LVM library
*/
struct id get_pv_id(pv_t *pv)
{
return pv_field(pv, id);
}
const struct format_type *get_pv_format_type(pv_t *pv)
{
return pv_field(pv, fmt);
}
struct id get_pv_vgid(pv_t *pv)
{
return pv_field(pv, vgid);
}
struct device *get_pv_dev(pv_t *pv)
{
return pv_field(pv, dev);
}
const char *get_pv_vg_name(pv_t *pv)
{
return pv_field(pv, vg_name);
}
uint64_t get_pv_size(pv_t *pv)
{
return pv_field(pv, size);
}
uint32_t get_pv_status(pv_t *pv)
{
return pv_field(pv, status);
}
uint32_t get_pv_pe_size(pv_t *pv)
{
return pv_field(pv, pe_size);
}
uint64_t get_pv_pe_start(pv_t *pv)
{
return pv_field(pv, pe_start);
}
uint32_t get_pv_pe_count(pv_t *pv)
{
return pv_field(pv, pe_count);
}
uint32_t get_pv_pe_alloc_count(pv_t *pv)
{
return pv_field(pv, pe_alloc_count);
}

View File

@@ -29,12 +29,12 @@
#define MAX_STRIPES 128U
#define SECTOR_SHIFT 9L
#define SECTOR_SIZE ( 1L << SECTOR_SHIFT )
#define STRIPE_SIZE_MIN ( (unsigned) getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
#define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1)
#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
#define PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */
#define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */
#define MIRROR_LOG_SIZE 1 /* Extents */
/* Various flags */
/* Note that the bits no longer necessarily correspond to LVM1 disk format */
@@ -78,16 +78,18 @@
#define FMT_RESIZE_PV 0x00000080U /* Supports pvresize? */
#define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */
/* Ordered list - see lv_manip.c */
typedef enum {
ALLOC_INVALID = 0,
ALLOC_INHERIT,
ALLOC_INVALID,
ALLOC_CONTIGUOUS,
ALLOC_CLING,
ALLOC_NORMAL,
ALLOC_ANYWHERE
ALLOC_ANYWHERE,
ALLOC_INHERIT
} alloc_policy_t;
typedef enum {
AREA_UNASSIGNED = 0,
AREA_UNASSIGNED,
AREA_PV,
AREA_LV
} area_type_t;
@@ -140,6 +142,7 @@ struct physical_volume {
struct list tags;
};
typedef struct physical_volume pv_t;
struct metadata_area;
struct format_instance;
@@ -176,6 +179,17 @@ struct metadata_area_ops {
struct volume_group * vg, struct metadata_area * mda);
int (*vg_remove) (struct format_instance * fi, struct volume_group * vg,
struct metadata_area * mda);
/*
* Check if metadata area belongs to vg
*/
int (*mda_in_vg) (struct format_instance * fi,
struct volume_group * vg, struct metadata_area *mda);
/*
* Analyze a metadata area on a PV.
*/
int (*pv_analyze_mda) (const struct format_type * fmt,
struct metadata_area *mda);
};
struct metadata_area {
@@ -284,7 +298,7 @@ struct logical_volume {
int32_t major;
int32_t minor;
uint64_t size;
uint64_t size; /* Sectors */
uint32_t le_count;
uint32_t origin_count;
@@ -403,6 +417,7 @@ struct format_handler {
/*
* Utility functions
*/
unsigned long pe_align(void);
int vg_validate(struct volume_group *vg);
int vg_write(struct volume_group *vg);
int vg_commit(struct volume_group *vg);
@@ -420,20 +435,24 @@ struct list *get_vgids(struct cmd_context *cmd, int full_scan);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
struct list *mdas, int64_t label_sector);
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
int is_orphan(pv_t *pv);
/* pe_start and pe_end relate to any existing data so that new metadata
* areas can avoid overlap */
struct physical_volume *pv_create(const struct format_type *fmt,
struct device *dev,
struct id *id,
uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas);
pv_t *pv_create(const struct format_type *fmt,
struct device *dev,
struct id *id,
uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas);
int pv_resize(struct physical_volume *pv, struct volume_group *vg,
uint32_t new_pe_count);
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
int64_t label_sector);
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, uint32_t max_pv,
@@ -446,6 +465,8 @@ int vg_extend(struct format_instance *fi, struct volume_group *vg,
int pv_count, char **pv_names);
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
uint32_t new_extent_size);
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
struct volume_group *vg_to);
/* Manipulate LVs */
struct logical_volume *lv_create_empty(struct format_instance *fi,
@@ -481,8 +502,7 @@ struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
/* Find a PV within a given VG */
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id);
pv_t *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id);
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
const char *vgid, const char *pvid,
struct physical_volume *pv);
@@ -559,6 +579,8 @@ int vg_add_snapshot(struct format_instance *fid, const char *name,
int vg_remove_snapshot(struct logical_volume *cow);
int vg_check_status(struct volume_group *vg, uint32_t status_flags);
/*
* Mirroring functions
*/
@@ -614,4 +636,19 @@ uint32_t find_free_lvnum(struct logical_volume *lv);
char *generate_lv_name(struct volume_group *vg, const char *format,
char *buffer, size_t len);
/*
* Gets/Sets for external LVM library
*/
struct id get_pv_id(pv_t *pv);
const struct format_type *get_pv_format_type(pv_t *pv);
struct id get_pv_vgid(pv_t *pv);
struct device *get_pv_dev(pv_t *pv);
const char *get_pv_vg_name(pv_t *pv);
uint64_t get_pv_size(pv_t *pv);
uint32_t get_pv_status(pv_t *pv);
uint32_t get_pv_pe_size(pv_t *pv);
uint64_t get_pv_pe_start(pv_t *pv);
uint32_t get_pv_pe_count(pv_t *pv);
uint32_t get_pv_pe_alloc_count(pv_t *pv);
#endif

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? */
@@ -36,20 +37,20 @@ struct lv_segment *find_mirror_seg(struct lv_segment *seg)
}
/*
* Ensure region size is compatible with volume size.
* Reduce the region size if necessary to ensure
* the volume size is a multiple of the region size.
*/
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
uint32_t region_size)
{
uint32_t region_max;
uint64_t region_max;
region_max = (1 << (ffs((int)extents) - 1)) * extent_size;
region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
if (region_max < region_size) {
region_size = region_max;
if (region_max < UINT32_MAX && region_size > region_max) {
region_size = (uint32_t) region_max;
log_print("Using reduced mirror region size of %" PRIu32
" sectors", region_max);
return region_max;
" sectors", region_size);
}
return region_size;
@@ -77,6 +78,42 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
lv_from->size = 0;
}
/*
* Delete independent/orphan LV, it must acquire lock.
*/
static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv)
{
struct cmd_context *cmd = mirrored_seg->lv->vg->cmd;
struct str_list *sl;
/* Inherit tags - maybe needed for activation */
if (!str_list_match_list(&mirrored_seg->lv->tags, &lv->tags)) {
list_iterate_items(sl, &mirrored_seg->lv->tags)
if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
log_error("Aborting. Unable to tag.");
return 0;
}
if (!vg_write(mirrored_seg->lv->vg) ||
!vg_commit(mirrored_seg->lv->vg)) {
log_error("Intermediate VG commit for orphan volume failed.");
return 0;
}
}
if (!activate_lv(cmd, lv))
return_0;
if (!deactivate_lv(cmd, lv))
return_0;
if (!lv_remove(lv))
return_0;
return 1;
}
/*
* Reduce mirrored_seg to num_mirrors images.
*/
@@ -84,6 +121,7 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
struct list *removable_pvs, int remove_log)
{
uint32_t m;
uint32_t extents;
uint32_t s, s1;
struct logical_volume *sub_lv;
struct logical_volume *log_lv = NULL;
@@ -95,6 +133,7 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
struct pv_list *pvl;
uint32_t old_area_count = mirrored_seg->area_count;
uint32_t new_area_count = mirrored_seg->area_count;
struct segment_type *segtype;
log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
PRIu32 " image(s)%s.",
@@ -156,14 +195,21 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
/* If no more mirrors, remove mirror layer */
if (num_mirrors == 1) {
lv1 = seg_lv(mirrored_seg, 0);
extents = lv1->le_count;
_move_lv_segments(mirrored_seg->lv, lv1);
mirrored_seg->lv->status &= ~MIRRORED;
remove_log = 1;
/* Replace mirror with error segment */
segtype = get_segtype_from_string(mirrored_seg->lv->vg->cmd, "error");
if (!lv_add_virtual_segment(lv1, 0, extents, segtype))
return_0;
}
if (remove_log) {
if (remove_log && mirrored_seg->log_lv) {
log_lv = mirrored_seg->log_lv;
mirrored_seg->log_lv = NULL;
log_lv->status &= ~MIRROR_LOG;
log_lv->status |= VISIBLE_LV;
}
/*
@@ -172,8 +218,6 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
* then deactivate and remove them fully.
*/
/* FIXME lv1 has no segments here so shouldn't be written to disk! */
if (!vg_write(mirrored_seg->lv->vg)) {
log_error("intermediate VG write failed.");
return 0;
@@ -198,41 +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++) {
if (!deactivate_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 (!lv_remove(seg_lv(mirrored_seg, m))) {
stack;
return 0;
}
}
if (lv1 && !_delete_lv(mirrored_seg, lv1))
return 0;
if (lv1) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
stack;
return 0;
}
if (!lv_remove(lv1)) {
stack;
return 0;
}
}
if (log_lv) {
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;
}
@@ -245,7 +263,7 @@ static int get_mirror_fault_policy(struct cmd_context *cmd, int log_policy)
policy = find_config_str(NULL, "activation/mirror_log_fault_policy",
DEFAULT_MIRROR_LOG_FAULT_POLICY);
else
policy = find_config_str(NULL, "activation/mirror_dev_fault_policy",
policy = find_config_str(NULL, "activation/mirror_device_fault_policy",
DEFAULT_MIRROR_DEV_FAULT_POLICY);
if (!strcmp(policy, "remove"))
@@ -258,7 +276,7 @@ static int get_mirror_fault_policy(struct cmd_context *cmd, int log_policy)
if (log_policy)
log_error("Bad activation/mirror_log_fault_policy");
else
log_error("Bad activation/mirror_dev_fault_policy");
log_error("Bad activation/mirror_device_fault_policy");
return MIRROR_REMOVE;
}
@@ -268,7 +286,7 @@ static int get_mirror_log_fault_policy(struct cmd_context *cmd)
return get_mirror_fault_policy(cmd, 1);
}
static int get_mirror_dev_fault_policy(struct cmd_context *cmd)
static int get_mirror_device_fault_policy(struct cmd_context *cmd)
{
return get_mirror_fault_policy(cmd, 0);
}
@@ -363,7 +381,7 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
log_policy = get_mirror_log_fault_policy(mirrored_seg->lv->vg->cmd);
dev_policy = get_mirror_dev_fault_policy(mirrored_seg->lv->vg->cmd);
dev_policy = get_mirror_device_fault_policy(mirrored_seg->lv->vg->cmd);
r = replace_mirror_images(mirrored_seg,
(dev_policy != MIRROR_REMOVE) ?
@@ -412,7 +430,7 @@ static int _create_layers_for_mirror(struct alloc_handle *ah,
return 0;
}
if (lvm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
if (dm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
log_error("img_name allocation failed. "
"Remove new LV and retry.");
return 0;
@@ -544,7 +562,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
}
if (activation() && segtype->ops->target_present &&
!segtype->ops->target_present()) {
!segtype->ops->target_present(NULL)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", segtype->name);
return 0;

View File

@@ -19,6 +19,8 @@
/*
* Areas are maintained in size order, largest first.
*
* FIXME Cope with overlap.
*/
static void _insert_area(struct list *head, struct pv_area *a)
{
@@ -30,6 +32,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
}
list_add(&pva->list, &a->list);
a->map->pe_count += a->count;
}
static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
@@ -126,23 +129,32 @@ static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
static int _create_maps(struct dm_pool *mem, struct list *pvs, struct list *pvms)
{
struct pv_map *pvm;
struct pv_map *pvm, *pvm2;
struct pv_list *pvl;
list_iterate_items(pvl, pvs) {
if (!(pvl->pv->status & ALLOCATABLE_PV))
continue;
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
stack;
return 0;
pvm = NULL;
list_iterate_items(pvm2, pvms)
if (pvm2->pv->dev == pvl->pv->dev) {
pvm = pvm2;
break;
}
if (!pvm) {
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
stack;
return 0;
}
pvm->pv = pvl->pv;
list_init(&pvm->areas);
list_add(pvms, &pvm->list);
}
pvm->pv = pvl->pv;
list_init(&pvm->areas);
list_add(pvms, &pvm->list);
if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
stack;
return 0;
@@ -180,6 +192,7 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
void consume_pv_area(struct pv_area *pva, uint32_t to_go)
{
list_del(&pva->list);
pva->map->pe_count -= pva->count;
assert(to_go <= pva->count);
@@ -190,3 +203,14 @@ void consume_pv_area(struct pv_area *pva, uint32_t to_go)
_insert_area(&pva->map->areas, pva);
}
}
uint32_t pv_maps_size(struct list *pvms)
{
struct pv_map *pvm;
uint32_t pe_count = 0;
list_iterate_items(pvm, pvms)
pe_count += pvm->pe_count;
return pe_count;
}

View File

@@ -37,6 +37,7 @@ struct pv_area {
struct pv_map {
struct physical_volume *pv;
struct list areas; /* struct pv_areas */
uint32_t pe_count; /* Total number of PEs */
struct list list;
};
@@ -49,4 +50,6 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
void consume_pv_area(struct pv_area *area, uint32_t to_go);
uint32_t pv_maps_size(struct list *pvms);
#endif

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