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

Compare commits

..

375 Commits

Author SHA1 Message Date
Alasdair Kergon
893ec9a302 1.01.05 2005-09-26 20:44:12 +00:00
Alasdair Kergon
05f65c38e6 Fix chunksize field in reports. 2005-09-23 17:06:01 +00:00
Alasdair Kergon
2e9d062ec0 Don't hide snapshots from default 'lvs' output. 2005-09-23 16:22:17 +00:00
Alasdair Kergon
6b0b394e61 Resync list.h with LVM2. 2005-09-22 12:06:34 +00:00
Alasdair Kergon
25621396c9 Remember increased buffer size and use for subsequent calls. 2005-09-20 18:04:28 +00:00
Alasdair Kergon
82aa0271f3 Explicitly initialise no_open_count 2005-09-20 16:39:12 +00:00
Alasdair Kergon
653cab13f8 On 'buffer full' condition, double buffer size and repeat ioctl. [Untested] 2005-09-19 14:29:17 +00:00
Alasdair Kergon
b526f86b49 Add is_dm_major() for use in duplicate device detection in lvmcache_add(). 2005-09-16 18:53:01 +00:00
Alasdair Kergon
53c0f00888 Really switch device number in lvmcache when it says it is doing so. 2005-09-16 18:44:52 +00:00
Alasdair Kergon
f0c4d9de40 Option for bitset memory allocation using malloc as well as pool. 2005-09-16 18:40:53 +00:00
Alasdair Kergon
03ef8cec83 Don't assume exactly two mirrors when parsing mirror status 2005-09-02 16:59:46 +00:00
Alasdair Kergon
85f2a2e8c2 Suppress fsync() error message on filesystems that don't support it. 2005-09-01 18:37:22 +00:00
Alasdair Kergon
584b3e6642 Fix yes_no_prompt() error handling. 2005-08-31 19:32:10 +00:00
Alasdair Kergon
39b7ef841d add comments to example conf file to warn about common filter line mistakes 2005-08-31 15:05:47 +00:00
Alasdair Kergon
aa16a9098d Fix termination of getopt_long() option array. 2005-08-18 19:40:19 +00:00
Alasdair Kergon
7b8c2707bc lvmconf.sh 2005-08-16 20:42:28 +00:00
Alasdair Kergon
60e26a31a7 Add copyright notice to lvmconf.sh and use unique exit codes. 2005-08-16 20:38:33 +00:00
Alasdair Kergon
3473c25c14 Add format1 dev_write debug messages. 2005-08-16 19:00:55 +00:00
Patrick Caulfield
e52f022026 clvmd no longer takes out locks for non-clusteed LVs,
and non-clustered LVs are only activated on the local node.
2005-08-16 08:25:09 +00:00
Alasdair Kergon
b1a7df8e43 Add clustered VG attribute to report. 2005-08-15 23:34:11 +00:00
Alasdair Kergon
0fd2479b7c Move lvconvert parameters into struct lvconvert_params. 2005-08-15 14:10:28 +00:00
Alasdair Kergon
273857f914 Add clustered VG flag to LV lock requests. 2005-08-15 13:24:46 +00:00
Alasdair Kergon
a08b85dbc8 Change LV locking macros to take lv instead of lvid. 2005-08-15 12:00:04 +00:00
Alasdair Kergon
a0aedf299a Prepare tools to support clustered mirrors. 2005-08-14 23:18:28 +00:00
Alasdair Kergon
3c61426844 Factor out generate_log_name_format(). 2005-08-12 20:02:21 +00:00
Alasdair Kergon
786f228076 Factor out adjusted_mirror_region_size() 2005-08-12 19:23:08 +00:00
Alasdair Kergon
004da28792 Move compose_log_line() into mirror directory. 2005-08-10 17:19:46 +00:00
Alasdair Kergon
6e2be6efb6 Don't kill idling clvmd threads. 2005-08-09 17:29:04 +00:00
Alasdair Kergon
a994dfcfbc Factor out _get_library_path(). 2005-08-09 17:24:21 +00:00
Patrick Caulfield
7a8ea2ac93 Don't send a signal to kill threads that are idling nicely as it upsets them.
This seems to cure bz#159727 on SMP systems.

Alasdair, can you include this patch in the lvm2-cluster package please ?
2005-08-09 10:39:57 +00:00
Alasdair Kergon
0da3965d19 Report 'buffer full' condition with v4 ioctl as well as with v1. 2005-08-08 18:40:17 +00:00
Alasdair Kergon
885fd7bb46 aoe 2005-08-08 17:55:35 +00:00
Alasdair Kergon
08771f9c89 Recognise aoe devices. 2005-08-08 17:54:23 +00:00
Alasdair Kergon
8be48195a5 post-release 2005-08-04 02:07:34 +00:00
Alasdair Kergon
98ce2d650e update po 2005-08-04 02:02:37 +00:00
Alasdair Kergon
3af327116a Fix lvconvert PV parameter in help string. 2005-08-04 01:50:17 +00:00
Alasdair Kergon
b75434db93 fix last checkin 2005-08-04 01:29:18 +00:00
Alasdair Kergon
04e912aacd Prevent snapshots getting activated in a clustered VG. 2005-08-04 01:27:25 +00:00
Alasdair Kergon
d7be352f87 Separate out _build_dev_string. 2005-08-04 01:15:30 +00:00
Alasdair Kergon
96be3ec22c Move zero_lv to toollib. 2005-08-04 01:14:36 +00:00
Alasdair Kergon
32e7e0d790 post-release 2005-08-02 21:46:49 +00:00
Alasdair Kergon
becc320e62 update vsn 2005-08-02 18:00:32 +00:00
Alasdair Kergon
7666ed57d1 Fix dmsetup ls -j and status --target with empty table. 2005-07-29 16:11:23 +00:00
AJ Lewis
5e61d0955e fix pool format handler to work with pvseg code 2005-07-26 21:48:18 +00:00
Alasdair Kergon
e8a4662ae7 post-release 2005-07-13 19:28:09 +00:00
Alasdair Kergon
a48da3bd3b update po 2005-07-13 19:23:48 +00:00
Alasdair Kergon
5f1a5d7b99 2.01.13 2005-07-13 19:15:09 +00:00
Alasdair Kergon
3e28a9db8f Fix pvmove segment splitting.
Abstract vg_validate.
2005-07-12 19:40:59 +00:00
Alasdair Kergon
ebf6071d77 Only make one attempt at contiguous allocation. 2005-07-12 14:50:45 +00:00
Alasdair Kergon
47a35fb9fb Fix lvm1 format metadata read. 2005-06-22 15:31:29 +00:00
Alasdair Kergon
48e88aba44 fix lvm1 non-mirror lvcreate 2005-06-22 14:56:14 +00:00
Benjamin Marzinski
b85f99c140 Fixing some makesfiles, so that the correct things link against pthreads.
Also changed dmevent so that in no longer links against pthreads, and
dynamically loads libdmevent.so.  Everything seems to work just fine like this.
2005-06-14 19:06:26 +00:00
Alasdair Kergon
0a5e0e1f71 preset pl to NULL 2005-06-14 18:29:12 +00:00
Alasdair Kergon
85dc22ebb7 missing fn defs 2005-06-14 18:22:31 +00:00
Alasdair Kergon
5c21526009 post-release 2005-06-14 18:22:22 +00:00
Alasdair Kergon
14dff1cefc 2.01.12 2005-06-14 17:59:57 +00:00
Alasdair Kergon
39fbb844f9 Various allocation-related pvmove fixes. 2005-06-14 17:54:48 +00:00
Patrick Caulfield
ca4e0c973a Log an error if clvmd can't resolve a host name got from CCS
Fix potential spin loop in clvmd
2005-06-14 10:35:02 +00:00
Alasdair Kergon
ecb42bee80 post-release 2005-06-13 14:53:07 +00:00
Alasdair Kergon
674ed2a9f3 2.01.11 2005-06-13 14:43:28 +00:00
Alasdair Kergon
252daf9717 Use matchpathcon mode parameter. 2005-06-13 13:13:15 +00:00
Alasdair Kergon
196b8eaad3 Use matchpathcon mode parameter 2005-06-13 13:11:48 +00:00
Patrick Caulfield
8e526ba1bf Don't defer closing of FDs in clvmd as it can cause trouble. 2005-06-13 10:16:21 +00:00
Alasdair Kergon
19225828d9 update version 2005-06-10 22:00:44 +00:00
Alasdair Kergon
7e594126be fix configure script to reenable selinux 2005-06-10 21:57:49 +00:00
AJ Lewis
d2529e6334 o print the context along with the path when setting selinux context 2005-06-10 21:30:21 +00:00
AJ Lewis
97344f18e2 o set umask and make tempfiles a bit nicer to deal with 2005-06-10 19:10:45 +00:00
AJ Lewis
33934db629 o script to adjust items in lvm.conf file - currently only handles turning
cluster lvm on and off
2005-06-10 17:11:48 +00:00
Patrick Caulfield
6c6165c9f5 Be a bit smarter about reading stuff from the sockets 2005-06-10 09:11:01 +00:00
Benjamin Marzinski
853460b20d Timeout event implementation:
The daemon side of this is mostly the same as the patch I sent out.  To select
a timeout period different than the default and to get the timeout period,
I added two library calls, dm_set_event_timeout() and dm_get_event_timeout().
If people are against them, the other option is to tack extra arguments onto
dm_regiser_for_event() and dm_get_registered_device().  I also added a
-t option to dmevent, so people can try out timeouts.
2005-06-09 18:40:49 +00:00
Alasdair Kergon
cc4d9676c5 Remove hard-coded 64k text metadata writing restriction. 2005-06-07 11:00:07 +00:00
Alasdair Kergon
1cf1b819f4 Make VG name restrictions consistent. 2005-06-06 18:16:33 +00:00
Alasdair Kergon
f916c66d2b Introduce lvconvert. So far only removes mirror images. 2005-06-06 17:12:08 +00:00
Alasdair Kergon
550aa86b45 prevent active mirror resize for now 2005-06-03 22:26:09 +00:00
Alasdair Kergon
014e764758 Allow mirror images to be resized. 2005-06-03 19:48:19 +00:00
Alasdair Kergon
d1fc28432b Allow mirror images to have more than one segment. 2005-06-03 18:07:13 +00:00
Alasdair Kergon
879576f0a2 lvremove mirror images 2005-06-03 15:44:12 +00:00
Alasdair Kergon
69098210be Always insert an intermediate layer for mirrors.
Suppress hidden LVs from reports unless --all is given.
Use square brackets for hidden LVs in reports.
Centralise restrictions on LV names.
2005-06-03 14:49:51 +00:00
Alasdair Kergon
99df4f892d Basic support for mirrors. 2005-06-01 16:51:55 +00:00
AJ Lewis
7bc04fbad3 Change the multilog code to toggle between async and sync writes for all
log types.  This means the threaded_syslog type is no longer valid.  A new
fxn multilog_async is available to toggle between the two modes.  If an
app is compiled without pthreads and tries to use async logging, no logging
will occur while async is enabled.

dmeventd has been modified to use the new code

I'm not positive I like the way the async_logger code calls the log fxn,
but it works for now.  Suggestions for other ways to do it would be helpful
2005-05-25 21:08:36 +00:00
Alasdair Kergon
8a74ce578d Fix non-orphan pvchange -u. 2005-05-24 17:38:26 +00:00
Alasdair Kergon
0805e4e5de Fix mem allocs after archiver code move. 2005-05-24 17:37:39 +00:00
Heinz Mauelshagen
f1060fc88e Exit after last unregister_for_event() 2005-05-20 13:53:26 +00:00
Alasdair Kergon
7d3d3d0a3a Fix vgmerge to handle duplicate LVIDs. 2005-05-19 16:48:51 +00:00
Alasdair Kergon
40377032e3 1.01.02 2005-05-17 15:50:25 +00:00
Alasdair Kergon
b2971edd7d Start merging cloned allocation functions. 2005-05-17 13:49:45 +00:00
Alasdair Kergon
c37d723692 Move archiver code from tools into library. 2005-05-17 13:46:38 +00:00
Alasdair Kergon
30f9026e1d vgscan/change/display/vgs automatically create metadata backup if out-of-date or missing. 2005-05-17 13:44:02 +00:00
Alasdair Kergon
332286072e Add dmsetup ls --exec. 2005-05-16 20:46:46 +00:00
Alasdair Kergon
d6da172a2a Add --target to dmsetup ls. 2005-05-16 16:04:34 +00:00
Alasdair Kergon
ebfe584afc Call dm_lib_exit() and dm_lib_release() automatically now. 2005-05-16 15:15:34 +00:00
Alasdair Kergon
6250023583 Add --target <target_type> filter to dmsetup table/status.
Fix dmsetup getopt_long usage.
2005-05-16 14:53:23 +00:00
Alasdair Kergon
6b4f3d63b8 Fix contiguous allocations with linear. 2005-05-11 16:46:59 +00:00
AJ Lewis
56db773a09 more clvmd rhel4 initscript cleanup
- don't echo after an 'action' call - action does the echo itself
 - use vgdisplay/vgs to determine which VGs are marked clustered and only
   deactivate those VGs (unless the LVM_VGS var is set in
   /etc/sysconfig/cluster)
2005-05-11 15:21:44 +00:00
Alasdair Kergon
fc6c472401 Cope with missing format1 PVs again. 2005-05-11 15:04:06 +00:00
Alasdair Kergon
2cd42a6866 Remove lists of free PV segments.
Simplify pv_maps code and remove slow bitset algorithm.
2005-05-11 15:02:49 +00:00
AJ Lewis
36a90c345c updated to reflect clvmd rhel4 initscript being redhatified 2005-05-10 20:15:39 +00:00
AJ Lewis
ef1e82c72c Fixes bz#155478
Redhatify the rhel4 initscript (use /etc/init.d/functions)
2005-05-10 20:14:33 +00:00
AJ Lewis
88f9534685 o Changed the multilog API a bit (I warned you)
- multilog_add_type, multilog_del_type, multilog_custom, and
     multilog_init_verbose all have different arguments.
   - Primary change is that caller only passes in config info, and the
     lib keeps track of state internally.  No more exporting of
     'struct log_data'.
   - Custom callers now only get the custom data pointer passed into their
     log fxn (that is set with multilog_custom)
   - Added basic README that describes libmultilog
2005-05-09 18:44:35 +00:00
Alasdair Kergon
68254a052a %Zu->zu 2005-05-09 17:45:06 +00:00
Alasdair Kergon
2425b3a166 fix compiler warnings 2005-05-09 17:41:36 +00:00
Alasdair Kergon
5524ed753b Fix loopfiles mem alloc. 2005-05-09 17:02:52 +00:00
Alasdair Kergon
89711723da Un-inline dbg_strdup. 2005-05-09 17:01:06 +00:00
Alasdair Kergon
bed2740ffd lv_reduce tidying.
Remove some unnecessary parameters.
Introduce seg_is macros.
2005-05-09 16:59:01 +00:00
Alasdair Kergon
751d633c3d post-release 2005-05-09 16:41:48 +00:00
Benjamin Marzinski
45952cbdf2 oops. Those are char **'s not char *'s 2005-05-04 19:24:03 +00:00
Benjamin Marzinski
b355dd7b23 fixed dmevent so that it doesn't do a double free when you run
# dmevent -l

Also, changed the behaviour of dm_get_registered_device(), so that it doesn't
change the pointer you passed in without freeing the memory on a non-next call,
and doesn't free your pointer without setting it to NULL on a failed next call.
2005-05-04 18:53:28 +00:00
Heinz Mauelshagen
48a186f172 o libmultilog needs introducing of list locking in order to stand
multilog_add_type()/multilog_del_type cycles correctly.
o fixed segfault in multilog_add_type()
o fixed test-multilog.c
o cleaned up libmultilog (list macros, indentation, braces, comments)
2005-05-04 11:52:07 +00:00
Jonathan Earl Brassow
39dc7ec2ab - make noop use multilog
- add event_nr to thread_status struct and set appropriately so that the
  thread actually waits for an event
- essentially make error_detected return true.  Let the DSOs determine
  how to interpret the status info
2005-05-04 01:57:31 +00:00
AJ Lewis
2fedabd3b9 o stick multilog into the dm-event lib and dmeventd code again
o more tweaks to libmultilog calls - the api isn't set in stone yet, so
   don't get too comfortable.
 o not sure the dmeventd in device-mapper/dmeventd works - i've been using
   the one in lib/event/
 o currently both daemons are set to log only to syslog
2005-05-03 21:29:13 +00:00
Alasdair Kergon
6d719e9480 2.01.10 2005-05-03 17:43:47 +00:00
Alasdair Kergon
05e278afda Don't create backup and archive dirs till needed. 2005-05-03 17:31:56 +00:00
Alasdair Kergon
87dbf462cb Reinstate full PV size when removing from VG.
Support loopfiles for testing.
Complete the pv_segment support.
2005-05-03 17:28:23 +00:00
Heinz Mauelshagen
40e896bc5b working dm_get_registered_device(). dmevent.c update to use it. 2005-05-03 16:15:20 +00:00
Heinz Mauelshagen
3e940f80c7 more dm_get_registered_device() code 2005-05-03 13:50:42 +00:00
Benjamin Marzinski
dbf2888d43 dmeventd was looking for dsos with libdmeventd<name>.so
The Makefile turned noop.c into    libdmeventnoop.so
The Makefile now turns noop.c into libdmeventdnoop.so
2005-05-02 19:34:25 +00:00
Benjamin Marzinski
d412355324 stopped printing a string after we erased the pointer to it. 2005-05-02 18:43:23 +00:00
Benjamin Marzinski
178732217f removed the -lmultilog for now. 2005-05-02 18:42:07 +00:00
Benjamin Marzinski
de17b95c3d get the makefile to clean up the .o's 2005-05-02 17:41:54 +00:00
Heinz Mauelshagen
d14e774525 Introduce exit() in main() and cleanup signal settings for parent/child 2005-05-02 11:02:19 +00:00
Benjamin Marzinski
ca5402a7fa more variable initialization. 2005-04-29 22:12:09 +00:00
Benjamin Marzinski
7a6fa7c5b4 changed client_path and sever_path from 'char *' to 'const char *' to stop
compiler warning messages.
2005-04-29 21:52:46 +00:00
Heinz Mauelshagen
da36c286a6 o checking in instrumented code for AJ to follow up on comms and logging
o changed

  int dm_get_next_registered_device(char **dso_name, char **device,
                                    enum event_type *events);

  to

  int dm_get_registered_device(char **dso_name, char **device,
                               enum event_type *events, int next)

  so that the daemon is able to retrive the next one of the list without
  running into locking issues.

o changed dmevent.c to use dm_get_registered_device()

o couldn't test this yet because of the comms issues
  (daemon exits in do_process_request())
2005-04-29 14:56:35 +00:00
Heinz Mauelshagen
d3901bcf2e first changes to get comms back to work after flock changes 2005-04-29 13:41:25 +00:00
Heinz Mauelshagen
94c8d4fdfb minor cleanup 2005-04-29 10:58:34 +00:00
AJ Lewis
ab8bdc18bb o Build dmeventd against multilog 2005-04-28 22:47:52 +00:00
Alasdair Kergon
c9dcd7442a build libdmeventnoop.so for testing 2005-04-28 17:32:27 +00:00
Alasdair Kergon
34c8f13346 test.c->dmevent.c 2005-04-28 14:49:41 +00:00
Alasdair Kergon
7a8ccda95c o adds dm_get_next_registered_device() (not functional yet)
to retrieve which devices got registered with the daemon;
  needs locking changes as well
2005-04-28 14:02:30 +00:00
Alasdair Kergon
44a1448542 Prototype for a device-mapper event-handling daemon. 2005-04-27 22:32:00 +00:00
Alasdair Kergon
c87d89ffaf extend alloc_lv_segment 2005-04-22 15:44:00 +00:00
Alasdair Kergon
0868749d42 set_lv_segment_area_pv/lv 2005-04-22 15:43:02 +00:00
Alasdair Kergon
1d40ee23f0 Initial pv_segment code. 2005-04-19 20:58:25 +00:00
Alasdair Kergon
8893f32603 initial pv_segment defns 2005-04-19 20:52:35 +00:00
Alasdair Kergon
adcf7e8dc3 _copy_pv -> int 2005-04-19 20:44:21 +00:00
Patrick Caulfield
901f7c5c36 Tidy clvmd's SIGHUP handler so it doesn't do all that work. 2005-04-19 10:36:42 +00:00
Alasdair Kergon
775bb413b3 vgchange --physicalextentsize (but only if it's an exact fit - may need to
use pvmove first)
2005-04-18 14:56:42 +00:00
Alasdair Kergon
64cd5b5a46 extract compose_log_line 2005-04-17 23:59:04 +00:00
Alasdair Kergon
ae356609b1 get_pv_from_vg_by_id 2005-04-17 23:57:44 +00:00
Patrick Caulfield
6102a5d2b0 Make clvmd work around some "limitations" in gulm's node state notifications.
Also make clvmd debuglog timestamps a little more helpful.
2005-04-13 13:50:07 +00:00
Alasdair Kergon
f8782ee2d7 Internal snapshot code restructuring. 2005-04-07 12:39:44 +00:00
Alasdair Kergon
6181ec4c77 add lvid to lv_create_empty 2005-04-07 12:29:46 +00:00
Alasdair Kergon
e0e7a685ef Remove unused internal non-persistent snapshot option. 2005-04-07 12:27:57 +00:00
Alasdair Kergon
ae1f8cdad2 fix unused o_direct label 2005-04-07 12:25:33 +00:00
Alasdair Kergon
a4cf792e6d store snapshot id as lvid internally 2005-04-07 12:24:48 +00:00
Alasdair Kergon
89109ded53 Allow offline extension of snapshot volumes.
NB Requires kernel patch that is not upstream.
2005-04-07 12:17:46 +00:00
Alasdair Kergon
e20e52a4b2 Move from 2-step to 3-step on-disk metadata commit. 2005-04-06 18:59:55 +00:00
Alasdair Kergon
20c4b1cbec Add ramdisk. 2005-04-06 16:43:59 +00:00
Alasdair Kergon
5238b0241d _vg_posn -> _find_vg_rlocn 2005-04-06 16:35:33 +00:00
Alasdair Kergon
9cdf6c203d more refinements 2005-04-06 15:21:28 +00:00
Alasdair Kergon
839335cae6 Annotate, tidy and extend list.h. 2005-04-06 14:50:37 +00:00
Alasdair Kergon
a99b2ce167 Alignment tidying. 2005-04-06 13:47:41 +00:00
Alasdair Kergon
b695141d87 post-release 2005-04-04 15:46:14 +00:00
Alasdair Kergon
92d5c9f866 2.01.09 2005-04-04 15:41:51 +00:00
Alasdair Kergon
7f18a1ffe0 Add --ignorelockingfailure to vgmknodes. 2005-04-04 14:44:49 +00:00
Patrick Caulfield
8c3fdaaa62 set SO_KEEPALIVE on sockets 2005-04-01 16:03:00 +00:00
Patrick Caulfield
5ac1c69710 Don't allow user operations to start until the lvm thread is fully up.
Hopefully finally nails bz#146056
2005-04-01 13:01:01 +00:00
Alasdair Kergon
de2d5fba63 post-release 2005-03-29 18:10:57 +00:00
Alasdair Kergon
33d516748f 1.01.01 2005-03-29 14:47:39 +00:00
Alasdair Kergon
de17f6f0fd Update dmsetup man page. 2005-03-29 14:46:30 +00:00
Alasdair Kergon
756731fc02 Drop-in devmap_name replacement. 2005-03-27 11:37:46 +00:00
Alasdair Kergon
e46be0415f post-release 2005-03-22 16:50:17 +00:00
Alasdair Kergon
aa02fb50bf update pofile 2005-03-22 15:13:48 +00:00
Alasdair Kergon
8b6cd9c772 2.01.08 2005-03-22 15:12:37 +00:00
Alasdair Kergon
cdd0d3351a Add clustered attribute so vgchange can identify clustered VGs w/o locking. 2005-03-21 22:55:12 +00:00
Alasdair Kergon
8b6d584529 Improve detection of external changes affecting internal cache. 2005-03-21 22:40:35 +00:00
Alasdair Kergon
f49fdd4141 Add 'already in device cache' debug message. 2005-03-21 14:51:49 +00:00
Alasdair Kergon
b26e1be81a Add -a to pvdisplay -C. 2005-03-21 14:47:36 +00:00
Alasdair Kergon
bacab38d7f Avoid rmdir opendir error messsages when dir was already removed. 2005-03-21 14:43:02 +00:00
Alasdair Kergon
701c05ce96 Tighten signal handlers. 2005-03-21 14:16:16 +00:00
Alasdair Kergon
438c452585 Fix WHATS_NEW. 2005-03-10 23:04:42 +00:00
Alasdair Kergon
0a7a1eff3f Avoid some compiler warnings. 2005-03-10 22:34:17 +00:00
Alasdair Kergon
87e743e381 Additional rename failure error message. 2005-03-10 22:31:10 +00:00
Alasdair Kergon
a03f1b3d55 read/write may be macros 2005-03-10 20:23:36 +00:00
Alasdair Kergon
2d8dc3d243 post-release 2005-03-10 20:22:40 +00:00
Patrick Caulfield
b982232cc5 Don't take out the lvm_thread_lock at startup - it only protects the jobs list.
DEBUGLOG() message now print threadid rather than PID which is more useful.
2005-03-09 14:08:11 +00:00
Alasdair Kergon
61c8d728ac update pofile 2005-03-08 13:48:13 +00:00
Alasdair Kergon
851a2bf855 Cope with new devices appearing by rescanning /dev if a uuid can't be found. 2005-03-08 13:46:17 +00:00
Alasdair Kergon
e0bdde3630 Remove DESTDIR from LVM_SHARED_PATH. 2005-03-08 13:39:39 +00:00
Patrick Caulfield
6a0dcd7f0e make clvmd FDs close-on-exec, to avoid warnings when running lvm via popen.
clvmd-gulm unlocks VG & orphan locks at startup in case they are stale.
clvmd-gulm now unlocks VG & orphan locks if client dies.
2005-03-07 17:03:44 +00:00
Alasdair Kergon
75f0b4c879 post-release 2005-03-03 22:31:01 +00:00
Alasdair Kergon
db536a9504 2.01.06 2005-03-03 22:26:34 +00:00
Alasdair Kergon
0fb114dede Option to suppress warnings of file descriptors left open. 2005-03-03 22:09:20 +00:00
Alasdair Kergon
e703342179 Suppress 'open failed' error messages during scanning. 2005-03-03 21:54:35 +00:00
Alasdair Kergon
35c8f4a611 Fix default value of metadatacopies in documentation (2->1). 2005-03-03 21:52:58 +00:00
Patrick Caulfield
7c89ae44a9 Fix clvmd-gulm node up/down code so it actually works.
clvmd-gulm now releases locks when shut down.
2005-02-22 16:26:21 +00:00
Patrick Caulfield
84fe06da22 ./configure --enable-debug now enables debugging code in clvmd 2005-02-21 15:58:06 +00:00
Patrick Caulfield
806318c8b3 Always manipulate both locks in sync_lock() otherwise they get left
hanging around and cause trouble.
2005-02-21 14:36:09 +00:00
Alasdair Kergon
3aac2e1822 post-release 2005-02-18 19:06:16 +00:00
Alasdair Kergon
168baef433 Static binary invokes dynamic binary if appropriate. 2005-02-18 18:58:31 +00:00
Patrick Caulfield
6dba6cd78d Cope with more than one message arriving at the TCP socket, also
fix some instances where the length in the message was wrong (cman
code didn't notice this because it is packet-based comms anyway)
2005-02-18 15:31:32 +00:00
Patrick Caulfield
502250d08f Fix gulm->errno error number conversion. 2005-02-17 12:56:19 +00:00
Patrick Caulfield
7395f0e680 Make config check a little more tolerant of library names. 2005-02-14 09:07:14 +00:00
Alasdair Kergon
494d3fdaca post-release 2005-02-09 18:26:38 +00:00
Alasdair Kergon
7b86a157de Add fixed offset to imported pool minor numbers. 2005-02-09 17:49:36 +00:00
Adam Manthei
0988c41785 o cluster lvm requires that /usr/sbin/$TOOL is used instead of
/sbin/lvm.static $TOOL

o made variables LVDISPLAY, VGSCAN and VGCHANGE configurable in
  /etc/sysconfig/cluster
2005-02-08 17:20:24 +00:00
Patrick Caulfield
522db1bf01 Fix thread shutdown race which could cause clvmd to hang in pthread_join. 2005-02-08 09:05:58 +00:00
Patrick Caulfield
06f066f90d Revert last clvmd patch. More testing reveals that this just doesn't
work yet.
2005-02-07 14:45:38 +00:00
Patrick Caulfield
f37b20677b Make clvmd use the command library rather than popen() to
preload the lock state.
2005-02-07 10:04:27 +00:00
Alasdair Kergon
cd2eac1032 lvm2cmd.so should skip the check for open fds. 2005-02-03 16:34:53 +00:00
Alasdair Kergon
8ac38d58d7 Remove unused -f from pvmove 2005-02-02 14:31:48 +00:00
Patrick Caulfield
4c80cc313a Make clvmd do a quick sanity check on the clustering bits of lvm.conf 2005-02-02 11:42:29 +00:00
Patrick Caulfield
1c65fee9b4 Get rid of "connection refused" message because Corey doesn't like it. 2005-02-02 09:17:56 +00:00
Alasdair Kergon
90dda7edc1 post-release 2005-02-01 16:40:16 +00:00
Alasdair Kergon
da054fae20 pofile 2005-02-01 16:33:45 +00:00
Alasdair Kergon
bdb6611e30 2.01.03 2005-02-01 16:29:22 +00:00
Alasdair Kergon
9284f973f1 More 64-bit display/report fixes. 2005-02-01 16:19:48 +00:00
Alasdair Kergon
2bfd64c3c9 Add option to compile without ioctl for testing. 2005-01-27 16:16:54 +00:00
Alasdair Kergon
939d24cce5 Fix DM_LIB_VERSION sed 2005-01-27 15:53:28 +00:00
Alasdair Kergon
27b0183c46 More informative startup mesg if can't create /etc/lvm. 2005-01-27 15:50:34 +00:00
Alasdair Kergon
d14efacac7 Fix snapshot device size bug (since 2.01.01). 2005-01-27 15:48:49 +00:00
Patrick Caulfield
150a002c40 Don't print CMAN error if initial probe fails - we could be running with GULM. 2005-01-26 09:30:52 +00:00
Patrick Caulfield
ce0def3bd8 Remove superflous &
Gulm clvmd no longer hangs trying to talk to a rebooted node.
2005-01-25 16:46:29 +00:00
Patrick Caulfield
ee20fa97c2 Make clvmd announce it's startup and cluster connection in syslog. 2005-01-24 15:31:13 +00:00
Alasdair Kergon
7403b7d700 postrelease 2005-01-21 19:03:48 +00:00
Alasdair Kergon
87ef173e0a update pofile 2005-01-21 18:51:48 +00:00
Alasdair Kergon
52a3fb6bc7 pre-release 2005-01-21 18:49:06 +00:00
Patrick Caulfield
92e2a257a6 Get rid of libclvm as it's out-of-date and not used at all. 2005-01-21 11:56:30 +00:00
Patrick Caulfield
32e175752c Fix clvmd startup bug introduced in cman/gulm amalgamation. bz#145729
Improve reporting of node-specific locking errors so you'll get
somthing a little more helpfiul than "host is down" - it will now tell
you /which/ host it thinks is down.
2005-01-21 11:35:24 +00:00
Alasdair Kergon
d43f7180dc Update clvmd_init_rhel4: use lvm.static and don't load dlm. 2005-01-20 22:16:55 +00:00
Alasdair Kergon
0129c2b0fc Fix some size_t printing. 2005-01-20 18:14:04 +00:00
Alasdair Kergon
4ed1990001 Fix 64 bit xlate consts. 2005-01-20 18:13:17 +00:00
Alasdair Kergon
5bd6ab27ae Split out pool sptype_names to avoid unused const. 2005-01-20 18:12:41 +00:00
Alasdair Kergon
f3593b89fa Always fail if random id generation fails. 2005-01-20 18:11:53 +00:00
Alasdair Kergon
23d84b2310 Recognise gnbd. 2005-01-19 18:56:01 +00:00
Alasdair Kergon
fdc49402ec fix clvmd lv_info_by_lvid open_count 2005-01-19 18:10:09 +00:00
Alasdair Kergon
5457c133e1 Add some comments. 2005-01-19 17:31:51 +00:00
Alasdair Kergon
292e588ee3 move recover_vg 2005-01-19 17:30:50 +00:00
Alasdair Kergon
243494c25e Store snapshot and origin sizes separately. 2005-01-19 17:19:39 +00:00
Alasdair Kergon
e4365f3706 Update vgcreate man page. 2005-01-19 17:01:18 +00:00
Alasdair Kergon
310f3038d3 Post-2.01.00 2005-01-17 20:45:05 +00:00
Alasdair Kergon
4e6033273d update po 2005-01-17 20:16:37 +00:00
Alasdair Kergon
73718586d3 2.01.00 2005-01-17 20:13:01 +00:00
Alasdair Kergon
011abe61e8 post-1.01.00 2005-01-17 20:12:12 +00:00
Alasdair Kergon
fe3a37f89d 1.01.00 2005-01-17 20:00:28 +00:00
Alasdair Kergon
8aea44e77b Fix vgscan metadata auto-correction. 2005-01-17 18:24:28 +00:00
Patrick Caulfield
5529aec0d6 You can now build clvmd with cman & gulm support in the same binary.
./configure --with-clvmd
wil do this by default. Or you can choose which you want with
./configure --with-clvmd=gulm    or
./configure --with-clvmd=cman

When clvmd with both included is run, it will automatically detect the cluster
manager in use.
2005-01-13 13:24:02 +00:00
Alasdair Kergon
369549d23f Only ask libdevmapper for open_count when we need it. 2005-01-12 22:58:21 +00:00
Alasdair Kergon
181ea9a381 Add dm_task_no_open_count() to skip getting open_count. 2005-01-12 22:10:14 +00:00
Alasdair Kergon
76b8f2854e Adjust RHEL4 clvmd init script priority. 2005-01-11 22:00:36 +00:00
Alasdair Kergon
320e5198f9 post-2.00.33 2005-01-07 20:06:49 +00:00
Alasdair Kergon
e522539e2d 2.00.33 2005-01-07 19:50:54 +00:00
Alasdair Kergon
7c996b83d2 post-1.00.21 2005-01-07 17:10:16 +00:00
Alasdair Kergon
3dd354d7aa 1.00.21 2005-01-07 15:53:37 +00:00
Alasdair Kergon
f4ad6e2157 Fix /proc/devices parsing. 2005-01-07 15:39:53 +00:00
Patrick Caulfield
8b170dc2bf Fix off-by-one error in cluster_locking that could case read hangs. 2005-01-07 14:22:49 +00:00
Alasdair Kergon
dcb9d779bf post-1.00.20 2005-01-06 18:41:38 +00:00
Alasdair Kergon
80f736d670 1.00.20 2005-01-06 18:30:17 +00:00
Alasdair Kergon
8502c6da3c Attempt to fix /dev/mapper/control transparently if it's wrong. 2005-01-06 18:22:44 +00:00
Patrick Caulfield
b131449422 Some more gulm fixes from "Mr gulm" himself. 2005-01-06 11:48:25 +00:00
Alasdair Kergon
6eebc4a620 Configuration-time option for setting uid/gid/mode for /dev/mapper nodes. 2005-01-05 22:00:40 +00:00
Alasdair Kergon
4661ab1179 pvcreate wipes first 4 sectors unless given --zero n. 2005-01-05 17:25:25 +00:00
Patrick Caulfield
86046445ed Improve clvmd failure message if it's already running.
Allow user to kill clvmd during initialisation.
2005-01-05 14:41:54 +00:00
Patrick Caulfield
baea9bf944 Typo in "for" caused first node in ccs to be ignored. 2005-01-04 15:11:34 +00:00
Patrick Caulfield
0951ee9e63 Use new CCS key names for nodes in the GULM version of clvmd.
based on a patch from Mike Tilstra
2005-01-04 11:48:10 +00:00
Alasdair Kergon
5492528287 post-2.00.32 2004-12-22 22:04:03 +00:00
Alasdair Kergon
14dbd220c2 update pofile 2004-12-22 21:58:26 +00:00
Alasdair Kergon
babc890c59 Drop static/dl config restriction for now. 2004-12-22 21:55:36 +00:00
Alasdair Kergon
6f7b47ff40 update version 2004-12-22 21:47:50 +00:00
Alasdair Kergon
3991f03202 Fix an error fprintf. 2004-12-22 21:47:31 +00:00
Alasdair Kergon
27271d5da7 Fix vgdisplay -s. Breaks (undocumented) lvs/pvs/vgs -s instead for now. 2004-12-21 21:40:36 +00:00
Alasdair Kergon
627312e1de Fix device reference counting on re-opens. 2004-12-21 20:23:16 +00:00
Alasdair Kergon
bfc9550e4e Ignore sysfs symlinks when DT_UNKNOWN. 2004-12-21 18:29:46 +00:00
Alasdair Kergon
2b9c21268b Add RHEL4 clvmd init script. 2004-12-21 18:07:15 +00:00
Alasdair Kergon
3dce4ed6f1 Skip devices that are too small to be PVs. 2004-12-21 17:54:52 +00:00
Alasdair Kergon
0f16c2ea87 Add CONTRIBUTORS file. 2004-12-21 16:24:19 +00:00
Alasdair Kergon
9a635f0686 Fix pvchange -x segfault with lvm2-format orphan. 2004-12-21 16:12:02 +00:00
Alasdair Kergon
6a0d4b2baa Cope with empty msdos partition tables. 2004-12-21 16:10:25 +00:00
Alasdair Kergon
ac017098ad post-2.00.31 2004-12-12 21:55:46 +00:00
Alasdair Kergon
98fef2640d update pofile 2004-12-12 21:51:59 +00:00
Alasdair Kergon
8bb66e133a 2.00.31 2004-12-12 21:47:55 +00:00
Alasdair Kergon
68a582901d Reopen RO file descriptor RW if necessary. 2004-12-12 21:47:14 +00:00
Alasdair Kergon
c094f4c06e post-2.00.30 2004-12-10 18:01:49 +00:00
Alasdair Kergon
f7ca545544 update pofile 2004-12-10 16:07:37 +00:00
Alasdair Kergon
69b4716894 2.00.30 2004-12-10 16:02:35 +00:00
Alasdair Kergon
7e44dcc5bf Additional device-handling debug messages.
Additional verbosity level -vvvv includes line numbers and backtraces.
Verbose messages now go to stderr not stdout.
Close any stray file descriptors before starting.
Refine partitionable checks for certain device types.
Allow devices/types to override built-ins.
2004-12-10 16:01:35 +00:00
Alasdair Kergon
ab9843e183 Fix lvreduce man page .i->.I 2004-12-09 16:59:18 +00:00
Alasdair Kergon
01af706ade Fix vgsplit man page title. 2004-12-09 16:58:31 +00:00
Alasdair Kergon
9ebdb08e99 Fix clvmd man makefile. 2004-12-09 16:57:37 +00:00
Alasdair Kergon
a74ffe25d9 Extend dev_open logging. 2004-12-09 16:56:51 +00:00
Patrick Caulfield
7f95e27707 Make clvmd_fix_conf.sh UNDOable 2004-12-01 14:47:31 +00:00
Alasdair Kergon
1facf5bba3 post-29 2004-11-27 22:56:58 +00:00
Alasdair Kergon
03d77009eb xlate compilation fix 2004-11-27 22:07:41 +00:00
Alasdair Kergon
8afd6812b5 update version 2004-11-27 21:38:34 +00:00
Alasdair Kergon
ec9ad78fcf Endian fix to signature detection. 2004-11-27 21:37:54 +00:00
Alasdair Kergon
6f4e93dc90 Configure/makefile tidy. 2004-11-26 18:07:17 +00:00
Alasdair Kergon
a38e43862d fix partition table signature size 2004-11-26 14:40:34 +00:00
Alasdair Kergon
39294bb037 update pofile 2004-11-24 21:39:30 +00:00
Alasdair Kergon
edc5e59b78 Trap large memory allocation requests. 2004-11-24 21:34:56 +00:00
Alasdair Kergon
c00fd9fd37 Fix to partition table detection code. 2004-11-24 20:38:05 +00:00
Alasdair Kergon
b3e621dd9f Improve filter debug msgs. 2004-11-24 20:36:52 +00:00
Alasdair Kergon
6e8c49b978 post-release 2004-11-23 18:36:01 +00:00
Alasdair Kergon
398d57133d update po 2004-11-23 18:27:57 +00:00
Alasdair Kergon
16521a6feb pool debugging 2004-11-23 18:23:23 +00:00
Alasdair Kergon
3ca0b37a3e 2.00.26 2004-11-23 17:47:19 +00:00
Alasdair Kergon
cf2ec1229d fix a md filter log mesg 2004-11-23 17:45:48 +00:00
Alasdair Kergon
fe9b1e5f9b update pofile 2004-11-23 17:44:10 +00:00
Alasdair Kergon
f5b96ddf01 Detect partition table signature. 2004-11-23 11:44:04 +00:00
Alasdair Kergon
2fe076fb27 Only wipe signature bytes when destroying md superblock, so process
is reversible.
2004-11-19 19:32:09 +00:00
Alasdair Kergon
99249cff04 pvcreate wipes md superblocks. (With --uuid or --restorefile it prompts.) 2004-11-19 19:25:07 +00:00
Alasdair Kergon
0cdf7b0613 Separate out md superblock detection code. 2004-11-18 20:02:21 +00:00
Alasdair Kergon
90bcf4f157 Prevent snapshot origin resizing. 2004-11-18 19:49:48 +00:00
Alasdair Kergon
03c3ec4e12 Improve a vgremove error message. 2004-11-18 19:45:53 +00:00
Alasdair Kergon
ca9bb20d64 More tagging documentation, with some cluster examples. 2004-11-17 18:34:49 +00:00
Alasdair Kergon
c6bc078fd9 More lvm.conf and tagging documentation. 2004-11-17 17:49:32 +00:00
Alasdair Kergon
2f4bd6e52c More man page updates. 2004-11-16 18:09:32 +00:00
Patrick Caulfield
2affe53727 Tidy the socket callbacks so that all the work is done outside the
main loop.
2004-11-16 10:55:01 +00:00
Alasdair Kergon
09654d7dd8 update WHATS_NEW 2004-11-12 16:02:08 +00:00
Alasdair Kergon
90a4e37815 Update some man pages. 2004-11-12 15:59:09 +00:00
Alasdair Kergon
60889c0c79 Also accept y/n with -ae. 2004-11-12 15:58:26 +00:00
Patrick Caulfield
20f3408d96 Report detailed errors in cluster initialisation to syslog, and point the user
at syslog if clvmd fails to intialise.
2004-11-11 14:51:23 +00:00
Patrick Caulfield
e9d86789db Can now build a gulm version of clvmd instead of a cman one. use
./configure --with-clvmd=gulm

The default is still cman, and you can't have both - sorry.
2004-11-03 10:45:07 +00:00
Alasdair Kergon
5152b7c66c update 2004-10-15 17:31:37 +00:00
Alasdair Kergon
c494c4e12c Fixes to lvcreate vgname processing. 2004-10-15 15:53:18 +00:00
Alasdair Kergon
54d58ccb7e Add --noheadings option to dmsetup -c for colon-separated output. 2004-10-12 16:42:40 +00:00
Alasdair Kergon
714a77bfbe Fix size of dm_name string. 2004-10-11 15:59:23 +00:00
Patrick Caulfield
d48f8bf5cc Make clvmd -V display the lvm version number too rather than just
the protocol version (which is not that useful and doesn't change very often).
2004-10-06 12:36:47 +00:00
Patrick Caulfield
99d97754a6 Revert the fork back to where it was as it seems to confuse pthreads.
Instead, the parent now waits for the daemon to signal that it has
completed successfully (or not) so it can return status to the user.
2004-10-06 10:12:34 +00:00
Patrick Caulfield
b9d437de2a Change some perror() calls to log_error() so they'll appear in
syslog when we're a daemon.
2004-10-06 10:02:25 +00:00
Patrick Caulfield
11403f2019 Check the UUID length when readingthe output of the "lvs" command at startup.
This way we should not get quite so confused by any debugging output
that may come our way.
2004-10-04 09:23:52 +00:00
Alasdair Kergon
1ca102d639 Support device referencing by uuid or major/minor. 2004-10-01 19:11:37 +00:00
Alasdair Kergon
339ba55111 printf->fprintf 2004-10-01 19:07:41 +00:00
Patrick Caulfield
14ae59885a Make clvmd cope with large gaps in nodeIDs 2004-09-30 14:18:29 +00:00
Patrick Caulfield
e3ef54f99b Fork a little later in the startup sequence so that we can return
an error code if the cluster infrastructure isn't there.
2004-09-30 14:16:28 +00:00
Alasdair Kergon
001901f9a9 post-2.00.25 2004-09-29 15:25:43 +00:00
Alasdair Kergon
6a98f60e2e 2.00.25 2004-09-29 15:08:20 +00:00
Alasdair Kergon
6f2e24c47d Use macro in vgremove locking fix. 2004-09-27 10:32:36 +00:00
Patrick Caulfield
aafa368923 Hold VG lock while doing vgremove.
agk - you may want to check this.
2004-09-24 12:48:43 +00:00
Patrick Caulfield
eb783cab4c Remove spurious trailing dot in man page. 2004-09-24 10:34:53 +00:00
Patrick Caulfield
6533aa865a Keep client locks (VG locks usually) in their own hash table so
we can actually have more then one of them per client.
2004-09-24 09:39:57 +00:00
Patrick Caulfield
f1a1e1bc07 Update WHATS_NEW with latest clvmd change 2004-09-23 13:12:09 +00:00
Patrick Caulfield
953f4838dd Make the thread handling a little less cavalier. In particular, calling
pthread_exit in a signal handler was a /really/ bad idea.
2004-09-23 12:51:56 +00:00
Patrick Caulfield
130b892d34 Don't use hold_lock for VG locks as that doesn't stop processes contending
on the same node, only across the cluster.
2004-09-23 12:29:35 +00:00
Alasdair Kergon
6ad525c77e Fix return code from rm_link for vgmknodes. 2004-09-22 13:38:37 +00:00
Patrick Caulfield
d0ca74ad27 Put some locking round the LV hash table as it could be accessed by
different threads concurrently.
2004-09-22 12:10:34 +00:00
Alasdair Kergon
9806f69b4d post-2.00.24 2004-09-16 21:48:26 +00:00
Alasdair Kergon
34d9b5e3d7 2.00.24 2004-09-16 20:56:18 +00:00
Alasdair Kergon
3bf5189d86 Fix pool_empty so it really does empty the memory pool. 2004-09-16 20:09:55 +00:00
Alasdair Kergon
12e5b0681b Rename old segtypes files to segtype. 2004-09-16 18:40:56 +00:00
Alasdair Kergon
8c0285d608 Some fixes to memory debugging code.
Exclude internal commands formats & segtypes from install.
2004-09-16 16:53:39 +00:00
Alasdair Kergon
36558fa3b8 post-2.00.23 2004-09-15 15:59:19 +00:00
Alasdair Kergon
235f940cde 2.00.23 2004-09-15 15:32:21 +00:00
Alasdair Kergon
803d61fcbc Add formats & segtypes files. 2004-09-15 15:27:26 +00:00
Alasdair Kergon
ffbd7d8de4 Export dm name build & split functions. 2004-09-15 15:02:36 +00:00
Alasdair Kergon
4ed924d7c7 Use O_NOATIME on devices if available. 2004-09-14 22:23:23 +00:00
Alasdair Kergon
798dc9948b Write log message when each segtype/format gets initialised. 2004-09-14 17:37:51 +00:00
Alasdair Kergon
13515f7ee4 New commands 'segtypes' and 'formats'. 2004-09-14 16:42:46 +00:00
Alasdair Kergon
ef80824c26 Suppress pvmove abort message in test mode. 2004-09-14 15:23:42 +00:00
Alasdair Kergon
c8503fd65e Improve pvcreate/remove device not found error message. 2004-09-14 14:54:58 +00:00
Alasdair Kergon
b3c454fb1c Allow pvmove to move data within the same PV. 2004-09-14 13:59:17 +00:00
Alasdair Kergon
1d7723e873 Describe how pvmove works on man page. 2004-09-14 13:58:11 +00:00
Alasdair Kergon
77100b2365 Test for incompatible format/segtype combinations in lv_extend. 2004-09-14 13:56:18 +00:00
Patrick Caulfield
259a788134 Fix man page for lvchange. The example seems to have been lifted from pvchange. 2004-09-13 08:01:54 +00:00
Alasdair Kergon
39511455cb post 2.00.22 2004-09-03 19:18:23 +00:00
Alasdair Kergon
b04c16178e 2.00.22 2004-09-03 19:08:50 +00:00
Alasdair Kergon
49a959c06e Fix /dev/vgname mkdir perms. 2004-09-02 14:38:46 +00:00
Alasdair Kergon
096a8932b4 clvmd man page tweaks 2004-09-02 14:16:54 +00:00
Alasdair Kergon
e39e66df93 Restructure xlate.h 2004-09-02 13:53:25 +00:00
Patrick Caulfield
513633f49a clvmd man page. 2004-08-23 08:42:53 +00:00
Alasdair Kergon
eb3740daaf post-2.4.21 2004-08-19 17:13:49 +00:00
Alasdair Kergon
f7947b148a 2.00.21 2004-08-19 16:10:15 +00:00
Alasdair Kergon
9a2a702f3f Recognise iseries/vd devices. 2004-08-18 19:13:01 +00:00
Alasdair Kergon
c65d95bf29 Cluster-extension-only installation. 2004-08-18 18:57:40 +00:00
Alasdair Kergon
753a5edc4f Cope with DT_UNKNOWN in sysfs. 2004-08-18 18:50:21 +00:00
Alasdair Kergon
0b3f853c2d Update pvmove prototype. 2004-08-18 18:49:29 +00:00
Patrick Caulfield
3527fcf1d5 Updated file from cman. 2004-08-18 16:04:35 +00:00
Alasdair Kergon
4544a89c7a Support for PE ranges in pvmove source PV. 2004-08-17 22:09:02 +00:00
Alasdair Kergon
ffeae9005e Remove duplicate line in pvremove help text. 2004-08-17 22:06:06 +00:00
Alasdair Kergon
47217bcfb7 Change alloc_areas to pe_ranges and allow suppression of availability checks. 2004-08-17 21:55:23 +00:00
Alasdair Kergon
80ff58b57a Add a const. 2004-08-11 13:15:35 +00:00
Alasdair Kergon
d15dd368f1 Add dev_size column to pvs. 2004-08-11 13:15:05 +00:00
Alasdair Kergon
8a2ec32bd8 Add report columns for in-kernel device number. 2004-07-03 22:07:52 +00:00
Alasdair Kergon
410496ed52 update version 2004-07-03 18:29:48 +00:00
Alasdair Kergon
b7b07552e5 Misc autoconf fixes 2004-07-03 18:21:13 +00:00
Alasdair Kergon
44486e80d9 Fix ftp urls 2004-07-03 18:20:25 +00:00
217 changed files with 26315 additions and 8624 deletions

0
CONTRIBUTORS Normal file
View File

4
README
View File

@@ -9,8 +9,8 @@ Installation instructions are in INSTALL.
There is no warranty - see COPYING and COPYING.LIB.
Tarballs are available from:
ftp://ftp.sistina.com/pub/LVM2/tools/
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
ftp://sources.redhat.com/pub/lvm2/
ftp://sources.redhat.com/pub/dm/
To access the CVS tree use:
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login

View File

@@ -1 +1 @@
2.00.20-cvs (2004-06-29)
2.01.15-cvs (2005-08-04)

324
WHATS_NEW
View File

@@ -1,5 +1,327 @@
Version 2.00.20 -
Version 2.01.15 -
=================================
Fix chunksize field in reports.
Don't hide snapshots from default 'lvs' output.
Add is_dm_major() for use in duplicate device detection in lvmcache_add().
Really switch device number in lvmcache when it says it is doing so.
Option for bitset memory allocation using malloc as well as pool.
Don't assume exactly two mirrors when parsing mirror status.
Suppress fsync() error message on filesystems that don't support it.
Fix yes_no_prompt() error handling.
Add lvm.conf comment warning against multiple filter lines.
Tidy lvmconf.sh.
Add format1 dev_write debug messages.
Add clustered VG attribute to report.
Move lvconvert parameters into struct lvconvert_params.
Add clustered VG flag to LV lock requests.
Change LV locking macros to take lv instead of lvid.
Prepend 'cluster' activation parameter to mirror log when appropriate.
Pass exclusive flag to lv_activate and on to target activation code.
Prevent snapshot creation in a clustered VG for now.
Factor out adjusted_mirror_region_size() and generate_log_name_format().
Move compose_log_line() into mirror directory.
Factor out _get_library_path().
Don't kill idling clvmd threads.
clvmd no longer takes out locks for non-clustered LVs.
Recognise ATA over Ethernet (aoe) devices.
Version 2.01.14 - 4th August 2005
=================================
Fix lvconvert PV parameter in help string.
Prevent snapshots getting activated in a clustered VG.
Separate out _build_dev_string.
Move zero_lv to toollib.
Fix pool format handler to work with pv segment code.
Version 2.01.13 - 13th July 2005
================================
Fix pvmove segment splitting.
Abstract vg_validate.
Only make one attempt at contiguous allocation.
Fix lvm1 format metadata read.
Fix lvm1 format non-mirror lvcreate.
Version 2.01.12 - 14th June 2005
================================
Various allocation-related pvmove fixes.
Log an error if clvmd can't resolve a host name got from CCS.
Fix potential spin loop in clvmd.
Version 2.01.11 - 13th June 2005
================================
Added lvmconf.sh.
Use matchpathcon mode parameter.
Don't defer closing dead FDs in clvmd.
Remove hard-coded 64k text metadata writing restriction.
Make VG name restrictions consistent.
Introduce lvconvert. So far only removes mirror images.
Allow mirror images to be resized.
Allow mirror images to have more than one segment.
Centralise restrictions on LV names.
Always insert an intermediate layer for mirrors.
Suppress hidden LVs from reports unless --all is given.
Use square brackets for hidden LVs in reports.
Allow the creation of mirrors with contiguous extents.
Always perform sanity checks against metadata before committing it to disk.
Split lv_extend into two steps: choosing extents + allocation to LV(s).
Add mirror log region size to metadata.
Use list_iterate_items throughout and add list*back macros.
Introduce seg_ macros to access areas.
Add segtype_is_ macros.
Support tiny metadata areas for pool conversions.
Mirror activation handles disk log as well as core.
Activation code recognises mirror log dependency.
Add mirror_log and regionsize fields to report.
Fix non-orphan pvchange -u.
Fix vgmerge to handle duplicate LVIDs.
Move archiver code from tools into library.
vgscan/change/display/vgs automatically create metadata backups if needed.
Merge cloned allocation functions.
Fix contiguous allocation policy with linear.
Cope with missing format1 PVs again.
Remove lists of free PV segments.
Simplify pv_maps code and remove slow bitset algorithm.
Red-Hat-ify the clvmd rhel4 initscript.
%Zu->%zu
Fix loopfiles alias alloc & mem debugging.
Un-inline dbg_strdup.
lv_reduce tidying.
Remove some unnecessary parameters.
Introduce seg_is macros.
Version 2.01.10 - 3rd May 2005
==============================
Don't create backup and archive dirs till needed.
Reinstate full PV size when removing from VG.
Support loopfiles for testing.
Tidy lv_segment interface.
pv_segment support.
vgchange --physicalextentsize
Internal snapshot restructuring.
Remove unused internal non-persistent snapshot option.
Allow offline extension of snapshot volumes.
Move from 2-step to 3-step on-disk metadata commit.
Scan ramdisks too and allow non-O_DIRECT fallback.
Annotate, tidy and extend list.h.
Alignment tidying.
Make clvmd work around some "bugs" in gulm's node state notifications.
Tidy clvmd's SIGHUP handler
Version 2.01.09 - 4th April 2005
================================
Add --ignorelockingfailure to vgmknodes.
clvmd: Don't allow user operations to start until the lvm thread is fully up.
clvmd-gulm: set KEEPALIVE on sockets.
Version 2.01.08 - 22nd March 2005
=================================
Add clustered attribute so vgchange can identify clustered VGs w/o locking.
Improve detection of external changes affecting internal cache.
Add 'already in device cache' debug message.
Add -a to pvdisplay -C.
Avoid rmdir opendir error messsages when dir was already removed.
Tighten signal handlers.
Avoid some compiler warnings.
Additional rename failure error message.
read/write may be macros.
clvmd: don't take out lvm thread lock at startup, it only protects jobs list.
Version 2.01.07 - 8th March 2005
================================
Cope with new devices appearing by rescanning /dev if a uuid can't be found.
Remove DESTDIR from LVM_SHARED_PATH.
clvmd fixes: make FDs close-on-exec
gulm unlocks VG & orphan locks at startup in case they are stale
gulm now unlocks VG & orphan locks if client dies.
Version 2.01.06 - 1st March 2005
================================
Suppress 'open failed' error messages during scanning.
Option to suppress warnings of file descriptors left open.
Fix default value of metadatacopies in documentation (2->1).
Fix clvmd-gulm locking.
./configure --enable-debug now enables debugging code in clvmd.
Fix clvmd-gulm node up/down code so it actually works.
clvmd-gulm now releases locks when shut down.
Version 2.01.05 - 18th February 2005
====================================
Static binary invokes dynamic binary if appropriate.
Make clvmd config check a little more tolerant.
gulm clvmd can now cope with >1 message arriving in a TCP message.
Version 2.01.04 - 9th February 2005
===================================
Add fixed offset to imported pool minor numbers.
Update binary pathnames in clvmd_init_rhel4.
lvm2cmd.so should skip the check for open fds.
Remove unused -f from pvmove.
Gulm clvmd doesn't report "connection refused" errors.
clvmd does a basic config file sanity check at startup.
Fix potential thread shutdown race in clvmd.
Version 2.01.03 - 1st February 2005
===================================
More 64-bit display/report fixes.
More informative startup mesg if can't create /etc/lvm.
Fix snapshot device size bug (since 2.01.01).
clvmd announces startup and cluster connection in syslog.
Gulm clvmd doesn't hang trying to talk to a rebooted node.
Gulm clvmd doesn't print cman error on startup.
Version 2.01.02 - 21st January 2005
===================================
Update clvmd_init_rhel4: use lvm.static and don't load dlm.
Fix some size_t printing.
Fix 64 bit xlate consts.
Split out pool sptype_names to avoid unused const.
Always fail if random id generation fails.
Recognise gnbd devices.
Fix clvmd startup bug introduced in cman/gulm amalgamation.
Improve reporting of node-specific locking errors.
Version 2.01.01 - 19th January 2005
===================================
Fix clvmd lv_info_by_lvid open_count.
Store snapshot and origin sizes separately.
Update vgcreate man page.
Version 2.01.00 - 17th January 2005
===================================
Fix vgscan metadata auto-correction.
Only ask libdevmapper for open_count when we need it.
Adjust RHEL4 clvmd init script priority.
Enable building of CMAN & GULM versions of clvmd into a single binary
Version 2.00.33 - 7th January 2005
==================================
pvcreate wipes first 4 sectors unless given --zero n.
gulm clvmd now uses new ccsd key names.
gulm clvmd now doesn't ignore the first node in cluster.conf
Improve clvmd failure message if it's already running.
Allow user to kill clvmd during initialisation.
Fix off-by-one error in cluster_locking that could cause read hangs.
Version 2.00.32 - 22nd December 2004
====================================
Drop static/dl restriction for now.
Fix an error fprintf.
Fix vgdisplay -s. Breaks (undocumented) lvs/pvs/vgs -s instead for now.
Fix device reference counting on re-opens.
Ignore sysfs symlinks when DT_UNKNOWN.
Add clvmd init script for RHEL4.
Skip devices that are too small to be PVs.
Fix pvchange -x segfault with lvm2-format orphan.
Cope with empty msdos partition tables.
Add CONTRIBUTORS file.
Version 2.00.31 - 12th December 2004
====================================
Reopen RO file descriptors RW if necessary.
Version 2.00.30 - 10th December 2004
====================================
Additional device-handling debug messages.
Additional verbosity level -vvvv includes line numbers and backtraces.
Verbose messages now go to stderr not stdout.
Close any stray file descriptors before starting.
Refine partitionable checks for certain device types.
Allow devices/types to override built-ins.
Fix lvreduce man page .i->.I
Fix vgsplit man page title.
Fix clvmd man makefile.
Extend dev_open logging.
Make clvmd_fix_conf.sh UNDOable.
Version 2.00.29 - 27th November 2004
====================================
xlate compilation fix.
Version 2.00.28 - 27th November 2004
====================================
Fix partition table & md signature detection.
Minor configure/makefile tidy.
Export version.h from tools for clvmd.
Version 2.00.27 - 24th November 2004
====================================
Trap large memory allocation requests.
Fix to partition table detection code.
Improve filter debug mesgs.
Make clvmd_fix_conf.sh UNDOable
Version 2.00.26 - 23rd November 2004
====================================
Improve pool debugging stats.
Detect partition table signature.
pvcreate wipes md superblocks. (With --uuid or --restorefile it prompts.)
Separate out md superblock detection code.
Prevent snapshot origin resizing.
Improve a vgremove error message.
Update some man pages.
Allow y/n with -ae args (exclusive activation).
Fixes to lvcreate vgname parsing.
Fix dm_name string size calculation.
Improve clvmd error reporting during startup.
Make clvmd cope with large gaps in node numbers IDs.
Make clvmd initialisation cope better with debugging output.
Tidy clvmd socket callbacks so all work happens outside main loop.
clvmd -V now displays lvm version too.
Add optional gulm build for clvmd
Version 2.00.25 - 29th September 2004
=====================================
Fix return code from rm_link for vgmknodes.
Make clvmd LV hash table thread-safe.
Fix clvmd locking so it will lock out multiple users on the same node.
Fix clvmd VG locking to it can cope with multiple VG locks.
Remove spurious trailing dot in lvreduce man page.
Fix vgremove locking.
Version 2.00.24 - 16th September 2004
=====================================
Fix pool_empty so it really does empty the memory pool.
Rename old segtypes files to segtype.
Some fixes to memory debugging code.
Exclude internal commands formats & segtypes from install.
Version 2.00.23 - 15th September 2004
=====================================
Export dm name build & split functions.
Use O_NOATIME on devices if available.
Write log message when each segtype/format gets initialised.
New commands 'segtypes' and 'formats'.
Suppress pvmove abort message in test mode.
Improve pvcreate/remove device not found error message.
Allow pvmove to move data within the same PV.
Describe how pvmove works on man page.
Test for incompatible format/segtype combinations in lv_extend.
Fix lvchange example on man page.
Version 2.00.22 - 3rd September 2004
====================================
Fix /dev/vgname perms.
Restructure xlate.h.
Add clvmd man page.
Version 2.00.21 - 19th August 2004
==================================
Update cnxman-socket.h from cman.
Recognise iseries/vd devices.
Use 'make install_cluster' to install cluster extensions only.
Cope with DT_UNKNOWN in sysfs.
Fix extents_moved metadata size comment.
Remove duplicate line in pvremove help text.
Support variable mirror region size.
Support PE ranges in pvmove source PV.
Fixes to as-yet-unused LV segment splitting code.
Change alloc_areas to pe_ranges and allow suppression of availability checks.
Add dev_size column to pvs.
Add report columns for in-kernel device number.
Version 2.00.20 - 3 July 2004
=============================
More autoconf fixes.
Fix device number handling for 2.6 kernels.
Version 2.00.19 - 29 June 2004

View File

@@ -1,3 +1,52 @@
Version 1.01.05 - 26 Sep 2005
=============================
Resync list.h with LVM2.
Remember increased buffer size and use for subsequent calls.
On 'buffer full' condition, double buffer size and repeat ioctl.
Fix termination of getopt_long() option array.
Report 'buffer full' condition with v4 ioctl as well as with v1.
Version 1.01.04 - 2 Aug 2005
============================
Fix dmsetup ls -j and status --target with empty table.
Version 1.01.03 - 13 Jun 2005
=============================
Use matchpathcon mode parameter.
Fix configure script to re-enable selinux.
Version 1.01.02 - 17 May 2005
=============================
Call dm_lib_exit() and dm_lib_release() automatically now.
Add --target <target_type> filter to dmsetup table/status/ls.
Add --exec <command> to dmsetup ls.
Fix dmsetup getopt_long usage.
Version 1.01.01 - 29 Mar 2005
=============================
Update dmsetup man page.
Drop-in devmap_name replacement.
Add option to compile without ioctl for testing.
Fix DM_LIB_VERSION sed.
Version 1.01.00 - 17 Jan 2005
=============================
Add dm_task_no_open_count() to skip getting open_count.
Version 1.00.21 - 7 Jan 2005
============================
Fix /proc/devices parsing.
Version 1.00.20 - 6 Jan 2005
============================
Attempt to fix /dev/mapper/control transparently if it's wrong.
Configuration-time option for setting uid/gid/mode for /dev/mapper nodes.
Update kernel patches for 2.4.27/2.4.28-pre-4 (includes minor fixes).
Add --noheadings columns option for colon-separated dmsetup output.
Support device referencing by uuid or major/minor.
Warn if kernel data didn't fit in buffer.
Fix a printf.
Version 1.00.19 - 3 July 2004
=============================
More autoconf fixes.

12679
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,25 @@
##
## Copyright 1999-2000 Sistina Software, Inc.
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
## Copyright (C) 2004 Red Hat, Inc. All rights reserved.
##
## This is free software released under the GNU General Public License.
## There is no warranty for this software. See the file COPYING for
## details.
## This file is part of the LVM2.
##
## See the file CONTRIBUTORS for a list of contributors.
## 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.
##
## This file is maintained by:
## AJ Lewis <lewis@sistina.com>
##
## File name: configure.in
##
## Description: Input file for autoconf. Generates the configure script
## that tries to keep everything nice and portable. It also
## simplifies distribution package building considerably.
## 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
################################################################################
AC_PREREQ(2.53)
################################################################################
dnl -- Process this file with autoconf to produce a configure script.
AC_INIT(lib/device/dev-cache.h)
################################################################################
dnl -- setup the directory where autoconf has auxilary files
dnl -- Setup the directory where autoconf has auxilary files
AC_CONFIG_AUX_DIR(autoconf)
################################################################################
@@ -73,7 +70,18 @@ AC_PROG_RANLIB
dnl -- Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h malloc.h sys/ioctl.h unistd.h)
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS(fcntl.h limits.h locale.h stddef.h syslog.h sys/file.h sys/ioctl.h sys/param.h sys/time.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_HEADERS(assert.h ctype.h libgen.h signal.h stdio.h sys/mman.h sys/resource.h sys/stat.h sys/types.h sys/utsname.h sys/wait.h time.h,,AC_MSG_ERROR(bailing out))
case "$host_os" in
linux*)
AC_CHECK_HEADERS(asm/byteorder.h linux/fs.h malloc.h,,AC_MSG_ERROR(bailing out)) ;;
darwin*)
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
esac
################################################################################
dnl -- Checks for typedefs, structures, and compiler characteristics.
@@ -82,8 +90,22 @@ AC_C_INLINE
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_MODE_T
AC_STRUCT_ST_RDEV
AC_HEADER_TIME
AC_STRUCT_TM
################################################################################
dnl -- Check for functions
AC_CHECK_FUNCS(gethostname getpagesize memset munmap setlocale strcasecmp strchr strdup strncasecmp strerror strrchr strstr strtol strtoul,,AC_MSG_ERROR(bailing out))
AC_FUNC_ALLOCA
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_FORK
AC_FUNC_LSTAT
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_STAT
AC_FUNC_STRTOD
################################################################################
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
@@ -95,13 +117,13 @@ AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneou
################################################################################
dnl -- Setup the ownership of the files
echo $ac_n "Setting file owner to""... $ac_c" 1>&6
AC_MSG_CHECKING(file owner)
OWNER="root"
AC_ARG_WITH(user,
[ --with-user=USER Set the owner of installed files ],
[ OWNER="$withval" ])
echo "$ac_t""$OWNER" 1>&6
AC_MSG_RESULT($OWNER)
if test x$OWNER != x; then
OWNER="-o $OWNER"
@@ -109,12 +131,12 @@ fi
################################################################################
dnl -- Setup the group ownership of the files
echo $ac_n "Setting group owner to""... $ac_c" 1>&6
AC_MSG_CHECKING(group owner)
GROUP="root"
AC_ARG_WITH(group,
[ --with-group=GROUP Set the group owner of installed files ],
[ GROUP="$withval" ])
echo "$ac_t""$GROUP" 1>&6
AC_MSG_RESULT($GROUP)
if test x$GROUP != x; then
GROUP="-g $GROUP"
@@ -122,10 +144,10 @@ fi
################################################################################
dnl -- LVM1 tool fallback option
echo $ac_n "checking whether to enable lvm1 fallback""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to enable lvm1 fallback)
AC_ARG_ENABLE(lvm1_fallback, [ --enable-lvm1_fallback Use this to fall back and use LVM1 binaries if
device-mapper is missing from the kernel], LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no)
echo "$ac_t""$LVM1_FALLBACK" 1>&6
AC_MSG_RESULT($LVM1_FALLBACK)
if test x$LVM1_FALLBACK = xyes; then
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
@@ -133,19 +155,18 @@ fi
################################################################################
dnl -- format1 inclusion type
echo $ac_n "checking whether to include support for lvm1 metadata""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to include support for lvm1 metadata)
AC_ARG_WITH(lvm1,
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] ],
[ LVM1="$withval" ],
[ LVM1="internal" ])
echo "$ac_t""$LVM1" 1>&6
AC_MSG_RESULT($LVM1)
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
then AC_MSG_ERROR(
--with-lvm1 parameter invalid
)
exit
fi;
if test x$LVM1 = xinternal; then
@@ -154,19 +175,18 @@ fi
################################################################################
dnl -- format_pool inclusion type
echo $ac_n "checking whether to include support for GFS pool metadata""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to include support for GFS pool metadata)
AC_ARG_WITH(pool,
[ --with-pool=TYPE GFS pool read-only support: internal/shared/none
[TYPE=internal] ],
[ POOL="$withval" ],
[ POOL="internal" ])
echo "$ac_t""$POOL" 1>&6
AC_MSG_RESULT($POOL)
if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]];
then AC_MSG_ERROR(
--with-pool parameter invalid
)
exit
fi;
if test x$POOL = xinternal; then
@@ -175,18 +195,17 @@ fi
################################################################################
dnl -- cluster_locking inclusion type
echo $ac_n "checking whether to include support for cluster locking""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to include support for cluster locking)
AC_ARG_WITH(cluster,
[ --with-cluster=TYPE Cluster LVM locking support: internal/shared/none
[TYPE=internal] ],
[ CLUSTER="$withval" ])
echo "$ac_t""$CLUSTER" 1>&6
AC_MSG_RESULT($CLUSTER)
if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]];
then AC_MSG_ERROR(
--with-cluster parameter invalid
)
exit
fi;
if test x$CLUSTER = xinternal; then
@@ -195,19 +214,18 @@ fi
################################################################################
dnl -- snapshots inclusion type
echo $ac_n "checking whether to include snapshots""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to include snapshots)
AC_ARG_WITH(snapshots,
[ --with-snapshots=TYPE Snapshot support: internal/shared/none
[TYPE=internal] ],
[ SNAPSHOTS="$withval" ],
[ SNAPSHOTS="internal" ])
echo "$ac_t""$SNAPSHOTS" 1>&6
AC_MSG_RESULT($SNAPSHOTS)
if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]];
then AC_MSG_ERROR(
--with-snapshots parameter invalid
)
exit
fi;
if test x$SNAPSHOTS = xinternal; then
@@ -216,19 +234,18 @@ fi
################################################################################
dnl -- mirrors inclusion type
echo $ac_n "checking whether to include mirrors""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to include mirrors)
AC_ARG_WITH(mirrors,
[ --with-mirrors=TYPE Mirror support: internal/shared/none
[TYPE=internal] ],
[ MIRRORS="$withval" ],
[ MIRRORS="internal" ])
echo "$ac_t""$MIRRORS" 1>&6
AC_MSG_RESULT($MIRRORS)
if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]];
then AC_MSG_ERROR(
--with-mirrors parameter invalid
)
exit
fi;
if test x$MIRRORS = xinternal; then
@@ -237,17 +254,17 @@ fi
################################################################################
dnl -- Enables staticly-linked tools
echo $ac_n "checking whether to use static linking""... $ac_c" 1>&6
AC_MSG_CHECKING(whether to use static linking)
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to their libraries
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
echo "$ac_t""$STATIC_LINK" 1>&6
AC_MSG_RESULT($STATIC_LINK)
################################################################################
dnl -- Enable readline
echo $ac_n "checking whether to enable readline""... $ac_c" 1>&6
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
AC_MSG_CHECKING(whether to enable readline)
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support],
READLINE=$enableval, READLINE=no)
echo "$ac_t""$READLINE" 1>&6
AC_MSG_RESULT($READLINE)
if test x$READLINE = xyes; then
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
@@ -255,29 +272,35 @@ fi
################################################################################
dnl -- Disable selinux
echo $ac_n "checking whether to enable selinux support""... $ac_c" 1>&6
AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support], \
AC_MSG_CHECKING(whether to enable selinux support)
AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
SELINUX=$enableval)
echo "$ac_t""$SELINUX" 1>&6
AC_MSG_RESULT($SELINUX)
################################################################################
dnl -- Build cluster LVM daemon
echo $ac_n "checking whether to build cluster LVM daemon""... $ac_c" 1>&6
AC_ARG_WITH(clvmd, [ --with-clvmd Build cluster LVM Daemon], \
CLVMD=$withval, CLVMD=no)
echo "$ac_t""$CLVMD" 1>&6
AC_MSG_CHECKING(whether to build cluster LVM daemon)
AC_ARG_WITH(clvmd,
[ --with-clvmd=TYPE Build cluster LVM Daemon: cman/gulm/none/all
[TYPE=none] ],
[ CLVMD="$withval" ],
[ CLVMD="none" ])
if test x$CLVMD = xyes; then
CLVMD=all
fi
AC_MSG_RESULT($CLVMD)
dnl -- If clvmd enabled without cluster locking, automagically include it
if test x$CLVMD = xyes && test x$CLUSTER = xnone; then
if test x$CLVMD != xnone && test x$CLUSTER = xnone; then
CLUSTER=internal
fi
################################################################################
dnl -- Enable debugging
echo $ac_n "checking whether to enable debugging""... $ac_c" 1>&6
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging], \
DEBUG=yes, DEBUG=no)
echo "$ac_t""$DEBUG" 1>&6
AC_MSG_CHECKING(whether to enable debugging)
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging],
DEBUG=$enableval, DEBUG=no)
AC_MSG_RESULT($DEBUG)
dnl -- Normally turn off optimisation for debug builds
if test x$DEBUG = xyes; then
@@ -286,18 +309,18 @@ fi
################################################################################
dnl -- Override optimisation
echo $ac_n "checking for C optimisation flag""... $ac_c" 1>&6
AC_MSG_CHECKING(for C optimisation flag)
AC_ARG_WITH(optimisation,
[ --with-optimisation=OPT C optimisation flag [OPT=-O2] ],
[ COPTIMISE_FLAG="$withval" ])
echo "$ac_t""$COPTIMISE_FLAG" 1>&6
AC_MSG_RESULT($COPTIMISE_FLAG)
################################################################################
dnl -- Disable devmapper
echo $ac_n "checking whether to use device-mapper""... $ac_c" 1>&6
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction], \
DEVMAPPER=no)
echo "$ac_t""$DEVMAPPER" 1>&6
AC_MSG_CHECKING(whether to use device-mapper)
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction],
DEVMAPPER=$enableval)
AC_MSG_RESULT($DEVMAPPER)
if test x$DEVMAPPER = xyes; then
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
@@ -305,10 +328,10 @@ fi
################################################################################
dnl -- Disable O_DIRECT
echo $ac_n "checking whether to enable O_DIRECT""... $ac_c" 1>&6
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT], \
ODIRECT=no)
echo "$ac_t""$ODIRECT" 1>&6
AC_MSG_CHECKING(whether to enable O_DIRECT)
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT],
ODIRECT=$enableval)
AC_MSG_RESULT($ODIRECT)
if test x$ODIRECT = xyes; then
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
@@ -316,10 +339,10 @@ fi
################################################################################
dnl -- Enable cmdlib
echo $ac_n "checking whether to compile liblvm2cmd.so""... $ac_c" 1>&6
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library], \
CMDLIB=yes, CMDLIB=no)
echo "$ac_t""$CMDLIB" 1>&6
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library],
CMDLIB=$enableval, CMDLIB=no)
AC_MSG_RESULT($CMDLIB)
if test x$CMDLIB = xyes; then
CFLAGS="$CFLAGS -DCMDLIB"
@@ -327,9 +350,10 @@ fi
################################################################################
dnl -- Enable fsadm
echo $ac_n "checking whether to build fsadm""... $ac_c" 1>&6
AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm], FSADM=yes)
echo "$ac_t""$FSADM" 1>&6
AC_MSG_CHECKING(whether to build fsadm)
AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
FSADM=$enableval)
AC_MSG_RESULT($FSADM)
################################################################################
dnl -- Mess with default exec_prefix
@@ -342,7 +366,7 @@ dnl -- Checks for library functions.
AC_PROG_GCC_TRADITIONAL
AC_TYPE_SIGNAL
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(mkdir rmdir uname)
AC_CHECK_FUNCS(mkdir rmdir uname,,AC_MSG_ERROR(bailing out))
################################################################################
dnl -- Check for termcap (Shamelessly copied from parted 1.4.17)
@@ -358,7 +382,6 @@ Note: if you are using precompiled packages you will also need the development
Note: (n)curses also seems to work as a substitute for termcap. This was
not found either - but you could try installing that as well.
)
exit
)
fi
@@ -366,7 +389,7 @@ fi
dnl -- Check for dlopen
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; then
if [[ "x$HAVE_LIBDL" = xyes ]]; then
CFLAGS="$CFLAGS -DHAVE_LIBDL"
LIBS="-ldl $LIBS"
else
@@ -381,19 +404,20 @@ if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
then AC_MSG_ERROR(
Features cannot be 'shared' when building statically
)
exit
fi
################################################################################
dnl -- Check for is_selinux_enabled
if test x$SELINUX = xyes; then
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
CFLAGS="$CFLAGS -DHAVE_SELINUX"
LIBS="-lselinux $LIBS"
else
echo "Disabling selinux" 1>&6
AC_MSG_WARN(Disabling selinux)
fi
fi
@@ -413,7 +437,6 @@ support with --disable-readline or download and install readline from:
Note: if you are using precompiled packages you will also need the development
package as well (which may be called readline-devel or something similar).
)
exit
)
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
@@ -421,10 +444,10 @@ fi
################################################################################
dnl -- Internationalisation stuff
echo $ac_n "checking whether to enable internationalisation""... $ac_c" 1>&6
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],\
INTL=yes, INTL=no)
echo "$ac_t""$INTL" 1>&6
AC_MSG_CHECKING(whether to enable internationalisation)
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],
INTL=$enableval, INTL=no)
AC_MSG_RESULT($INTL)
if test x$INTL = xyes; then
INTL_PACKAGE="lvm2"
@@ -433,7 +456,6 @@ if test x$INTL = xyes; then
then AC_MSG_ERROR(
msgfmt not found in path $PATH
)
exit
fi;
AC_ARG_WITH(localedir,
@@ -453,6 +475,45 @@ AC_ARG_WITH(staticdir,
[ STATICDIR="$withval" ],
[ STATICDIR='${exec_prefix}/sbin' ])
################################################################################
dnl -- Ensure additional headers required
if test x$READLINE = xyes; then
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out))
fi
if test x$CLVMD != xnone; then
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out))
AC_FUNC_GETMNTENT
# AC_FUNC_REALLOC
AC_FUNC_SELECT_ARGTYPES
fi
if test x$FSADM = xyes; then
AC_CHECK_HEADERS(fstab.h sys/mount.h sys/vfs.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_FUNCS(memmove,,AC_MSG_ERROR(bailing out))
fi
if test x$CLUSTER != xnone; then
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out))
fi
if test x$HAVE_LIBDL = xyes; then
AC_CHECK_HEADERS(dlfcn.h,,AC_MSG_ERROR(bailing out))
fi
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
if test x$HAVE_SELINUX = xyes; then
AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out))
fi
################################################################################
if test "-f VERSION"; then
@@ -525,14 +586,9 @@ test/filters/Makefile \
)
if test x$ODIRECT != xyes; then
echo
echo Warning: O_DIRECT disabled.
echo Use of pvmove may cause machine to lock up under low memory conditions.
echo
AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up)
fi
if test x$FSADM == xyes; then
echo
echo Warning: fsadm support is untested.
echo
AC_MSG_WARN(fsadm support is untested)
fi

View File

@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
ifeq ("@CLVMD@", "yes")
ifneq ("@CLVMD@", "none")
SUBDIRS = clvmd
endif

View File

@@ -16,26 +16,53 @@ top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES = \
clvmd-cman.c \
clvmd-command.c \
clvmd.c \
libclvm.c \
lvm-functions.c \
system-lv.c
ifeq ("@CLVMD@", "gulm")
GULM = yes
endif
ifeq ("@CLVMD@", "cman")
CMAN = yes
endif
ifeq ("@CLVMD@", "all")
GULM = yes
CMAN = yes
endif
ifeq ("@DEBUG@", "yes")
CFLAGS += -DDEBUG
endif
ifeq ("$(GULM)", "yes")
SOURCES += clvmd-gulm.c tcp-comms.c
LMLIBS += -lccs -lgulm
CFLAGS += -DUSE_GULM
endif
ifeq ("$(CMAN)", "yes")
SOURCES += clvmd-cman.c
LMLIBS += -ldlm
CFLAGS += -DUSE_CMAN
endif
TARGETS = \
clvmd
include $(top_srcdir)/make.tmpl
CFLAGS += -D_REENTRANT -fno-strict-aliasing
LIBS += -ldevmapper -ldlm -llvm -lpthread
LIBS += -ldevmapper -llvm -lpthread
INSTALL_TARGETS = \
install_clvmd
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LIBS)
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS)
.PHONY: install_clvmd
@@ -44,3 +71,6 @@ install_clvmd: $(TARGETS)
$(sbindir)/clvmd
install: $(INSTALL_TARGETS)
install_cluster: $(INSTALL_TARGETS)

View File

@@ -43,6 +43,7 @@ struct clvm_header {
/* Flags */
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
#define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */
/* Name of the local socket to communicate between libclvm and clvmd */
//static const char CLVMD_SOCKNAME[]="/var/run/clvmd";

View File

@@ -55,7 +55,6 @@ static int max_updown_nodes = 50; /* Current size of the allocated array */
static int *node_updown = NULL;
static dlm_lshandle_t *lockspace;
static void sigusr1_handler(int sig);
static void count_clvmds_running(void);
static void get_members(void);
static int nodeid_from_csid(char *csid);
@@ -67,7 +66,7 @@ struct lock_wait {
struct dlm_lksb lksb;
};
int init_cluster()
static int _init_cluster(void)
{
struct sockaddr_cl saddr;
int port = CLUSTER_PORT_CLVMD;
@@ -75,9 +74,11 @@ int init_cluster()
/* Open the cluster communication socket */
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
if (cluster_sock == -1) {
perror("Can't open cluster socket");
/* Don't print an error here because we could be just probing for CMAN */
return -1;
}
/* Set Close-on-exec */
fcntl(cluster_sock, F_SETFD, 1);
/* Bind to our port number on the cluster.
Writes to this will block if the cluster loses quorum */
@@ -87,7 +88,7 @@ int init_cluster()
if (bind
(cluster_sock, (struct sockaddr *) &saddr,
sizeof(struct sockaddr_cl))) {
log_error("Can't bind cluster socket: %m");
syslog(LOG_ERR, "Can't bind cluster socket: %m");
return -1;
}
@@ -98,25 +99,31 @@ int init_cluster()
/* Create a lockspace for LV & VG locks to live in */
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
if (!lockspace) {
log_error("Unable to create lockspace for CLVM\n");
syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m");
return -1;
}
dlm_ls_pthread_init(lockspace);
return 0;
}
int get_main_cluster_fd()
static void _cluster_init_completed(void)
{
clvmd_cluster_init_completed();
}
static int _get_main_cluster_fd()
{
return cluster_sock;
}
int get_num_nodes()
static int _get_num_nodes()
{
return num_nodes;
}
/* send_message with the fd check removed */
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
{
struct iovec iov[2];
struct msghdr msg;
@@ -136,7 +143,7 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
if (csid) {
msg.msg_name = &saddr;
msg.msg_namelen = sizeof(saddr);
memcpy(&saddr.scl_nodeid, csid, MAX_CSID_LEN);
memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN);
} else { /* Cluster broadcast */
msg.msg_name = NULL;
@@ -152,26 +159,26 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
return len;
}
void get_our_csid(char *csid)
static void _get_our_csid(char *csid)
{
int i;
memset(csid, 0, MAX_CSID_LEN);
memset(csid, 0, CMAN_MAX_CSID_LEN);
for (i = 0; i < num_nodes; i++) {
if (nodes[i].us)
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
}
}
/* Call a callback routine for each node that known (down mean not running a clvmd) */
int cluster_do_node_callback(struct local_client *client,
static int _cluster_do_node_callback(struct local_client *client,
void (*callback) (struct local_client *, char *,
int))
{
int i;
int somedown = 0;
for (i = 0; i < get_num_nodes(); i++) {
for (i = 0; i < _get_num_nodes(); i++) {
callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
if (!node_updown[nodes[i].node_id])
somedown = -1;
@@ -203,7 +210,7 @@ static void process_oob_msg(char *buf, int len, int nodeid)
}
}
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
struct local_client **new_client)
{
struct iovec iov[2];
@@ -247,34 +254,39 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
len = -1;
errno = EAGAIN;
}
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
else {
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
/* Send it back to clvmd */
process_message(client, buf, len, csid);
}
return len;
}
void add_up_node(char *csid)
static void _add_up_node(char *csid)
{
/* It's up ! */
int nodeid = nodeid_from_csid(csid);
if (nodeid >= max_updown_nodes) {
int *new_updown = realloc(node_updown, max_updown_nodes + 10);
int new_size = nodeid + 10;
int *new_updown = realloc(node_updown, new_size);
if (new_updown) {
node_updown = new_updown;
max_updown_nodes += 10;
max_updown_nodes = new_size;
DEBUGLOG("realloced more space for nodes. now %d\n",
max_updown_nodes);
} else {
log_error
("Realloc failed. Node status for clvmd will be wrong\n");
return;
("Realloc failed. Node status for clvmd will be wrong. quitting\n");
exit(999);
}
}
node_updown[nodeid] = 1;
DEBUGLOG("Added new node %d to updown list\n", nodeid);
}
void cluster_closedown()
static void _cluster_closedown()
{
unlock_all();
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
@@ -303,7 +315,7 @@ static int is_listening(int nodeid)
/* Populate the list of CLVMDs running.
called only at startup time */
void count_clvmds_running(void)
static void count_clvmds_running(void)
{
int i;
@@ -319,7 +331,7 @@ static void get_members()
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
if (num_nodes == -1) {
perror("get nodes");
log_error("Unable to get node count");
} else {
/* Not enough room for new nodes list ? */
if (num_nodes > count_nodes && nodes) {
@@ -331,16 +343,16 @@ static void get_members()
count_nodes = num_nodes + 10; /* Overallocate a little */
nodes = malloc(count_nodes * sizeof(struct cl_cluster_node));
if (!nodes) {
perror("Unable to allocate nodes array\n");
log_error("Unable to allocate nodes array\n");
exit(5);
}
}
nodelist.max_members = count_nodes;
nodelist.nodes = nodes;
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
if (num_nodes <= 0) {
perror("get node details");
log_error("Unable to get node details");
exit(6);
}
@@ -362,13 +374,13 @@ static void get_members()
}
/* Convert a node name to a CSID */
int csid_from_name(char *csid, char *name)
static int _csid_from_name(char *csid, char *name)
{
int i;
for (i = 0; i < num_nodes; i++) {
if (strcmp(name, nodes[i].name) == 0) {
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
return 0;
}
}
@@ -376,12 +388,12 @@ int csid_from_name(char *csid, char *name)
}
/* Convert a CSID to a node name */
int name_from_csid(char *csid, char *name)
static int _name_from_csid(char *csid, char *name)
{
int i;
for (i = 0; i < num_nodes; i++) {
if (memcmp(csid, &nodes[i].node_id, MAX_CSID_LEN) == 0) {
if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) {
strcpy(name, nodes[i].name);
return 0;
}
@@ -392,7 +404,7 @@ int name_from_csid(char *csid, char *name)
}
/* Convert a node ID to a node name */
int name_from_nodeid(int nodeid, char *name)
static int name_from_nodeid(int nodeid, char *name)
{
int i;
@@ -412,12 +424,12 @@ static int nodeid_from_csid(char *csid)
{
int nodeid;
memcpy(&nodeid, csid, MAX_CSID_LEN);
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
return nodeid;
}
int is_quorate()
static int _is_quorate()
{
return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
}
@@ -431,7 +443,7 @@ static void sync_ast_routine(void *arg)
pthread_mutex_unlock(&lwait->mutex);
}
int sync_lock(const char *resource, int mode, int flags, int *lockid)
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
{
int status;
struct lock_wait lwait;
@@ -441,6 +453,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
return -1;
}
DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
/* Conversions need the lockid in the LKSB */
if (flags & LKF_CONVERT)
lwait.lksb.sb_lkid = *lockid;
@@ -466,17 +479,20 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
*lockid = lwait.lksb.sb_lkid;
errno = lwait.lksb.sb_status;
DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
if (lwait.lksb.sb_status)
return -1;
else
return 0;
}
int sync_unlock(const char *resource /* UNUSED */, int lockid)
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
{
int status;
struct lock_wait lwait;
DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
pthread_cond_init(&lwait.cond, NULL);
pthread_mutex_init(&lwait.mutex, NULL);
pthread_mutex_lock(&lwait.mutex);
@@ -497,3 +513,28 @@ int sync_unlock(const char *resource /* UNUSED */, int lockid)
return 0;
}
static struct cluster_ops _cluster_cman_ops = {
.cluster_init_completed = _cluster_init_completed,
.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,
.cluster_closedown = _cluster_closedown,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};
struct cluster_ops *init_cman_cluster(void)
{
if (!_init_cluster())
return &_cluster_cman_ops;
else
return NULL;
}

View File

@@ -66,6 +66,7 @@
#include <errno.h>
#include "list.h"
#include "hash.h"
#include "locking.h"
#include "log.h"
#include "lvm-functions.h"
@@ -108,7 +109,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
case CLVMD_CMD_LOCK_LV:
/* This is the biggie */
lock_cmd = args[0];
lock_cmd = args[0] & 0x3F;
lock_flags = args[1];
lockname = &args[2];
status = do_lock_lv(lock_cmd, lock_flags, lockname);
@@ -135,6 +136,61 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
}
static int lock_vg(struct local_client *client)
{
struct hash_table *lock_hash;
struct clvm_header *header =
(struct clvm_header *) client->bits.localsock.cmd;
unsigned char lock_cmd;
unsigned char lock_flags;
char *args = header->node + strlen(header->node) + 1;
int lkid;
int status = 0;
char *lockname;
/* Keep a track of VG locks in our own hash table. In current
practice there should only ever be more than two VGs locked
if a user tries to merge lots of them at once */
if (client->bits.localsock.private) {
lock_hash = (struct hash_table *)client->bits.localsock.private;
}
else {
lock_hash = hash_create(3);
if (!lock_hash)
return ENOMEM;
client->bits.localsock.private = (void *)lock_hash;
}
lock_cmd = args[0] & 0x3F;
lock_flags = args[1];
lockname = &args[2];
DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
if (lock_cmd == LCK_UNLOCK) {
lkid = (int)(long)hash_lookup(lock_hash, lockname);
if (lkid == 0)
return EINVAL;
status = sync_unlock(lockname, lkid);
if (status)
status = errno;
else
hash_remove(lock_hash, lockname);
}
else {
status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid);
if (status)
status = errno;
else
hash_insert(lock_hash, lockname, (void *)lkid);
}
return status;
}
/* Pre-command is a good place to get locks that are needed only for the duration
of the commands around the cluster (don't forget to free them in post-command),
and to sanity check the command arguments */
@@ -156,20 +212,7 @@ int do_pre_command(struct local_client *client)
break;
case CLVMD_CMD_LOCK_VG:
lock_cmd = args[0];
lock_flags = args[1];
lockname = &args[2];
DEBUGLOG("doing PRE command LOCK_VG %s at %x\n", lockname,
lock_cmd);
if (lock_cmd == LCK_UNLOCK) {
hold_unlock(lockname);
} else {
status =
hold_lock(lockname, (int) lock_cmd,
(int) lock_flags);
if (status)
status = errno;
}
status = lock_vg(client);
break;
case CLVMD_CMD_LOCK_LV:
@@ -202,6 +245,7 @@ int do_post_command(struct local_client *client)
case CLVMD_CMD_TEST:
status =
sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
client->bits.localsock.private = 0;
break;
case CLVMD_CMD_LOCK_VG:
@@ -217,3 +261,26 @@ int do_post_command(struct local_client *client)
}
return status;
}
/* Called when the client is about to be deleted */
void cmd_client_cleanup(struct local_client *client)
{
if (client->bits.localsock.private) {
struct hash_node *v;
struct hash_table *lock_hash =
(struct hash_table *)client->bits.localsock.private;
hash_iterate(v, lock_hash) {
int lkid = (int)(long)hash_get_data(lock_hash, v);
char *lockname = hash_get_key(lock_hash, v);
DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
sync_unlock(lockname, lkid);
}
hash_destroy(lock_hash);
client->bits.localsock.private = 0;
}
}

View File

@@ -22,33 +22,48 @@
struct local_client;
extern int cluster_send_message(void *buf, int msglen, char *csid,
struct cluster_ops {
void (*cluster_init_completed) (void);
int (*cluster_send_message) (void *buf, int msglen, char *csid,
const char *errtext);
extern int name_from_csid(char *csid, char *name);
extern int csid_from_name(char *csid, char *name);
extern int get_num_nodes(void);
extern int cluster_fd_callback(struct local_client *fd, char *buf, int len,
int (*name_from_csid) (char *csid, char *name);
int (*csid_from_name) (char *csid, 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);
extern int init_cluster(void);
extern int get_main_cluster_fd(void); /* gets accept FD or cman cluster socket */
extern int cluster_do_node_callback(struct local_client *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));
extern int is_quorate(void);
int (*is_quorate) (void);
extern void get_our_csid(char *csid);
extern void add_up_node(char *csid);
extern void cluster_closedown(void);
void (*get_our_csid) (char *csid);
void (*add_up_node) (char *csid);
void (*reread_config) (void);
void (*cluster_closedown) (void);
extern int sync_lock(const char *resource, int mode, int flags, int *lockid);
extern int sync_unlock(const char *resource, int lockid);
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
int (*sync_unlock) (const char *resource, int lockid);
};
#ifdef USE_GULM
#include "tcp-comms.h"
#else
/* cman */
#include "cnxman-socket.h"
#define MAX_CSID_LEN 4
# include "tcp-comms.h"
struct cluster_ops *init_gulm_cluster(void);
#define MAX_CSID_LEN GULM_MAX_CSID_LEN
#define MAX_CLUSTER_MEMBER_NAME_LEN GULM_MAX_CLUSTER_MEMBER_NAME_LEN
#endif
#ifdef USE_CMAN
# include "cnxman-socket.h"
# define CMAN_MAX_CSID_LEN 4
# ifndef MAX_CSID_LEN
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
# endif
# undef MAX_CLUSTER_MEMBER_NAME_LEN
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_CLUSTER_MEMBER_NAME_LEN
struct cluster_ops *init_cman_cluster(void);
#endif

View File

@@ -2,6 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
**
*******************************************************************************
******************************************************************************/
@@ -46,6 +47,7 @@
#include "log.h"
#include "clvm.h"
#include "clvmd-comms.h"
#include "lvm-functions.h"
#include "clvmd.h"
#include "hash.h"
#include "clvmd-gulm.h"
@@ -58,13 +60,15 @@ static struct hash_table *node_hash;
/* hash list of outstanding lock requests */
static struct hash_table *lock_hash;
/* Copy of the current core state */
static uint8_t current_corestate;
/* Copy of the current quorate state */
static uint8_t gulm_quorate = 0;
static enum {INIT_NOTDONE, INIT_DONE, INIT_WAITQUORATE} init_state = INIT_NOTDONE;
/* Number of active nodes */
static int num_nodes;
static char *cluster_name;
static int in_shutdown = 0;
static pthread_mutex_t lock_start_mutex;
static volatile int lock_start_flag;
@@ -72,7 +76,7 @@ static volatile int lock_start_flag;
struct node_info
{
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
};
struct lock_wait
@@ -88,6 +92,8 @@ static int read_from_core_sock(struct local_client *client, char *buf, int len,
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
struct local_client **new_client);
static int get_all_cluster_nodes(void);
static int _csid_from_name(char *csid, char *name);
static void _cluster_closedown(void);
/* In tcp-comms.c */
extern struct hash_table *sock_hash;
@@ -112,6 +118,9 @@ static int add_internal_client(int fd, fd_callback_t callback)
client->callback = callback;
add_client(client);
/* Set Close-on-exec */
fcntl(fd, F_SETFD, 1);
return 0;
}
@@ -123,27 +132,45 @@ static lg_lockspace_callbacks_t lock_callbacks;
static void badsig_handler(int sig)
{
DEBUGLOG("got sig %d\n", sig);
cluster_closedown();
_cluster_closedown();
exit(0);
}
static void sighup_handler(int sig)
static void _reread_config(void)
{
DEBUGLOG("got SIGHUP\n");
/* Re-read CCS node list */
get_all_cluster_nodes();
/* Re-read CCS node list */
DEBUGLOG("Re-reading CCS config\n");
get_all_cluster_nodes();
}
int init_cluster()
static int _init_cluster(void)
{
int status;
int ccs_h;
int port = 0;
char *portstr;
/* Get cluster name from CCS */
/* TODO: is this right? */
ccs_h = ccs_connect();
ccs_h = ccs_force_connect(NULL, 0);
if (ccs_h < 0)
{
syslog(LOG_ERR, "Cannot login in to CCSD server\n");
return -1;
}
ccs_get(ccs_h, "//cluster/@name", &cluster_name);
DEBUGLOG("got cluster name %s\n", cluster_name);
if (!ccs_get(ccs_h, "//cluster/clvm/@port", &portstr))
{
port = atoi(portstr);
free(portstr);
DEBUGLOG("got port number %d\n", port);
if (port <= 0 && port >= 65536)
port = 0;
}
ccs_disconnect(ccs_h);
/* Block locking until we are logged in */
@@ -155,7 +182,8 @@ int init_cluster()
lock_hash = hash_create(10);
/* Get all nodes from CCS */
get_all_cluster_nodes();
if (get_all_cluster_nodes())
return -1;
/* Initialise GULM library */
status = lg_initialize(&gulm_if, cluster_name, "clvmd");
@@ -174,7 +202,7 @@ int init_cluster()
}
/* Initialise the inter-node comms */
status = init_comms();
status = init_comms(port);
if (status)
return status;
@@ -202,7 +230,7 @@ int init_cluster()
exit(status);
}
/* Request a list of nodes, we can;t really do anything until
/* Request a list of nodes, we can't really do anything until
this comes back */
status = lg_core_nodelist(gulm_if);
if (status)
@@ -215,18 +243,16 @@ int init_cluster()
signal(SIGINT, badsig_handler);
signal(SIGTERM, badsig_handler);
/* Re-read the node list on SIGHUP */
signal(SIGHUP, sighup_handler);
return 0;
}
void cluster_closedown()
static void _cluster_closedown(void)
{
DEBUGLOG("cluster_closedown\n");
in_shutdown = 1;
unlock_all();
lg_lock_logout(gulm_if);
lg_core_logout(gulm_if);
lg_core_shutdown(gulm_if);
lg_release(gulm_if);
}
@@ -237,6 +263,7 @@ static void drop_expired_locks(char *nodename)
struct utsname nodeinfo;
uint8_t mask[GIO_KEY_SIZE];
DEBUGLOG("Dropping expired locks for %s\n", nodename?nodename:"(null)");
memset(mask, 0xff, GIO_KEY_SIZE);
if (!nodename)
@@ -282,12 +309,16 @@ static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t r
if (error)
exit(error);
current_corestate = corestate;
/* Get the current core state (for quorum) */
lg_core_corestate(gulm_if);
return 0;
}
static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
{
int oldstate = ninfo->state;
if (nodestate == lg_core_Logged_in)
{
/* Don't clobber NODE_CLVMD state */
@@ -309,18 +340,24 @@ static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestat
if (ninfo->state != NODE_DOWN)
num_nodes--;
ninfo->state = NODE_DOWN;
tcp_remove_client(csid);
}
}
DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
ninfo->name, ninfo->state, num_nodes);
/* Gulm doesn't always send node DOWN events, so even if this a a node UP we must
* assume (ahem) that it prevously went down at some time. So we close
* the sockets here to make sure that we don't have any dead connections
* to that node.
*/
tcp_remove_client(csid);
DEBUGLOG("set_node_state, '%s' state = %d (oldstate=%d), num_nodes=%d\n",
ninfo->name, ninfo->state, oldstate, num_nodes);
}
static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
if (!ninfo)
{
/* If we can't find that node then re-read the config file in case it
@@ -329,7 +366,7 @@ static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
get_all_cluster_nodes();
/* Now try again */
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
if (!ninfo)
{
DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name);
@@ -337,12 +374,17 @@ static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
}
}
set_node_state(ninfo, (char *)&ip, state);
set_node_state(ninfo, (char *)ip, state);
return ninfo;
}
static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint8_t state)
static void _get_our_csid(char *csid)
{
get_our_gulm_csid(csid);
}
static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *ip, uint8_t state)
{
DEBUGLOG("CORE nodelist\n");
@@ -354,7 +396,7 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint
{
if (type == lglcb_item)
{
DEBUGLOG("Got nodelist, item: %s, %#x, %#x\n", name, ip, state);
DEBUGLOG("Got nodelist, item: %s, %#x\n", name, state);
add_or_set_node(name, ip, state);
}
@@ -362,14 +404,23 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint
{
if (type == lglcb_stop)
{
char ourcsid[MAX_CSID_LEN];
char ourcsid[GULM_MAX_CSID_LEN];
DEBUGLOG("Got Nodelist, stop\n");
clvmd_cluster_init_completed();
if (gulm_quorate)
{
clvmd_cluster_init_completed();
init_state = INIT_DONE;
}
else
{
if (init_state == INIT_NOTDONE)
init_state = INIT_WAITQUORATE;
}
/* Mark ourself as up */
get_our_csid(ourcsid);
add_up_node(ourcsid);
_get_our_csid(ourcsid);
gulm_add_up_node(ourcsid);
}
else
{
@@ -381,24 +432,29 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint
return 0;
}
static int core_statechange(void *misc, uint8_t corestate, uint32_t masterip, char *mastername)
static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername)
{
DEBUGLOG("CORE Got statechange corestate:%#x masterip:%#x mastername:%s\n",
corestate, masterip, mastername);
DEBUGLOG("CORE Got statechange. quorate:%d, corestate:%x mastername:%s\n",
quorate, corestate, mastername);
current_corestate = corestate;
gulm_quorate = quorate;
if (quorate && init_state == INIT_WAITQUORATE)
{
clvmd_cluster_init_completed();
init_state = INIT_DONE;
}
return 0;
}
static int core_nodechange(void *misc, char *nodename, uint32_t nodeip, uint8_t nodestate)
static int core_nodechange(void *misc, char *nodename, struct in6_addr *nodeip, uint8_t nodestate)
{
struct node_info *ninfo;
DEBUGLOG("CORE node change, name=%s, ip=%x, state = %d\n", nodename, nodeip, nodestate);
DEBUGLOG("CORE node change, name=%s, state = %d\n", nodename, nodestate);
/* If we don't get nodeip here, try a lookup by name */
if (!nodeip)
csid_from_name((char *)&nodeip, nodename);
_csid_from_name((char *)nodeip, nodename);
if (!nodeip)
return 0;
@@ -443,13 +499,19 @@ static int lock_login_reply(void *misc, uint32_t error, uint8_t which)
return 0;
}
static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen, uint8_t state, uint32_t flags, uint32_t error,
static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen,
uint64_t subid, uint64_t start, uint64_t stop,
uint8_t state, uint32_t flags, uint32_t error,
uint8_t *LVB, uint16_t LVBlen)
{
struct lock_wait *lwait;
DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
/* No waiting process to wake up when we are shutting down */
if (in_shutdown)
return 0;
lwait = hash_lookup(lock_hash, key);
if (!lwait)
{
@@ -519,19 +581,18 @@ int get_next_node_csid(void **context, char *csid)
return 0;
}
memcpy(csid, hash_get_key(node_hash, *context), MAX_CSID_LEN);
memcpy(csid, hash_get_key(node_hash, *context), GULM_MAX_CSID_LEN);
return 1;
}
int name_from_csid(char *csid, char *name)
int gulm_name_from_csid(char *csid, char *name)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
if (!ninfo)
{
sprintf(name, "UNKNOWN [%d.%d.%d.%d]",
csid[0], csid[1], csid[2], csid[3]);
sprintf(name, "UNKNOWN %s", print_csid(csid));
return -1;
}
@@ -540,7 +601,7 @@ int name_from_csid(char *csid, char *name)
}
int csid_from_name(char *csid, char *name)
static int _csid_from_name(char *csid, char *name)
{
struct hash_node *hn;
struct node_info *ninfo;
@@ -550,29 +611,36 @@ int csid_from_name(char *csid, char *name)
ninfo = hash_get_data(node_hash, hn);
if (strcmp(ninfo->name, name) == 0)
{
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
return 0;
}
}
return -1;
}
int get_num_nodes()
static int _get_num_nodes()
{
DEBUGLOG("num_nodes = %d\n", num_nodes);
return num_nodes;
}
/* Node is now known to be running a clvmd */
void add_up_node(char *csid)
void gulm_add_up_node(char *csid)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
if (!ninfo)
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
if (!ninfo) {
DEBUGLOG("gulm_add_up_node no node_hash entry for csid %s\n", print_csid(csid));
return;
}
DEBUGLOG("gulm_add_up_node %s\n", ninfo->name);
if (ninfo->state == NODE_DOWN)
num_nodes++;
ninfo->state = NODE_CLVMD;
return;
}
@@ -581,7 +649,7 @@ void add_down_node(char *csid)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
if (!ninfo)
return;
@@ -589,30 +657,42 @@ void add_down_node(char *csid)
running clvmd - gulm may set it DOWN quite soon */
if (ninfo->state == NODE_CLVMD)
ninfo->state = NODE_UP;
drop_expired_locks(ninfo->name);
return;
}
/* Call a callback for each node, so the caller knows whether it's up or down */
int cluster_do_node_callback(struct local_client *master_client,
void (*callback)(struct local_client *, char *csid, int node_up))
static int _cluster_do_node_callback(struct local_client *master_client,
void (*callback)(struct local_client *, char *csid, int node_up))
{
struct hash_node *hn;
struct node_info *ninfo;
hash_iterate(hn, node_hash)
{
char csid[MAX_CSID_LEN];
char csid[GULM_MAX_CSID_LEN];
struct local_client *client;
ninfo = hash_get_data(node_hash, hn);
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
if (client)
callback(master_client, csid, ninfo->state == NODE_CLVMD);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (!client)
{
/* If it's up but not connected, try to make contact */
if (ninfo->state == NODE_UP)
gulm_connect_csid(csid, &client);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
}
if (ninfo->state != NODE_DOWN)
callback(master_client, csid, ninfo->state == NODE_CLVMD);
}
return 0;
}
@@ -623,15 +703,13 @@ static int gulm_to_errno(int gulm_ret)
switch (gulm_ret)
{
case lg_err_TryFailed:
errno = EAGAIN;
break;
case lg_err_AlreadyPend:
errno = EBUSY;
errno = EAGAIN;
break;
/* More?? */
default:
errno = EINVAL;
errno = EINVAL;
}
return gulm_ret ? -1 : 0;
@@ -661,6 +739,7 @@ static int _lock_resource(char *resource, int mode, int flags, int *lockid)
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
0, 0, 0,
mode, flags, NULL, 0);
if (status)
{
@@ -692,6 +771,7 @@ static int _unlock_resource(char *resource, int lockid)
DEBUGLOG("unlock_resource %s\n", resource);
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
0, 0, 0,
lg_lock_state_Unlock, 0, NULL, 0);
if (status)
@@ -700,6 +780,11 @@ static int _unlock_resource(char *resource, int lockid)
return status;
}
/* When we are shutting down, don't wait for unlocks
to be acknowledged, just do it. */
if (in_shutdown)
return status;
/* Wait for it to complete */
pthread_cond_wait(&lwait.cond, &lwait.mutex);
@@ -720,7 +805,7 @@ static int _unlock_resource(char *resource, int lockid)
To aid unlocking, we store the lock mode in the lockid (as GULM
doesn't use this).
*/
int sync_lock(const char *resource, int mode, int flags, int *lockid)
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
{
int status;
char lock1[strlen(resource)+3];
@@ -736,7 +821,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
if (status)
goto out;
/* If we can't get this lock then bail out */
/* If we can't get this lock too then bail out */
status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
if (status == lg_err_TryFailed)
{
@@ -748,10 +833,16 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
case LCK_READ:
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
if (status)
goto out;
status = _unlock_resource(lock2, *lockid);
break;
case LCK_WRITE:
status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
if (status)
goto out;
status = _unlock_resource(lock1, *lockid);
break;
default:
@@ -764,7 +855,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
return status;
}
int sync_unlock(const char *resource, int lockid)
static int _sync_unlock(const char *resource, int lockid)
{
int status = 0;
char lock1[strlen(resource)+3];
@@ -778,36 +869,16 @@ int sync_unlock(const char *resource, int lockid)
lockid == LCK_READ ||
lockid == LCK_WRITE);
switch (lockid)
{
case LCK_EXCL:
status = _unlock_resource(lock1, lockid);
if (status)
goto out;
status = _unlock_resource(lock2, lockid);
break;
status = _unlock_resource(lock1, lockid);
if (!status)
status = _unlock_resource(lock2, lockid);
case LCK_READ:
status = _unlock_resource(lock1, lockid);
break;
case LCK_WRITE:
status = _unlock_resource(lock2, lockid);
break;
}
out:
return status;
}
int is_quorate()
static int _is_quorate()
{
if (current_corestate == lg_core_Slave ||
current_corestate == lg_core_Master ||
current_corestate == lg_core_Client)
return 1;
else
return 0;
return gulm_quorate;
}
/* Get all the cluster node names & IPs from CCS and
@@ -819,31 +890,43 @@ static int get_all_cluster_nodes()
int ctree;
char *nodename;
int error;
int i;
/* Open the config file */
ctree = ccs_connect();
if (ctree <= 0)
ctree = ccs_force_connect(NULL, 1);
if (ctree < 0)
{
log_error("Error connecting to CCS");
return -1;
}
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
while (nodename)
for (i=1;;i++)
{
char nodeip[MAX_CSID_LEN];
char *clvmflag;
char nodekey[256];
char nodeip[GULM_MAX_CSID_LEN];
int clvmflag = 1;
char *clvmflagstr;
char key[256];
sprintf(key, "//nodes/node[@name=\"%s\"]/clvm", nodename);
ccs_get(ctree, key, &clvmflag);
sprintf(nodekey, "//cluster/clusternodes/clusternode[%d]/@name", i);
error = ccs_get(ctree, nodekey, &nodename);
if (error)
break;
if ((get_ip_address(nodename, nodeip) == 0) && atoi(clvmflag))
sprintf(key, "//cluster/clusternodes/clusternode[@name=\"%s\"]/clvm", nodename);
if (!ccs_get(ctree, key, &clvmflagstr))
{
clvmflag = atoi(clvmflagstr);
free(clvmflagstr);
}
DEBUGLOG("Got node %s from ccs(clvmflag = %d)\n", nodename, clvmflag);
if ((get_ip_address(nodename, nodeip) == 0) && clvmflag)
{
struct node_info *ninfo;
/* If it's not in the list, then add it */
ninfo = hash_lookup_binary(node_hash, nodeip, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, nodeip, GULM_MAX_CSID_LEN);
if (!ninfo)
{
ninfo = malloc(sizeof(struct node_info));
@@ -856,16 +939,20 @@ static int get_all_cluster_nodes()
strcpy(ninfo->name, nodename);
ninfo->state = NODE_DOWN;
hash_insert_binary(node_hash, nodeip, MAX_CSID_LEN, ninfo);
hash_insert_binary(node_hash, nodeip, GULM_MAX_CSID_LEN, ninfo);
}
}
else
{
DEBUGLOG("node %s has clvm disabled\n", nodename);
if (!clvmflag) {
DEBUGLOG("node %s has clvm disabled\n", nodename);
}
else {
DEBUGLOG("Cannot resolve host name %s\n", nodename);
log_err("Cannot resolve host name %s\n", nodename);
}
}
if (clvmflag) free(clvmflag);
free(nodename);
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
}
/* Finished with config file */
@@ -874,7 +961,43 @@ static int get_all_cluster_nodes()
return 0;
}
int gulm_fd(void)
static int _get_main_cluster_fd(void)
{
return lg_core_selector(gulm_if);
return get_main_gulm_cluster_fd();
}
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client)
{
return cluster_fd_gulm_callback(fd, buf, len, csid, new_client);
}
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
{
return gulm_cluster_send_message(buf, msglen, csid, errtext);
}
static struct cluster_ops _cluster_gulm_ops = {
.cluster_init_completed = NULL,
.cluster_send_message = _cluster_send_message,
.name_from_csid = gulm_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 = gulm_add_up_node,
.reread_config = _reread_config,
.cluster_closedown = _cluster_closedown,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};
struct cluster_ops *init_gulm_cluster(void)
{
if (!_init_cluster())
return &_cluster_gulm_ops;
else
return NULL;
}

View File

@@ -7,3 +7,6 @@ extern int gulm_fd(void);
extern int get_ip_address(char *node, char *addr);
extern void tcp_remove_client(char *csid);
extern int alloc_client(int fd, char *csid, struct local_client **new_client);
void gulm_add_up_node(char *csid);
int gulm_name_from_csid(char *csid, char *name);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -34,11 +34,13 @@
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <syslog.h>
#include <errno.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"
@@ -54,9 +56,9 @@
/* 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_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, MAX_CSID_LEN) == 0)
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
/* Head of the fd list. Also contains
the cluster_socket details */
@@ -64,7 +66,12 @@ static struct local_client local_client_head;
static unsigned short global_xid = 0; /* Last transaction ID issued */
static struct cluster_ops *clops = NULL;
static char our_csid[MAX_CSID_LEN];
static unsigned max_csid_len;
static unsigned max_cluster_message;
static unsigned max_cluster_member_name_len;
/* Structure of items on the LVM thread list */
struct lvm_thread_cmd {
@@ -80,11 +87,22 @@ struct lvm_thread_cmd {
static pthread_t lvm_thread;
static pthread_mutex_t lvm_thread_mutex;
static pthread_cond_t lvm_thread_cond;
static pthread_mutex_t lvm_start_mutex;
static struct list lvm_cmd_head;
static int quit = 0;
static volatile sig_atomic_t quit = 0;
static volatile sig_atomic_t reread_config = 0;
static int child_pipe[2];
/* Reasons the daemon failed initialisation */
#define DFAIL_INIT 1
#define DFAIL_LOCAL_SOCK 2
#define DFAIL_CLUSTER_IF 3
#define DFAIL_MALLOC 4
#define SUCCESS 0
/* Prototypes for code further down */
static void sigusr2_handler(int sig);
static void sighup_handler(int sig);
static void sigterm_handler(int sig);
static void send_local_reply(struct local_client *client, int status,
int clientid);
@@ -129,6 +147,18 @@ static void usage(char *prog, FILE *file)
fprintf(file, "\n");
}
/* Called to signal the parent how well we got on during initialisation */
static void child_init_signal(int status)
{
if (child_pipe[1]) {
write(child_pipe[1], &status, sizeof(status));
close(child_pipe[1]);
}
if (status)
exit(status);
}
int main(int argc, char *argv[])
{
int local_sock;
@@ -138,6 +168,7 @@ int main(int argc, char *argv[])
int debug = 0;
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
sigset_t ss;
int using_gulm = 0;
/* Deal with command-line arguments */
opterr = 0;
@@ -166,7 +197,8 @@ int main(int argc, char *argv[])
break;
case 'V':
printf("\nCluster LVM Daemon version %d.%d.%d\n\n",
printf("Cluster LVM daemon version: %s\n", LVM_VERSION);
printf("Protocol version: %d.%d.%d\n",
CLVMD_MAJOR_VERSION, CLVMD_MINOR_VERSION,
CLVMD_PATCH_VERSION);
exit(1);
@@ -188,14 +220,14 @@ int main(int argc, char *argv[])
but the cluster is not ready yet */
local_sock = open_local_sock();
if (local_sock < 0)
exit(2);
child_init_signal(DFAIL_LOCAL_SOCK);
/* Set up signal handlers, USR1 is for cluster change notifications (in cman)
USR2 causes child threads to exit.
HUP causes gulm version to re-read nodes list from CCS.
PIPE should be ignored */
signal(SIGUSR2, sigusr2_handler);
signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler);
signal(SIGHUP, sighup_handler);
signal(SIGPIPE, SIG_IGN);
/* Block SIGUSR2 in the main process */
@@ -207,31 +239,52 @@ int main(int argc, char *argv[])
list_init(&lvm_cmd_head);
pthread_mutex_init(&lvm_thread_mutex, NULL);
pthread_cond_init(&lvm_thread_cond, NULL);
pthread_mutex_init(&lvm_start_mutex, NULL);
init_lvhash();
/* Start the cluster interface */
if (init_cluster()) {
#ifdef USE_CMAN
if ((clops = init_cman_cluster())) {
max_csid_len = CMAN_MAX_CSID_LEN;
max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE;
max_cluster_member_name_len = CMAN_MAX_CLUSTER_MEMBER_NAME_LEN;
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
}
#endif
#ifdef USE_GULM
if (!clops)
if ((clops = init_gulm_cluster())) {
max_csid_len = GULM_MAX_CSID_LEN;
max_cluster_message = GULM_MAX_CLUSTER_MESSAGE;
max_cluster_member_name_len = GULM_MAX_CLUSTER_MEMBER_NAME_LEN;
using_gulm = 1;
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
}
#endif
if (!clops) {
DEBUGLOG("Can't initialise cluster interface\n");
log_error("Can't initialise cluster interface\n");
exit(5);
child_init_signal(DFAIL_CLUSTER_IF);
}
DEBUGLOG("Cluster ready, doing some more initialisation\n");
/* Save our CSID */
uname(&nodeinfo);
get_our_csid(our_csid);
clops->get_our_csid(our_csid);
/* Initialise the FD list head */
local_client_head.fd = get_main_cluster_fd();
local_client_head.fd = clops->get_main_cluster_fd();
local_client_head.type = CLUSTER_MAIN_SOCK;
local_client_head.callback = cluster_fd_callback;
local_client_head.callback = clops->cluster_fd_callback;
/* Add the local socket to the list */
newfd = malloc(sizeof(struct local_client));
if (!newfd)
exit(2);
child_init_signal(DFAIL_MALLOC);
newfd->fd = local_sock;
newfd->removeme = 0;
newfd->type = LOCAL_RENDEZVOUS;
newfd->callback = local_rendezvous_callback;
newfd->next = local_client_head.next;
@@ -240,17 +293,21 @@ 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, nodeinfo.nodename);
pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
#ifndef USE_GULM
/* Tell the rest of the cluster our version number */
/* CMAN can do this immediately, gulm needs to wait until
the core initialisation has finished and the node list
has been gathered */
send_version_message();
#endif
if (clops->cluster_init_completed)
clops->cluster_init_completed();
DEBUGLOG("clvmd ready for work\n");
child_init_signal(SUCCESS);
/* Try to shutdown neatly */
signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler);
/* Do some work */
main_loop(local_sock, cmd_timeout);
@@ -294,6 +351,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->fd = client_fd;
newfd->type = LOCAL_SOCK;
newfd->xid = 0;
newfd->removeme = 0;
newfd->callback = local_sock_callback;
newfd->bits.localsock.replies = NULL;
newfd->bits.localsock.expected_replies = 0;
@@ -303,6 +361,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->bits.localsock.threadid = 0;
newfd->bits.localsock.finished = 0;
newfd->bits.localsock.pipe_client = NULL;
newfd->bits.localsock.private = NULL;
newfd->bits.localsock.all_success = 1;
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
*new_client = newfd;
@@ -391,9 +450,9 @@ static void timedout_callback(struct local_client *client, char *csid,
{
if (node_up) {
struct node_reply *reply;
char nodename[MAX_CLUSTER_MEMBER_NAME_LEN];
char nodename[max_cluster_member_name_len];
name_from_csid(csid, nodename);
clops->name_from_csid(csid, nodename);
DEBUGLOG("PJC: checking for a reply from %s\n", nodename);
pthread_mutex_lock(&client->bits.localsock.reply_mutex);
@@ -422,7 +481,7 @@ static void timedout_callback(struct local_client *client, char *csid,
static void request_timed_out(struct local_client *client)
{
DEBUGLOG("Request timed-out. padding\n");
cluster_do_node_callback(client, timedout_callback);
clops->cluster_do_node_callback(client, timedout_callback);
if (client->bits.localsock.num_replies !=
client->bits.localsock.expected_replies) {
@@ -447,26 +506,54 @@ static void main_loop(int local_sock, int cmd_timeout)
int select_status;
struct local_client *thisfd;
struct timeval tv = { cmd_timeout, 0 };
int quorate = is_quorate();
int quorate = clops->is_quorate();
/* Wait on the cluster FD and all local sockets/pipes */
FD_ZERO(&in);
for (thisfd = &local_client_head; thisfd != NULL;
thisfd = thisfd->next) {
if (thisfd->removeme)
continue;
/* if the cluster is not quorate then don't listen for new requests */
if ((thisfd->type != LOCAL_RENDEZVOUS &&
thisfd->type != LOCAL_SOCK) || quorate)
FD_SET(thisfd->fd, &in);
}
if ((select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv)) > 0) {
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
if (reread_config) {
int saved_errno = errno;
reread_config = 0;
if (clops->reread_config)
clops->reread_config();
errno = saved_errno;
}
if (select_status > 0) {
struct local_client *lastfd = NULL;
struct clvm_header *inheader;
char csid[MAX_CSID_LEN];
char buf[MAX_CLUSTER_MESSAGE];
char buf[max_cluster_message];
for (thisfd = &local_client_head; thisfd != NULL;
thisfd = thisfd->next) {
if (thisfd->removeme) {
struct local_client *free_fd;
lastfd->next = thisfd->next;
free_fd = thisfd;
thisfd = lastfd;
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
break;
}
if (FD_ISSET(thisfd->fd, &in)) {
struct local_client *newfd;
int ret;
@@ -490,13 +577,15 @@ static void main_loop(int local_sock, int cmd_timeout)
type == CLUSTER_INTERNAL)
goto closedown;
DEBUGLOG
("ret == %d, errno = %d. removing client\n",
ret, errno);
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
lastfd->next = thisfd->next;
free_fd = thisfd;
thisfd = lastfd;
free(free_fd);
close(free_fd->fd);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
break;
}
@@ -506,33 +595,6 @@ static void main_loop(int local_sock, int cmd_timeout)
thisfd->next = newfd;
break;
}
switch (thisfd->type) {
case CLUSTER_MAIN_SOCK:
case CLUSTER_DATA_SOCK:
inheader =
(struct clvm_header *) buf;
ntoh_clvm(inheader); /* Byteswap fields */
if (inheader->cmd ==
CLVMD_CMD_REPLY)
process_reply
(inheader, ret,
csid);
else
add_to_lvmqueue(thisfd,
inheader,
ret,
csid);
break;
/* All the work for these is done in the callback
rightly or wrongly... */
case LOCAL_RENDEZVOUS:
case LOCAL_SOCK:
case THREAD_PIPE:
case CLUSTER_INTERNAL:
break;
}
}
lastfd = thisfd;
}
@@ -575,30 +637,69 @@ static void main_loop(int local_sock, int cmd_timeout)
}
closedown:
cluster_closedown();
clops->cluster_closedown();
close(local_sock);
}
/* Fork into the background and detach from our parent process */
/*
* 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()
{
pid_t pid;
pid_t pid;
int child_status;
int devnull = open("/dev/null", O_RDWR);
if (devnull == -1) {
perror("Can't open /dev/null");
exit(3);
}
pipe(child_pipe);
switch (pid = fork()) {
case -1:
perror("clvmd: can't fork");
exit(2);
case 0: /* child */
case 0: /* Child */
close(child_pipe[0]);
break;
default: /* Parent */
exit(0);
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);
}
}
/* Detach ourself from the calling environment */
@@ -646,6 +747,7 @@ static int read_from_local_sock(struct local_client *thisfd)
/* If the client went away in mid command then tidy up */
if (thisfd->bits.localsock.in_progress) {
pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2);
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
thisfd->bits.localsock.state = POST_COMMAND;
pthread_cond_signal(&thisfd->bits.localsock.cond);
@@ -659,10 +761,9 @@ static int read_from_local_sock(struct local_client *thisfd)
if (thisfd->bits.localsock.threadid) {
DEBUGLOG("Waiting for child thread\n");
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
thisfd->bits.localsock.state = POST_COMMAND;
thisfd->bits.localsock.state = PRE_COMMAND;
pthread_cond_signal(&thisfd->bits.localsock.cond);
pthread_mutex_unlock(&thisfd->bits.localsock.mutex);
pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2);
jstat =
pthread_join(thisfd->bits.localsock.threadid,
@@ -717,6 +818,7 @@ static int read_from_local_sock(struct local_client *thisfd)
struct local_client *newfd;
char csid[MAX_CSID_LEN];
struct clvm_header *inheader;
int status;
inheader = (struct clvm_header *) buffer;
@@ -727,7 +829,7 @@ static int read_from_local_sock(struct local_client *thisfd)
if (thisfd->bits.localsock.in_progress) {
struct clvm_header reply;
reply.cmd = CLVMD_CMD_REPLY;
reply.status = -EBUSY;
reply.status = EBUSY;
reply.arglen = 0;
reply.flags = 0;
send_message(&reply, sizeof(reply), our_csid,
@@ -750,7 +852,7 @@ static int read_from_local_sock(struct local_client *thisfd)
if (!thisfd->bits.localsock.cmd) {
struct clvm_header reply;
reply.cmd = CLVMD_CMD_REPLY;
reply.status = -ENOMEM;
reply.status = ENOMEM;
reply.arglen = 0;
reply.flags = 0;
send_message(&reply, sizeof(reply), our_csid,
@@ -791,13 +893,13 @@ static int read_from_local_sock(struct local_client *thisfd)
}
/* Check the node name for validity */
if (inheader->node[0] && csid_from_name(csid, inheader->node)) {
if (inheader->node[0] && clops->csid_from_name(csid, inheader->node)) {
/* Error, node is not in the cluster */
struct clvm_header reply;
DEBUGLOG("Unknown node: '%s'\n", inheader->node);
reply.cmd = CLVMD_CMD_REPLY;
reply.status = -ENOENT;
reply.status = ENOENT;
reply.flags = 0;
reply.arglen = 0;
send_message(&reply, sizeof(reply), our_csid,
@@ -828,7 +930,7 @@ static int read_from_local_sock(struct local_client *thisfd)
close(comms_pipe[1]);
reply.cmd = CLVMD_CMD_REPLY;
reply.status = -ENOMEM;
reply.status = ENOMEM;
reply.arglen = 0;
reply.flags = 0;
send_message(&reply, sizeof(reply), our_csid,
@@ -839,6 +941,7 @@ static int read_from_local_sock(struct local_client *thisfd)
DEBUGLOG("creating pipe, [%d, %d]\n", comms_pipe[0],
comms_pipe[1]);
newfd->fd = comms_pipe[0];
newfd->removeme = 0;
newfd->type = THREAD_PIPE;
newfd->callback = local_pipe_callback;
newfd->next = thisfd->next;
@@ -863,8 +966,10 @@ static int read_from_local_sock(struct local_client *thisfd)
/* Run the pre routine */
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
pthread_create(&thisfd->bits.localsock.threadid, NULL,
DEBUGLOG("Creating pre&post thread\n");
status = pthread_create(&thisfd->bits.localsock.threadid, NULL,
pre_and_post_thread, thisfd);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
}
return len;
}
@@ -921,7 +1026,7 @@ static int distribute_command(struct local_client *thisfd)
/* if node is empty then do it on the whole cluster */
if (inheader->node[0] == '\0') {
thisfd->bits.localsock.expected_replies =
get_num_nodes();
clops->get_num_nodes();
thisfd->bits.localsock.num_replies = 0;
thisfd->bits.localsock.sent_time = time(NULL);
thisfd->bits.localsock.in_progress = TRUE;
@@ -942,7 +1047,7 @@ static int distribute_command(struct local_client *thisfd)
/* Do it on a single node */
char csid[MAX_CSID_LEN];
if (csid_from_name(csid, inheader->node)) {
if (clops->csid_from_name(csid, inheader->node)) {
/* This has already been checked so should not happen */
return 0;
} else {
@@ -952,7 +1057,7 @@ static int distribute_command(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
/* Are we the requested node ?? */
if (memcmp(csid, our_csid, MAX_CSID_LEN) == 0) {
if (memcmp(csid, our_csid, max_csid_len) == 0) {
DEBUGLOG("Doing command on local node only\n");
add_to_lvmqueue(thisfd, inheader, len, NULL);
} else {
@@ -984,17 +1089,17 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
char *csid)
{
char *replyargs;
char nodename[MAX_CLUSTER_MEMBER_NAME_LEN];
char nodename[max_cluster_member_name_len];
int replylen = 0;
int buflen = MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header) - 1;
int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
int status;
int msg_malloced = 0;
/* Get the node name as we /may/ need it later */
name_from_csid(csid, nodename);
clops->name_from_csid(csid, nodename);
DEBUGLOG("process_remote_command %d for clientid 0x%x on node %s\n",
msg->cmd, msg->clientid, nodename);
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) {
@@ -1016,7 +1121,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
/* Return a failure response */
head.cmd = CLVMD_CMD_REPLY;
head.status = -EFBIG;
head.status = EFBIG;
head.flags = 0;
head.clientid = msg->clientid;
head.arglen = 0;
@@ -1033,7 +1138,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
msg->arglen);
/* Return a failure response */
head.cmd = CLVMD_CMD_REPLY;
head.status = -ENOMEM;
head.status = ENOMEM;
head.flags = 0;
head.clientid = msg->clientid;
head.arglen = 0;
@@ -1057,7 +1162,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
if (msg->cmd == CLVMD_CMD_VERSION) {
int *version_nums = (int *) msg->args;
char node[256];
name_from_csid(csid, node);
clops->name_from_csid(csid, node);
DEBUGLOG("Remote node %s is version %d.%d.%d\n",
node,
ntohl(version_nums[0]),
@@ -1078,17 +1183,17 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
byebyemsg.flags = 0;
byebyemsg.arglen = 0;
byebyemsg.clientid = 0;
cluster_send_message(&byebyemsg, sizeof(byebyemsg),
clops->cluster_send_message(&byebyemsg, sizeof(byebyemsg),
our_csid,
"Error Sending GOAWAY message");
} else {
add_up_node(csid);
clops->add_up_node(csid);
}
return;
}
/* Allocate a default reply buffer */
replyargs = malloc(MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header));
replyargs = malloc(max_cluster_message - sizeof(struct clvm_header));
if (replyargs != NULL) {
/* Run the command */
@@ -1096,7 +1201,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
do_command(NULL, msg, msglen, &replyargs, buflen,
&replylen);
} else {
status = -ENOMEM;
status = ENOMEM;
}
/* If it wasn't a reply, then reply */
@@ -1127,11 +1232,10 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
/* 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
if (system_lv_write_data(aggreply,
replylen + sizeof(struct clvm_header)) < 0
&& replylen > 0)
agghead->status = -EFBIG;
agghead->status = EFBIG;
send_message(agghead,
sizeof(struct clvm_header), csid,
@@ -1147,7 +1251,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
agghead->node[0] = '\0';
send_message(aggreply,
sizeof(struct clvm_header) +
replylen + 2, csid, fd,
replylen, csid, fd,
"Error sending command reply");
}
} else {
@@ -1156,7 +1260,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
DEBUGLOG("Error attempting to realloc return buffer\n");
/* Return a failure response */
head.cmd = CLVMD_CMD_REPLY;
head.status = -ENOMEM;
head.status = ENOMEM;
head.flags = 0;
head.clientid = msg->clientid;
head.arglen = 0;
@@ -1188,13 +1292,13 @@ static void add_reply_to_list(struct local_client *client, int status,
reply = malloc(sizeof(struct node_reply));
if (reply) {
reply->status = status;
name_from_csid(csid, reply->node);
clops->name_from_csid(csid, reply->node);
DEBUGLOG("Reply from node %s: %d bytes\n", reply->node, len);
if (len > 0) {
reply->replymsg = malloc(len);
if (!reply->replymsg) {
reply->status = -ENOMEM;
reply->status = ENOMEM;
} else {
memcpy(reply->replymsg, buf, len);
}
@@ -1238,6 +1342,11 @@ static void *pre_and_post_thread(void *arg)
DEBUGLOG("in sub thread: client = %p\n", client);
/* Don't start until the LVM thread is ready */
pthread_mutex_lock(&lvm_start_mutex);
pthread_mutex_unlock(&lvm_start_mutex);
DEBUGLOG("Sub thread ready for work.\n");
/* Ignore SIGUSR1 (handled by master process) but enable
SIGUSR2 (kills subthreads) */
sigemptyset(&ss);
@@ -1273,13 +1382,12 @@ static void *pre_and_post_thread(void *arg)
DEBUGLOG("Got post command condition...\n");
/* POST function must always run, even if the client aborts */
status = 0;
do_post_command(client);
write(pipe_fd, &status, sizeof(int));
if (client->bits.localsock.finished)
break;
DEBUGLOG("Waiting for next pre command\n");
pthread_mutex_lock(&client->bits.localsock.mutex);
@@ -1292,7 +1400,8 @@ static void *pre_and_post_thread(void *arg)
DEBUGLOG("Got pre command condition...\n");
}
DEBUGLOG("Subthread finished\n");
return (void *) 0;
pthread_exit((void *) 0);
return 0;
}
/* Process a command on the local node and store the result */
@@ -1300,8 +1409,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
struct local_client *client,
unsigned short xid)
{
char *replybuf = malloc(MAX_CLUSTER_MESSAGE);
int buflen = MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header) - 1;
char *replybuf = malloc(max_cluster_message);
int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
int replylen = 0;
int status;
@@ -1383,9 +1492,10 @@ static void send_local_reply(struct local_client *client, int status, int fd)
replybuf = malloc(message_len);
clientreply = (struct clvm_header *) replybuf;
clientreply->status = -status;
clientreply->status = status;
clientreply->cmd = CLVMD_CMD_REPLY;
clientreply->node[0] = '\0';
clientreply->flags = 0;
ptr = clientreply->args;
@@ -1397,6 +1507,9 @@ static void send_local_reply(struct local_client *client, int status, int fd)
strcpy(ptr, thisreply->node);
ptr += strlen(thisreply->node) + 1;
if (thisreply->status)
clientreply->flags |= CLVMD_FLAG_NODEERRS;
*(int *) ptr = thisreply->status;
ptr += sizeof(int);
@@ -1465,7 +1578,8 @@ static void send_version_message()
version_nums[1] = htonl(CLVMD_MINOR_VERSION);
version_nums[2] = htonl(CLVMD_PATCH_VERSION);
cluster_send_message(message, sizeof(message), NULL,
hton_clvm(msg);
clops->cluster_send_message(message, sizeof(message), NULL,
"Error Sending version number");
}
@@ -1477,8 +1591,8 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
/* Send remote messages down the cluster socket */
if (csid == NULL || !ISLOCAL_CSID(csid)) {
hton_clvm((struct clvm_header *) buf); /* Byte swap if necessary */
return cluster_send_message(buf, msglen, csid, errtext);
hton_clvm((struct clvm_header *) buf);
return clops->cluster_send_message(buf, msglen, csid, errtext);
} else {
int ptr = 0;
@@ -1498,6 +1612,14 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
static int process_work_item(struct lvm_thread_cmd *cmd)
{
/* If msg is NULL then this is a cleanup request */
if (cmd->msg == NULL) {
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
cmd_client_cleanup(cmd->client);
free(cmd->client);
return 0;
}
if (!cmd->remote) {
DEBUGLOG("process_work_item: local\n");
process_local_command(cmd->msg, cmd->msglen, cmd->client,
@@ -1517,9 +1639,12 @@ static void *lvm_thread_fn(void *arg)
{
struct list *cmdl, *tmp;
sigset_t ss;
int using_gulm = (int)arg;
/* Don't let anyone else to do work until we are started */
pthread_mutex_lock(&lvm_start_mutex);
DEBUGLOG("LVM thread function started\n");
pthread_mutex_lock(&lvm_thread_mutex);
/* Ignore SIGUSR1 & 2 */
sigemptyset(&ss);
@@ -1528,8 +1653,10 @@ static void *lvm_thread_fn(void *arg)
pthread_sigmask(SIG_BLOCK, &ss, NULL);
/* Initialise the interface to liblvm */
init_lvm();
pthread_mutex_unlock(&lvm_thread_mutex);
init_lvm(using_gulm);
/* Allow others to get moving */
pthread_mutex_unlock(&lvm_start_mutex);
/* Now wait for some actual work */
for (;;) {
@@ -1548,7 +1675,8 @@ static void *lvm_thread_fn(void *arg)
pthread_mutex_unlock(&lvm_thread_mutex);
process_work_item(cmd);
free(cmd->msg);
if (cmd->msg)
free(cmd->msg);
free(cmd);
pthread_mutex_lock(&lvm_thread_mutex);
@@ -1565,21 +1693,26 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
cmd = malloc(sizeof(struct lvm_thread_cmd));
if (!cmd)
return -ENOMEM;
return ENOMEM;
cmd->msg = malloc(msglen);
if (!cmd->msg) {
log_error("Unable to allocate buffer space\n");
free(cmd);
return -1;
if (msglen) {
cmd->msg = malloc(msglen);
if (!cmd->msg) {
log_error("Unable to allocate buffer space\n");
free(cmd);
return -1;
}
memcpy(cmd->msg, msg, msglen);
}
else {
cmd->msg = NULL;
}
cmd->client = client;
cmd->msglen = msglen;
cmd->xid = client->xid;
memcpy(cmd->msg, msg, msglen);
if (csid) {
memcpy(cmd->csid, csid, MAX_CSID_LEN);
memcpy(cmd->csid, csid, max_csid_len);
cmd->remote = 1;
} else {
cmd->remote = 0;
@@ -1610,6 +1743,8 @@ static int open_local_sock()
log_error("Can't create local socket: %m");
return -1;
}
/* Set Close-on-exec */
fcntl(local_socket, F_SETFD, 1);
memset(&sockaddr, 0, sizeof(sockaddr));
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
@@ -1630,11 +1765,24 @@ static int open_local_sock()
return local_socket;
}
void process_message(struct local_client *client, char *buf, int len, char *csid)
{
struct clvm_header *inheader;
inheader = (struct clvm_header *) buf;
ntoh_clvm(inheader); /* Byteswap fields */
if (inheader->cmd == CLVMD_CMD_REPLY)
process_reply(inheader, len, csid);
else
add_to_lvmqueue(client, inheader, len, csid);
}
static void check_all_callback(struct local_client *client, char *csid,
int node_up)
{
if (!node_up)
add_reply_to_list(client, -EHOSTDOWN, csid, "CLVMD not running",
add_reply_to_list(client, EHOSTDOWN, csid, "CLVMD not running",
18);
}
@@ -1644,7 +1792,7 @@ static void check_all_callback(struct local_client *client, char *csid,
static int check_all_clvmds_running(struct local_client *client)
{
DEBUGLOG("check_all_clvmds_running\n");
return cluster_do_node_callback(client, check_all_callback);
return clops->cluster_do_node_callback(client, check_all_callback);
}
/* Return a local_client struct given a client ID.
@@ -1681,7 +1829,6 @@ static void ntoh_clvm(struct clvm_header *hdr)
static void sigusr2_handler(int sig)
{
DEBUGLOG("SIGUSR2 received\n");
pthread_exit((void *) -1);
return;
}
@@ -1691,3 +1838,20 @@ static void sigterm_handler(int sig)
quit = 1;
return;
}
static void sighup_handler(int sig)
{
DEBUGLOG("got SIGHUP\n");
reread_config = 1;
}
int sync_lock(const char *resource, int mode, int flags, int *lockid)
{
return clops->sync_lock(resource, mode, flags, lockid);
}
int sync_unlock(const char *resource, int lockid)
{
return clops->sync_unlock(resource, lockid);
}

View File

@@ -86,6 +86,7 @@ struct local_client {
struct local_client *next;
unsigned short xid;
fd_callback_t callback;
uint8_t removeme;
union {
struct localsock_bits localsock;
@@ -95,7 +96,7 @@ struct local_client {
};
#ifdef DEBUG
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
#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
@@ -111,9 +112,13 @@ extern int do_command(struct local_client *client, struct clvm_header *msg,
/* Pre and post command routines are called only on the local node */
extern int do_pre_command(struct local_client *client);
extern int do_post_command(struct local_client *client);
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);
int sync_lock(const char *resource, int mode, int flags, int *lockid);
int sync_unlock(const char *resource, int lockid);
#endif

View File

@@ -17,26 +17,16 @@
#ifndef __CNXMAN_SOCKET_H
#define __CNXMAN_SOCKET_H
/* Just made these up but the address family must be less than 32 (NPROTO) */
#define AF_CLUSTER 31
/* A currently unused number. TIPC also uses this number and you're unlikely
to be using both.
*/
#define AF_CLUSTER 30
#define PF_CLUSTER AF_CLUSTER
/* Protocol(socket) types */
#define CLPROTO_MASTER 2
#define CLPROTO_CLIENT 3
/* Setsockopt -- maybe should be ioctls?? */
#define CLU_SET_MULTICAST 100
#define CLU_JOIN_CLUSTER 101
#define CLU_LEAVE_CLUSTER 102
#define CLU_SET_RCVONLY 103
#define CLU_SET_UNICAST 104
#define KCL_SET_MULTICAST 105
#define KCL_SET_RCVONLY 106
#define KCL_SET_UNICAST 107
#define KCL_SET_NODENAME 108
#define CLU_SET_NODENAME 109
/* ioctls -- should register these properly */
#define SIOCCLUSTER_NOTIFY _IOW('x', 0x01, int)
#define SIOCCLUSTER_REMOVENOTIFY _IO( 'x', 0x02)
@@ -58,15 +48,23 @@
#define SIOCCLUSTER_SERVICE_SETSIGNAL _IOW('x', 0x30, int)
#define SIOCCLUSTER_SERVICE_STARTDONE _IOW('x', 0x40, unsigned int)
#define SIOCCLUSTER_SERVICE_GETEVENT _IOR('x', 0x50, struct cl_service_event)
#define SIOCCLUSTER_SERVICE_GETMEMBERS _IOR('x', 0x60, struct cl_cluster_node)
#define SIOCCLUSTER_SERVICE_GETMEMBERS _IOR('x', 0x60, struct cl_cluster_nodelist)
#define SIOCCLUSTER_SERVICE_GLOBALID _IOR('x', 0x70, uint32_t)
#define SIOCCLUSTER_SERVICE_SETLEVEL _IOR('x', 0x80, int)
#define SIOCCLUSTER_GETNODE _IOWR('x', 0x90, struct cl_cluster_node)
#define SIOCCLUSTER_BARRIER _IOW('x', 0x0a0, struct cl_barrier_info)
/* These were setsockopts */
#define SIOCCLUSTER_PASS_SOCKET _IOW('x', 0x0b0, struct cl_passed_sock)
#define SIOCCLUSTER_SET_NODENAME _IOW('x', 0x0b1, char *)
#define SIOCCLUSTER_SET_NODEID _IOW('x', 0x0b2, int)
#define SIOCCLUSTER_JOIN_CLUSTER _IOW('x', 0x0b3, struct cl_join_cluster_info)
#define SIOCCLUSTER_LEAVE_CLUSTER _IOW('x', 0x0b4, int)
/* Maximum size of a cluster message */
#define MAX_CLUSTER_MESSAGE 1500
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
#define CMAN_MAX_CLUSTER_MESSAGE 1500
#define CMAN_MAX_CLUSTER_MEMBER_NAME_LEN 255
#define MAX_BARRIER_NAME_LEN 33
#define MAX_SA_ADDR_LEN 12
#define MAX_CLUSTER_NAME_LEN 16
@@ -107,9 +105,10 @@
#define MSG_MULTICAST 0x080000 /* Message was sent to all nodes in the cluster
*/
#define MSG_ALLINT 0x100000 /* Send out of all interfaces */
#define MSG_REPLYEXP 0x200000 /* Reply is expected */
typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER,
NODESTATE_DEAD } nodestate_t;
NODESTATE_DEAD } nodestate_t;
struct sockaddr_cl {
@@ -119,13 +118,14 @@ struct sockaddr_cl {
int scl_nodeid;
};
/* This is how we pass the multicast socket into kernel space. addr is the
* multicast address to use in the address family of the socket (eg for UDP it
* might be 255.255.255.0) */
struct cl_multicast_sock {
/*
* This is how we pass the multicast & receive sockets into kernel space.
*/
struct cl_passed_sock {
int fd; /* FD of master socket to do multicast on */
int number; /* Socket number, to match up recvonly & bcast
* sockets */
int multicast; /* Is it multicast or receive ? */
};
/* Cluster configuration info passed when we join the cluster */
@@ -147,7 +147,7 @@ struct cl_cluster_node {
unsigned int leave_reason;
unsigned int incarnation;
nodestate_t state;
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
char name[CMAN_MAX_CLUSTER_MEMBER_NAME_LEN];
unsigned char votes;
};

View File

@@ -1,446 +0,0 @@
/*
* Copyright (C) 1997-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
*/
/* library functions for Cluster LVM Daemon */
#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/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 <search.h>
#include <errno.h>
#include "clvm.h"
#include "libclvm.h"
/* CLVM in hex! */
#define LVM_SIGNATURE 0x434C564D
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
/* NOTE: the LVMD uses the socket FD as the client ID, this means
that any client that calls fork() will inherit the context of
it's parent. */
static int clvmd_sock = -1;
static int open_local_sock(void)
{
int local_socket;
struct sockaddr_un sockaddr;
/* Open local socket */
local_socket = socket(PF_UNIX, SOCK_STREAM, 0);
if (local_socket < 0) {
perror("Can't create local socket");
return -1;
}
fcntl(local_socket, F_SETFD, !FD_CLOEXEC);
strcpy(sockaddr.sun_path, CLVMD_SOCKNAME);
sockaddr.sun_family = AF_UNIX;
if (connect
(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
int saved_errno = errno;
close(local_socket);
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;
fd_set fds;
FD_ZERO(&fds);
FD_SET(clvmd_sock, &fds);
/* Send it to CLVMD */
if (write(clvmd_sock, inbuf, inlen) != inlen) {
perror("Error writing to CLVMD");
return -1;
}
/* Get the response */
if ((len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
perror("Error reading CLVMD");
return -1;
}
if (len == 0) {
fprintf(stderr, "EOF reading CLVMD");
errno = ENOTCONN;
return -1;
}
/* Allocate buffer */
*retbuf = malloc(len + outheader->arglen);
if (!*retbuf) {
errno = ENOMEM;
return -1;
}
/* 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, PIPE_BUF);
if (len > 0)
off += len;
}
/* Was it an error ? */
if (outheader->status < 0) {
errno = -outheader->status;
return -2;
}
return 0;
}
/* Build the structure header and parse-out wildcard node names */
static void build_header(struct clvm_header *head, int cmd, const char *node,
void *data, 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 */
int lvm_cluster_write(char cmd, char *node, void *data, int len)
{
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
char *retbuf = NULL;
int status;
struct clvm_header *head = (struct clvm_header *) outbuf;
if (clvmd_sock == -1)
clvmd_sock = open_local_sock();
if (clvmd_sock == -1)
return -1;
build_header(head, cmd, node, data, len);
memcpy(head->node + strlen(head->node) + 1, data, len);
status =
send_request(outbuf,
sizeof(struct clvm_header) + strlen(head->node) + len,
&retbuf);
if (retbuf)
free(retbuf);
return status;
}
/* API: Send a message to a(or all) node(s) in the cluster
and wait for replies */
int lvm_cluster_request(char cmd, const char *node, void *data, int len,
lvm_response_t ** response, int *num)
{
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
int *outptr;
char *inptr;
char *retbuf = NULL;
int status;
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 -1;
build_header(head, cmd, node, data, 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 == 0 || status == -2) {
/* 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 */
outptr =
malloc(sizeof(lvm_response_t) * num_responses +
sizeof(int) * 2);
if (!outptr) {
if (retbuf)
free(retbuf);
errno = ENOMEM;
return -1;
}
*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 */
inptr = head->args;
i = 0;
while (inptr[0]) {
strcpy(rarray[i].node, inptr);
inptr += strlen(inptr) + 1;
rarray[i].status = *(int *) inptr;
inptr += sizeof(int);
rarray[i].response = malloc(strlen(inptr) + 1);
if (rarray[i].response == NULL) {
/* Free up everything else and return error */
int j;
for (j = 0; j < i; j++)
free(rarray[i].response);
free(outptr);
errno = ENOMEM;
return -1;
}
strcpy(rarray[i].response, inptr);
rarray[i].len = strlen(inptr);
inptr += strlen(inptr) + 1;
i++;
}
*num = num_responses;
*response = rarray;
}
if (retbuf)
free(retbuf);
return status;
}
/* API: Free reply array */
int lvm_cluster_free_request(lvm_response_t * response)
{
int *ptr = (int *) response - 2;
int i;
int num;
/* Check it's ours to free */
if (response == NULL || *ptr != LVM_SIGNATURE) {
errno = EINVAL;
return -1;
}
num = ptr[1];
for (i = 0; i < num; i++) {
free(response[i].response);
}
free(ptr);
return 0;
}
/* These are a "higher-level" API providing black-box lock/unlock
functions for cluster LVM...maybe */
/* Set by lock(), used by unlock() */
static int num_responses;
static lvm_response_t *response;
int lvm_lock_for_cluster(char scope, char *name, int verbosity)
{
int status;
int i;
char *args;
int len;
if (name) {
len = strlen(name) + 2;
args = alloca(len);
strcpy(args + 1, name);
} else {
len = 2;
args = alloca(len);
args[1] = '\0';
}
args[0] = scope;
status = lvm_cluster_request(CLVMD_CMD_LOCK,
"", args, len, &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) {
if (verbosity)
fprintf(stderr,
"clvmd not running on node %s\n",
response[i].node);
status = -1;
}
}
/* If there was an error then free the memory now as the caller won't
want to do the unlock */
if (status) {
int saved_errno = errno;
lvm_cluster_free_request(response);
num_responses = 0;
errno = saved_errno;
}
return status;
}
int lvm_unlock_for_cluster(char scope, char *name, int verbosity)
{
int status;
int i;
int len;
int failed;
int num_unlock_responses;
char *args;
lvm_response_t *unlock_response;
/* We failed - this should not have been called */
if (num_responses == 0)
return 0;
if (name) {
len = strlen(name) + 2;
args = alloca(len);
strcpy(args + 1, name);
} else {
len = 2;
args = alloca(len);
args[1] = '\0';
}
args[0] = scope;
/* See if it failed anywhere */
failed = 0;
for (i = 0; i < num_responses; i++) {
if (response[i].status != 0)
failed++;
}
/* If it failed on any nodes then we only unlock on
the nodes that succeeded */
if (failed) {
for (i = 0; i < num_responses; i++) {
/* Unlock the ones that succeeded */
if (response[i].status == 0) {
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
response[i].node,
args, len,
&unlock_response,
&num_unlock_responses);
if (status) {
if (verbosity)
fprintf(stderr,
"cluster command to node %s failed: %s\n",
response[i].node,
strerror(errno));
} else if (unlock_response[0].status != 0) {
if (verbosity > 1)
fprintf(stderr,
"unlock on node %s failed: %s\n",
response[i].node,
strerror(unlock_response
[0].status));
}
lvm_cluster_free_request(unlock_response);
} else {
if (verbosity)
fprintf(stderr,
"command on node %s failed: '%s' - will be left locked\n",
response[i].node,
strerror(response[i].status));
}
}
} else {
/* All OK, we can do a full cluster unlock */
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
"",
args, len,
&unlock_response,
&num_unlock_responses);
if (status) {
if (verbosity > 1)
fprintf(stderr, "cluster command failed: %s\n",
strerror(errno));
} else {
for (i = 0; i < num_unlock_responses; i++) {
if (unlock_response[i].status != 0) {
if (verbosity > 1)
fprintf(stderr,
"unlock on node %s failed: %s\n",
response[i].node,
strerror(unlock_response
[0].status));
}
}
}
lvm_cluster_free_request(unlock_response);
}
lvm_cluster_free_request(response);
return 0;
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (C) 1997-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 _LIBCLVM_H
#define _LIBCLVM_H
typedef struct lvm_response {
char node[255];
char *response;
int status;
int len;
} lvm_response_t;
extern int lvm_cluster_request(char cmd, const char *node, void *data, int len,
lvm_response_t ** response, int *num);
extern int lvm_cluster_write(char cmd, char *node, void *data, int len);
extern int lvm_cluster_free_request(lvm_response_t * response);
/* The "high-level" API */
extern int lvm_lock_for_cluster(char scope, char *name, int verbosity);
extern int lvm_unlock_for_cluster(char scope, char *name, int verbosity);
#endif

View File

@@ -46,6 +46,7 @@
static struct cmd_context *cmd = NULL;
static struct hash_table *lv_hash = NULL;
static pthread_mutex_t lv_hash_lock;
struct lv_info {
int lock_id;
@@ -57,7 +58,9 @@ static int get_current_lock(char *resource)
{
struct lv_info *lvi;
pthread_mutex_lock(&lv_hash_lock);
lvi = hash_lookup(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
if (lvi) {
return lvi->lock_mode;
} else {
@@ -69,11 +72,14 @@ static int get_current_lock(char *resource)
void unlock_all()
{
struct hash_node *v;
pthread_mutex_lock(&lv_hash_lock);
hash_iterate(v, lv_hash) {
struct lv_info *lvi = hash_get_data(lv_hash, v);
sync_unlock(hash_get_key(lv_hash, v), lvi->lock_id);
}
pthread_mutex_unlock(&lv_hash_lock);
}
/* Gets a real lock and keeps the info in the hash table */
@@ -85,7 +91,9 @@ int hold_lock(char *resource, int mode, int flags)
flags &= LKF_NOQUEUE; /* Only LKF_NOQUEUE is valid here */
pthread_mutex_lock(&lv_hash_lock);
lvi = hash_lookup(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
if (lvi) {
/* Already exists - convert it */
status =
@@ -113,7 +121,9 @@ int hold_lock(char *resource, int mode, int flags)
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
strerror(errno));
} else {
pthread_mutex_lock(&lv_hash_lock);
hash_insert(lv_hash, resource, lvi);
pthread_mutex_unlock(&lv_hash_lock);
}
errno = saved_errno;
}
@@ -127,8 +137,9 @@ int hold_unlock(char *resource)
int status;
int saved_errno;
pthread_mutex_lock(&lv_hash_lock);
lvi = hash_lookup(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
if (!lvi) {
DEBUGLOG("hold_unlock, lock not already held\n");
return 0;
@@ -137,7 +148,9 @@ int hold_unlock(char *resource)
status = sync_unlock(resource, lvi->lock_id);
saved_errno = errno;
if (!status) {
pthread_mutex_lock(&lv_hash_lock);
hash_remove(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
free(lvi);
} else {
DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
@@ -155,11 +168,12 @@ int hold_unlock(char *resource)
*/
/* Activate LV exclusive or non-exclusive */
static int do_activate_lv(char *resource, int mode)
static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
{
int oldmode;
int status;
int activate_lv;
int exclusive = 0;
struct lvinfo lvi;
/* Is it already open ? */
@@ -176,16 +190,20 @@ static int do_activate_lv(char *resource, int mode)
return 0; /* Success, we did nothing! */
/* Do we need to activate exclusively? */
if (activate_lv == 2)
if ((activate_lv == 2) || (mode == LKM_EXMODE)) {
exclusive = 1;
mode = LKM_EXMODE;
}
/* OK, try to get the lock */
status = hold_lock(resource, mode, LKF_NOQUEUE);
if (status)
return errno;
/* 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)
return errno;
}
/* If it's suspended then resume it */
if (!lv_info_by_lvid(cmd, resource, &lvi))
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
return EIO;
if (lvi.suspended)
@@ -193,7 +211,7 @@ static int do_activate_lv(char *resource, int mode)
return EIO;
/* Now activate it */
if (!lv_activate(cmd, resource))
if (!lv_activate(cmd, resource, exclusive))
return EIO;
return 0;
@@ -231,7 +249,7 @@ static int do_suspend_lv(char *resource)
}
/* Only suspend it if it exists */
if (!lv_info_by_lvid(cmd, resource, &lvi))
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
return EIO;
if (lvi.exists) {
@@ -242,14 +260,14 @@ static int do_suspend_lv(char *resource)
return 0;
}
static int do_deactivate_lv(char *resource)
static int do_deactivate_lv(char *resource, unsigned char lock_flags)
{
int oldmode;
int status;
/* Is it open ? */
oldmode = get_current_lock(resource);
if (oldmode == -1) {
if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) {
DEBUGLOG("do_deactivate_lock, lock not already held\n");
return 0; /* We don't need to do anything */
}
@@ -257,9 +275,11 @@ static int do_deactivate_lv(char *resource)
if (!lv_deactivate(cmd, resource))
return EIO;
status = hold_unlock(resource);
if (status)
return errno;
if (lock_flags & LCK_CLUSTER_VG) {
status = hold_unlock(resource);
if (status)
return errno;
}
return 0;
}
@@ -270,7 +290,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
{
int status = 0;
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %x\n",
resource, command, lock_flags);
if (!cmd->config_valid || config_files_changed(cmd)) {
@@ -283,7 +303,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
switch (command) {
case LCK_LV_EXCLUSIVE:
status = do_activate_lv(resource, LKM_EXMODE);
status = do_activate_lv(resource, lock_flags, LKM_EXMODE);
break;
case LCK_LV_SUSPEND:
@@ -296,11 +316,11 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
break;
case LCK_LV_ACTIVATE:
status = do_activate_lv(resource, LKM_CRMODE);
status = do_activate_lv(resource, lock_flags, LKM_CRMODE);
break;
case LCK_LV_DEACTIVATE:
status = do_deactivate_lv(resource);
status = do_deactivate_lv(resource, lock_flags);
break;
default:
@@ -350,7 +370,7 @@ 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))
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
return EIO;
if (lvi.exists) {
@@ -375,6 +395,44 @@ int do_check_lvm1(char *vgname)
return status == 1 ? 0 : EBUSY;
}
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
that might be hanging around if we died for any reason
*/
static void drop_vg_locks()
{
char vg[128];
char line[255];
FILE *vgs =
popen
("lvm pvs --nolocking --noheadings -o vg_name", "r");
sync_unlock("P_orphans", LCK_EXCL);
if (!vgs)
return;
while (fgets(line, sizeof(line), vgs)) {
char *vgend;
char *vgstart;
if (line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
vgstart = line + strspn(line, " ");
vgend = vgstart + strcspn(vgstart, " ");
*vgend = '\0';
if (strncmp(vgstart, "WARNING:", 8) == 0)
continue;
sprintf(vg, "V_%s", vgstart);
sync_unlock(vg, LCK_EXCL);
}
fclose(vgs);
}
/*
* Ideally, clvmd should be started before any LVs are active
* but this may not be the case...
@@ -382,21 +440,24 @@ int do_check_lvm1(char *vgname)
*/
static void *get_initial_state()
{
char lv[64], vg[64], flags[25];
char lv[64], vg[64], flags[25], vg_flags[25];
char uuid[65];
char line[255];
FILE *lvs =
popen
("/sbin/lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
("lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
"r");
if (!lvs)
return NULL;
while (fgets(line, sizeof(line), lvs)) {
if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) {
if (sscanf(line, "%s %s %s %s\n", vg, lv, flags, vg_flags) == 4) {
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
if (flags[4] == 'a' || flags[4] == 's') { /* is it active or suspended? */
if (strlen(vg) == 38 && /* is is a valid UUID ? */
(flags[4] == 'a' || flags[4] == 's') && /* is it active or suspended? */
vg_flags[5] == 'c') { /* is it clustered ? */
/* Convert hyphen-separated UUIDs into one */
memcpy(&uuid[0], &vg[0], 6);
memcpy(&uuid[6], &vg[7], 4);
@@ -423,14 +484,39 @@ static void *get_initial_state()
return NULL;
}
/* 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);
if (locking_type == 3) /* compiled-in cluster support */
return;
if (locking_type == 2) { /* External library, check name */
const char *libname;
libname = find_config_str(cmd->cft->root, "global/locking_library",
"");
if (strstr(libname, "liblvm2clusterlock.so"))
return;
log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
return;
}
log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
}
void init_lvhash()
{
/* Create hash table for keeping LV locks & status */
lv_hash = hash_create(100);
pthread_mutex_init(&lv_hash_lock, NULL);
}
/* Called to initialise the LVM context of the daemon */
int init_lvm(void)
int init_lvm(int using_gulm)
{
if (!(cmd = create_toolcontext(NULL))) {
log_error("Failed to allocate command context");
@@ -441,6 +527,13 @@ int init_lvm(void)
init_syslog(LOG_DAEMON);
init_debug(_LOG_ERR);
/* Check lvm.conf is setup for cluster-LVM */
check_config();
/* Remove any non-LV locks that may have been left around */
if (using_gulm)
drop_vg_locks();
get_initial_state();
return 1;

View File

@@ -25,7 +25,7 @@ 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 init_lvm(void);
extern int init_lvm(int using_gulm);
extern void init_lvhash(void);
extern int hold_unlock(char *resource);

View File

@@ -42,7 +42,9 @@
#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

View File

@@ -2,6 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
**
*******************************************************************************
******************************************************************************/
@@ -34,7 +35,6 @@
#include <netdb.h>
#include <assert.h>
#include "ccs.h"
#include "clvm.h"
#include "clvmd-comms.h"
#include "clvmd.h"
@@ -47,43 +47,19 @@ static int listen_fd = -1;
static int tcp_port;
struct hash_table *sock_hash;
static int get_tcp_port(int default_port);
static int get_our_ip_address(char *addr, int *family);
static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid,
struct local_client **new_client);
/* Called by init_cluster() to open up the listening socket */
// TODO: IPv6 compat.
int init_comms()
int init_comms(unsigned short port)
{
struct sockaddr *addr = NULL;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
int addr_len;
int family;
char address[MAX_CSID_LEN];
struct sockaddr_in6 addr;
sock_hash = hash_create(100);
tcp_port = get_tcp_port(DEFAULT_TCP_PORT);
tcp_port = port ? port : DEFAULT_TCP_PORT;
/* Get IP address and IP type */
get_our_ip_address(address, &family);
if (family == AF_INET)
{
memcpy(&addr4.sin_addr, addr, sizeof(struct in_addr));
addr = (struct sockaddr *)&addr4;
addr4.sin_port = htons(tcp_port);
addr_len = sizeof(addr4);
}
else
{
memcpy(&addr6.sin6_addr, addr, sizeof(struct in6_addr));
addr = (struct sockaddr *)&addr6;
addr6.sin6_port = htons(tcp_port);
addr_len = sizeof(addr6);
}
listen_fd = socket(family, SOCK_STREAM, 0);
listen_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (listen_fd < 0)
{
@@ -93,13 +69,16 @@ int init_comms()
{
int one = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
}
addr->sa_family = family;
memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(tcp_port);
if (bind(listen_fd, addr, addr_len) < 0)
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
DEBUGLOG("Can't bind to port\n");
DEBUGLOG("Can't bind to port: %s\n", strerror(errno));
syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port);
close(listen_fd);
return -1;
@@ -107,6 +86,9 @@ int init_comms()
listen(listen_fd, 5);
/* Set Close-on-exec */
fcntl(listen_fd, F_SETFD, 1);
return 0;
}
@@ -119,19 +101,23 @@ void tcp_remove_client(char *csid)
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 = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
{
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
close(client->fd);
}
/* Look for a mangled one too */
csid[0] ^= 0x80;
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
{
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
close(client->fd);
}
/* Put it back as we found it */
@@ -142,7 +128,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
{
struct local_client *client;
DEBUGLOG("alloc_client %d csid = [%d.%d.%d.%d]\n", fd,csid[0],csid[1],csid[2],csid[3]);
DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid));
/* Create a local_client and return it */
client = malloc(sizeof(struct local_client));
@@ -160,7 +146,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
*new_client = client;
/* Add to our list of node sockets */
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
if (hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
{
DEBUGLOG("alloc_client mangling CSID for second connection\n");
/* This is a duplicate connection but we can't close it because
@@ -173,7 +159,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
/* If it still exists then kill the connection as we should only
ever have one incoming connection from each node */
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
if (hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
{
DEBUGLOG("Multiple incoming connections from node\n");
syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]);
@@ -183,26 +169,26 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
return -1;
}
}
hash_insert_binary(sock_hash, csid, MAX_CSID_LEN, client);
hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client);
return 0;
}
int get_main_cluster_fd()
int get_main_gulm_cluster_fd()
{
return listen_fd;
}
/* Read on main comms (listen) socket, accept it */
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid,
struct local_client **new_client)
{
int newfd;
struct sockaddr_in addr;
struct sockaddr_in6 addr;
socklen_t addrlen = sizeof(addr);
int status;
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
DEBUGLOG("cluster_fd_callback\n");
*new_client = NULL;
@@ -218,22 +204,20 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
/* Check that the client is a member of the cluster
and reject if not.
// FIXME: IPv4 specific
*/
if (name_from_csid((char *)&addr.sin_addr.s_addr, name) < 0)
if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0)
{
char *ip = (char *)&addr.sin_addr.s_addr;
syslog(LOG_ERR, "Got connect from non-cluster node %d.%d.%d.%d\n",
ip[0], ip[1], ip[2], ip[3]);
DEBUGLOG("Got connect from non-cluster node %d.%d.%d.%d\n",
ip[0], ip[1], ip[2], ip[3]);
syslog(LOG_ERR, "Got connect from non-cluster node %s\n",
print_csid((char *)&addr.sin6_addr));
DEBUGLOG("Got connect from non-cluster node %s\n",
print_csid((char *)&addr.sin6_addr));
close(newfd);
errno = EAGAIN;
return -1;
}
status = alloc_client(newfd, (char *)&addr.sin_addr.s_addr, new_client);
status = alloc_client(newfd, (char *)&addr.sin6_addr, new_client);
if (status)
{
DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status);
@@ -246,22 +230,62 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
return newfd;
}
/* Try to get at least 'len' bytes from the socket */
static int really_read(int fd, char *buf, int len)
{
int got, offset;
got = offset = 0;
do {
got = read(fd, buf+offset, len-offset);
DEBUGLOG("really_read. got %d bytes\n", got);
offset += got;
} while (got > 0 && offset < len);
if (got < 0)
return got;
else
return offset;
}
static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
struct local_client **new_client)
{
struct sockaddr_in addr;
struct sockaddr_in6 addr;
socklen_t slen = sizeof(addr);
struct clvm_header *header = (struct clvm_header *)buf;
int status;
uint32_t arglen;
DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
*new_client = NULL;
/* Get "csid" */
getpeername(client->fd, (struct sockaddr *)&addr, &slen);
memcpy(csid, &addr.sin_addr.s_addr, MAX_CSID_LEN);
memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN);
status = read(client->fd, buf, len);
/* Read just the header first, then get the rest if there is any.
* Stream sockets, sigh.
*/
status = really_read(client->fd, buf, sizeof(struct clvm_header));
if (status > 0)
{
int status2;
arglen = ntohl(header->arglen);
/* Get the rest */
if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE)
{
status2 = really_read(client->fd, buf+status, arglen);
if (status2 > 0)
status += status2;
else
status = status2;
}
}
DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
@@ -270,30 +294,36 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
if (status == 0 ||
(status < 0 && errno != EAGAIN && errno != EINTR))
{
char remcsid[MAX_CSID_LEN];
char remcsid[GULM_MAX_CSID_LEN];
memcpy(remcsid, csid, MAX_CSID_LEN);
memcpy(remcsid, csid, GULM_MAX_CSID_LEN);
close(client->fd);
/* If the csid was mangled, then make sure we remove the right entry */
if (client->bits.net.flags)
remcsid[0] ^= 0x80;
hash_remove_binary(sock_hash, remcsid, MAX_CSID_LEN);
hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN);
/* Tell cluster manager layer */
add_down_node(remcsid);
}
else {
gulm_add_up_node(csid);
/* Send it back to clvmd */
process_message(client, buf, status, csid);
}
return status;
}
static int connect_csid(char *csid, struct local_client **newclient)
int gulm_connect_csid(char *csid, struct local_client **newclient)
{
int fd;
struct sockaddr_in addr;
struct sockaddr_in6 addr;
int status;
int one = 1;
DEBUGLOG("Connecting socket\n");
fd = socket(PF_INET, SOCK_STREAM, 0);
fd = socket(PF_INET6, SOCK_STREAM, 0);
if (fd < 0)
{
@@ -301,19 +331,29 @@ static int connect_csid(char *csid, struct local_client **newclient)
return -1;
}
addr.sin_family = AF_INET;
memcpy(&addr.sin_addr.s_addr, csid, MAX_CSID_LEN);
addr.sin_port = htons(tcp_port);
addr.sin6_family = AF_INET6;
memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN);
addr.sin6_port = htons(tcp_port);
DEBUGLOG("Connecting socket %d\n", fd);
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0)
{
syslog(LOG_ERR, "Unable to connect to remote node: %m");
/* "Connection refused" is "normal" because clvmd may not yet be running
* on that node.
*/
if (errno != ECONNREFUSED)
{
syslog(LOG_ERR, "Unable to connect to remote node: %m");
}
DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
close(fd);
return -1;
}
/* Set Close-on-exec */
fcntl(fd, F_SETFD, 1);
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
status = alloc_client(fd, csid, newclient);
if (status)
close(fd);
@@ -321,7 +361,7 @@ static int connect_csid(char *csid, struct local_client **newclient)
add_client(*newclient);
/* If we can connect to it, it must be running a clvmd */
add_up_node(csid);
gulm_add_up_node(csid);
return status;
}
@@ -330,21 +370,21 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
{
int status;
struct local_client *client;
char ourcsid[MAX_CSID_LEN];
char ourcsid[GULM_MAX_CSID_LEN];
assert(csid);
DEBUGLOG("tcp_send_message, csid = [%d.%d.%d.%d], msglen = %d\n", csid[0],csid[1],csid[2],csid[3], msglen);
DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen);
/* Don't connect to ourself */
get_our_csid(ourcsid);
if (memcmp(csid, ourcsid, MAX_CSID_LEN) == 0)
get_our_gulm_csid(ourcsid);
if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0)
return msglen;
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (!client)
{
status = connect_csid(csid, &client);
status = gulm_connect_csid(csid, &client);
if (status)
return -1;
}
@@ -354,7 +394,7 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
}
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
{
int status=0;
@@ -364,7 +404,7 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
if (!csid)
{
void *context = NULL;
char loop_csid[MAX_CSID_LEN];
char loop_csid[GULM_MAX_CSID_LEN];
/* Loop round all gulm-known nodes */
while (get_next_node_csid(&context, loop_csid))
@@ -383,62 +423,24 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
return status;
}
static int get_tcp_port(int default_port)
{
int ccs_handle;
int port = default_port;
char *portstr;
ccs_handle = ccs_connect();
if (ccs_handle)
{
return port;
}
if (!ccs_get(ccs_handle, "//clvm/@port", &portstr))
{
port = atoi(portstr);
free(portstr);
if (port <= 0 && port >= 65536)
port = default_port;
}
ccs_disconnect(ccs_handle);
DEBUGLOG("Using port %d for communications\n", port);
return port;
}
/* To get our own IP address we get the locally bound address of the
socket that's talking to GULM in the assumption(eek) that it will
be on the "right" network in a multi-homed system */
static int get_our_ip_address(char *addr, int *family)
{
/* Use a sockaddr_in6 to make sure it's big enough */
struct sockaddr_in6 saddr;
int socklen = sizeof(saddr);
struct utsname info;
uname(&info);
get_ip_address(info.nodename, addr);
if (!getsockname(gulm_fd(), (struct sockaddr *)&saddr, &socklen))
{
if (saddr.sin6_family == AF_INET6)
{
memcpy(addr, &saddr.sin6_addr, sizeof(saddr.sin6_addr));
}
else
{
struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
memcpy(addr, &sin4->sin_addr, sizeof(sin4->sin_addr));
}
return 0;
}
return -1;
}
/* Public version of above for those that don't care what protocol
we're using */
void get_our_csid(char *csid)
void get_our_gulm_csid(char *csid)
{
static char our_csid[MAX_CSID_LEN];
static char our_csid[GULM_MAX_CSID_LEN];
static int got_csid = 0;
if (!got_csid)
@@ -451,7 +453,15 @@ void get_our_csid(char *csid)
got_csid = 1;
}
}
memcpy(csid, our_csid, MAX_CSID_LEN);
memcpy(csid, our_csid, GULM_MAX_CSID_LEN);
}
static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6)
{
ip6->s6_addr32[0] = 0;
ip6->s6_addr32[1] = 0;
ip6->s6_addr32[2] = htonl(0xffff);
ip6->s6_addr32[3] = ip4->s_addr;
}
/* Get someone else's IP address from DNS */
@@ -459,7 +469,7 @@ int get_ip_address(char *node, char *addr)
{
struct hostent *he;
memset(addr, 0, MAX_CSID_LEN);
memset(addr, 0, GULM_MAX_CSID_LEN);
// TODO: what do we do about multi-homed hosts ???
// CCSs ip_interfaces solved this but some bugger removed it.
@@ -467,14 +477,29 @@ int get_ip_address(char *node, char *addr)
/* Try IPv6 first. The man page for gethostbyname implies that
it will lookup ip6 & ip4 names, but it seems not to */
he = gethostbyname2(node, AF_INET6);
if (!he)
if (he)
{
memcpy(addr, he->h_addr_list[0],
he->h_length);
}
else
{
he = gethostbyname2(node, AF_INET);
if (!he)
return -1;
/* For IPv4 address just use the lower 4 bytes */
memcpy(&addr, he->h_addr_list[0],
he->h_length);
if (!he)
return -1;
map_v4_to_v6((struct in_addr *)he->h_addr_list[0], (struct in6_addr *)addr);
}
return 0;
}
char *print_csid(char *csid)
{
static char buf[128];
int *icsid = (int *)csid;
sprintf(buf, "[%x.%x.%x.%x]",
icsid[0],icsid[1],icsid[2],icsid[3]);
return buf;
}

View File

@@ -1,7 +1,13 @@
#include <netinet/in.h>
#define MAX_CLUSTER_MESSAGE 1600
#define MAX_CSID_LEN sizeof(struct in6_addr)
#define MAX_CLUSTER_MEMBER_NAME_LEN 128
#define GULM_MAX_CLUSTER_MESSAGE 1600
#define GULM_MAX_CSID_LEN sizeof(struct in6_addr)
#define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128
extern int init_comms(void);
extern int init_comms(unsigned short);
extern char *print_csid(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);

View File

@@ -0,0 +1,3 @@
process_event
register_device
unregister_device

View File

@@ -0,0 +1,51 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
TARGETS = dmevent dmeventd
INSTALL_TYPE = install_dynamic
SOURCES = noop.c
CLEAN_TARGETS = dmevent.o dmeventd.o
ifeq ("@LIB_SUFFIX@","dylib")
LIB_SHARED = libdmeventdnoop.dylib
else
LIB_SHARED = libdmeventdnoop.so
endif
LDFLAGS += -ldl -ldevmapper -lmultilog
include ../make.tmpl
libdmeventdnoop.so: noop.o
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
$(CC) -o $@ dmevent.o $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog $(LIBS)
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -lpthread -ldmevent $(LIBS)
install: $(INSTALL_TYPE)
.PHONY: install_dynamic
install_dynamic: dmeventd
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd

240
daemons/dmeventd/dmevent.c Normal file
View File

@@ -0,0 +1,240 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "libdevmapper.h"
#include "libdm-event.h"
#include "libmultilog.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
static char default_dso_name[] = "noop"; /* default DSO is noop */
static int default_reg = 1; /* default action is register */
static uint32_t timeout;
struct event_ops {
int (*dm_register_for_event)(char *dso_name, char *device,
enum event_type event_types);
int (*dm_unregister_for_event)(char *dso_name, char *device,
enum event_type event_types);
int (*dm_get_registered_device)(char **dso_name, char **device,
enum event_type *event_types, int next);
int (*dm_set_event_timeout)(char *device, uint32_t time);
int (*dm_get_event_timeout)(char *device, uint32_t *time);
};
/* Display help. */
static void print_usage(char *name)
{
char *cmd = strrchr(name, '/');
cmd = cmd ? cmd + 1 : name;
printf("Usage::\n"
"%s [options] <device>\n"
"\n"
"Options:\n"
" -d <dso> Specify the DSO to use.\n"
" -h Print this usage.\n"
" -l List registered devices.\n"
" -r Register for event (default).\n"
" -t <timeout> (un)register for timeout event.\n"
" -u Unregister for event.\n"
"\n", cmd);
}
/* Parse command line arguments. */
static int parse_argv(int argc, char **argv, char **dso_name_arg,
char **device_arg, int *reg, int *list)
{
int c;
const char *options = "d:hlrt:u";
while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'd':
*dso_name_arg = optarg;
break;
case 'h':
print_usage(argv[0]);
exit(EXIT_SUCCESS);
case 'l':
*list = 1;
break;
case 'r':
*reg = 1;
break;
case 't':
events = TIMEOUT;
if (sscanf(optarg, "%"SCNu32, &timeout) != 1){
fprintf(stderr, "invalid timeout '%s'\n",
optarg);
timeout = 0;
}
break;
case 'u':
*reg = 0;
break;
default:
fprintf(stderr, "Unknown option '%c'.\n"
"Try '-h' for help.\n", c);
return 0;
}
}
if (optind >= argc) {
if (!*list) {
fprintf(stderr, "You need to specify a device.\n");
return 0;
}
} else
*device_arg = argv[optind];
return 1;
}
static int lookup_symbol(void *dl, void **symbol, const char *name)
{
if ((*symbol = dlsym(dl, name)))
return 1;
fprintf(stderr, "error looking up %s symbol: %s\n", name, dlerror());
return 0;
}
static int lookup_symbols(void *dl, struct event_ops *e)
{
return lookup_symbol(dl, (void *) &e->dm_register_for_event,
"dm_register_for_event") &&
lookup_symbol(dl, (void *) &e->dm_unregister_for_event,
"dm_unregister_for_event") &&
lookup_symbol(dl, (void *) &e->dm_get_registered_device,
"dm_get_registered_device") &&
lookup_symbol(dl, (void *) &e->dm_set_event_timeout,
"dm_set_event_timeout") &&
lookup_symbol(dl, (void *) &e->dm_get_event_timeout,
"dm_get_event_timeout");
}
int main(int argc, char **argv)
{
void *dl;
struct event_ops e;
int list = 0, next = 0, ret, reg = default_reg;
char *device, *device_arg = NULL, *dso_name, *dso_name_arg = NULL;
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, &reg, &list))
exit(EXIT_FAILURE);
if (device_arg) {
if (!(device = strdup(device_arg)))
exit(EXIT_FAILURE);
} else
device = NULL;
if (dso_name_arg) {
if (!(dso_name = strdup(dso_name_arg)))
exit(EXIT_FAILURE);
} else {
if (!(dso_name = strdup(default_dso_name)))
exit(EXIT_FAILURE);
}
/* FIXME: use -v/-q options to set this */
multilog_add_type(standard, NULL);
multilog_init_verbose(standard, _LOG_DEBUG);
if (!(dl = dlopen("libdmevent.so", RTLD_NOW))){
fprintf(stderr, "Cannot dlopen libdmevent.so: %s\n", dlerror());
goto out;
}
if (!(lookup_symbols(dl, &e)))
goto out;
if (list) {
while (1) {
if ((ret= e.dm_get_registered_device(&dso_name,
&device,
&events, next)))
break;
printf("%s %s 0x%x", dso_name, device, events);
if (events & TIMEOUT){
if ((ret = e.dm_get_event_timeout(device,
&timeout))) {
ret = EXIT_FAILURE;
goto out;
}
printf(" %"PRIu32"\n", timeout);
} else
printf("\n");
if (device_arg)
break;
next = 1;
}
ret = (ret && device_arg) ? EXIT_FAILURE : EXIT_SUCCESS;
goto out;
}
if ((ret = reg ? e.dm_register_for_event(dso_name, device, events) :
e.dm_unregister_for_event(dso_name, device, events))) {
fprintf(stderr, "Failed to %sregister %s: %s\n",
reg ? "": "un", device, strerror(-ret));
ret = EXIT_FAILURE;
} else {
if (reg && (events & TIMEOUT) &&
((ret = e.dm_set_event_timeout(device, timeout)))){
fprintf(stderr, "Failed to set timeout for %s: %s\n",
device, strerror(-ret));
ret = EXIT_FAILURE;
} else {
printf("%s %sregistered successfully.\n",
device, reg ? "" : "un");
ret = EXIT_SUCCESS;
}
}
out:
multilog_del_type(standard);
if (device)
free(device);
if (dso_name)
free(dso_name);
exit(ret);
}
/*
* 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:
*/

1083
daemons/dmeventd/dmeventd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
#!/bin/sh
#
# Create test devices for dmeventd
#
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
echo "0 1024 zero" > /tmp/tmp.$$
dmsetup create test /tmp/tmp.$$
dmsetup create test1 /tmp/tmp.$$
kill -15 $$

39
daemons/dmeventd/noop.c Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "libdm-event.h"
#include "libmultilog.h"
void process_event(char *device, enum event_type event)
{
log_err("[%s] %s(%d) - Device: %s, Event %d\n",
__FILE__, __func__, __LINE__, device, event);
}
int register_device(char *device)
{
log_err("[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
int unregister_device(char *device)
{
log_err("[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}

View File

@@ -27,8 +27,18 @@ devices {
# the device will be accepted or rejected (ignored). Devices that
# don't match any patterns are accepted.
# Remember to run vgscan after you change this parameter to ensure
# that the cache file gets regenerated (see below).
# Be careful if there there are symbolic links or multiple filesystem
# entries for the same device as each name is checked separately against
# the list of patterns. The effect is that if any name matches any 'a'
# pattern, the device is accepted; otherwise if any name matches any 'r'
# pattern it is rejected; otherwise it is accepted.
# Don't have more than one filter line active at once: only one gets used.
# Run vgscan after you change this parameter to ensure that
# the cache file gets regenerated (see below).
# If it doesn't do what you expect, check the output of 'vgscan -vvvv'.
# By default we accept every block device:
filter = [ "a/.*/" ]
@@ -252,11 +262,10 @@ activation {
#
# metadata {
# Default number of copies of metadata to hold on each PV. 0, 1 or 2.
# It's best to leave this at 2.
# You might want to override it from the command line with 0 or 1
# You might want to override it from the command line with 0
# when running pvcreate on new PVs which are to be added to large VGs.
# pvmetadatacopies = 2
# pvmetadatacopies = 1
# Approximate default size of on-disk metadata areas in sectors.
# You should increase this if you have large volume groups or

165
doc/tagging.txt Normal file
View File

@@ -0,0 +1,165 @@
Tagging aims
============
1) Ability to attach an unordered list of tags to LVM metadata objects.
2) Ability to add or remove tags easily.
3) Ability to select LVM objects for processing according to presence/absence
of specific tags.
4) Ability to control through the config file which VGs/LVs are activated
on different machines using names or tags.
5) Ability to overlay settings from different config files e.g. override
some settings in a global config file locally.
Clarifications
==============
1) Tag character set: A-Za-z0-9_+.-
Can't start with hyphen & max length is 128 (NAME_LEN).
2) LVM object types that can be tagged:
VG, LV, LV segment
PV - tags are stored in VG metadata so disappear when PV becomes orphaned
Snapshots can't be tagged, but their origin may be.
3) A tag can be used in place of any command line LVM object reference that
accepts (a) a list of objects; or (b) a single object as long as the
tag expands to a single object. This is not supported everywhere yet.
Duplicate arguments in a list after argument expansion may get removed
retaining the first copy of each argument.
4) Wherever there may be ambiguity of argument type, a tag must be prefixed
by '@'; elsewhere an '@' prefix is optional.
5) LVM1 objects cannot be tagged, as the disk format doesn't support it.
6) Tags can be added or removed with --addtag or --deltag.
Config file Extensions
======================
To define host tags in config file:
tags {
# Set a tag with the hostname
hosttags = 1
tag1 { }
tag2 {
# If no exact match, tag is not set.
host_list = [ "hostname", "dbase" ]
}
}
Activation config file example
==============================
activation {
volume_list = [ "vg1/lvol0", "@database" ]
}
Matches against vgname, vgname/lvname or @tag set in *metadata*.
@* matches exactly against *any* tag set on the host.
The VG or LV only gets activated if a metadata tag matches.
The default if there is no match is not to activate.
If volume_list is not present and any tags are defined on the host
then it only activates if a host tag matches a metadata tag.
If volume_list is not present and no tags are defined on the host
then it does activate.
Multiple config files
=====================
(a) lvm.conf
(b) lvm_<host_tag>.conf
At startup, load lvm.conf.
Process tag settings.
If any host tags were defined, load lvm_tag.conf for each tag, if present.
When searching for a specific config file entry, search order is (b)
then (a), stopping at the first match.
Within (b) use reverse order tags got set, so file for last tag set is
searched first.
New tags set in (b) *do* trigger additional config file loads.
Usage Examples
==============
1) Simple activation control via metadata with static config files
lvm.conf: (Identical on every machine - global settings)
tags {
hostname_tags = 1
}
From any machine in the cluster, add db1 to the list of machines that
activate vg1/lvol2:
lvchange --tag @db1 vg1/lvol2
(followed by lvchange -ay to actually activate it)
2) Multiple hosts.
Activate vg1 only on the database hosts, db1 and db2.
Activate vg2 only on the fileserver host fs1.
Activate nothing initially on the fileserver backup host fsb1, but be
prepared for it to take over from fs1.
Option (i) - centralised admin, static configuration replicated between hosts
# Add @database tag to vg1's metadata
vgchange --tag @database vg1
# Add @fileserver tag to vg2's metadata
vgchange --tag @fileserver vg2
lvm.conf: (Identical on every machine)
tags {
database {
host_list = [ "db1", "db2" ]
}
fileserver {
host_list = [ "fs1" ]
}
fileserverbackup {
host_list = [ "fsb1" ]
}
}
activation {
# Only activate if host has a tag that matches a metadata tag
volume_list = [ "@*" ]
}
In the event of the fileserver host going down, vg2 can be brought up
on fsb1 by running *on any node* 'vgchange --tag @fileserverbackup vg2'
followed by 'vgchange -ay vg2'
Option (ii) - localised admin & configuation
(i.e. each host holds *locally* which classes of volumes to activate)
# Add @database tag to vg1's metadata
vgchange --tag @database vg1
# Add @fileserver tag to vg2's metadata
vgchange --tag @fileserver vg2
lvm.conf: (Identical on every machine - global settings)
tags {
hosttags = 1
}
lvm_db1.conf: (only needs to be on db1 - could be symlink to lvm_db.conf)
activation {
volume_list = [ "@database" ]
}
lvm_db2.conf: (only needs to be on db2 - could be symlink to lvm_db.conf)
activation {
volume_list = [ "@database" ]
}
lvm_fs1.conf: (only needs to be on fs1 - could be symlink to lvm_fs.conf)
activation {
volume_list = [ "@fileserver" ]
}
If fileserver goes down, to bring a spare machine fsb1 in as fileserver,
create lvm_fsb1.conf on fsb1 (or symlink to lvm_fs.conf):
activation {
volume_list = [ "@fileserver" ]
}
and run 'vgchange -ay vg2' or 'vgchange -ay @fileserver'

View File

@@ -23,6 +23,7 @@
../lib/filters/filter.h
../lib/format1/format1.h
../lib/format_pool/format_pool.h
../lib/format_text/archiver.h
../lib/format_text/format-text.h
../lib/format_text/text_export.h
../lib/format_text/text_import.h
@@ -31,7 +32,8 @@
../lib/log/log.h
../lib/metadata/lv_alloc.h
../lib/metadata/metadata.h
../lib/metadata/segtypes.h
../lib/metadata/pv_alloc.h
../lib/metadata/segtype.h
../lib/mm/dbg_malloc.h
../lib/mm/memlock.h
../lib/mm/pool.h
@@ -47,3 +49,4 @@
../lib/report/report.h
../lib/uuid/uuid.h
../po/pogen.h
../tools/version.h

View File

@@ -20,6 +20,8 @@ VPATH = @srcdir@
LN_S = @LN_S@
.PHONY: clean distclean all install pofile install_cluster
all: .symlinks_created
.symlinks_created: .symlinks
@@ -37,5 +39,5 @@ clean:
install:
.PHONY: clean distclean all install pofile
install_cluster:

View File

@@ -43,6 +43,7 @@ SOURCES =\
datastruct/str_list.c \
device/dev-cache.c \
device/dev-io.c \
device/dev-md.c \
device/device.c \
display/display.c \
error/errseg.c \
@@ -53,6 +54,7 @@ SOURCES =\
filters/filter-md.c \
filters/filter.c \
format_text/archive.c \
format_text/archiver.c \
format_text/export.c \
format_text/flags.c \
format_text/format-text.c \
@@ -69,12 +71,14 @@ SOURCES =\
metadata/merge.c \
metadata/metadata.c \
metadata/mirror.c \
metadata/pv_manip.c \
metadata/pv_map.c \
metadata/segtypes.c \
metadata/segtype.c \
metadata/snapshot_manip.c \
misc/crc.c \
misc/lvm-file.c \
misc/lvm-string.c \
mm/dbg_malloc.c \
mm/memlock.c \
mm/pool.c \
regex/matcher.c \
@@ -120,10 +124,6 @@ ifeq ("@MIRRORS@", "internal")
SOURCES += mirror/mirrored.c
endif
ifeq ("@DEBUG@", "yes")
SOURCES += mm/dbg_malloc.c
endif
ifeq ("@DEVMAPPER@", "yes")
SOURCES +=\
activate/dev_manager.c \

View File

@@ -78,12 +78,13 @@ int target_present(const char *target_name)
{
return 0;
}
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
int with_open_count)
{
return 0;
}
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
struct lvinfo *info)
struct lvinfo *info, int with_open_count)
{
return 0;
}
@@ -129,11 +130,11 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
{
return 1;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return 1;
}
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s)
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return 1;
}
@@ -333,7 +334,7 @@ int target_present(const char *target_name)
* Returns 1 if info structure populated, else 0 on failure.
*/
static int _lv_info(const struct logical_volume *lv, int mknodes,
struct lvinfo *info)
struct lvinfo *info, int with_open_count)
{
int r;
struct dev_manager *dm;
@@ -347,7 +348,7 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
return 0;
}
if (!(r = dev_manager_info(dm, lv, mknodes, &dminfo)))
if (!(r = dev_manager_info(dm, lv, mknodes, with_open_count, &dminfo)))
stack;
info->exists = dminfo.exists;
@@ -361,20 +362,21 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
return r;
}
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
int with_open_count)
{
return _lv_info(lv, 0, info);
return _lv_info(lv, 0, info, with_open_count);
}
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
struct lvinfo *info)
struct lvinfo *info, int with_open_count)
{
struct logical_volume *lv;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
return _lv_info(lv, 0, info);
return _lv_info(lv, 0, info, with_open_count);
}
/*
@@ -412,7 +414,7 @@ int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
if (!activation())
return 0;
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -437,7 +439,7 @@ static int _lv_active(struct logical_volume *lv)
{
struct lvinfo info;
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return -1;
}
@@ -449,7 +451,7 @@ static int _lv_open_count(struct logical_volume *lv)
{
struct lvinfo info;
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 1)) {
stack;
return -1;
}
@@ -515,17 +517,15 @@ static int _lv_suspend_lv(struct logical_volume *lv)
*/
int lvs_in_vg_activated(struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (lv->status & VISIBLE_LV)
count += (_lv_active(lv) == 1);
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & VISIBLE_LV)
count += (_lv_active(lvl->lv) == 1);
}
return count;
@@ -533,17 +533,15 @@ int lvs_in_vg_activated(struct volume_group *vg)
int lvs_in_vg_opened(struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (lv->status & VISIBLE_LV)
count += (_lv_open_count(lv) > 0);
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & VISIBLE_LV)
count += (_lv_open_count(lvl->lv) > 0);
}
return count;
@@ -566,7 +564,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -612,7 +610,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -657,7 +655,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 1)) {
stack;
return 0;
}
@@ -703,7 +701,8 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
int exclusive, int filter)
{
struct logical_volume *lv;
struct lvinfo info;
@@ -726,7 +725,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -734,6 +733,9 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
if (info.exists && !info.suspended)
return 1;
if (exclusive)
lv->status |= ACTIVATE_EXCL;
memlock_inc();
r = _lv_activate_lv(lv);
memlock_dec();
@@ -743,15 +745,15 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
}
/* Activate LV */
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return _lv_activate(cmd, lvid_s, 0);
return _lv_activate(cmd, lvid_s, exclusive, 0);
}
/* Activate LV only if it passes filter */
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s)
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return _lv_activate(cmd, lvid_s, 1);
return _lv_activate(cmd, lvid_s, exclusive, 1);
}
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
@@ -765,7 +767,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return r;
}
if (!_lv_info(lv, 1, &info)) {
if (!_lv_info(lv, 1, &info, 0)) {
stack;
return 0;
}

View File

@@ -46,8 +46,9 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s);
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_resume(struct cmd_context *cmd, const char *lvid_s);
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive);
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s,
int exclusive);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
@@ -55,9 +56,10 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
/*
* Returns 1 if info structure has been populated, else 0.
*/
int lv_info(const struct logical_volume *lv, struct lvinfo *info);
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
int with_open_count);
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
struct lvinfo *info);
struct lvinfo *info, int with_open_count);
/*
* Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.

View File

@@ -21,7 +21,7 @@
#include "lvm-string.h"
#include "fs.h"
#include "defaults.h"
#include "segtypes.h"
#include "segtype.h"
#include "display.h"
#include "toolcontext.h"
#include "targets.h"
@@ -165,89 +165,6 @@ static inline void _clear_flag(struct dev_layer *dl, int bit)
dl->flags &= ~(1 << bit);
}
/*
* Device layer names are all of the form <vg>-<lv>-<layer>, any
* other hyphens that appear in these names are quoted with yet
* another hyphen. The top layer of any device has no layer
* name. eg, vg0-lvol0.
*/
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
{
const char *ptr;
for (ptr = str; *ptr; ptr++, (*len)++)
if (*ptr == '-')
(*hyphens)++;
}
/*
* Copies a string, quoting hyphens with hyphens.
*/
static void _quote_hyphens(char **out, const char *src)
{
while (*src) {
if (*src == '-')
*(*out)++ = '-';
*(*out)++ = *src++;
}
}
/*
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
*/
static char *_build_name(struct pool *mem, const char *vg,
const char *lv, const char *layer)
{
size_t len = 0;
int hyphens = 0;
char *r, *out;
_count_hyphens(vg, &len, &hyphens);
_count_hyphens(lv, &len, &hyphens);
if (layer && *layer)
_count_hyphens(layer, &len, &hyphens);
len += hyphens + 2;
if (!(r = pool_alloc(mem, len))) {
stack;
return NULL;
}
out = r;
_quote_hyphens(&out, vg);
*out++ = '-';
_quote_hyphens(&out, lv);
if (layer && *layer) {
*out++ = '-';
_quote_hyphens(&out, layer);
}
*out = '\0';
return r;
}
/* Find start of LV component in hyphenated name */
static char *_find_lv_name(char *vg)
{
char *c = vg;
while (*c && *(c + 1)) {
if (*c == '-') {
if (*(c + 1) == '-')
c++;
else
return (c + 1);
}
c++;
}
return NULL;
}
static char *_build_dlid(struct pool *mem, const char *lvid, const char *layer)
{
char *dlid;
@@ -294,7 +211,8 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
}
static int _info_run(const char *name, const char *uuid, struct dm_info *info,
int mknodes, struct pool *mem, char **uuid_out)
int mknodes, int with_open_count, struct pool *mem,
char **uuid_out)
{
int r = 0;
struct dm_task *dmt;
@@ -308,6 +226,10 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
return 0;
}
if (!with_open_count)
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt)) {
stack;
goto out;
@@ -333,14 +255,17 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
}
static int _info(const char *name, const char *uuid, int mknodes,
struct dm_info *info, struct pool *mem, char **uuid_out)
int with_open_count, struct dm_info *info,
struct pool *mem, char **uuid_out)
{
if (!mknodes && uuid && *uuid &&
_info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists)
_info_run(NULL, uuid, info, 0, with_open_count, mem, uuid_out) &&
info->exists)
return 1;
if (name)
return _info_run(name, NULL, info, mknodes, mem, uuid_out);
return _info_run(name, NULL, info, mknodes, with_open_count,
mem, uuid_out);
return 0;
}
@@ -362,6 +287,9 @@ static int _status_run(const char *name, const char *uuid,
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt)) {
stack;
goto out;
@@ -440,6 +368,9 @@ static int _percent_run(struct dev_manager *dm, const char *name,
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt)) {
stack;
goto out;
@@ -519,10 +450,16 @@ static int _percent(struct dev_manager *dm, const char *name, const char *uuid,
return 0;
}
static int _rename(struct dev_layer *dl, char *newname)
static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname)
{
int r = 1;
struct dm_task *dmt;
char *vgname, *lvname, *layer;
if (!split_dm_name(dm->mem, dl->name, &vgname, &lvname, &layer)) {
log_error("Couldn't split up dm layer name %s", dl->name);
return 0;
}
log_verbose("Renaming %s to %s", dl->name, newname);
@@ -537,11 +474,16 @@ static int _rename(struct dev_layer *dl, char *newname)
goto out;
}
if (!(r = dm_task_run(dmt)))
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt))) {
log_error("Couldn't rename device '%s'.", dl->name);
goto out;
}
if (r && _get_flag(dl, VISIBLE))
fs_rename_lv(dl->lv, newname, _find_lv_name(dl->name));
fs_rename_lv(dl->lv, newname, lvname);
dl->name = newname;
@@ -563,6 +505,9 @@ static int _suspend_or_resume(const char *name, action_t suspend)
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt)))
log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
name);
@@ -654,6 +599,9 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
log_very_verbose("Activating %s read-only", dl->name);
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt))) {
log_error("Couldn't load device '%s'.", dl->name);
if ((dl->lv->minor >= 0 || dl->lv->major >= 0) &&
@@ -710,6 +658,9 @@ static int _remove(struct dev_layer *dl)
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
/* Suppress error message if it's still in use - we'll log it later */
log_suppress(1);
@@ -776,6 +727,28 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
return 1;
}
int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf,
size_t bufsize, const char *desc)
{
struct dev_layer *dl;
if (!(dl = hash_lookup(dm->layers, dlid))) {
log_error("%s device layer %s missing from hash",
desc, dlid);
return 0;
}
if (!dm_format_dev(devbuf, bufsize, dl->info.major,
dl->info.minor)) {
log_error("Failed to format %s device number for %s as dm "
"target (%u,%u)",
desc, dlid, dl->info.major, dl->info.minor);
return 0;
}
return 1;
}
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos, int start_area,
int areas)
@@ -784,43 +757,39 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
int tw = 0;
const char *trailing_space;
uint64_t esize = seg->lv->vg->extent_size;
struct dev_layer *dl;
char devbuf[10];
for (s = start_area; s < areas; s++, *pos += tw) {
trailing_space = (areas - s - 1) ? " " : "";
if ((seg->area[s].type == AREA_PV &&
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
if ((seg_type(seg, s) == AREA_PV &&
(!seg_pvseg(seg, s) ||
!seg_pv(seg, s) ||
!seg_dev(seg, s))) ||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s 0%s", dm->stripe_filler,
trailing_space);
else if (seg->area[s].type == AREA_PV)
else if (seg_type(seg, s) == AREA_PV)
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].u.pv.pv->dev),
(seg->area[s].u.pv.pv->pe_start +
(esize * seg->area[s].u.pv.pe)),
dev_name(seg_dev(seg, s)),
(seg_pv(seg, s)->pe_start +
(esize * seg_pe(seg, s))),
trailing_space);
else {
if (!(dl = hash_lookup(dm->layers,
seg->area[s].u.lv.lv->lvid.s))) {
log_error("device layer %s missing from hash",
seg->area[s].u.lv.lv->lvid.s);
return 0;
}
if (!dm_format_dev
(devbuf, sizeof(devbuf), dl->info.major,
dl->info.minor)) {
log_error
("Failed to format device number as dm target (%u,%u)",
dl->info.major, dl->info.minor);
else if (seg_type(seg, s) == AREA_LV) {
if (!build_dev_string(dm, seg_lv(seg, s)->lvid.s, devbuf,
sizeof(devbuf), "LV")) {
stack;
return 0;
}
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s %" PRIu64 "%s", devbuf,
esize * seg->area[s].u.lv.le,
esize * seg_le(seg, s),
trailing_space);
} else {
log_error("Internal error: Unassigned area found in LV %s.",
seg->lv->name);
return 0;
}
if (tw < 0) {
@@ -867,14 +836,12 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
static int _populate_vanilla(struct dev_manager *dm,
struct dm_task *dmt, struct dev_layer *dl)
{
struct list *segh;
struct lv_segment *seg;
struct logical_volume *lv = dl->lv;
dm->pvmove_mirror_count = 0u;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
list_iterate_items(seg, &lv->segments) {
if (!_emit_target(dm, dmt, seg)) {
log_error("Unable to build table for '%s'", lv->name);
return 0;
@@ -889,22 +856,14 @@ static int _populate_origin(struct dev_manager *dm,
{
char *real;
char params[PATH_MAX + 32];
struct dev_layer *dlr;
if (!(real = _build_dlid(dm->mem, dl->lv->lvid.s, "real"))) {
stack;
return 0;
}
if (!(dlr = hash_lookup(dm->layers, real))) {
log_error("Couldn't find real device layer %s in hash", real);
return 0;
}
if (!dm_format_dev(params, sizeof(params), dlr->info.major,
dlr->info.minor)) {
log_error("Couldn't create origin device parameters for '%s'.",
real);
if (!build_dev_string(dm, real, params, sizeof(params), "origin")) {
stack;
return 0;
}
@@ -924,60 +883,46 @@ static int _populate_snapshot(struct dev_manager *dm,
{
char *origin, *cow;
char params[PATH_MAX * 2 + 32];
struct snapshot *s;
struct dev_layer *dlo, *dlc;
struct lv_segment *snap_seg;
char devbufo[10], devbufc[10];
uint64_t size;
if (!(s = find_cow(dl->lv))) {
if (!(snap_seg = find_cow(dl->lv))) {
log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
return 0;
}
if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s,
"real"))) {
stack;
return 0;
}
if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) {
if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) {
stack;
return 0;
}
if (!(dlo = hash_lookup(dm->layers, origin))) {
log_error("Couldn't find origin device layer %s in hash",
origin);
if (!build_dev_string(dm, origin, devbufo, sizeof(devbufo), "origin")) {
stack;
return 0;
}
if (!(dlc = hash_lookup(dm->layers, cow))) {
log_error("Couldn't find cow device layer %s in hash", cow);
return 0;
}
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
dlo->info.minor)) {
log_error("Couldn't create origin device parameters for '%s'.",
s->origin->name);
return 0;
}
if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
dlc->info.minor)) {
log_error("Couldn't create cow device parameters for '%s'.",
s->cow->name);
if (!build_dev_string(dm, cow, devbufc, sizeof(devbufc), "cow")) {
stack;
return 0;
}
if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
devbufo, devbufc, s->chunk_size) == -1) {
devbufo, devbufc, snap_seg->chunk_size) == -1) {
stack;
return 0;
}
log_debug("Adding target: 0 %" PRIu64 " snapshot %s",
s->origin->size, params);
if (!dm_task_add_target
(dmt, UINT64_C(0), s->origin->size, "snapshot", params)) {
size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) {
stack;
return 0;
}
@@ -994,7 +939,7 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
struct pool *mem;
struct dev_manager *dm;
if (!(mem = pool_create(16 * 1024))) {
if (!(mem = pool_create("dev_manager", 16 * 1024))) {
stack;
return NULL;
}
@@ -1045,14 +990,14 @@ void dev_manager_destroy(struct dev_manager *dm)
}
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
int mknodes, struct dm_info *info)
int mknodes, int with_open_count, struct dm_info *info)
{
char *name;
/*
* Build a name for the top layer.
*/
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
stack;
return 0;
}
@@ -1061,7 +1006,8 @@ int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
* Try and get some info on this device.
*/
log_debug("Getting device info for %s", name);
if (!_info(name, lv->lvid.s, mknodes, info, NULL, NULL)) {
if (!_info(name, lv->lvid.s, mknodes, with_open_count, info, NULL,
NULL)) {
stack;
return 0;
}
@@ -1077,7 +1023,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
/*
* Build a name for the top layer.
*/
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
stack;
return 0;
}
@@ -1109,7 +1055,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
/*
* Build a name for the top layer.
*/
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
stack;
return 0;
}
@@ -1140,7 +1086,7 @@ static struct dev_layer *_create_dev(struct dev_manager *dm, char *name,
dl->name = name;
log_debug("Getting device info for %s", dl->name);
if (!_info(dl->name, dlid, 0, &dl->info, dm->mem, &uuid)) {
if (!_info(dl->name, dlid, 0, 0, &dl->info, dm->mem, &uuid)) {
stack;
return NULL;
}
@@ -1173,7 +1119,7 @@ static struct dev_layer *_create_layer(struct dev_manager *dm,
char *name, *dlid;
struct dev_layer *dl;
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, layer))) {
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) {
stack;
return NULL;
}
@@ -1223,7 +1169,6 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
* only one layer.
*/
struct dev_layer *dl, *dlr;
struct list *segh;
struct lv_segment *seg;
uint32_t s;
@@ -1241,19 +1186,30 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
_set_flag(dl, TOPLEVEL);
/* Add dependencies for any LVs that segments refer to */
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
list_iterate_items(seg, &lv->segments) {
// When do we need? _set_flag(dl, REMOVE) on the log?
if (seg->log_lv &&
!str_list_add(dm->mem, &dl->pre_create,
_build_dlid(dm->mem, seg->log_lv->lvid.s,
NULL))) {
stack;
return 0;
}
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_LV)
if (seg_type(seg, s) != AREA_LV)
continue;
if (!str_list_add(dm->mem, &dl->pre_create,
_build_dlid(dm->mem,
seg->area[s].u.lv.lv->
seg_lv(seg, s)->
lvid.s, NULL))) {
stack;
return 0;
}
// ? if (seg_lv(seg, s)->status & PVMOVE)
_set_flag(dl, NOPROPAGATE);
// When do we need? _set_flag(dl, REMOVE)
}
}
@@ -1321,16 +1277,16 @@ static int _expand_origin_real(struct dev_manager *dm,
static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
{
struct logical_volume *active;
struct snapshot *s;
struct list *sh;
struct lv_segment *snap_seg;
struct lv_list *lvl;
/*
* We only need to create an origin layer if one of our
* snapshots is in the active list
*/
list_iterate(sh, &dm->active_list) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && (s->origin == lv))
list_iterate_items(lvl, &dm->active_list) {
active = lvl->lv;
if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
return _expand_origin_real(dm, lv);
}
@@ -1341,7 +1297,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
}
static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
struct snapshot *s)
struct lv_segment *snap_seg)
{
/*
* snapshot(org, cow)
@@ -1378,13 +1334,15 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
/* add the dependency on the real origin device */
if (!str_list_add(dm->mem, &dl->pre_create,
_build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
_build_dlid(dm->mem, snap_seg->origin->lvid.s,
"real"))) {
stack;
return 0;
}
/* add the dependency on the visible origin device */
if (!str_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) {
if (!str_list_add(dm->mem, &dl->pre_suspend,
snap_seg->origin->lvid.s)) {
stack;
return 0;
}
@@ -1397,16 +1355,24 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
*/
static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
{
struct snapshot *s;
struct lv_segment *snap_seg;
/*
* FIXME: this doesn't cope with recursive snapshots yet.
*/
if ((s = find_cow(lv)))
return _expand_snapshot(dm, lv, s);
else if (lv_is_origin(lv))
if ((snap_seg = find_cow(lv))) {
if (lv->vg->status & CLUSTERED) {
log_error("Clustered snapshots are not yet supported");
return 0;
}
return _expand_snapshot(dm, lv, snap_seg);
} else if (lv_is_origin(lv)) {
if (lv->vg->status & CLUSTERED) {
log_error("Clustered snapshots are not yet supported");
return 0;
}
return _expand_origin(dm, lv);
}
return _expand_vanilla(dm, lv, 0);
}
@@ -1431,12 +1397,12 @@ static void _clear_marks(struct dev_manager *dm, int flag)
static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
int flag)
{
struct list *sh;
struct str_list *strl;
const char *dlid;
struct dev_layer *dep;
list_iterate(sh, &dl->pre_create) {
dlid = list_item(sh, struct str_list)->str;
list_iterate_items(strl, &dl->pre_create) {
dlid = strl->str;
if (!(dep = hash_lookup(dm->layers, dlid))) {
log_error("Couldn't find device layer '%s'.", dlid);
@@ -1486,14 +1452,14 @@ static int _trace_all_marks(struct dev_manager *dm, int flag)
*/
static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
struct dev_layer *dl;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
list_iterate_items(lvl, lvs) {
if (lvl->lv->status & SNAPSHOT)
continue;
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) {
stack;
return 0;
}
@@ -1511,12 +1477,12 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
{
struct list *sh;
struct str_list *strl;
struct dev_layer *dep;
const char *dlid;
list_iterate(sh, &dl->pre_suspend) {
dlid = list_item(sh, struct str_list)->str;
list_iterate_items(strl, &dl->pre_suspend) {
dlid = strl->str;
if (!(dep = hash_lookup(dm->layers, dlid))) {
log_debug("_suspend_parents couldn't find device "
@@ -1545,12 +1511,12 @@ static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
{
struct list *sh;
struct str_list *strl;
struct dev_layer *dep;
const char *dlid;
list_iterate(sh, &dl->pre_create) {
dlid = list_item(sh, struct str_list)->str;
list_iterate_items(strl, &dl->pre_create) {
dlid = strl->str;
if (!(dep = hash_lookup(dm->layers, dlid))) {
log_debug("_resume_with_deps couldn't find device "
@@ -1583,7 +1549,7 @@ static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
*/
static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
{
struct list *sh;
struct str_list *strl;
struct dev_layer *dep;
const char *dlid;
char *newname, *suffix;
@@ -1595,8 +1561,8 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
return 0;
}
list_iterate(sh, &dl->pre_create) {
dlid = list_item(sh, struct str_list)->str;
list_iterate_items(strl, &dl->pre_create) {
dlid = strl->str;
if (!(dep = hash_lookup(dm->layers, dlid))) {
log_error("Couldn't find device layer '%s'.", dlid);
@@ -1618,11 +1584,11 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
if (dl->info.exists) {
if ((suffix = rindex(dl->dlid, '-')))
suffix++;
newname = _build_name(dm->mem, dm->vg_name, dl->lv->name,
suffix);
newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
suffix);
if (strcmp(newname, dl->name)) {
if (!_suspend_parents(dm, dl) ||
!_suspend(dl) || !_rename(dl, newname)) {
!_suspend(dl) || !_rename(dm, dl, newname)) {
stack;
return 0;
}
@@ -1652,15 +1618,15 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lvt;
struct lv_list *lvl;
/*
* Build layers for complete vg.
*/
list_iterate(lvh, &vg->lvs) {
lvt = list_item(lvh, struct lv_list)->lv;
if (!_expand_lv(dm, lvt)) {
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & SNAPSHOT)
continue;
if (!_expand_lv(dm, lvl->lv)) {
stack;
return 0;
}
@@ -1700,15 +1666,15 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
{
struct hash_node *hn;
struct dev_layer *dl;
struct list *sh;
struct str_list *strl;
const char *dlid;
struct dev_layer *dep;
hash_iterate(hn, dm->layers) {
dl = hash_get_data(dm->layers, hn);
list_iterate(sh, &dl->pre_suspend) {
dlid = list_item(sh, struct str_list)->str;
list_iterate_items(strl, &dl->pre_suspend) {
dlid = strl->str;
if (!(dep = hash_lookup(dm->layers, dlid))) {
log_debug("_populate_pre_suspend_lists: "
@@ -1723,8 +1689,8 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
}
}
list_iterate(sh, &dl->pre_create) {
dlid = list_item(sh, struct str_list)->str;
list_iterate_items(strl, &dl->pre_create) {
dlid = strl->str;
if (!(dep = hash_lookup(dm->layers, dlid))) {
log_debug("_populate_pre_suspend_lists: "
@@ -1749,6 +1715,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
static int _remove_old_layers(struct dev_manager *dm)
{
int change;
struct dl_list *dll;
struct list *rh, *n;
struct dev_layer *dl;
@@ -1771,10 +1738,8 @@ static int _remove_old_layers(struct dev_manager *dm)
} while (change);
if (!list_empty(&dm->remove_list)) {
list_iterate(rh, &dm->remove_list) {
dl = list_item(rh, struct dl_list)->dl;
log_error("Couldn't deactivate device %s", dl->name);
}
list_iterate_items(dll, &dm->remove_list)
log_error("Couldn't deactivate device %s", dll->dl->name);
return 0;
}
@@ -1961,14 +1926,14 @@ static int _add_lv(struct pool *mem,
static int _add_lvs(struct pool *mem,
struct list *head, struct logical_volume *origin)
{
struct logical_volume *lv;
struct snapshot *s;
struct list *lvh;
struct lv_segment *snap_seg;
struct lv_list *lvl;
list_iterate(lvh, &origin->vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if ((s = find_cow(lv)) && s->origin == origin)
if (!_add_lv(mem, head, lv))
list_iterate_items(lvl, &origin->vg->lvs) {
if (lvl->lv->status & SNAPSHOT)
continue;
if ((snap_seg = find_cow(lvl->lv)) && snap_seg->origin == origin)
if (!_add_lv(mem, head, lvl->lv))
return 0;
}
@@ -1977,13 +1942,11 @@ static int _add_lvs(struct pool *mem,
static void _remove_lv(struct list *head, struct logical_volume *lv)
{
struct list *lvh;
struct lv_list *lvl;
list_iterate(lvh, head) {
lvl = list_item(lvh, struct lv_list);
list_iterate_items(lvl, head) {
if (lvl->lv == lv) {
list_del(lvh);
list_del(&lvl->list);
break;
}
}
@@ -1992,30 +1955,32 @@ static void _remove_lv(struct list *head, struct logical_volume *lv)
static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
{
struct logical_volume *active, *old_origin;
struct snapshot *s;
struct list *sh, *active_head;
struct lv_segment *snap_seg;
struct list *active_head;
struct lv_list *lvl;
active_head = &dm->active_list;
/* Remove any snapshots with given origin */
list_iterate(sh, active_head) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && s->origin == lv) {
list_iterate_items(lvl, active_head) {
active = lvl->lv;
if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) {
_remove_lv(active_head, active);
}
}
_remove_lv(active_head, lv);
if (!(s = find_cow(lv)))
if (!(snap_seg = find_cow(lv)))
return 1;
old_origin = s->origin;
old_origin = snap_seg->origin;
/* Was this the last active snapshot with this origin? */
list_iterate(sh, active_head) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && s->origin == old_origin) {
list_iterate_items(lvl, active_head) {
active = lvl->lv;
if ((snap_seg = find_cow(active)) &&
snap_seg->origin == old_origin) {
return 1;
}
}
@@ -2027,15 +1992,17 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
struct logical_volume *lv)
{
struct logical_volume *suspended;
struct snapshot *s;
struct list *sh, *suspend_head;
struct lv_segment *snap_seg;
struct list *suspend_head;
struct lv_list *lvl;
suspend_head = &dm->suspend_list;
/* Remove from list any snapshots with given origin */
list_iterate(sh, suspend_head) {
suspended = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(suspended)) && s->origin == lv) {
list_iterate_items(lvl, suspend_head) {
suspended = lvl->lv;
if ((snap_seg = find_cow(suspended)) &&
snap_seg->origin == lv) {
_remove_lv(suspend_head, suspended);
}
}
@@ -2048,13 +2015,13 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
static int _targets_present(struct dev_manager *dm, struct list *lvs)
{
struct logical_volume *lv;
struct list *lvh, *segh;
struct lv_list *lvl;
struct segment_type *segtype;
struct lv_segment *seg;
int snapshots = 0, mirrors = 0;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
list_iterate_items(lvl, lvs) {
lv = lvl->lv;
if (!snapshots)
if (lv_is_cow(lv) || lv_is_origin(lv))
@@ -2065,8 +2032,7 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs)
mirrors = 1;
if (lv->status & VIRTUAL) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
list_iterate_items(seg, &lv->segments) {
if (seg->segtype->ops->target_present &&
!seg->segtype->ops->target_present()) {
log_error("Can't expand LV: %s target "
@@ -2115,14 +2081,14 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs)
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
{
char *dlid;
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
struct dev_layer *dl;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & SNAPSHOT)
continue;
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) {
stack;
return 0;
}
@@ -2131,16 +2097,16 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
pool_free(dm->mem, dlid);
if (dl) {
log_debug("Found active lv %s%s", lv->name,
log_debug("Found active lv %s%s", lvl->lv->name,
dl->info.suspended ? " (suspended)" : "");
if (!_add_lv(dm->mem, &dm->active_list, lv)) {
if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) {
stack;
return 0;
}
if (dl->info.suspended) {
if (!_add_lv(dm->mem, &dm->suspend_list, lv)) {
if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) {
stack;
return 0;
}
@@ -2227,8 +2193,8 @@ int dev_manager_lv_mknodes(const struct logical_volume *lv)
{
char *name;
if (!(name = _build_name(lv->vg->cmd->mem, lv->vg->name,
lv->name, NULL))) {
if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
lv->name, NULL))) {
stack;
return 0;
}

View File

@@ -36,7 +36,7 @@ void dev_manager_exit(void);
* unsuspended until the snapshot is also created.)
*/
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
int mknodes, struct dm_info *info);
int mknodes, int with_open_count, struct dm_info *info);
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent);
int dev_manager_mirror_percent(struct dev_manager *dm,

View File

@@ -46,7 +46,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
return 1;
log_very_verbose("Creating directory %s", vg_path);
if (mkdir(vg_path, 0555)) {
if (mkdir(vg_path, 0777)) {
log_sys_error("mkdir", vg_path);
return 0;
}
@@ -65,10 +65,10 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
return 0;
}
log_very_verbose("Removing directory %s", vg_path);
if (is_empty_dir(vg_path))
if (dir_exists(vg_path) && is_empty_dir(vg_path)) {
log_very_verbose("Removing directory %s", vg_path);
rmdir(vg_path);
}
return 1;
}
@@ -180,7 +180,7 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
}
#ifdef HAVE_SELINUX
if (!set_selinux_context(lv_path)) {
if (!set_selinux_context(lv_path, S_IFLNK)) {
stack;
return 0;
}
@@ -202,9 +202,9 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
}
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
if (errno != ENOENT)
log_error("%s not symbolic link - not removing",
lv_path);
if (errno == ENOENT)
return 1;
log_error("%s not symbolic link - not removing", lv_path);
return 0;
}

View File

@@ -19,7 +19,11 @@
struct dev_manager;
struct lv_segment;
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos,
int start_area, int areas);
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos,
int start_area, int areas);
int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf,
size_t bufsize, const char *desc);
#endif

59
lib/cache/lvmcache.c vendored
View File

@@ -104,10 +104,31 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
const struct format_type *fmt_from_vgname(const char *vgname)
{
struct lvmcache_vginfo *vginfo;
struct lvmcache_info *info;
struct label *label;
struct list *devh, *tmp;
struct list devs;
struct device_list *devl;
if (!(vginfo = vginfo_from_vgname(vgname)))
return NULL;
/* This function is normally called before reading metadata so
* we check cached labels here. Unfortunately vginfo is volatile. */
list_init(&devs);
list_iterate_items(info, &vginfo->infos) {
devl = dbg_malloc(sizeof(*devl));
devl->dev = info->dev;
list_add(&devs, &devl->list);
}
list_iterate_safe(devh, tmp, &devs) {
devl = list_item(devh, struct device_list);
label_read(devl->dev, &label);
list_del(&devl->list);
dbg_free(devl);
}
return vginfo->fmt;
}
@@ -166,7 +187,6 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
struct label *label;
struct dev_iter *iter;
struct device *dev;
struct list *fmth;
struct format_type *fmt;
static int _scanning_in_progress = 0;
@@ -188,7 +208,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
goto out;
}
if (!(iter = dev_iter_create(cmd->filter))) {
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
log_error("dev_iter creation failed");
goto out;
}
@@ -201,8 +221,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
_has_scanned = 1;
/* Perform any format-specific scanning e.g. text files */
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
list_iterate_items(fmt, &cmd->formats) {
if (fmt->ops->scan && !fmt->ops->scan(fmt))
goto out;
}
@@ -266,7 +285,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
if (memlock())
return NULL;
lvmcache_label_scan(cmd, 1);
lvmcache_label_scan(cmd, 2);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
@@ -403,23 +422,24 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
/* FIXME Check consistency of list! */
vginfo->fmt = info->fmt;
log_debug("lvmcache: %s now %s%s", dev_name(info->dev),
*vgname ? "in VG " : "orphaned", vgname);
return 1;
}
int lvmcache_update_vg(struct volume_group *vg)
{
struct list *pvh;
struct physical_volume *pv;
struct pv_list *pvl;
struct lvmcache_info *info;
char pvid_s[ID_LEN + 1];
int vgid_updated = 0;
pvid_s[sizeof(pvid_s) - 1] = '\0';
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
/* FIXME Could pv->dev->pvid ever be different? */
list_iterate_items(pvl, &vg->pvs) {
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
/* FIXME Could pvl->pv->dev->pvid ever be different? */
if ((info = info_from_pvid(pvid_s))) {
lvmcache_update_vgname(info, vg->name);
if (!vgid_updated) {
@@ -475,17 +495,32 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
pvid, dev_name(dev),
dev_name(existing->dev));
return NULL;
} else if (is_dm_major(MAJOR(existing->dev->dev)) &&
!is_dm_major(MAJOR(dev->dev))) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s - using dm %s",
pvid, dev_name(dev),
dev_name(existing->dev));
return NULL;
} else if (MAJOR(existing->dev->dev) != md_major() &&
MAJOR(dev->dev) == md_major())
log_very_verbose("Duplicate PV %s on %s - "
"using md %s", pvid,
dev_name(existing->dev),
dev_name(dev));
else if (!is_dm_major(MAJOR(existing->dev->dev)) &&
is_dm_major(MAJOR(dev->dev)))
log_very_verbose("Duplicate PV %s on %s - "
"using dm %s", pvid,
dev_name(existing->dev),
dev_name(dev));
else
log_error("Found duplicate PV %s: using %s not "
"%s", pvid, dev_name(dev),
dev_name(existing->dev));
}
/* Switch over to new preferred device */
existing->dev = dev;
info = existing;
/* Has labeller changed? */
if (info->label->labeller != labeller) {
@@ -551,6 +586,8 @@ static void _lvmcache_destroy_lockname(int present)
void lvmcache_destroy(void)
{
log_verbose("Wiping internal VG cache");
_has_scanned = 0;
if (_vgid_hash) {

View File

@@ -36,9 +36,10 @@ struct volume_group;
struct lvmcache_vginfo {
struct list list; /* Join these vginfos together */
struct list infos; /* List head for lvmcache_infos */
const struct format_type *fmt;
char *vgname; /* "" == orphan */
char vgid[ID_LEN + 1];
const struct format_type *fmt;
char _padding[7];
};
struct lvmcache_info {
@@ -56,7 +57,8 @@ struct lvmcache_info {
int lvmcache_init(void);
void lvmcache_destroy(void);
/* Set full_scan to 1 to reread every filtered device label */
/* Set full_scan to 1 to reread every filtered device label or
* 2 to rescan /dev for new devices */
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
/* Add/delete a device */

View File

@@ -33,8 +33,10 @@
#include "display.h"
#include "memlock.h"
#include "str_list.h"
#include "segtypes.h"
#include "segtype.h"
#include "lvmcache.h"
#include "dev-cache.h"
#include "archiver.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
@@ -181,6 +183,12 @@ static int _process_config(struct cmd_context *cmd)
return 0;
}
if (*cmd->proc_dir && !dir_exists(cmd->proc_dir)) {
log_error("Warning: proc dir %s not found - some checks will be bypassed",
cmd->proc_dir);
cmd->proc_dir[0] = '\0';
}
/* activation? */
cmd->default_settings.activation = find_config_int(cmd->cft->root,
"global/activation",
@@ -487,6 +495,24 @@ static int _init_dev_cache(struct cmd_context *cmd)
}
}
if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
return 1;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"devices/loopfiles");
return 0;
}
if (!dev_cache_add_loopfile(cv->v.str)) {
log_error("Failed to add loopfile %s to internal "
"device cache", cv->v.str);
return 0;
}
}
return 1;
}
@@ -519,8 +545,8 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
/* regex filter. Optional. */
if (!(cn = find_config_node(cmd->cft->root, "devices/filter")))
log_debug("devices/filter not found in config file: no regex "
"filter installed");
log_very_verbose("devices/filter not found in config file: "
"no regex filter installed");
else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
log_error("Failed to create regex device filter");
@@ -537,6 +563,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
/* md component filter. Optional, non-critical. */
if (find_config_bool(cmd->cft->root, "devices/md_component_detection",
DEFAULT_MD_COMPONENT_DETECTION)) {
init_md_filtering(1);
if ((filters[nr_filt] = md_filter_create()))
nr_filt++;
}
@@ -595,7 +622,6 @@ static int _init_formats(struct cmd_context *cmd)
const char *format;
struct format_type *fmt;
struct list *fmth;
#ifdef HAVE_LIBDL
const struct config_node *cn;
@@ -662,8 +688,7 @@ static int _init_formats(struct cmd_context *cmd)
format = find_config_str(cmd->cft->root, "global/format",
DEFAULT_FORMAT);
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
list_iterate_items(fmt, &cmd->formats) {
if (!strcasecmp(fmt->name, format) ||
(fmt->alias && !strcasecmp(fmt->alias, format))) {
cmd->default_settings.fmt = fmt;
@@ -788,6 +813,69 @@ static int _init_hostname(struct cmd_context *cmd)
return 1;
}
static int _init_backup(struct cmd_context *cmd)
{
uint32_t days, min;
char default_dir[PATH_MAX];
const char *dir;
if (!cmd->sys_dir) {
log_warn("WARNING: Metadata changes will NOT be backed up");
backup_init(cmd, "");
archive_init(cmd, "", 0, 0);
return 1;
}
/* set up archiving */
cmd->default_settings.archive =
find_config_bool(cmd->cft->root, "backup/archive",
DEFAULT_ARCHIVE_ENABLED);
days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
DEFAULT_ARCHIVE_DAYS);
min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
DEFAULT_ARCHIVE_NUMBER);
if (lvm_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'.",
cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/archive_dir",
default_dir);
if (!archive_init(cmd, dir, days, min)) {
log_debug("backup_init failed.");
return 0;
}
/* set up the backup */
cmd->default_settings.backup =
find_config_bool(cmd->cft->root, "backup/backup",
DEFAULT_BACKUP_ENABLED);
if (lvm_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'.",
cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
if (!backup_init(cmd, dir)) {
log_debug("backup_init failed.");
return 0;
}
return 1;
}
/* Entry point */
struct cmd_context *create_toolcontext(struct arg *the_args)
{
@@ -824,10 +912,15 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
goto error;
/* Create system directory if it doesn't already exist */
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
if (*cmd->sys_dir && !create_dir(cmd->sys_dir)) {
log_error("Failed to create LVM2 system dir for metadata backups, config "
"files and internal cache.");
log_error("Set environment variable LVM_SYSTEM_DIR to alternative location "
"or empty string.");
goto error;
}
if (!(cmd->libmem = pool_create(4 * 1024))) {
if (!(cmd->libmem = pool_create("library", 4 * 1024))) {
log_error("Library memory pool creation failed");
return 0;
}
@@ -858,7 +951,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!_init_filters(cmd))
goto error;
if (!(cmd->mem = pool_create(4 * 1024))) {
if (!(cmd->mem = pool_create("command", 4 * 1024))) {
log_error("Command memory pool creation failed");
return 0;
}
@@ -871,6 +964,9 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!_init_segtypes(cmd))
goto error;
if (!_init_backup(cmd))
goto error;
cmd->current_settings = cmd->default_settings;
cmd->config_valid = 1;
@@ -981,6 +1077,8 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
archive_exit(cmd);
backup_exit(cmd);
activation_exit();
lvmcache_destroy();
label_exit();

View File

@@ -32,20 +32,20 @@ struct config_info {
int syslog;
int activation;
int suffix;
uint64_t unit_factor;
char unit_type;
const char *msg_prefix;
int cmd_name; /* Show command name? */
int archive; /* should we archive ? */
int backup; /* should we backup ? */
const char *msg_prefix;
struct format_type *fmt;
uint64_t unit_factor;
int cmd_name; /* Show command name? */
mode_t umask;
char unit_type;
char _padding[1];
};
struct config_tree;
struct archive_params;
struct backup_params;
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
@@ -75,6 +75,9 @@ struct cmd_context {
struct config_info default_settings;
struct config_info current_settings;
struct archive_params *archive_params;
struct backup_params *backup_params;
/* List of defined tags */
struct list tags;
int hosttags;

View File

@@ -99,7 +99,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
struct config_tree *create_config_tree(const char *filename)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
struct pool *mem = pool_create("config", 10 * 1024);
if (!mem) {
stack;
@@ -235,7 +235,7 @@ int read_config_file(struct config_tree *cft)
return 1;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
stack;
return 0;
}

View File

@@ -91,19 +91,22 @@
#define DEFAULT_REP_HEADINGS 1
#define DEFAULT_REP_SEPARATOR " "
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent"
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent"
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,lv_uuid"
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
#define DEFAULT_LVS_SORT "vg_name,lv_name"
#define DEFAULT_VGS_SORT "vg_name"
#define DEFAULT_PVS_SORT "pv_name"
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
#define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -23,12 +23,21 @@ bitset_t bitset_create(struct pool *mem, unsigned num_bits)
{
unsigned n = (num_bits / BITS_PER_INT) + 2;
size_t size = sizeof(int) * n;
unsigned *bs = pool_zalloc(mem, size);
bitset_t bs;
if (mem)
bs = pool_zalloc(mem, size);
else
bs = dbg_malloc(size);
if (!bs)
return NULL;
*bs = num_bits;
if (!mem)
bit_clear_all(bs);
return bs;
}

View File

@@ -18,17 +18,30 @@
#include <assert.h>
/*
* A list consists of a list head plus elements.
* Each element has 'next' and 'previous' pointers.
* The list head's pointers point to the first and the last element.
*/
struct list {
struct list *n, *p;
};
/*
* Initialise a list before use.
* The list head's next and previous pointers point back to itself.
*/
#define LIST_INIT(name) struct list name = { &(name), &(name) }
static inline void list_init(struct list *head)
{
head->n = head->p = head;
}
/*
* Insert an element before 'head'.
* If 'head' is the list head, this adds an element to the end of the list.
*/
static inline void list_add(struct list *head, struct list *elem)
{
assert(head->n);
@@ -40,6 +53,10 @@ static inline void list_add(struct list *head, struct list *elem)
head->p = elem;
}
/*
* Insert an element after 'head'.
* If 'head' is the list head, this adds an element to the front of the list.
*/
static inline void list_add_h(struct list *head, struct list *elem)
{
assert(head->n);
@@ -51,53 +68,162 @@ static inline void list_add_h(struct list *head, struct list *elem)
head->n = elem;
}
/*
* Delete an element from its list.
* Note that this doesn't change the element itself - it may still be safe
* to follow its pointers.
*/
static inline void list_del(struct list *elem)
{
elem->n->p = elem->p;
elem->p->n = elem->n;
}
/*
* Is the list empty?
*/
static inline int list_empty(struct list *head)
{
return head->n == head;
}
/*
* Is this the first element of the list?
*/
static inline int list_start(struct list *head, struct list *elem)
{
return elem->p == head;
}
/*
* Is this the last element of the list?
*/
static inline int list_end(struct list *head, struct list *elem)
{
return elem->n == head;
}
/*
* Return first element of the list or NULL if empty
*/
static inline struct list *list_first(struct list *head)
{
return (list_empty(head) ? NULL : head->n);
}
/*
* Return last element of the list or NULL if empty
*/
static inline struct list *list_last(struct list *head)
{
return (list_empty(head) ? NULL : head->p);
}
/*
* Return the previous element of the list, or NULL if we've reached the start.
*/
static inline struct list *list_prev(struct list *head, struct list *elem)
{
return (list_start(head, elem) ? NULL : elem->p);
}
/*
* Return the next element of the list, or NULL if we've reached the end.
*/
static inline struct list *list_next(struct list *head, struct list *elem)
{
return (list_end(head, elem) ? NULL : elem->n);
}
#define list_item(v, t) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
/*
* Given the address v of an instance of 'struct list' called 'head'
* contained in a structure of type t, return the containing structure.
*/
#define list_struct_base(v, t, head) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head))
#define list_struct_base(v, t, h) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
/*
* Given the address v of an instance of 'struct list list' contained in
* a structure of type t, return the containing structure.
*/
#define list_item(v, t) list_struct_base((v), t, list)
/* Given a known element in a known structure, locate another */
/*
* Given the address v of one known element e in a known structure of type t,
* return another element f.
*/
#define struct_field(v, t, e, f) \
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
/* Given a known element in a known structure, locate the list head */
/*
* Given the address v of a known element e in a known structure of type t,
* return the list head 'list'
*/
#define list_head(v, t, e) struct_field(v, t, e, list)
/*
* Set v to each element of a list in turn.
*/
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
/*
* Set v to each element in a list in turn, starting from the element
* in front of 'start'.
* You can use this to 'unwind' a list_iterate and back out actions on
* already-processed elements.
* If 'start' is 'head' it walks the list backwards.
*/
#define list_uniterate(v, head, start) \
for (v = (start)->p; v != head; v = v->p)
/*
* A safe way to walk a list and delete and free some elements along
* the way.
* t must be defined as a temporary variable of the same type as v.
*/
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
#define list_iterate_items(v, head) \
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
v = list_item(v->list.n, typeof(*v)))
/*
* Walk a list, setting 'v' in turn to the containing structure of each item.
* The containing structure should be the same type as 'v'.
* The 'struct list' variable within the containing structure is 'field'.
*/
#define list_iterate_items_gen(v, head, field) \
for (v = list_struct_base((head)->n, typeof(*v), field); \
&v->field != (head); \
v = list_struct_base(v->field.n, typeof(*v), field))
/*
* Walk a list, setting 'v' in turn to the containing structure of each item.
* The containing structure should be the same type as 'v'.
* The list should be 'struct list list' within the containing structure.
*/
#define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list)
/*
* Walk a list backwards, setting 'v' in turn to the containing structure
* of each item.
* The containing structure should be the same type as 'v'.
* The 'struct list' variable within the containing structure is 'field'.
*/
#define list_iterate_back_items_gen(v, head, field) \
for (v = list_struct_base((head)->p, typeof(*v), field); \
&v->field != (head); \
v = list_struct_base(v->field.p, typeof(*v), field))
/*
* Walk a list backwards, setting 'v' in turn to the containing structure
* of each item.
* The containing structure should be the same type as 'v'.
* The list should be 'struct list list' within the containing structure.
*/
#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list)
/*
* Return the number of elements in a list by walking it.
*/
static inline unsigned int list_size(const struct list *head)
{
unsigned int s = 0;

View File

@@ -22,7 +22,7 @@
#include <inttypes.h>
/* Define some portable printing types */
#define PRIsize_t "Zu"
#define PRIsize_t "zu"
struct str_list {
struct list list;

View File

@@ -21,6 +21,7 @@
#include "lvm-types.h"
#include "btree.h"
#include "filter.h"
#include "filter-persistent.h"
#include <unistd.h>
#include <sys/param.h>
@@ -43,45 +44,67 @@ static struct {
int has_scanned;
struct list dirs;
struct list files;
} _cache;
#define _alloc(x) pool_alloc(_cache.mem, (x))
#define _alloc(x) pool_zalloc(_cache.mem, (x))
#define _free(x) pool_free(_cache.mem, (x))
#define _strdup(x) pool_strdup(_cache.mem, (x))
static int _insert(const char *path, int rec);
struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias)
struct str_list *alias, int use_malloc)
{
int allocate = !dev;
if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
log_error("struct device allocation failed");
return NULL;
}
if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
log_error("struct str_list allocation failed");
dbg_free(dev);
return NULL;
}
if (!(alias->str = dbg_strdup(filename))) {
log_error("filename strdup failed");
if (allocate) {
dbg_free(dev);
dbg_free(alias);
if (allocate) {
if (use_malloc) {
if (!(dev = dbg_malloc(sizeof(*dev)))) {
log_error("struct device allocation failed");
return NULL;
}
if (!(alias = dbg_malloc(sizeof(*alias)))) {
log_error("struct str_list allocation failed");
dbg_free(dev);
return NULL;
}
if (!(alias->str = dbg_strdup(filename))) {
log_error("filename strdup failed");
dbg_free(dev);
dbg_free(alias);
return NULL;
}
dev->flags = DEV_ALLOCED;
} else {
if (!(dev = _alloc(sizeof(*dev)))) {
log_error("struct device allocation failed");
return NULL;
}
if (!(alias = _alloc(sizeof(*alias)))) {
log_error("struct str_list allocation failed");
_free(dev);
return NULL;
}
if (!(alias->str = _strdup(filename))) {
log_error("filename strdup failed");
return NULL;
}
}
} else if (!(alias->str = dbg_strdup(filename))) {
log_error("filename strdup failed");
return NULL;
}
dev->flags = DEV_REGULAR;
if (allocate)
dev->flags |= DEV_ALLOCED;
dev->flags |= DEV_REGULAR;
list_init(&dev->aliases);
list_add(&dev->aliases, &alias->list);
dev->end = UINT64_C(0);
dev->dev = 0;
dev->fd = -1;
dev->open_count = 0;
dev->block_size = -1;
memset(dev->pvid, 0, sizeof(dev->pvid));
list_init(&dev->open_list);
@@ -101,6 +124,7 @@ static struct device *_dev_create(dev_t d)
dev->dev = d;
dev->fd = -1;
dev->open_count = 0;
dev->block_size = -1;
dev->end = UINT64_C(0);
memset(dev->pvid, 0, sizeof(dev->pvid));
list_init(&dev->open_list);
@@ -172,7 +196,7 @@ static int _compare_paths(const char *path0, const char *path1)
static int _add_alias(struct device *dev, const char *path)
{
struct str_list *sl = _alloc(sizeof(*sl));
struct list *ah;
struct str_list *strl;
const char *oldpath;
int prefer_old = 1;
@@ -182,9 +206,9 @@ static int _add_alias(struct device *dev, const char *path)
}
/* Is name already there? */
list_iterate(ah, &dev->aliases) {
if (!strcmp(list_item(ah, struct str_list)->str, path)) {
stack;
list_iterate_items(strl, &dev->aliases) {
if (!strcmp(strl->str, path)) {
log_debug("%s: Already in device cache", path);
return 1;
}
}
@@ -218,12 +242,27 @@ static int _add_alias(struct device *dev, const char *path)
static int _insert_dev(const char *path, dev_t d)
{
struct device *dev;
static dev_t loopfile_count = 0;
int loopfile = 0;
/* Generate pretend device numbers for loopfiles */
if (!d) {
if (hash_lookup(_cache.names, path))
return 1;
d = ++loopfile_count;
loopfile = 1;
}
/* is this device already registered ? */
if (!(dev = (struct device *) btree_lookup(_cache.devices,
(uint32_t) d))) {
/* create new device */
if (!(dev = _dev_create(d))) {
if (loopfile) {
if (!(dev = dev_create_file(path, NULL, NULL, 0))) {
stack;
return 0;
}
} else if (!(dev = _dev_create(d))) {
stack;
return 0;
}
@@ -235,7 +274,7 @@ static int _insert_dev(const char *path, dev_t d)
}
}
if (!_add_alias(dev, path)) {
if (!loopfile && !_add_alias(dev, path)) {
log_err("Couldn't add alias to dev cache.");
return 0;
}
@@ -311,6 +350,28 @@ static int _insert_dir(const char *dir)
return r;
}
static int _insert_file(const char *path)
{
struct stat info;
if (stat(path, &info) < 0) {
log_sys_very_verbose("stat", path);
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_debug("%s: Not a regular file", path);
return 0;
}
if (!_insert_dev(path, 0)) {
stack;
return 0;
}
return 1;
}
static int _insert(const char *path, int rec)
{
struct stat info;
@@ -353,19 +414,21 @@ static int _insert(const char *path, int rec)
return r;
}
static void _full_scan(void)
static void _full_scan(int dev_scan)
{
struct list *dh;
struct dir_list *dl;
if (_cache.has_scanned)
if (_cache.has_scanned && !dev_scan)
return;
list_iterate(dh, &_cache.dirs) {
struct dir_list *dl = list_item(dh, struct dir_list);
list_iterate_items(dl, &_cache.dirs)
_insert_dir(dl->dir);
};
list_iterate_items(dl, &_cache.files)
_insert_file(dl->dir);
_cache.has_scanned = 1;
init_full_scan_done(1);
}
int dev_cache_has_scanned(void)
@@ -377,17 +440,16 @@ void dev_cache_scan(int do_scan)
{
if (!do_scan)
_cache.has_scanned = 1;
else {
_cache.has_scanned = 0;
_full_scan();
}
else
_full_scan(1);
}
int dev_cache_init(void)
{
_cache.names = NULL;
_cache.has_scanned = 0;
if (!(_cache.mem = pool_create(10 * 1024))) {
if (!(_cache.mem = pool_create("dev_cache", 10 * 1024))) {
stack;
return 0;
}
@@ -405,6 +467,7 @@ int dev_cache_init(void)
}
list_init(&_cache.dirs);
list_init(&_cache.files);
return 1;
@@ -442,6 +505,7 @@ void dev_cache_exit(void)
_cache.devices = NULL;
_cache.has_scanned = 0;
list_init(&_cache.dirs);
list_init(&_cache.files);
}
int dev_cache_add_dir(const char *path)
@@ -470,6 +534,32 @@ int dev_cache_add_dir(const char *path)
return 1;
}
int dev_cache_add_loopfile(const char *path)
{
struct dir_list *dl;
struct stat st;
if (stat(path, &st)) {
log_error("Ignoring %s: %s", path, strerror(errno));
/* But don't fail */
return 1;
}
if (!S_ISREG(st.st_mode)) {
log_error("Ignoring %s: Not a regular file", path);
return 1;
}
if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
log_error("dir_list allocation failed for file");
return 0;
}
strcpy(dl->dir, path);
list_add(&_cache.files, &dl->list);
return 1;
}
/* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
@@ -480,6 +570,9 @@ const char *dev_name_confirmed(struct device *dev, int quiet)
const char *name;
int r;
if ((dev->flags & DEV_REGULAR))
return dev_name(dev);
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
@@ -524,6 +617,9 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
struct stat buf;
struct device *d = (struct device *) hash_lookup(_cache.names, name);
if (d && (d->flags & DEV_REGULAR))
return d;
/* If the entry's wrong, remove it */
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
hash_remove(_cache.names, name);
@@ -533,12 +629,17 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
if (!d) {
_insert(name, 0);
d = (struct device *) hash_lookup(_cache.names, name);
if (!d) {
_full_scan(0);
d = (struct device *) hash_lookup(_cache.names, name);
}
}
return (d && (!f || f->passes_filter(f, d))) ? d : NULL;
return (d && (!f || (d->flags & DEV_REGULAR) ||
f->passes_filter(f, d))) ? d : NULL;
}
struct dev_iter *dev_iter_create(struct dev_filter *f)
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
{
struct dev_iter *di = dbg_malloc(sizeof(*di));
@@ -547,7 +648,14 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
return NULL;
}
_full_scan();
if (dev_scan) {
/* Flag gets reset between each command */
if (!full_scan_done())
persistent_filter_wipe(f); /* Calls _full_scan(1) */
} else
_full_scan(0);
di->current = btree_first(_cache.devices);
di->filter = f;
@@ -570,7 +678,7 @@ struct device *dev_iter_get(struct dev_iter *iter)
{
while (iter->current) {
struct device *d = _iter_next(iter);
if (!iter->filter ||
if (!iter->filter || (d->flags & DEV_REGULAR) ||
iter->filter->passes_filter(iter->filter, d))
return d;
}

View File

@@ -39,13 +39,14 @@ void dev_cache_scan(int do_scan);
int dev_cache_has_scanned(void);
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);
/*
* Object for iterating through the cache.
*/
struct dev_iter;
struct dev_iter *dev_iter_create(struct dev_filter *f);
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
void dev_iter_destroy(struct dev_iter *iter);
struct device *dev_iter_get(struct dev_iter *iter);

View File

@@ -81,7 +81,9 @@ static int _io(struct device_area *where, void *buffer, int should_write)
}
if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) {
log_sys_error("lseek", dev_name(where->dev));
log_error("%s: lseek %" PRIu64 " failed: %s",
dev_name(where->dev), (uint64_t) where->start,
strerror(errno));
return 0;
}
@@ -92,6 +94,14 @@ static int _io(struct device_area *where, void *buffer, int should_write)
read(fd, buffer, (size_t) where->size - total);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n < 0)
log_error("%s: %s failed after %" PRIu64 " of %" PRIu64
" at %" PRIu64 ": %s", dev_name(where->dev),
should_write ? "write" : "read",
(uint64_t) total,
(uint64_t) where->size,
(uint64_t) where->start, strerror(errno));
if (n <= 0)
break;
@@ -114,14 +124,18 @@ static int _io(struct device_area *where, void *buffer, int should_write)
*/
static int _get_block_size(struct device *dev, unsigned int *size)
{
int s;
const char *name = dev_name(dev);
if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) {
log_sys_error("ioctl BLKBSZGET", dev_name(dev));
return 0;
if ((dev->block_size == -1)) {
if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) {
log_sys_error("ioctl BLKBSZGET", name);
return 0;
}
log_debug("%s: block size is %u bytes", name, dev->block_size);
}
*size = (unsigned int) s;
*size = (unsigned int) dev->block_size;
return 1;
}
@@ -208,16 +222,29 @@ static int _aligned_io(struct device_area *where, void *buffer,
return 1;
}
/*-----------------------------------------------------------------
* Public functions
*---------------------------------------------------------------*/
static int _dev_get_size_file(const struct device *dev, uint64_t *size)
{
const char *name = dev_name(dev);
struct stat info;
int dev_get_size(struct device *dev, uint64_t *size)
if (stat(name, &info)) {
log_sys_error("stat", name);
return 0;
}
*size = info.st_size;
*size >>= SECTOR_SHIFT; /* Convert to sectors */
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
return 1;
}
static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
{
int fd;
const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name);
if ((fd = open(name, O_RDONLY)) < 0) {
log_sys_error("open", name);
return 0;
@@ -225,22 +252,39 @@ int dev_get_size(struct device *dev, uint64_t *size)
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
log_sys_error("ioctl BLKGETSIZE64", name);
close(fd);
if (close(fd))
log_sys_error("close", name);
return 0;
}
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
close(fd);
if (close(fd))
log_sys_error("close", name);
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
return 1;
}
/*-----------------------------------------------------------------
* Public functions
*---------------------------------------------------------------*/
int dev_get_size(const struct device *dev, uint64_t *size)
{
if ((dev->flags & DEV_REGULAR))
return _dev_get_size_file(dev, size);
else
return _dev_get_size_dev(dev, size);
}
/* FIXME Unused
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
int fd;
int s;
const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name);
if ((fd = open(name, O_RDONLY)) < 0) {
log_sys_error("open", name);
return 0;
@@ -254,8 +298,12 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
close(fd);
*size = (uint32_t) s;
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
return 1;
}
*/
void dev_flush(struct device *dev)
{
@@ -274,8 +322,20 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
const char *name;
if (dev->fd >= 0) {
dev->open_count++;
return 1;
if ((dev->flags & DEV_OPENED_RW) ||
((flags & O_ACCMODE) != O_RDWR)) {
dev->open_count++;
return 1;
}
if (dev->open_count) {
/* FIXME Ensure we never get here */
log_debug("WARNING: %s already opened read-only",
dev_name(dev));
dev->open_count++;
}
dev_close_immediate(dev);
}
if (memlock())
@@ -296,23 +356,57 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
}
#ifdef O_DIRECT_SUPPORT
if (direct)
flags |= O_DIRECT;
if (direct) {
if (!(dev->flags & DEV_O_DIRECT_TESTED))
dev->flags |= DEV_O_DIRECT;
if ((dev->flags & DEV_O_DIRECT))
flags |= O_DIRECT;
}
#endif
#ifdef O_NOATIME
/* Don't update atime on device inodes */
if (!(dev->flags & DEV_REGULAR))
flags |= O_NOATIME;
#endif
if ((dev->fd = open(name, flags, 0777)) < 0) {
log_sys_error("open", name);
#ifdef O_DIRECT_SUPPORT
if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) {
flags &= ~O_DIRECT;
if ((dev->fd = open(name, flags, 0777)) >= 0) {
dev->flags &= ~DEV_O_DIRECT;
log_debug("%s: Not using O_DIRECT", name);
goto opened;
}
}
#endif
if (quiet)
log_sys_debug("open", name);
else
log_sys_error("open", name);
return 0;
}
dev->open_count = 1;
#ifdef O_DIRECT_SUPPORT
opened:
if (direct)
dev->flags |= DEV_O_DIRECT_TESTED;
#endif
dev->open_count++;
dev->flags &= ~DEV_ACCESSED_W;
if ((flags & O_ACCMODE) == O_RDWR)
dev->flags |= DEV_OPENED_RW;
else
dev->flags &= ~DEV_OPENED_RW;
if (!(dev->flags & DEV_REGULAR) &&
((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) {
log_error("%s: fstat failed: Has device name changed?", name);
dev_close(dev);
dev->fd = -1;
dev_close_immediate(dev);
dev->open_count = 0;
return 0;
}
@@ -321,12 +415,14 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
dev_flush(dev);
#endif
if ((flags & O_CREAT) && !(flags & O_TRUNC)) {
if ((flags & O_CREAT) && !(flags & O_TRUNC))
dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
}
list_add(&_open_devices, &dev->open_list);
log_debug("Opened %s", dev_name(dev));
log_debug("Opened %s %s%s", dev_name(dev),
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
return 1;
}
@@ -354,6 +450,7 @@ static void _close(struct device *dev)
if (close(dev->fd))
log_sys_error("close", dev_name(dev));
dev->fd = -1;
dev->block_size = -1;
list_del(&dev->open_list);
log_debug("Closed %s", dev_name(dev));
@@ -379,8 +476,11 @@ static int _dev_close(struct device *dev, int immediate)
dev_flush(dev);
#endif
if (dev->open_count > 0)
dev->open_count--;
/* FIXME lookup device in cache to get vgname and see if it's locked? */
if (--dev->open_count < 1 && (immediate || !vgs_locked()))
if (immediate || (dev->open_count < 1 && !vgs_locked()))
_close(dev);
return 1;
@@ -412,8 +512,10 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
{
struct device_area where;
if (!dev->open_count)
if (!dev->open_count) {
stack;
return 0;
}
where.dev = dev;
where.start = offset;
@@ -431,8 +533,10 @@ int dev_append(struct device *dev, size_t len, void *buffer)
{
int r;
if (!dev->open_count)
if (!dev->open_count) {
stack;
return 0;
}
r = dev_write(dev, dev->end, len, buffer);
dev->end += (uint64_t) len;
@@ -447,8 +551,10 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
{
struct device_area where;
if (!dev->open_count)
if (!dev->open_count) {
stack;
return 0;
}
where.dev = dev;
where.start = offset;
@@ -495,6 +601,5 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len)
if (!dev_close(dev))
stack;
/* FIXME: Always display error */
return (len == 0);
}

69
lib/device/dev-md.c Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2004 Luca Berra
* 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 Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "metadata.h"
#include "xlate.h"
/* 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)
/*
* Returns -1 on error
*/
int dev_is_md(struct device *dev, uint64_t *sb)
{
int ret = 0;
#ifdef linux
uint64_t size, sb_offset;
uint32_t md_magic;
if (!dev_get_size(dev, &size)) {
stack;
return -1;
}
if (size < MD_RESERVED_SECTORS * 2)
return 0;
if (!dev_open(dev)) {
stack;
return -1;
}
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
/* Check if it is an md component device. */
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
(md_magic == xlate32(MD_SB_MAGIC))) {
if (sb)
*sb = sb_offset;
ret = 1;
}
if (!dev_close(dev))
stack;
#endif
return ret;
}

View File

@@ -13,6 +13,93 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "lvm-types.h"
#include "device.h"
#include "metadata.h"
#include "filter.h"
#include "xlate.h"
/* See linux/genhd.h and fs/partitions/msdos */
#define PART_MAGIC 0xAA55
#define PART_MAGIC_OFFSET UINT64_C(0x1FE)
#define PART_OFFSET UINT64_C(0x1BE)
struct partition {
uint8_t boot_ind;
uint8_t head;
uint8_t sector;
uint8_t cyl;
uint8_t sys_ind; /* partition type */
uint8_t end_head;
uint8_t end_sector;
uint8_t end_cyl;
uint32_t start_sect;
uint32_t nr_sects;
} __attribute__((packed));
static int _is_partitionable(struct device *dev)
{
int parts = max_partitions(MAJOR(dev->dev));
if ((parts <= 1) || (MINOR(dev->dev) % parts))
return 0;
return 1;
}
static int _has_partition_table(struct device *dev)
{
int ret = 0;
unsigned p;
uint8_t buf[SECTOR_SIZE];
uint16_t *part_magic;
struct partition *part;
if (!dev_open(dev)) {
stack;
return -1;
}
if (!dev_read(dev, 0, sizeof(buf), &buf)) {
stack;
goto out;
}
/* FIXME Check for other types of partition table too */
/* Check for msdos partition table */
part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET);
if ((*part_magic == xlate16(PART_MAGIC))) {
part = (struct partition *) (buf + PART_OFFSET);
for (p = 0; p < 4; p++, part++) {
/* Table is invalid if boot indicator not 0 or 0x80 */
if ((part->boot_ind & 0x7f)) {
ret = 0;
break;
}
/* Must have at least one non-empty partition */
if (part->nr_sects)
ret = 1;
}
}
out:
if (!dev_close(dev))
stack;
return ret;
}
int is_partitioned_dev(struct device *dev)
{
if (!_is_partitionable(dev))
return 0;
return _has_partition_table(dev);
}
#if 0
#include <sys/stat.h>
#include <sys/mman.h>
@@ -27,24 +114,13 @@
#include <linux/major.h>
#include <linux/genhd.h>
#include "dbg_malloc.h"
#include "log.h"
#include "dev-cache.h"
#include "metadata.h"
#include "device.h"
int _get_partition_type(struct dev_filter *filter, struct device *d);
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
#define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
int is_whole_disk(struct dev_filter *filter, struct device *d)
int is_extended_partition(struct device *d)
{
return (MINOR_PART(dm, d)) ? 0 : 1;
}
int is_extended_partition(struct dev_mgr *dm, struct device *d)
{
return (MINOR_PART(dm, d) > 4) ? 1 : 0;
return (MINOR_PART(d) > 4) ? 1 : 0;
}
struct device *dev_primary(struct dev_mgr *dm, struct device *d)

View File

@@ -22,6 +22,9 @@
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
#define DEV_REGULAR 0x00000002 /* Regular file? */
#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */
#define DEV_OPENED_RW 0x00000008 /* Opened RW */
#define DEV_O_DIRECT 0x00000010 /* Use O_DIRECT */
#define DEV_O_DIRECT_TESTED 0x00000020 /* DEV_O_DIRECT is reliable */
/*
* All devices in LVM will be represented by one of these.
@@ -34,11 +37,13 @@ struct device {
/* private */
int fd;
int open_count;
int block_size;
uint32_t flags;
uint64_t end;
struct list open_list;
char pvid[ID_LEN + 1];
char _padding[7];
};
struct device_list {
@@ -55,13 +60,13 @@ struct device_area {
/*
* All io should use these routines.
*/
int dev_get_size(struct device *dev, uint64_t *size);
int dev_get_size(const struct device *dev, uint64_t *size);
int dev_get_sectsize(struct device *dev, uint32_t *size);
/* Use quiet version if device number could change e.g. when opening LV */
int dev_open(struct device *dev);
int dev_open_quiet(struct device *dev);
int dev_open_flags(struct device *dev, int flags, int append, int quiet);
int dev_open_flags(struct device *dev, int flags, int direct, int quiet);
int dev_close(struct device *dev);
int dev_close_immediate(struct device *dev);
void dev_close_all(void);
@@ -78,7 +83,7 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len);
void dev_flush(struct device *dev);
struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias);
struct str_list *alias, int use_malloc);
static inline const char *dev_name(const struct device *dev)
{
@@ -89,15 +94,14 @@ static inline const char *dev_name(const struct device *dev)
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
/* Does device contain md superblock? If so, where? */
int dev_is_md(struct device *dev, uint64_t *sb);
/* FIXME Check partition type if appropriate */
#define is_lvm_partition(a) 1
/* int is_lvm_partition(const char *name); */
/*
static inline int is_lvm_partition(const char *name)
{
return 1;
}
*/
int is_partitioned_dev(struct device *dev);
#endif

View File

@@ -18,7 +18,7 @@
#include "display.h"
#include "activate.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "segtype.h"
#define SIZE_BUF 128
@@ -258,7 +258,7 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
size,
display_size(cmd, (pv->size -
pv->pe_count * pv->pe_size),
(uint64_t) pv->pe_count * pv->pe_size),
SIZE_SHORT));
} else
@@ -317,7 +317,7 @@ void lvdisplay_colons(struct logical_volume *lv)
{
int inkernel;
struct lvinfo info;
inkernel = lv_info(lv, &info) && info.exists;
inkernel = lv_info(lv, &info, 1) && info.exists;
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
lv->vg->cmd->dev_dir,
@@ -337,10 +337,9 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
struct lvinfo info;
int inkernel, snap_active;
int inkernel, snap_active = 0;
char uuid[64];
struct snapshot *snap = NULL;
struct list *slh, *snaplist;
struct lv_segment *snap_seg = NULL;
float snap_percent; /* fused, fsize; */
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
@@ -348,7 +347,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
inkernel = lv_info(lv, &info) && info.exists;
inkernel = lv_info(lv, &info, 1) && info.exists;
log_print("--- Logical volume ---");
@@ -364,27 +363,30 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
if (lv_is_origin(lv)) {
log_print("LV snapshot status source of");
snaplist = find_snapshots(lv);
list_iterate(slh, snaplist) {
snap = list_item(slh, struct snapshot_list)->snapshot;
snap_active = lv_snapshot_percent(snap->cow,
&snap_percent);
if (!snap_active || snap_percent < 0 ||
snap_percent >= 100) snap_active = 0;
list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
origin_list) {
if (inkernel &&
(snap_active = lv_snapshot_percent(snap_seg->cow,
&snap_percent)))
if (snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
snap_seg->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
}
snap = NULL;
} else if ((snap = find_cow(lv))) {
snap_active = lv_snapshot_percent(lv, &snap_percent);
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
snap_seg = NULL;
} else if ((snap_seg = find_cow(lv))) {
if (inkernel &&
(snap_active = lv_snapshot_percent(snap_seg->cow,
&snap_percent)))
if (snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
snap_seg->origin->name);
}
if (inkernel && info.suspended)
@@ -402,15 +404,24 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
log_print("LV Size %s",
display_size(cmd,
snap ? snap->origin->size : lv->size,
snap_seg ? snap_seg->origin->size : lv->size,
SIZE_SHORT));
log_print("Current LE %u",
snap ? snap->origin->le_count : lv->le_count);
snap_seg ? snap_seg->origin->le_count : lv->le_count);
/********** FIXME allocation
log_print("Allocated LE %u", lv->allocated_le);
**********/
if (snap_seg) {
log_print("COW-table size %s",
display_size(cmd, (uint64_t) lv->size, SIZE_SHORT));
log_print("COW-table LE %u", lv->le_count);
if (snap_active)
log_print("Allocated to snapshot %.2f%% ", snap_percent);
log_print("Snapshot chunk size %s",
display_size(cmd, (uint64_t) snap_seg->chunk_size,
SIZE_SHORT));
}
log_print("Segments %u", list_size(&lv->segments));
@@ -418,31 +429,6 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
***********/
if (snap) {
if (snap_percent == -1)
snap_percent = 100;
log_print("Snapshot chunk size %s",
display_size(cmd, (uint64_t) snap->chunk_size,
SIZE_SHORT));
/*
size = display_size(lv->size, SIZE_SHORT);
sscanf(size, "%f", &fsize);
fused = fsize * snap_percent / 100;
*/
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
snap_percent); /*, fused, size); */
/* dbg_free(size); */
}
/********** FIXME Snapshot
size = ???
log_print("Allocated to COW-table %s", size);
dbg_free(size);
}
******************/
log_print("Allocation %s", get_alloc_string(lv->alloc));
log_print("Read ahead sectors %u", lv->read_ahead);
@@ -463,27 +449,31 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
{
switch (seg->area[s].type) {
switch (seg_type(seg, s)) {
case AREA_PV:
/* FIXME Re-check the conditions for 'Missing' */
log_print("%sPhysical volume\t%s", pre,
seg->area[s].u.pv.pv ?
dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
seg_pv(seg, s) ?
dev_name(seg_dev(seg, s)) :
"Missing");
if (seg->area[s].u.pv.pv)
if (seg_pv(seg, s))
log_print("%sPhysical extents\t%d to %d", pre,
seg->area[s].u.pv.pe,
seg->area[s].u.pv.pe + seg->area_len - 1);
seg_pe(seg, s),
seg_pe(seg, s) + seg->area_len - 1);
break;
case AREA_LV:
log_print("%sLogical volume\t%s", pre,
seg->area[s].u.lv.lv ?
seg->area[s].u.lv.lv->name : "Missing");
seg_lv(seg, s) ?
seg_lv(seg, s)->name : "Missing");
if (seg->area[s].u.lv.lv)
if (seg_lv(seg, s))
log_print("%sLogical extents\t%d to %d", pre,
seg->area[s].u.lv.le,
seg->area[s].u.lv.le + seg->area_len - 1);
seg_le(seg, s),
seg_le(seg, s) + seg->area_len - 1);
break;
case AREA_UNASSIGNED:
log_print("%sUnassigned area", pre);
}
}
@@ -550,7 +540,7 @@ void vgdisplay_full(struct volume_group *vg)
vg->status & SHARED ? "yes" : "no");
}
log_print("MAX LV %u", vg->max_lv);
log_print("Cur LV %u", vg->lv_count);
log_print("Cur LV %u", vg->lv_count + vg->snapshot_count);
log_print("Open LV %u", lvs_in_vg_opened(vg));
/****** FIXME Max LV Size
log_print ( "MAX LV Size %s",
@@ -662,3 +652,22 @@ void vgdisplay_short(struct volume_group *vg)
SIZE_SHORT));
return;
}
void display_formats(struct cmd_context *cmd)
{
struct format_type *fmt;
list_iterate_items(fmt, &cmd->formats) {
log_print("%s", fmt->name);
}
}
void display_segtypes(struct cmd_context *cmd)
{
struct segment_type *segtype;
list_iterate_items(segtype, &cmd->segtypes) {
log_print("%s", segtype->name);
}
}

View File

@@ -45,6 +45,9 @@ void vgdisplay_full(struct volume_group *vg);
void vgdisplay_colons(struct volume_group *vg);
void vgdisplay_short(struct volume_group *vg);
void display_formats(struct cmd_context *cmd);
void display_segtypes(struct cmd_context *cmd);
/*
* Allocation policy display conversion routines.
*/

View File

@@ -16,7 +16,7 @@
#include "pool.h"
#include "list.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "segtype.h"
#include "display.h"
#include "text_export.h"
#include "text_import.h"
@@ -97,5 +97,7 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
segtype->private = NULL;
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
log_very_verbose("Initialised segtype: %s", segtype->name);
return segtype;
}

View File

@@ -28,42 +28,24 @@
static int _ignore_md(struct dev_filter *f, struct device *dev)
{
uint64_t size, sector;
uint32_t md_magic;
if (!dev_get_size(dev, &size)) {
stack;
return 0;
}
if (size < MD_RESERVED_SECTORS * 2)
/*
* We could ignore it since it is obviously too
* small, but that's not our job.
*/
int ret;
if (!md_filtering())
return 1;
ret = dev_is_md(dev, NULL);
if (!dev_open(dev)) {
stack;
if (ret == 1) {
log_debug("%s: Skipping md component device", dev_name(dev));
return 0;
}
sector = MD_NEW_SIZE_SECTORS(size);
/* Check if it is an md component device. */
if (dev_read(dev, sector << SECTOR_SHIFT, sizeof(uint32_t), &md_magic)) {
if (md_magic == MD_SB_MAGIC) {
log_debug("%s: Skipping md component device",
dev_name(dev));
if (!dev_close(dev))
stack;
return 0;
}
if (ret < 0) {
log_debug("%s: Skipping: error in md component detection",
dev_name(dev));
return 0;
}
if (!dev_close(dev))
stack;
return 1;
}

View File

@@ -53,7 +53,9 @@ int persistent_filter_wipe(struct dev_filter *f)
{
struct pfilter *pf = (struct pfilter *) f->private;
log_verbose("Wiping cache of LVM-capable devices");
hash_wipe(pf->devices);
/* Trigger complete device scan */
dev_cache_scan(1);
@@ -202,23 +204,18 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
struct pfilter *pf = (struct pfilter *) f->private;
void *l = hash_lookup(pf->devices, dev_name(dev));
struct str_list *sl;
struct list *ah;
if (!l) {
l = pf->real->passes_filter(pf->real, dev) ?
PF_GOOD_DEVICE : PF_BAD_DEVICE;
list_iterate(ah, &dev->aliases) {
sl = list_item(ah, struct str_list);
list_iterate_items(sl, &dev->aliases)
hash_insert(pf->devices, sl->str, l);
}
}
if (l == PF_BAD_DEVICE) {
log_debug("%s: Skipping (cached)", dev_name(dev));
return 0;
} else
return 1;
} else if (l == PF_BAD_DEVICE)
log_debug("%s: Skipping (cached)", dev_name(dev));
return (l == PF_BAD_DEVICE) ? 0 : 1;
}
static void _destroy(struct dev_filter *f)

View File

@@ -101,7 +101,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
unsigned count = 0;
int i, r = 0;
if (!(scratch = pool_create(1024))) {
if (!(scratch = pool_create("filter matcher", 1024))) {
stack;
return 0;
}
@@ -158,13 +158,11 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
static int _accept_p(struct dev_filter *f, struct device *dev)
{
struct list *ah;
int m, first = 1, rejected = 0;
struct rfilter *rf = (struct rfilter *) f->private;
struct str_list *sl;
list_iterate(ah, &dev->aliases) {
sl = list_item(ah, struct str_list);
list_iterate_items(sl, &dev->aliases) {
m = matcher_run(rf->engine, sl->str);
if (m >= 0) {
@@ -186,6 +184,9 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
first = 0;
}
if (rejected)
log_debug("%s: Skipping (regex)", dev_name(dev));
/*
* pass everything that doesn't match
* anything.
@@ -201,7 +202,7 @@ static void _destroy(struct dev_filter *f)
struct dev_filter *regex_filter_create(struct config_value *patterns)
{
struct pool *mem = pool_create(10 * 1024);
struct pool *mem = pool_create("filter regex", 10 * 1024);
struct rfilter *rf;
struct dev_filter *f;

View File

@@ -169,8 +169,10 @@ static int _read_devs(struct dev_set *ds, const char *dir)
{
struct dirent *d;
DIR *dr;
unsigned char dtype;
struct stat info;
char path[PATH_MAX];
dev_t dev;
dev_t dev = { 0 };
int r = 1;
if (!(dr = opendir(dir))) {
@@ -189,19 +191,31 @@ static int _read_devs(struct dev_set *ds, const char *dir)
continue;
}
if (d->d_type == DT_DIR) {
dtype = d->d_type;
if (dtype == DT_UNKNOWN) {
if (lstat(path, &info) >= 0) {
if (S_ISLNK(info.st_mode))
dtype = DT_LNK;
else if (S_ISDIR(info.st_mode))
dtype = DT_DIR;
else if (S_ISREG(info.st_mode))
dtype = DT_REG;
}
}
if (dtype == DT_DIR) {
if (!_read_devs(ds, path)) {
r = 0;
break;
}
}
if ((d->d_type == DT_REG && !strcmp(d->d_name, "dev")))
if ((dtype == DT_REG && !strcmp(d->d_name, "dev")))
if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) {
r = 0;
break;
}
}
if (closedir(dr))
@@ -234,7 +248,11 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
if (ds->initialised != 1)
return 1;
return _set_lookup(ds, dev->dev);
if (!_set_lookup(ds, dev->dev)) {
log_debug("%s: Skipping (sysfs)", dev_name(dev));
return 0;
} else
return 1;
}
static void _destroy(struct dev_filter *f)
@@ -253,7 +271,7 @@ struct dev_filter *sysfs_filter_create(const char *proc)
if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block)))
return NULL;
if (!(mem = pool_create(256))) {
if (!(mem = pool_create("sysfs", 256))) {
log_error("sysfs pool creation failed");
return NULL;
}

View File

@@ -18,6 +18,8 @@
#include "filter.h"
#include "lvm-string.h"
#include "config.h"
#include "metadata.h"
#include "bitset.h"
#include <dirent.h>
#include <unistd.h>
@@ -27,24 +29,41 @@
#define NUMBER_OF_MAJORS 4096
/* FIXME Make this sparse */
/* 0 means LVM won't use this major number. */
static int _max_partitions_by_major[NUMBER_OF_MAJORS];
typedef struct {
const char *name;
const int max_partitions;
} device_info_t;
static int _md_major = -1;
static bitset_t _dm_bitset;
int md_major(void)
{
return _md_major;
}
/* This list can be supplemented with devices/types in the config file */
int is_dm_major(int major)
{
return bit(_dm_bitset, major) ? 1 : 0;
}
/*
* Devices are only checked for partition tables if their minor number
* is a multiple of the number corresponding to their type below
* i.e. this gives the granularity of whole-device minor numbers.
* Use 1 if the device is not partitionable.
*
* The list can be supplemented with devices/types in the config file.
*/
static const device_info_t device_info[] = {
{"ide", 16}, /* IDE disk */
{"ide", 64}, /* IDE disk */
{"sd", 16}, /* SCSI disk */
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
{"loop", 16}, /* Loop device */
{"md", 1}, /* Multiple Disk driver (SoftRAID) */
{"loop", 1}, /* Loop device */
{"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */
{"dac960", 8}, /* DAC960 */
{"nbd", 16}, /* Network Block Device */
@@ -53,37 +72,62 @@ static const device_info_t device_info[] = {
{"ubd", 16}, /* User-mode virtual block device */
{"ataraid", 16}, /* ATA Raid */
{"drbd", 16}, /* Distributed Replicated Block Device */
{"emcpower", 16}, /* EMC Powerpath */
{"power2", 16}, /* EMC Powerpath */
{"i2o_block", 16}, /* i2o Block Disk */
{"iseries/vd", 8}, /* iSeries disks */
{"gnbd", 1}, /* Network block device */
{"ramdisk", 1}, /* RAM disk */
{"aoe", 16}, /* ATA over Ethernet */
{NULL, 0}
};
static int _passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
{
int fd;
const char *name = dev_name(dev);
int ret = 0;
uint64_t size;
/* Is this a recognised device type? */
if (!(((int *) f->private)[MAJOR(dev->dev)])) {
if (!_max_partitions_by_major[MAJOR(dev->dev)]) {
log_debug("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev));
return 0;
}
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("%s: Skipping: open failed: %s", name,
strerror(errno));
if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
log_debug("%s: Skipping: open failed", name);
return 0;
}
/* Check it's not too small */
if (!dev_get_size(dev, &size)) {
log_debug("%s: Skipping: dev_get_size failed", name);
goto out;
}
close(fd);
if (size < PV_MIN_SIZE) {
log_debug("%s: Skipping: Too small to hold a PV", name);
goto out;
}
return 1;
if (is_partitioned_dev(dev)) {
log_debug("%s: Skipping: Partition table signature found",
name);
goto out;
}
ret = 1;
out:
dev_close(dev);
return ret;
}
static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
static int _scan_proc_dev(const char *proc, const struct config_node *cn)
{
char line[80];
char proc_devices[PATH_MAX];
@@ -93,36 +137,31 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
int blocksection = 0;
size_t dev_len = 0;
struct config_value *cv;
int *max_partitions_by_major;
char *name;
/* FIXME Make this sparse */
if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
log_error("Filter failed to allocate max_partitions_by_major");
return NULL;
}
if (!*proc) {
log_verbose("No proc filesystem found: using all block device "
"types");
for (i = 0; i < NUMBER_OF_MAJORS; i++)
max_partitions_by_major[i] = 1;
return max_partitions_by_major;
_max_partitions_by_major[i] = 1;
return 1;
}
/* All types unrecognised initially */
memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return NULL;
return 0;
}
if (!(pd = fopen(proc_devices, "r"))) {
log_sys_error("fopen", proc_devices);
return NULL;
return 0;
}
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
while (fgets(line, 80, pd) != NULL) {
i = 0;
while (line[i] == ' ' && line[i] != '\0')
@@ -149,6 +188,11 @@ 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 dm devices */
if (!strncmp("device-mapper", line + i, 13) &&
isspace(*(line + i + 13)))
bit_set(_dm_bitset, 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++) {
@@ -157,13 +201,13 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
if (dev_len <= strlen(line + i) &&
!strncmp(device_info[j].name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
max_partitions_by_major[line_maj] =
_max_partitions_by_major[line_maj] =
device_info[j].max_partitions;
break;
}
}
if (max_partitions_by_major[line_maj] || !cn)
if (!cn)
continue;
/* Check devices/types for local variations */
@@ -171,7 +215,7 @@ 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");
return NULL;
return 0;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
@@ -180,24 +224,29 @@ 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);
return NULL;
return 0;
}
if (!cv->v.i) {
log_error("Zero partition count invalid for "
"%s in devices/types in config file",
name);
return NULL;
return 0;
}
if (dev_len <= strlen(line + i) &&
!strncmp(name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
max_partitions_by_major[line_maj] = cv->v.i;
_max_partitions_by_major[line_maj] = cv->v.i;
break;
}
}
}
fclose(pd);
return max_partitions_by_major;
return 1;
}
int max_partitions(int major)
{
return _max_partitions_by_major[major];
}
struct dev_filter *lvm_type_filter_create(const char *proc,
@@ -212,8 +261,15 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
f->passes_filter = _passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
f->private = NULL;
if (!(f->private = _scan_proc_dev(proc, cn))) {
if (!(_dm_bitset = bitset_create(NULL, NUMBER_OF_MAJORS))) {
stack;
dbg_free(f);
return NULL;
}
if (!_scan_proc_dev(proc, cn)) {
stack;
return NULL;
}
@@ -223,7 +279,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
bitset_destroy(_dm_bitset);
dbg_free(f);
return;
}

View File

@@ -36,5 +36,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
void lvm_type_filter_destroy(struct dev_filter *f);
int md_major(void);
int is_dm_major(int major);
int max_partitions(int major);
#endif

View File

@@ -29,8 +29,6 @@ LIB_SHARED = liblvm2format1.so
include $(top_srcdir)/make.tmpl
.PHONY: install
install: liblvm2format1.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2format1.so.$(LIB_VERSION)

View File

@@ -424,11 +424,11 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
static void _add_pv_to_list(struct list *head, struct disk_list *data)
{
struct list *pvdh;
struct pv_disk *pvd;
struct disk_list *diskl;
list_iterate(pvdh, head) {
pvd = &list_item(pvdh, struct disk_list)->pvd;
list_iterate_items(diskl, head) {
pvd = &diskl->pvd;
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
sizeof(pvd->pv_uuid))) {
if (MAJOR(data->dev->dev) != md_major()) {
@@ -439,7 +439,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
}
log_very_verbose("Duplicate PV %s - using md %s",
pvd->pv_uuid, dev_name(data->dev));
list_del(pvdh);
list_del(&diskl->list);
break;
}
}
@@ -458,14 +458,14 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_iter *iter;
struct device *dev;
struct disk_list *data = NULL;
struct list *vgih;
struct lvmcache_vginfo *vginfo;
struct lvmcache_info *info;
/* Fast path if we already saw this VG and cached the list of PVs */
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
vginfo->infos.n) {
list_iterate(vgih, &vginfo->infos) {
dev = list_item(vgih, struct lvmcache_info)->dev;
list_iterate_items(info, &vginfo->infos) {
dev = info->dev;
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
break;
_add_pv_to_list(head, data);
@@ -482,7 +482,7 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
/* vgcache_del(vg_name); */
}
if (!(iter = dev_iter_create(filter))) {
if (!(iter = dev_iter_create(filter, 1))) {
log_error("read_pvs_in_vg: dev_iter_create failed");
return 0;
}
@@ -506,6 +506,9 @@ static int _write_vgd(struct disk_list *data)
struct vg_disk *vgd = &data->vgd;
uint64_t pos = data->pvd.vg_on_disk.base;
log_debug("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t,
data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd));
_xlate_vgd(vgd);
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
fail;
@@ -518,18 +521,20 @@ static int _write_vgd(struct disk_list *data)
static int _write_uuids(struct disk_list *data)
{
struct uuid_list *ul;
struct list *uh;
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
list_iterate(uh, &data->uuids) {
list_iterate_items(ul, &data->uuids) {
if (pos >= end) {
log_error("Too many uuids to fit on %s",
dev_name(data->dev));
return 0;
}
ul = list_item(uh, struct uuid_list);
log_debug("Writing %s uuidlist to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, NAME_LEN);
if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
fail;
@@ -541,6 +546,10 @@ static int _write_uuids(struct disk_list *data)
static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
{
log_debug("Writing %s LV %s metadata to %s at %" PRIu64 " len %"
PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev),
pos, sizeof(*disk));
_xlate_lvd(disk);
if (!dev_write(dev, pos, sizeof(*disk), disk))
fail;
@@ -552,7 +561,7 @@ static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
static int _write_lvs(struct disk_list *data)
{
struct list *lvh;
struct lvd_list *ll;
uint64_t pos, offset;
pos = data->pvd.lv_on_disk.base;
@@ -563,9 +572,7 @@ static int _write_lvs(struct disk_list *data)
return 0;
}
list_iterate(lvh, &data->lvds) {
struct lvd_list *ll = list_item(lvh, struct lvd_list);
list_iterate_items(ll, &data->lvds) {
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
log_error("lv_number %d too large", ll->lvd.lv_number);
@@ -585,6 +592,10 @@ static int _write_extents(struct disk_list *data)
struct pe_disk *extents = data->extents;
uint64_t pos = data->pvd.pe_on_disk.base;
log_debug("Writing %s extents metadata to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, len);
_xlate_extents(extents, data->pvd.pe_total);
if (!dev_write(data->dev, pos, len, extents))
fail;
@@ -617,6 +628,10 @@ static int _write_pvd(struct disk_list *data)
memset(buf, 0, size);
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
log_debug("Writing %s PV metadata to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, size);
_xlate_pvd((struct pv_disk *) buf);
if (!dev_write(data->dev, pos, size, buf)) {
dbg_free(buf);
@@ -704,11 +719,9 @@ static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
*/
int write_disks(const struct format_type *fmt, struct list *pvs)
{
struct list *pvh;
struct disk_list *dl;
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
list_iterate_items(dl, pvs) {
if (!(_write_all_pvd(fmt, dl)))
fail;

View File

@@ -24,6 +24,7 @@
#include "lvmcache.h"
#include "lvm1-label.h"
#include "format1.h"
#include "segtype.h"
#define FMT_LVM1_NAME "lvm1"
@@ -45,9 +46,7 @@ static int _check_vgs(struct list *pvs, int *partial)
* This means an active VG won't be affected if disks are inserted
* bearing an exported VG with the same name.
*/
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
list_iterate_items(dl, pvs) {
if (first_time) {
exported = dl->pvd.pv_status & VG_EXPORTED;
first_time = 0;
@@ -147,7 +146,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
vg->seqno = 0;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
if (!_check_vgs(pvs, &partial))
@@ -182,7 +180,7 @@ static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct pool *mem = pool_create("lvm1 vg_read", 1024 * 10);
struct list pvs;
struct volume_group *vg = NULL;
list_init(&pvs);
@@ -246,13 +244,10 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
struct list *pvds, const char *dev_dir,
struct dev_filter *filter)
{
struct list *pvh;
struct pv_list *pvl;
struct disk_list *data;
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
list_iterate_items(pvl, &vg->pvs) {
if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) {
stack;
return 0;
@@ -275,7 +270,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct pool *mem = pool_create("lvm1 vg_write", 1024 * 10);
struct list pvds;
int r = 0;
@@ -298,7 +293,7 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct pool *mem = pool_create("lvm1 pv_read", 1024);
struct disk_list *dl;
struct device *dev;
int r = 0;
@@ -420,7 +415,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
pv->pe_size = pv->pe_count = 0;
pv->pe_start = PE_ALIGN;
if (!(mem = pool_create(1024))) {
if (!(mem = pool_create("lvm1 pv_write", 1024))) {
stack;
return 0;
}
@@ -492,6 +487,17 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
return 1;
}
static int _segtype_supported (struct format_instance *fid,
struct segment_type *segtype)
{
if (!(segtype->flags & SEG_FORMAT1_SUPPORT)) {
stack;
return 0;
}
return 1;
}
static struct metadata_area_ops _metadata_format1_ops = {
vg_read:_vg_read,
vg_write:_vg_write,
@@ -542,6 +548,7 @@ static struct format_handler _format1_ops = {
pv_write:_pv_write,
lv_setup:_lv_setup,
vg_setup:_vg_setup,
segtype_supported:_segtype_supported,
create_instance:_create_instance,
destroy_instance:_destroy_instance,
destroy:_destroy,
@@ -578,5 +585,7 @@ struct format_type *init_format(struct cmd_context *cmd)
return NULL;
}
log_very_verbose("Initialised format: %s", fmt->name);
return fmt;
}

View File

@@ -25,7 +25,8 @@
#include "lvm-string.h"
#include "filter.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "segtype.h"
#include "pv_alloc.h"
#include <time.h>
@@ -86,9 +87,15 @@ int import_pv(struct pool *mem, struct device *dev,
pv->pe_size = pvd->pe_size;
pv->pe_start = pvd->pe_start;
pv->pe_count = pvd->pe_total;
pv->pe_alloc_count = pvd->pe_allocated;
pv->pe_alloc_count = 0;
list_init(&pv->tags);
list_init(&pv->segments);
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
return 1;
}
@@ -234,7 +241,7 @@ int import_vg(struct pool *mem,
vg->extent_size = vgd->pe_size;
vg->extent_count = vgd->pe_total;
vg->free_count = vgd->pe_total - vgd->pe_allocated;
vg->free_count = vgd->pe_total;
vg->max_lv = vgd->lv_max;
vg->max_pv = vgd->pv_max;
vg->alloc = ALLOC_NORMAL;
@@ -323,6 +330,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
lv->size = lvd->lv_size;
lv->le_count = lvd->lv_allocated_le;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
@@ -373,14 +382,11 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
int export_extents(struct disk_list *dl, uint32_t lv_num,
struct logical_volume *lv, struct physical_volume *pv)
{
struct list *segh;
struct pe_disk *ped;
struct lv_segment *seg;
uint32_t pe, s;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
list_iterate_items(seg, &lv->segments) {
for (s = 0; s < seg->area_count; s++) {
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
log_error("Segment type %s in LV %s: "
@@ -388,16 +394,16 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
seg->segtype->name, lv->name);
return 0;
}
if (seg->area[s].type != AREA_PV) {
log_error("LV stripe found in LV %s: "
if (seg_type(seg, s) != AREA_PV) {
log_error("Non-PV stripe found in LV %s: "
"unsupported by format1", lv->name);
return 0;
}
if (seg->area[s].u.pv.pv != pv)
if (seg_pv(seg, s) != pv)
continue; /* not our pv */
for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
ped = &dl->extents[pe + seg->area[s].u.pv.pe];
ped = &dl->extents[pe + seg_pe(seg, s)];
ped->lv_num = lv_num;
ped->le_num = (seg->le / seg->area_count) + pe +
s * (lv->le_count / seg->area_count);
@@ -412,15 +418,11 @@ int import_pvs(const struct format_type *fmt, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count)
{
struct list *pvdh;
struct disk_list *dl;
struct pv_list *pvl;
*count = 0;
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate_items(dl, pvds) {
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
stack;
@@ -471,12 +473,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds)
struct disk_list *dl;
struct lvd_list *ll;
struct lv_disk *lvd;
struct list *pvdh, *lvdh;
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate(lvdh, &dl->lvds) {
ll = list_item(lvdh, struct lvd_list);
list_iterate_items(dl, pvds) {
list_iterate_items(ll, &dl->lvds) {
lvd = &ll->lvd;
if (!find_lv(vg, lvd->lv_name) &&
@@ -495,7 +494,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct physical_volume *pv, const char *dev_dir)
{
int r = 0;
struct list *lvh, *sh;
struct lv_list *ll;
struct lvd_list *lvdl;
size_t len;
@@ -522,8 +520,10 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
}
memset(dl->extents, 0, len);
list_iterate(lvh, &vg->lvs) {
ll = list_item(lvh, struct lv_list);
list_iterate_items(ll, &vg->lvs) {
if (ll->lv->status & SNAPSHOT)
continue;
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
stack;
goto out;
@@ -532,7 +532,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
lv_num = lvnum_from_lvid(&ll->lv->lvid);
lvdl->lvd.lv_number = lv_num;
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
@@ -545,37 +544,20 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
goto out;
}
if (lv_is_origin(ll->lv))
lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
if (lv_is_cow(ll->lv)) {
lvdl->lvd.lv_access |= LV_SNAPSHOT;
lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
lvdl->lvd.lv_snapshot_minor =
lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
}
list_add(&dl->lvds, &lvdl->list);
dl->pvd.lv_cur++;
}
/*
* Now we need to run through the snapshots, exporting
* the SNAPSHOT_ORG flags etc.
*/
list_iterate(sh, &vg->snapshots) {
struct lv_disk *org, *cow;
struct snapshot *s = list_item(sh,
struct snapshot_list)->snapshot;
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
log_err("Couldn't find snapshot origin '%s'.",
s->origin->name);
goto out;
}
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
log_err("Couldn't find snapshot cow store '%s'.",
s->cow->name);
goto out;
}
org->lv_access |= LV_SNAPSHOT_ORG;
cow->lv_access |= LV_SNAPSHOT;
cow->lv_snapshot_minor = org->lv_number;
cow->lv_chunk_size = s->chunk_size;
}
r = 1;
out:
@@ -590,19 +572,17 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
struct list *pvds)
{
struct logical_volume *lvs[MAX_LV];
struct list *pvdh, *lvdh;
struct disk_list *dl;
struct lvd_list *ll;
struct lv_disk *lvd;
int lvnum;
struct logical_volume *org, *cow;
/* build an index of lv numbers */
memset(lvs, 0, sizeof(lvs));
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate(lvdh, &dl->lvds) {
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
list_iterate_items(dl, pvds) {
list_iterate_items(ll, &dl->lvds) {
lvd = &ll->lvd;
lvnum = lvd->lv_number;
@@ -624,11 +604,9 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
/*
* Now iterate through yet again adding the snapshots.
*/
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate(lvdh, &dl->lvds) {
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
list_iterate_items(dl, pvds) {
list_iterate_items(ll, &dl->lvds) {
lvd = &ll->lvd;
if (!(lvd->lv_access & LV_SNAPSHOT))
continue;
@@ -646,7 +624,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
continue;
/* insert the snapshot */
if (!vg_add_snapshot(org, cow, 1, NULL,
if (!vg_add_snapshot(vg->fid, NULL, org, cow, NULL,
org->le_count,
lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot.");
return 0;
@@ -661,10 +640,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
{
struct uuid_list *ul;
struct pv_list *pvl;
struct list *pvh;
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
list_iterate_items(pvl, &vg->pvs) {
if (!(ul = pool_alloc(dl->mem, sizeof(*ul)))) {
stack;
return 0;
@@ -684,14 +661,11 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
*/
void export_numbers(struct list *pvds, struct volume_group *vg)
{
struct list *pvdh;
struct disk_list *dl;
int pv_num = 1;
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate_items(dl, pvds)
dl->pvd.pv_number = pv_num++;
}
}
/*
@@ -699,26 +673,20 @@ void export_numbers(struct list *pvds, struct volume_group *vg)
*/
void export_pv_act(struct list *pvds)
{
struct list *pvdh;
struct disk_list *dl;
int act = 0;
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate_items(dl, pvds)
if (dl->pvd.pv_status & PV_ACTIVE)
act++;
}
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate_items(dl, pvds)
dl->vgd.pv_act = act;
}
}
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter)
{
struct list *pvdh;
struct disk_list *dl;
int vg_num;
@@ -727,10 +695,8 @@ int export_vg_number(struct format_instance *fid, struct list *pvds,
return 0;
}
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate_items(dl, pvds)
dl->vgd.vg_number = vg_num;
}
return 1;
}

View File

@@ -20,7 +20,7 @@
#include "disk-rep.h"
#include "lv_alloc.h"
#include "display.h"
#include "segtypes.h"
#include "segtype.h"
/*
* After much thought I have decided it is easier,
@@ -48,7 +48,6 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
struct volume_group *vg)
{
struct hash_table *maps = hash_create(32);
struct list *llh;
struct lv_list *ll;
struct lv_map *lvm;
@@ -58,8 +57,9 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
return NULL;
}
list_iterate(llh, &vg->lvs) {
ll = list_item(llh, struct lv_list);
list_iterate_items(ll, &vg->lvs) {
if (ll->lv->status & SNAPSHOT)
continue;
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
stack;
@@ -89,13 +89,12 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
static int _fill_lv_array(struct lv_map **lvs,
struct hash_table *maps, struct disk_list *dl)
{
struct list *lvh;
struct lvd_list *ll;
struct lv_map *lvm;
memset(lvs, 0, sizeof(*lvs) * MAX_LV);
list_iterate(lvh, &dl->lvds) {
struct lvd_list *ll = list_item(lvh, struct lvd_list);
list_iterate_items(ll, &dl->lvds) {
if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/')
+ 1))) {
log_err("Physical volume (%s) contains an "
@@ -116,15 +115,13 @@ static int _fill_lv_array(struct lv_map **lvs,
static int _fill_maps(struct hash_table *maps, struct volume_group *vg,
struct list *pvds)
{
struct list *pvdh;
struct disk_list *dl;
struct physical_volume *pv;
struct lv_map *lvms[MAX_LV], *lvm;
struct pe_disk *e;
uint32_t i, lv_num, le;
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate_items(dl, pvds) {
pv = find_pv(vg, dl->dev);
e = dl->extents;
@@ -205,58 +202,59 @@ static int _check_maps_are_complete(struct hash_table *maps)
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t le = 0;
uint32_t le = 0, len;
struct lv_segment *seg;
struct segment_type *segtype;
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
while (le < lvm->lv->le_count) {
seg = alloc_lv_segment(cmd->mem, 1);
len = 0;
seg->lv = lvm->lv;
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
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));
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
len, 0, 0, NULL, 1, len, 0, 0, 0))) {
log_error("Failed to allocate linear segment.");
return 0;
}
if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
lvm->map[le].pe)) {
stack;
return 0;
}
seg->le = le;
seg->len = 0;
seg->area_len = 0;
seg->stripe_size = 0;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = lvm->map[le].pv;
seg->area[0].u.pv.pe = lvm->map[le].pe;
do {
seg->len++;
seg->area_len++;
} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
(seg->area[0].u.pv.pv &&
lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
seg->len));
list_add(&lvm->lv->segments, &seg->list);
le += seg->len;
list_add(&lvm->lv->segments, &seg->list);
}
return 1;
}
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
uint32_t base_le, uint32_t len)
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 le, st;
le = base_le + seg->len;
uint32_t st;
/*
* Is the next physical extent in every stripe adjacent to the last?
*/
for (st = 0; st < seg->area_count; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
(seg->area[st].u.pv.pv &&
lvm->map[le + st * len].pe !=
seg->area[st].u.pv.pe + seg->len)) return 0;
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))
return 0;
return 1;
}
@@ -264,7 +262,9 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t st, le = 0, len;
uint32_t area_len;
struct lv_segment *seg;
struct segment_type *segtype;
/*
* Work out overall striped length
@@ -276,43 +276,46 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
}
len = lvm->lv->le_count / lvm->stripes;
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
while (le < len) {
if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
stack;
return 0;
}
seg->lv = lvm->lv;
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
seg->stripe_size = lvm->stripe_size;
seg->le = seg->area_count * le;
seg->len = 1;
seg->area_len = 1;
/*
* Set up start positions of each stripe in this segment
*/
for (st = 0; st < seg->area_count; st++) {
seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
}
area_len = 1;
/*
* Find how many blocks are contiguous in all stripes
* and so can form part of this segment
*/
while (_check_stripe(lvm, seg, le, len)) {
seg->len++;
seg->area_len++;
while (_check_stripe(lvm, lvm->stripes,
area_len * lvm->stripes, le, len))
area_len++;
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
lvm->stripes * le,
lvm->stripes * area_len,
0, lvm->stripe_size, NULL,
lvm->stripes,
area_len, 0, 0, 0))) {
log_error("Failed to allocate striped segment.");
return 0;
}
le += seg->len;
seg->len *= seg->area_count;
/*
* Set up start positions of each stripe in this segment
*/
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;
}
list_add(&lvm->lv->segments, &seg->list);
le += seg->len;
}
return 1;
@@ -344,7 +347,7 @@ int import_extents(struct cmd_context *cmd, struct volume_group *vg,
struct list *pvds)
{
int r = 0;
struct pool *scratch = pool_create(10 * 1024);
struct pool *scratch = pool_create("lvm1 import_extents", 10 * 1024);
struct hash_table *maps;
if (!scratch) {

View File

@@ -27,10 +27,9 @@
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
const char *candidate_vg, int *result)
{
struct list *pvh;
struct list all_pvs;
struct disk_list *dl;
struct pool *mem = pool_create(10 * 1024);
struct pool *mem = pool_create("lvm1 vg_number", 10 * 1024);
int numbers[MAX_VG], i, r = 0;
list_init(&all_pvs);
@@ -47,8 +46,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
memset(numbers, 0, sizeof(numbers));
list_iterate(pvh, &all_pvs) {
dl = list_item(pvh, struct disk_list);
list_iterate_items(dl, &all_pvs) {
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
continue;

View File

@@ -26,8 +26,6 @@ LIB_SHARED = liblvm2formatpool.so
include $(top_srcdir)/make.tmpl
.PHONY: install
install: liblvm2formatpool.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2formatpool.so.$(LIB_VERSION)

View File

@@ -57,12 +57,9 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
static void _add_pl_to_list(struct list *head, struct pool_list *data)
{
struct list *pvdh;
struct pool_list *pl;
list_iterate(pvdh, head) {
pl = list_item(pvdh, struct pool_list);
list_iterate_items(pl, head) {
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
char uuid[ID_LEN + 7];
@@ -76,7 +73,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data)
}
log_very_verbose("Duplicate PV %s - using md %s",
uuid, dev_name(data->dev));
list_del(pvdh);
list_del(&pl->list);
break;
}
}
@@ -247,11 +244,9 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
struct lvmcache_vginfo *vginfo, struct list *head,
uint32_t *devcount)
{
struct list *vgih = NULL;
struct device *dev;
struct lvmcache_info *info;
struct pool_list *pl = NULL;
struct pool *tmpmem = NULL;
struct pool *tmpmem;
uint32_t sp_count = 0;
uint32_t *sp_devs = NULL;
@@ -259,21 +254,21 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
/* FIXME: maybe should return a different error in memory
* allocation failure */
if (!(tmpmem = pool_create(512))) {
if (!(tmpmem = pool_create("pool read_vg", 512))) {
stack;
return 0;
}
list_iterate(vgih, &vginfo->infos) {
dev = list_item(vgih, struct lvmcache_info)->dev;
if (dev &&
!(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname)))
list_iterate_items(info, &vginfo->infos) {
if (info->dev &&
!(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
break;
/*
* We need to keep track of the total expected number
* of devices per subpool
*/
if (!sp_count) {
/* FIXME pl left uninitialised if !info->dev */
sp_count = pl->pd.pl_subpools;
if (!(sp_devs =
pool_zalloc(tmpmem,
@@ -298,9 +293,8 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
}
*devcount = 0;
for (i = 0; i < sp_count; i++) {
for (i = 0; i < sp_count; i++)
*devcount += sp_devs[i];
}
pool_destroy(tmpmem);

View File

@@ -20,6 +20,8 @@
#include "metadata.h"
#include "pool.h"
#define MINOR_OFFSET 65536
/* From NSP.cf */
#define NSPMajorVersion 4
#define NSPMinorVersion 1
@@ -66,29 +68,6 @@ struct pool_list;
struct user_subpool;
struct user_device;
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
/* Generic Labels */
#define SPTYPE_DATA (0x00000000)
/* GFS specific labels */
#define SPTYPE_GFS_DATA (0x68011670)
#define SPTYPE_GFS_JOURNAL (0x69011670)
struct sptype_name {
const char *name;
uint32_t label;
};
static const struct sptype_name sptype_names[] = {
{"data", SPTYPE_DATA},
{"gfs_data", SPTYPE_GFS_DATA},
{"gfs_journal", SPTYPE_GFS_JOURNAL},
{"", 0x0} /* This must be the last flag. */
};
struct pool_disk {
uint64_t pl_magic; /* Pool magic number */
uint64_t pl_pool_id; /* Unique pool identifier */

View File

@@ -33,8 +33,6 @@
static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
int *sps)
{
struct list *plhs;
struct pool_list *pl;
struct user_subpool *usp = NULL, *cur_sp = NULL;
struct user_device *cur_dev = NULL;
@@ -43,9 +41,7 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
* FIXME: Need to do some checks here - I'm tempted to add a
* user_pool structure and build the entire thing to check against.
*/
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
list_iterate_items(pl, pls) {
*sps = pl->pd.pl_subpools;
if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
log_error("Unable to allocate %d subpool structures",
@@ -72,13 +68,13 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
"structures", pl->pd.pl_sp_devs);
return 0;
}
cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
cur_dev->sp_id = cur_sp->id;
cur_dev->devid = pl->pd.pl_sp_id;
cur_dev->blocks = pl->pd.pl_blocks;
cur_dev->pv = pl->pv;
cur_dev->initialized = 1;
}
return usp;
@@ -132,7 +128,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
vg->system_id = NULL;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
if (!import_pool_vg(vg, smem, pds)) {
@@ -181,7 +176,7 @@ static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024);
struct pool *mem = pool_create("pool vg_read", 1024);
struct list pds;
struct volume_group *vg = NULL;
@@ -227,7 +222,7 @@ static int _pv_setup(const struct format_type *fmt,
static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct pool *mem = pool_create("pool pv_read", 1024);
struct pool_list *pl;
struct device *dev;
int r = 0;
@@ -357,5 +352,7 @@ struct format_type *init_format(struct cmd_context *cmd)
return NULL;
}
log_very_verbose("Initialised format: %s", fmt->name);
return fmt;
}

View File

@@ -19,21 +19,20 @@
#include "metadata.h"
#include "lvmcache.h"
#include "disk_rep.h"
#include "sptype_names.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "str_list.h"
#include "display.h"
#include "segtypes.h"
#include "segtype.h"
/* This file contains only imports at the moment... */
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
{
struct list *plhs;
struct pool_list *pl;
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
list_iterate_items(pl, pls) {
vg->extent_count +=
((pl->pd.pl_blocks) / POOL_PE_SIZE);
@@ -46,7 +45,7 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
get_pool_vg_uuid(&vg->id, &pl->pd);
vg->extent_size = POOL_PE_SIZE;
vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED;
vg->free_count = 0;
vg->free_count = vg->extent_count;
vg->max_lv = 1;
vg->max_pv = POOL_MAX_DEVICES;
vg->alloc = ALLOC_NORMAL;
@@ -59,7 +58,6 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
{
struct pool_list *pl;
struct list *plhs;
struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl));
struct logical_volume *lv;
@@ -81,12 +79,12 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
lv->name = NULL;
lv->le_count = 0;
lv->read_ahead = 0;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
list_iterate_items(pl, pls) {
lv->size += pl->pd.pl_blocks;
if (lv->name)
@@ -107,10 +105,12 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
/* for pool a minor of 0 is dynamic */
if (pl->pd.pl_minor) {
lv->status |= FIXED_MINOR;
lv->minor = pl->pd.pl_minor;
lv->minor = pl->pd.pl_minor + MINOR_OFFSET;
} else {
lv->minor = -1;
}
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
}
@@ -128,11 +128,8 @@ int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
{
struct pv_list *pvl;
struct pool_list *pl;
struct list *plhs;
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
list_iterate_items(pl, pls) {
if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
log_error("Unable to allocate pv list structure");
return 0;
@@ -146,7 +143,7 @@ int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
}
pl->pv = pvl->pv;
pvl->mdas = NULL;
pvl->alloc_areas = NULL;
pvl->pe_ranges = NULL;
list_add(pvs, &pvl->list);
}
@@ -174,9 +171,15 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem,
pv->pe_size = POOL_PE_SIZE;
pv->pe_start = POOL_PE_START;
pv->pe_count = pv->size / POOL_PE_SIZE;
pv->pe_alloc_count = pv->pe_count;
pv->pe_alloc_count = 0;
list_init(&pv->tags);
list_init(&pv->segments);
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
return 1;
}
@@ -199,40 +202,44 @@ static int _add_stripe_seg(struct pool *mem,
uint32_t *le_cur)
{
struct lv_segment *seg;
struct segment_type *segtype;
int j;
uint32_t area_len;
if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
log_error("Unable to allocate striped lv_segment structure");
return 0;
}
if(usp->striping & (usp->striping - 1)) {
if (usp->striping & (usp->striping - 1)) {
log_error("Stripe size must be a power of 2");
return 0;
}
seg->stripe_size = usp->striping;
seg->status |= 0;
seg->le += *le_cur;
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
for (j = 0; j < usp->num_devs; j++) {
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
stack;
return 0;
}
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
area_len * usp->num_devs, 0,
usp->striping, NULL, usp->num_devs,
area_len, 0, 0, 0))) {
log_error("Unable to allocate striped lv_segment structure");
return 0;
}
for (j = 0; j < usp->num_devs; j++)
if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) {
stack;
return 0;
}
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
seg->len += seg->area_len;
*le_cur += seg->area_len;
seg->lv = lv;
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
seg->area[j].type = AREA_PV;
seg->area[j].u.pv.pv = usp->devs[j].pv;
seg->area[j].u.pv.pe = 0;
}
list_add(&lv->segments, &seg->list);
*le_cur += seg->len;
return 1;
}
@@ -241,54 +248,56 @@ static int _add_linear_seg(struct pool *mem,
uint32_t *le_cur)
{
struct lv_segment *seg;
struct segment_type *segtype;
int j;
uint32_t area_len;
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
stack;
return 0;
}
for (j = 0; j < usp->num_devs; j++) {
/* linear segments only have 1 data area */
if (!(seg = alloc_lv_segment(mem, 1))) {
area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
area_len, 0, usp->striping,
NULL, 1, area_len,
POOL_PE_SIZE, 0, 0))) {
log_error("Unable to allocate linear lv_segment "
"structure");
return 0;
}
seg->stripe_size = usp->striping;
seg->le += *le_cur;
seg->chunk_size = POOL_PE_SIZE;
seg->status |= 0;
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
stack;
return 0;
}
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
seg->lv = lv;
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
seg->len = seg->area_len;
*le_cur += seg->len;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = usp->devs[j].pv;
seg->area[0].u.pv.pe = 0;
if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) {
stack;
return 0;
}
list_add(&lv->segments, &seg->list);
*le_cur += seg->len;
}
return 1;
}
int import_pool_segments(struct list *lvs, struct pool *mem,
struct user_subpool *usp, int subpools)
{
struct list *lvhs;
struct lv_list *lvl;
struct logical_volume *lv;
uint32_t le_cur = 0;
int i;
list_iterate(lvhs, lvs) {
lvl = list_item(lvhs, struct lv_list);
list_iterate_items(lvl, lvs) {
lv = lvl->lv;
if (lv->status & SNAPSHOT)
continue;
for (i = 0; i < subpools; i++) {
if (usp[i].striping) {
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
@@ -305,5 +314,4 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
}
return 1;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2005 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 SPTYPE_NAMES_H
#define SPTYPE_NAMES_H
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
/* Generic Labels */
#define SPTYPE_DATA (0x00000000)
/* GFS specific labels */
#define SPTYPE_GFS_DATA (0x68011670)
#define SPTYPE_GFS_JOURNAL (0x69011670)
struct sptype_name {
const char *name;
uint32_t label;
};
static const struct sptype_name sptype_names[] = {
{"data", SPTYPE_DATA},
{"gfs_data", SPTYPE_GFS_DATA},
{"gfs_journal", SPTYPE_GFS_JOURNAL},
{"", 0x0} /* This must be the last flag. */
};
#endif

View File

@@ -53,7 +53,7 @@ struct archive_file {
struct list list;
char *path;
int index;
uint32_t index;
};
/*
@@ -91,7 +91,6 @@ static int _split_vg(const char *filename, char *vgname, size_t vg_size,
static void _insert_file(struct list *head, struct archive_file *b)
{
struct list *bh;
struct archive_file *bf = NULL;
if (list_empty(head)) {
@@ -99,11 +98,9 @@ static void _insert_file(struct list *head, struct archive_file *b)
return;
}
/* index increases through list */
list_iterate(bh, head) {
bf = list_item(bh, struct archive_file);
if (bf->index > b->index) {
/* index reduces through list */
list_iterate_items(bf, head) {
if (b->index > bf->index) {
list_add(&bf->list, &b->list);
return;
}
@@ -132,7 +129,8 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
static struct list *_scan_archive(struct pool *mem,
const char *vgname, const char *dir)
{
int i, count, ix;
int i, count;
uint32_t ix;
char vgname_found[64], *path;
struct dirent **dirent;
struct archive_file *af;
@@ -147,13 +145,13 @@ static struct list *_scan_archive(struct pool *mem,
/* Sort fails beyond 5-digit indexes */
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
log_err("Couldn't scan archive directory.");
log_err("Couldn't scan the archive directory (%s).", dir);
return 0;
}
for (i = 0; i < count; i++) {
/* ignore dot files */
if (dirent[i]->d_name[0] == '.')
if (!strcmp(dirent[i]->d_name, ".") ||
!strcmp(dirent[i]->d_name, ".."))
continue;
/* check the name is the correct format */
@@ -199,7 +197,6 @@ static struct list *_scan_archive(struct pool *mem,
static void _remove_expired(struct list *archives, uint32_t archives_size,
uint32_t retain_days, uint32_t min_archive)
{
struct list *bh;
struct archive_file *bf;
struct stat sb;
time_t retain_time;
@@ -213,9 +210,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
/* Assume list is ordered oldest first (by index) */
list_iterate(bh, archives) {
bf = list_item(bh, struct archive_file);
list_iterate_items(bf, archives) {
/* Get the mtime of the file and unlink if too old */
if (stat(bf->path, &sb)) {
log_sys_error("stat", bf->path);
@@ -240,7 +235,7 @@ int archive_vg(struct volume_group *vg,
uint32_t retain_days, uint32_t min_archive)
{
int i, fd, renamed = 0;
unsigned int ix = 0;
uint32_t ix = 0;
struct archive_file *last;
FILE *fp = NULL;
char temp_file[PATH_MAX], archive_name[PATH_MAX];
@@ -272,20 +267,20 @@ int archive_vg(struct volume_group *vg,
* Now we want to rename this file to <vg>_index.vg.
*/
if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
log_err("Couldn't scan the archive directory (%s).", dir);
stack;
return 0;
}
if (list_empty(archives))
ix = 0;
else {
last = list_item(archives->p, struct archive_file);
last = list_item(list_first(archives), struct archive_file);
ix = last->index + 1;
}
for (i = 0; i < 10; i++) {
if (lvm_snprintf(archive_name, sizeof(archive_name),
"%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
"%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
log_error("Archive file name too long.");
return 0;
}
@@ -344,22 +339,19 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
{
struct list *archives, *ah;
struct list *archives;
struct archive_file *af;
if (!(archives = _scan_archive(cmd->mem, vgname, dir))) {
log_err("Couldn't scan the archive directory (%s).", dir);
stack;
return 0;
}
if (list_empty(archives))
log_print("No archives found in %s.", dir);
list_iterate(ah, archives) {
af = list_item(ah, struct archive_file);
list_iterate_back_items(af, archives)
_display_archive(cmd, af);
}
pool_free(cmd->mem, archives);

View File

@@ -13,53 +13,64 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tools.h"
#include "lib.h"
#include "archiver.h"
#include "format-text.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "lvmcache.h"
#include "toolcontext.h"
static struct {
#include <unistd.h>
struct archive_params {
int enabled;
char *dir;
unsigned int keep_days;
unsigned int keep_number;
};
} _archive_params;
static struct {
struct backup_params {
int enabled;
char *dir;
};
} _backup_params;
int archive_init(const char *dir, unsigned int keep_days, unsigned int keep_min)
int archive_init(struct cmd_context *cmd, const char *dir,
unsigned int keep_days, unsigned int keep_min)
{
_archive_params.dir = NULL;
if (!(cmd->archive_params = pool_zalloc(cmd->libmem,
sizeof(*cmd->archive_params)))) {
log_error("archive_params alloc failed");
return 0;
}
cmd->archive_params->dir = NULL;
if (!*dir)
return 1;
if (!create_dir(dir))
return 0;
if (!(_archive_params.dir = dbg_strdup(dir))) {
if (!(cmd->archive_params->dir = dbg_strdup(dir))) {
log_error("Couldn't copy archive directory name.");
return 0;
}
_archive_params.keep_days = keep_days;
_archive_params.keep_number = keep_min;
_archive_params.enabled = 1;
cmd->archive_params->keep_days = keep_days;
cmd->archive_params->keep_number = keep_min;
cmd->archive_params->enabled = 1;
return 1;
}
void archive_exit(void)
void archive_exit(struct cmd_context *cmd)
{
if (_archive_params.dir)
dbg_free(_archive_params.dir);
memset(&_archive_params, 0, sizeof(_archive_params));
if (cmd->archive_params->dir)
dbg_free(cmd->archive_params->dir);
memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
}
void archive_enable(int flag)
void archive_enable(struct cmd_context *cmd, int flag)
{
_archive_params.enabled = flag;
cmd->archive_params->enabled = flag;
}
static char *_build_desc(struct pool *mem, const char *line, int before)
@@ -91,14 +102,14 @@ static int __archive(struct volume_group *vg)
return 0;
}
return archive_vg(vg, _archive_params.dir, desc,
_archive_params.keep_days,
_archive_params.keep_number);
return archive_vg(vg, vg->cmd->archive_params->dir, desc,
vg->cmd->archive_params->keep_days,
vg->cmd->archive_params->keep_number);
}
int archive(struct volume_group *vg)
{
if (!_archive_params.enabled || !_archive_params.dir)
if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir)
return 1;
if (test_mode()) {
@@ -106,7 +117,16 @@ int archive(struct volume_group *vg)
return 1;
}
log_verbose("Archiving volume group \"%s\" metadata.", vg->name);
if (!create_dir(vg->cmd->archive_params->dir))
return 0;
/* Trap a read-only file system */
if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
(errno == EROFS))
return 0;
log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
vg->seqno);
if (!__archive(vg)) {
log_error("Volume group \"%s\" metadata archive failed.",
vg->name);
@@ -121,23 +141,26 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
int r1, r2;
init_partial(1);
r1 = archive_list(cmd, _archive_params.dir, vg_name);
r2 = backup_list(cmd, _backup_params.dir, vg_name);
r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
init_partial(0);
return r1 && r2;
}
int backup_init(const char *dir)
int backup_init(struct cmd_context *cmd, const char *dir)
{
_backup_params.dir = NULL;
if (!(cmd->backup_params = pool_zalloc(cmd->libmem,
sizeof(*cmd->archive_params)))) {
log_error("archive_params alloc failed");
return 0;
}
cmd->backup_params->dir = NULL;
if (!*dir)
return 1;
if (!create_dir(dir))
return 0;
if (!(_backup_params.dir = dbg_strdup(dir))) {
if (!(cmd->backup_params->dir = dbg_strdup(dir))) {
log_error("Couldn't copy backup directory name.");
return 0;
}
@@ -145,16 +168,16 @@ int backup_init(const char *dir)
return 1;
}
void backup_exit(void)
void backup_exit(struct cmd_context *cmd)
{
if (_backup_params.dir)
dbg_free(_backup_params.dir);
memset(&_backup_params, 0, sizeof(_backup_params));
if (cmd->backup_params->dir)
dbg_free(cmd->backup_params->dir);
memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
}
void backup_enable(int flag)
void backup_enable(struct cmd_context *cmd, int flag)
{
_backup_params.enabled = flag;
cmd->backup_params->enabled = flag;
}
static int __backup(struct volume_group *vg)
@@ -168,7 +191,7 @@ static int __backup(struct volume_group *vg)
}
if (lvm_snprintf(name, sizeof(name), "%s/%s",
_backup_params.dir, vg->name) < 0) {
vg->cmd->backup_params->dir, vg->name) < 0) {
log_error("Failed to generate volume group metadata backup "
"filename.");
return 0;
@@ -179,7 +202,7 @@ static int __backup(struct volume_group *vg)
int backup(struct volume_group *vg)
{
if (!_backup_params.enabled || !_backup_params.dir) {
if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
log_print("WARNING: This metadata update is NOT backed up");
return 1;
}
@@ -189,6 +212,14 @@ int backup(struct volume_group *vg)
return 1;
}
if (!create_dir(vg->cmd->backup_params->dir))
return 0;
/* Trap a read-only file system */
if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
(errno == EROFS))
return 0;
if (!__backup(vg)) {
log_error("Backup of volume group %s metadata failed.",
vg->name);
@@ -198,12 +229,12 @@ int backup(struct volume_group *vg)
return 1;
}
int backup_remove(const char *vg_name)
int backup_remove(struct cmd_context *cmd, const char *vg_name)
{
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/%s",
_backup_params.dir, vg_name) < 0) {
cmd->backup_params->dir, vg_name) < 0) {
log_err("Failed to generate backup filename (for removal).");
return 0;
}
@@ -269,7 +300,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
return 0;
}
if (cmd->fmt != info->fmt) {
log_error("PV %s is a different format (%s)",
log_error("PV %s is a different format (seqno %s)",
dev_name(pv->dev), info->fmt->name);
return 0;
}
@@ -312,7 +343,7 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/%s",
_backup_params.dir, vg_name) < 0) {
cmd->backup_params->dir, vg_name) < 0) {
log_err("Failed to generate backup filename (for restore).");
return 0;
}
@@ -330,7 +361,7 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
cmd = vg->cmd;
log_verbose("Creating volume group backup \"%s\"", file);
log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
if (!(context = create_text_context(cmd, file, desc)) ||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
@@ -354,3 +385,34 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
tf->fmt->ops->destroy_instance(tf);
return r;
}
/*
* Update backup (and archive) if they're out-of-date or don't exist.
*/
void check_current_backup(struct volume_group *vg)
{
char path[PATH_MAX];
struct volume_group *vg_backup;
if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
return;
if (lvm_snprintf(path, sizeof(path), "%s/%s",
vg->cmd->backup_params->dir, vg->name) < 0) {
log_debug("Failed to generate backup filename.");
return;
}
log_suppress(1);
/* Up-to-date backup exists? */
if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
(vg->seqno == vg_backup->seqno) &&
(id_equal(&vg->id, &vg_backup->id)))
return;
log_suppress(0);
if (vg_backup)
archive(vg_backup);
archive(vg);
backup(vg);
}

View File

@@ -18,11 +18,6 @@
#include "metadata.h"
/*
* FIXME: This file is going to merge with the archiving code in
* lib/format_text at some point.
*/
/*
* There are two operations that come under the general area of
* backups. 'Archiving' occurs just before a volume group
@@ -36,20 +31,20 @@
* Typically backups will be stored in /etc/lvm/backups.
*/
int archive_init(const char *dir,
int archive_init(struct cmd_context *cmd, const char *dir,
unsigned int keep_days, unsigned int keep_min);
void archive_exit(void);
void archive_exit(struct cmd_context *cmd);
void archive_enable(int flag);
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 backup_init(const char *dir);
void backup_exit(void);
int backup_init(struct cmd_context *cmd, const char *dir);
void backup_exit(struct cmd_context *cmd);
void backup_enable(int flag);
void backup_enable(struct cmd_context *cmd, int flag);
int backup(struct volume_group *vg);
int backup_remove(const char *vg_name);
int backup_remove(struct cmd_context *cmd, const char *vg_name);
struct volume_group *backup_read_vg(struct cmd_context *cmd,
const char *vg_name, const char *file);
@@ -60,4 +55,6 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name);
int backup_to_file(const char *file, const char *desc, struct volume_group *vg);
void check_current_backup(struct volume_group *vg);
#endif

View File

@@ -20,7 +20,7 @@
#include "pool.h"
#include "display.h"
#include "lvm-string.h"
#include "segtypes.h"
#include "segtype.h"
#include "text_export.h"
#include <stdarg.h>
@@ -30,7 +30,7 @@
struct formatter;
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
const char *fmt, va_list ap);
typedef void (*nl_fn) (struct formatter * f);
typedef int (*nl_fn) (struct formatter * f);
/*
* The first half of this file deals with
* exporting the vg, ie. writing it to a file.
@@ -42,7 +42,7 @@ struct formatter {
union {
FILE *fp; /* where we're writing to */
struct {
char *buf;
char *start;
uint32_t size;
uint32_t used;
} buf;
@@ -95,22 +95,34 @@ static void _dec_indent(struct formatter *f)
/*
* Newline function for prettier layout.
*/
static void _nl_file(struct formatter *f)
static int _nl_file(struct formatter *f)
{
fprintf(f->data.fp, "\n");
return 1;
}
static void _nl_raw(struct formatter *f)
static int _nl_raw(struct formatter *f)
{
if (f->data.buf.used >= f->data.buf.size - 1)
return;
char *newbuf;
*f->data.buf.buf = '\n';
f->data.buf.buf += 1;
/* If metadata doesn't fit, double the buffer size */
if (f->data.buf.used + 2 > f->data.buf.size) {
if (!(newbuf = dbg_realloc(f->data.buf.start,
f->data.buf.size * 2))) {
stack;
return 0;
}
f->data.buf.start = newbuf;
f->data.buf.size *= 2;
}
*(f->data.buf.start + f->data.buf.used) = '\n';
f->data.buf.used += 1;
*f->data.buf.buf = '\0';
return;
*(f->data.buf.start + f->data.buf.used) = '\0';
return 1;
}
#define COMMENT_TAB 6
@@ -153,17 +165,27 @@ static int _out_with_comment_raw(struct formatter *f, const char *comment,
const char *fmt, va_list ap)
{
int n;
char *newbuf;
n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
fmt, ap);
retry:
n = vsnprintf(f->data.buf.start + f->data.buf.used,
f->data.buf.size - f->data.buf.used, fmt, ap);
if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
return 0;
/* If metadata doesn't fit, double the buffer size */
if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
if (!(newbuf = dbg_realloc(f->data.buf.start,
f->data.buf.size * 2))) {
stack;
return 0;
}
f->data.buf.start = newbuf;
f->data.buf.size *= 2;
goto retry;
}
f->data.buf.buf += n;
f->data.buf.used += n;
f->nl(f);
outnl(f);
return 1;
}
@@ -257,10 +279,10 @@ static int _print_header(struct formatter *f,
outf(f, "# Generated by LVM2: %s", ctime(&t));
outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
f->nl(f);
outnl(f);
outf(f, "description = \"%s\"", desc);
f->nl(f);
outnl(f);
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
_utsname.sysname, _utsname.nodename, _utsname.release,
_utsname.version, _utsname.machine);
@@ -309,7 +331,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
/* Default policy is NORMAL; INHERIT is meaningless */
if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
f->nl(f);
outnl(f);
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(vg->alloc));
}
@@ -330,7 +352,7 @@ static inline const char *_get_pv_name(struct formatter *f,
static int _print_pvs(struct formatter *f, struct volume_group *vg)
{
struct list *pvh;
struct pv_list *pvl;
struct physical_volume *pv;
char buffer[4096];
const char *name;
@@ -338,15 +360,15 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
outf(f, "physical_volumes {");
_inc_indent(f);
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
list_iterate_items(pvl, &vg->pvs) {
pv = pvl->pv;
if (!(name = _get_pv_name(f, pv))) {
stack;
return 0;
}
f->nl(f);
outnl(f);
outf(f, "%s {", name);
_inc_indent(f);
@@ -360,7 +382,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
stack;
return 0;
}
f->nl(f);
outnl(f);
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
stack;
@@ -407,7 +429,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
return 0;
}
f->nl(f);
outnl(f);
outf(f, "type = \"%s\"", seg->segtype->name);
if (!list_empty(&seg->tags)) {
@@ -436,28 +458,31 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
const char *name;
unsigned int s;
f->nl(f);
outnl(f);
outf(f, "%ss = [", type);
_inc_indent(f);
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
switch (seg_type(seg, s)) {
case AREA_PV:
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
if (!(name = _get_pv_name(f, seg_pv(seg, s)))) {
stack;
return 0;
}
outf(f, "\"%s\", %u%s", name,
seg->area[s].u.pv.pe,
seg_pe(seg, s),
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_LV:
outf(f, "\"%s\", %u%s",
seg->area[s].u.lv.lv->name,
seg->area[s].u.lv.le,
seg_lv(seg, s)->name,
seg_le(seg, s),
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_UNASSIGNED:
return 0;
}
}
@@ -466,72 +491,57 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
return 1;
}
static int _count_segments(struct logical_volume *lv)
static int _print_lv(struct formatter *f, struct logical_volume *lv)
{
int r = 0;
struct list *segh;
struct lv_segment *seg;
char buffer[4096];
int seg_count;
list_iterate(segh, &lv->segments)
r++;
return r;
}
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
unsigned int count)
{
char buffer[256];
struct lv_segment seg;
f->nl(f);
outf(f, "snapshot%u {", count);
outnl(f);
outf(f, "%s {", lv->name);
_inc_indent(f);
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
/* FIXME: Write full lvid */
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "id = \"%s\"", buffer);
seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "status = %s", buffer);
outf(f, "segment_count = 1");
f->nl(f);
if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
"snapshot"))) {
stack;
return 0;
if (!list_empty(&lv->tags)) {
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "tags = %s", buffer);
}
seg.le = 0;
seg.len = snap->origin->le_count;
seg.origin = snap->origin;
seg.cow = snap->cow;
seg.chunk_size = snap->chunk_size;
if (lv->alloc != ALLOC_INHERIT)
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));
/* FIXME Dummy values */
list_init(&seg.list);
seg.lv = snap->cow;
seg.stripe_size = 0;
seg.area_count = 0;
seg.area_len = 0;
seg.extents_copied = 0;
if (lv->read_ahead)
outf(f, "read_ahead = %u", lv->read_ahead);
if (lv->major >= 0)
outf(f, "major = %d", lv->major);
if (lv->minor >= 0)
outf(f, "minor = %d", lv->minor);
outf(f, "segment_count = %u", list_size(&lv->segments));
outnl(f);
/* Can't tag a snapshot independently of its origin */
list_init(&seg.tags);
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
stack;
return 0;
seg_count = 1;
list_iterate_items(seg, &lv->segments) {
if (!_print_segment(f, lv->vg, seg_count++, seg)) {
stack;
return 0;
}
}
_dec_indent(f);
@@ -540,31 +550,9 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
return 1;
}
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
{
struct list *sh;
struct snapshot *s;
unsigned int count = 0;
list_iterate(sh, &vg->snapshots) {
s = list_item(sh, struct snapshot_list)->snapshot;
if (!_print_snapshot(f, s, count++)) {
stack;
return 0;
}
}
return 1;
}
static int _print_lvs(struct formatter *f, struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_segment *seg;
char buffer[4096];
int seg_count;
struct lv_list *lvl;
/*
* Don't bother with an lv section if there are no lvs.
@@ -575,63 +563,25 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
outf(f, "logical_volumes {");
_inc_indent(f);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
f->nl(f);
outf(f, "%s {", lv->name);
_inc_indent(f);
/* FIXME: Write full lvid */
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
/*
* Write visible LVs first
*/
list_iterate_items(lvl, &vg->lvs) {
if (!(lvl->lv->status & VISIBLE_LV))
continue;
if (!_print_lv(f, lvl->lv)) {
stack;
return 0;
}
outf(f, "id = \"%s\"", buffer);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "status = %s", buffer);
if (!list_empty(&lv->tags)) {
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "tags = %s", buffer);
}
if (lv->alloc != ALLOC_INHERIT)
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));
if (lv->read_ahead)
outf(f, "read_ahead = %u", lv->read_ahead);
if (lv->major >= 0)
outf(f, "major = %d", lv->major);
if (lv->minor >= 0)
outf(f, "minor = %d", lv->minor);
outf(f, "segment_count = %u", _count_segments(lv));
f->nl(f);
seg_count = 1;
list_iterate_items(seg, &lv->segments) {
if (!_print_segment(f, vg, seg_count++, seg)) {
stack;
return 0;
}
}
_dec_indent(f);
outf(f, "}");
}
if (!_print_snapshots(f, vg)) {
stack;
return 0;
list_iterate_items(lvl, &vg->lvs) {
if ((lvl->lv->status & VISIBLE_LV))
continue;
if (!_print_lv(f, lvl->lv)) {
stack;
return 0;
}
}
_dec_indent(f);
@@ -648,11 +598,11 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
{
int count = 0;
struct list *pvh;
struct pv_list *pvl;
struct physical_volume *pv;
char buffer[32], *name;
if (!(f->mem = pool_create(512))) {
if (!(f->mem = pool_create("text pv_names", 512))) {
stack;
goto bad;
}
@@ -662,8 +612,8 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
goto bad;
}
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
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) {
@@ -716,11 +666,11 @@ static int _text_vg_export(struct formatter *f,
if (!_print_vg(f, vg))
fail;
f->nl(f);
outnl(f);
if (!_print_pvs(f, vg))
fail;
f->nl(f);
outnl(f);
if (!_print_lvs(f, vg))
fail;
@@ -771,11 +721,10 @@ int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
}
/* Returns amount of buffer used incl. terminating NUL */
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
uint32_t size)
int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
{
struct formatter *f;
int r;
int r = 0;
_init();
@@ -785,8 +734,13 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
}
memset(f, 0, sizeof(*f));
f->data.buf.buf = buf;
f->data.buf.size = size;
f->data.buf.size = 65536; /* Initial metadata limit */
if (!(f->data.buf.start = dbg_malloc(f->data.buf.size))) {
log_error("text_export buffer allocation failed");
goto out;
}
f->indent = 0;
f->header = 0;
f->out_with_comment = &_out_with_comment_raw;
@@ -794,11 +748,12 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
if (!_text_vg_export(f, vg, desc)) {
stack;
r = 0;
dbg_free(f->data.buf.start);
goto out;
}
r = f->data.buf.used + 1;
*buf = f->data.buf.start;
out:
dbg_free(f);
@@ -806,3 +761,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
}
#undef outf
#undef outnl

View File

@@ -52,8 +52,12 @@ static struct flag _lv_flags[] = {
{VISIBLE_LV, "VISIBLE"},
{PVMOVE, "PVMOVE"},
{LOCKED, "LOCKED"},
{MIRROR_IMAGE, NULL},
{MIRROR_LOG, NULL},
{MIRRORED, NULL},
{VIRTUAL, NULL},
{SNAPSHOT, NULL},
{ACTIVATE_EXCL, NULL},
{0, NULL}
};

View File

@@ -88,8 +88,11 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
}
*/
if (!*lv->lvid.s)
lvid_create(&lv->lvid, &lv->vg->id);
if (!*lv->lvid.s && !lvid_create(&lv->lvid, &lv->vg->id)) {
log_error("Random lvid creation failed for %s/%s.",
lv->vg->name, lv->name);
return 0;
}
return 1;
}
@@ -180,57 +183,74 @@ static int _raw_write_mda_header(const struct format_type *fmt,
static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
struct mda_header *mdah,
const char *vgname)
const char *vgname,
int precommit)
{
size_t len;
char vgnamebuf[NAME_LEN + 2];
struct raw_locn *rlocn;
struct lvmcache_info *info;
rlocn = mdah->raw_locns;
rlocn = mdah->raw_locns; /* Slot 0 */
if (precommit)
rlocn++; /* Slot 1 */
/* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
/* FIXME Ignore if checksum incorrect!!! */
while (rlocn->offset) {
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
sizeof(vgnamebuf), vgnamebuf)) {
stack;
return NULL;
}
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
return rlocn;
}
rlocn++;
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
sizeof(vgnamebuf), vgnamebuf)) {
stack;
goto error;
}
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
return rlocn;
}
error:
if ((info = info_from_pvid(dev_area->dev->pvid)))
lvmcache_update_vgname(info, ORPHAN);
return NULL;
}
static struct raw_locn *_vg_posn(struct format_instance *fid,
struct device_area *dev_area,
const char *vgname)
/*
* Determine offset for uncommitted metadata
*/
static uint64_t _next_rlocn_offset(struct raw_locn *rlocn,
struct mda_header *mdah)
{
if (!rlocn)
/* Find an empty slot */
/* FIXME Assume only one VG per mdah for now */
return MDA_HEADER_SIZE;
struct mda_header *mdah;
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
stack;
return NULL;
}
return _find_vg_rlocn(dev_area, mdah, vgname);
/* Start of free space - round up to next sector; circular */
return ((rlocn->offset + rlocn->size +
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
+ MDA_HEADER_SIZE;
}
static int _raw_holds_vgname(struct format_instance *fid,
struct device_area *dev_area, const char *vgname)
{
int r = 0;
struct mda_header *mdah;
if (!dev_open(dev_area->dev)) {
stack;
return 0;
}
if (_vg_posn(fid, dev_area, vgname))
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
stack;
return 0;
}
if (_find_vg_rlocn(dev_area, mdah, vgname, 0))
r = 1;
if (!dev_close(dev_area->dev))
@@ -241,7 +261,8 @@ static int _raw_holds_vgname(struct format_instance *fid,
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
const char *vgname,
struct device_area *area)
struct device_area *area,
int precommit)
{
struct volume_group *vg = NULL;
struct raw_locn *rlocn;
@@ -260,8 +281,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
goto out;
}
if (!(rlocn = _vg_posn(fid, area, vgname))) {
stack;
if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, precommit))) {
log_debug("VG %s not found on %s", vgname, dev_name(area->dev));
goto out;
}
@@ -284,8 +305,9 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
stack;
goto out;
}
log_debug("Read %s metadata (%u) from %s at %" PRIu64 " size %" PRIu64,
vg->name, vg->seqno, dev_name(area->dev),
log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
PRIu64, vg->name, precommit ? "pre-commit " : "",
vg->seqno, dev_name(area->dev),
area->start + rlocn->offset, rlocn->size);
out:
@@ -301,7 +323,16 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
return _vg_read_raw_area(fid, vgname, &mdac->area);
return _vg_read_raw_area(fid, vgname, &mdac->area, 0);
}
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
return _vg_read_raw_area(fid, vgname, &mdac->area, 1);
}
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
@@ -310,19 +341,15 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct raw_locn *rlocn;
struct mda_header *mdah;
struct physical_volume *pv;
struct list *pvh;
struct pv_list *pvl;
int r = 0;
uint32_t new_wrap = 0, old_wrap = 0;
/* FIXME Essential fix! Make dynamic (realloc? pool?) */
char buf[65536];
char *buf = NULL;
int found = 0;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
if (pv->dev == mdac->area.dev) {
list_iterate_items(pvl, &vg->pvs) {
if (pvl->pv->dev == mdac->area.dev) {
found = 1;
break;
}
@@ -341,20 +368,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
if ((rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
/* Start of free space - round up to next sector; circular */
mdac->rlocn.offset =
((rlocn->offset + rlocn->size +
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
+ MDA_HEADER_SIZE;
} else {
/* Find an empty slot */
/* FIXME Assume only one VG per mdah for now */
mdac->rlocn.offset = MDA_HEADER_SIZE;
}
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", buf, sizeof(buf)))) {
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", &buf))) {
log_error("VG %s metadata writing failed", vg->name);
goto out;
}
@@ -414,24 +431,26 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
if (!r && !dev_close(mdac->area.dev))
stack;
if (buf)
dbg_free(buf);
return r;
}
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
static int _vg_commit_raw_rlocn(struct format_instance *fid,
struct volume_group *vg,
struct metadata_area *mda,
int precommit)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct mda_header *mdah;
struct raw_locn *rlocn;
struct physical_volume *pv;
struct list *pvh;
struct pv_list *pvl;
int r = 0;
int found = 0;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
if (pv->dev == mdac->area.dev) {
list_iterate_items(pvl, &vg->pvs) {
if (pvl->pv->dev == mdac->area.dev) {
found = 1;
break;
}
@@ -445,18 +464,23 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
rlocn = &mdah->raw_locns[0];
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
mdah->raw_locns[0].offset = 0;
mdah->raw_locns[1].offset = 0;
mdah->raw_locns[2].offset = 0;
rlocn = &mdah->raw_locns[0];
}
if (precommit)
rlocn++;
rlocn->offset = mdac->rlocn.offset;
rlocn->size = mdac->rlocn.size;
rlocn->checksum = mdac->rlocn.checksum;
log_debug("Committing %s metadata (%u) to %s header at %" PRIu64,
vg->name, vg->seqno, dev_name(mdac->area.dev),
mdac->area.start);
log_debug("%sCommitting %s metadata (%u) to %s header at %" PRIu64,
precommit ? "Pre-" : "", vg->name, vg->seqno,
dev_name(mdac->area.dev), mdac->area.start);
if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
mdah)) {
log_error("Failed to write metadata area header");
@@ -466,25 +490,36 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
r = 1;
out:
if (!dev_close(mdac->area.dev))
if (!precommit && !dev_close(mdac->area.dev))
stack;
return r;
}
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
return _vg_commit_raw_rlocn(fid, vg, mda, 0);
}
static int _vg_precommit_raw(struct format_instance *fid,
struct volume_group *vg,
struct metadata_area *mda)
{
return _vg_commit_raw_rlocn(fid, vg, mda, 1);
}
/* Close metadata area devices */
static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct physical_volume *pv;
struct list *pvh;
struct pv_list *pvl;
int found = 0;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
if (pv->dev == mdac->area.dev) {
list_iterate_items(pvl, &vg->pvs) {
if (pvl->pv->dev == mdac->area.dev) {
found = 1;
break;
}
@@ -517,7 +552,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
rlocn = &mdah->raw_locns[0];
mdah->raw_locns[1].offset = 0;
}
@@ -543,13 +578,13 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
static struct volume_group *_vg_read_file_name(struct format_instance *fid,
const char *vgname,
const char *path_live)
const char *read_path)
{
struct volume_group *vg;
time_t when;
char *desc;
if (!(vg = text_vg_import_file(fid, path_live, &when, &desc))) {
if (!(vg = text_vg_import_file(fid, read_path, &when, &desc))) {
stack;
return NULL;
}
@@ -562,10 +597,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
if (vgname && strcmp(vgname, vg->name)) {
pool_free(fid->fmt->cmd->mem, vg);
log_err("'%s' does not contain volume group '%s'.",
path_live, vgname);
read_path, vgname);
return NULL;
} else
log_debug("Read volume group %s from %s", vg->name, path_live);
log_debug("Read volume group %s from %s", vg->name, read_path);
return vg;
}
@@ -579,6 +614,15 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
return _vg_read_file_name(fid, vgname, tc->path_live);
}
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda)
{
struct text_context *tc = (struct text_context *) mda->metadata_locn;
return _vg_read_file_name(fid, vgname, tc->path_edit);
}
static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
@@ -622,7 +666,7 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
return 0;
}
if (fsync(fd)) {
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
log_sys_error("fsync", tc->path_edit);
fclose(fp);
return 0;
@@ -734,7 +778,7 @@ static int _scan_file(const struct format_type *fmt)
{
struct dirent *dirent;
struct dir_list *dl;
struct list *dlh, *dir_list;
struct list *dir_list;
char *tmp;
DIR *d;
struct volume_group *vg;
@@ -744,8 +788,7 @@ static int _scan_file(const struct format_type *fmt)
dir_list = &((struct mda_lists *) fmt->private)->dirs;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
list_iterate_items(dl, dir_list) {
if (!(d = opendir(dl->dir))) {
log_sys_error("opendir", dl->dir);
continue;
@@ -833,7 +876,7 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
static int _scan_raw(const struct format_type *fmt)
{
struct raw_list *rl;
struct list *rlh, *raw_list;
struct list *raw_list;
char vgnamebuf[NAME_LEN + 2];
struct volume_group *vg;
struct format_instance fid;
@@ -843,14 +886,12 @@ static int _scan_raw(const struct format_type *fmt)
fid.fmt = fmt;
list_init(&fid.metadata_areas);
list_iterate(rlh, raw_list) {
rl = list_item(rlh, struct raw_list);
list_iterate_items(rl, raw_list) {
/* FIXME We're reading mdah twice here... */
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
sizeof(vgnamebuf))) {
if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
&rl->dev_area)))
&rl->dev_area, 0)))
lvmcache_update_vg(vg);
}
}
@@ -875,6 +916,7 @@ 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();
if (!pvmetadatacopies) {
/* Space available for PEs */
@@ -902,10 +944,21 @@ static int _mda_setup(const struct format_type *fmt,
/* Place mda straight after label area at start of disk */
start1 = LABEL_SCAN_SIZE;
/* Unless the space available is tiny, round to PAGE_SIZE boundary */
if ((!pe_start && !pe_end) ||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
mda_adjustment = start1 % pagesize;
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! */
if (mda_size1 > disk_size) {
log_print("Warning: metadata area fills disk %s",
dev_name(pv->dev));
if (start1 + mda_size1 > disk_size) {
log_print("Warning: metadata area fills disk leaving no "
"space for data on %s.", dev_name(pv->dev));
/* Leave some free space for rounding */
/* Avoid empty data area as could cause tools problems */
mda_size1 = disk_size - start1 - alignment * 2;
@@ -998,7 +1051,6 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
struct label *label;
struct lvmcache_info *info;
struct mda_context *mdac;
struct list *mdash;
struct metadata_area *mda;
char buf[MDA_HEADER_SIZE];
struct mda_header *mdah = (struct mda_header *) buf;
@@ -1026,8 +1078,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
del_mdas(&info->mdas);
else
list_init(&info->mdas);
list_iterate(mdash, mdas) {
mda = list_item(mdash, struct metadata_area);
list_iterate_items(mda, mdas) {
mdac = mda->metadata_locn;
log_debug("Creating metadata area on %s at sector %"
PRIu64 " size %" PRIu64 " sectors",
@@ -1050,8 +1101,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
/* Set pe_start to first aligned sector after any metadata
* areas that begin before pe_start */
pv->pe_start = PE_ALIGN;
list_iterate(mdash, &info->mdas) {
mda = list_item(mdash, struct metadata_area);
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)) &&
@@ -1075,8 +1125,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
return 0;
}
list_iterate(mdash, &info->mdas) {
mda = list_item(mdash, struct metadata_area);
list_iterate_items(mda, &info->mdas) {
mdac = mda->metadata_locn;
memset(&buf, 0, sizeof(buf));
mdah->size = mdac->area.size;
@@ -1099,45 +1148,16 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
return 1;
}
static int _get_pv_from_vg(const struct format_type *fmt, const char *vg_name,
const char *id, struct physical_volume *pv)
{
struct volume_group *vg;
struct list *pvh;
struct pv_list *pvl;
int consistent = 0;
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
log_error("format_text: _vg_read failed to read VG %s",
vg_name);
return 0;
}
if (!consistent)
log_error("Warning: Volume group %s is not consistent",
vg_name);
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
memcpy(pv, pvl->pv, sizeof(*pv));
return 1;
}
}
return 0;
}
static int _add_raw(struct list *raw_list, struct device_area *dev_area)
{
struct raw_list *rl;
struct list *rlh;
/* Already present? */
list_iterate(rlh, raw_list) {
rl = list_item(rlh, struct raw_list);
list_iterate_items(rl, raw_list) {
/* FIXME Check size/overlap consistency too */
if (rl->dev_area.dev == dev_area->dev &&
rl->dev_area.start == dev_area->start) return 1;
rl->dev_area.start == dev_area->start)
return 1;
}
if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
@@ -1158,7 +1178,6 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct lvmcache_info *info;
struct metadata_area *mda, *mda_new;
struct mda_context *mdac, *mdac_new;
struct list *mdah, *dah;
struct data_area_list *da;
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
@@ -1175,19 +1194,19 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
/* Have we already cached vgname? */
if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
_get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
pv)) {
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
info->dev->pvid, pv)) {
return 1;
}
/* Perform full scan and try again */
if (!memlock()) {
lvmcache_label_scan(fmt->cmd, 1);
/* Perform full scan (just the first time) and try again */
if (!memlock() && !full_scan_done()) {
lvmcache_label_scan(fmt->cmd, 2);
if (info->vginfo && info->vginfo->vgname &&
*info->vginfo->vgname &&
_get_pv_from_vg(info->fmt, info->vginfo->vgname,
info->dev->pvid, pv)) {
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
info->dev->pvid, pv)) {
return 1;
}
}
@@ -1205,17 +1224,15 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
list_size(&info->das), dev_name(dev));
return 0;
}
list_iterate(dah, &info->das) {
da = list_item(dah, struct data_area_list);
list_iterate_items(da, &info->das)
pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
}
if (!mdas)
return 1;
/* Add copy of mdas to supplied list */
list_iterate(mdah, &info->mdas) {
mda = list_item(mdah, struct metadata_area);
list_iterate_items(mda, &info->mdas) {
mdac = (struct mda_context *) mda->metadata_locn;
if (!(mda_new = pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) {
log_error("metadata_area allocation failed");
@@ -1272,6 +1289,7 @@ static void _destroy(const struct format_type *fmt)
static struct metadata_area_ops _metadata_text_file_ops = {
vg_read:_vg_read_file,
vg_read_precommit:_vg_read_precommit_file,
vg_write:_vg_write_file,
vg_remove:_vg_remove_file,
vg_commit:_vg_commit_file
@@ -1286,8 +1304,10 @@ static struct metadata_area_ops _metadata_text_file_backup_ops = {
static struct metadata_area_ops _metadata_text_raw_ops = {
vg_read:_vg_read_raw,
vg_read_precommit:_vg_read_precommit_raw,
vg_write:_vg_write_raw,
vg_remove:_vg_remove_raw,
vg_precommit:_vg_precommit_raw,
vg_commit:_vg_commit_raw,
vg_revert:_vg_revert_raw
};
@@ -1302,7 +1322,7 @@ static int _pv_setup(const struct format_type *fmt,
{
struct metadata_area *mda, *mda_new, *mda2;
struct mda_context *mdac, *mdac_new, *mdac2;
struct list *pvmdas, *pvmdash, *mdash;
struct list *pvmdas;
struct lvmcache_info *info;
int found;
uint64_t pe_end = 0;
@@ -1317,8 +1337,7 @@ static int _pv_setup(const struct format_type *fmt,
/* Iterate through all mdas on this PV */
if ((info = info_from_pvid(pv->dev->pvid))) {
pvmdas = &info->mdas;
list_iterate(pvmdash, pvmdas) {
mda = list_item(pvmdash, struct metadata_area);
list_iterate_items(mda, pvmdas) {
mdac =
(struct mda_context *) mda->metadata_locn;
@@ -1326,10 +1345,7 @@ static int _pv_setup(const struct format_type *fmt,
/* Ensure it isn't already on list */
found = 0;
list_iterate(mdash, mdas) {
mda2 =
list_item(mdash,
struct metadata_area);
list_iterate_items(mda2, mdas) {
if (mda2->ops !=
&_metadata_text_raw_ops) continue;
mdac2 =
@@ -1391,9 +1407,10 @@ static struct format_instance *_create_text_instance(const struct format_type
struct mda_context *mdac, *mdac_new;
struct dir_list *dl;
struct raw_list *rl;
struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh;
struct list *dir_list, *raw_list, *mdas;
char path[PATH_MAX];
struct lvmcache_vginfo *vginfo;
struct lvmcache_info *info;
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
log_error("Couldn't allocate format instance object.");
@@ -1415,8 +1432,7 @@ static struct format_instance *_create_text_instance(const struct format_type
} else {
dir_list = &((struct mda_lists *) fmt->private)->dirs;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
list_iterate_items(dl, dir_list) {
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
dl->dir, vgname) < 0) {
log_error("Name too long %s/%s", dl->dir,
@@ -1436,9 +1452,7 @@ static struct format_instance *_create_text_instance(const struct format_type
raw_list = &((struct mda_lists *) fmt->private)->raws;
list_iterate(rlh, raw_list) {
rl = list_item(rlh, struct raw_list);
list_iterate_items(rl, raw_list) {
/* FIXME Cache this; rescan below if some missing */
if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
continue;
@@ -1466,10 +1480,9 @@ static struct format_instance *_create_text_instance(const struct format_type
stack;
goto out;
}
list_iterate(infoh, &vginfo->infos) {
mdas = &(list_item(infoh, struct lvmcache_info)->mdas);
list_iterate(mdash, mdas) {
mda = list_item(mdash, struct metadata_area);
list_iterate_items(info, &vginfo->infos) {
mdas = &info->mdas;
list_iterate_items(mda, mdas) {
mdac =
(struct mda_context *) mda->metadata_locn;
@@ -1643,7 +1656,8 @@ struct format_type *create_text_format(struct cmd_context *cmd)
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
fmt->alias = FMT_TEXT_ALIAS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
FMT_UNLIMITED_VOLS;
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
log_error("Failed to allocate dir_list");
@@ -1682,14 +1696,15 @@ struct format_type *create_text_format(struct cmd_context *cmd)
}
}
if (!(cn = find_config_node(cmd->cft->root, "metadata/disk_areas")))
return fmt;
for (cn = cn->child; cn; cn = cn->sib) {
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
goto err;
if ((cn = find_config_node(cmd->cft->root, "metadata/disk_areas"))) {
for (cn = cn->child; cn; cn = cn->sib) {
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
goto err;
}
}
log_very_verbose("Initialised format: %s", fmt->name);
return fmt;
err:

View File

@@ -59,8 +59,7 @@ int print_tags(struct list *tags, char *buffer, size_t size);
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
uint32_t size);
int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
struct volume_group *text_vg_import_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);

View File

@@ -22,7 +22,8 @@
#include "toolcontext.h"
#include "lvmcache.h"
#include "lv_alloc.h"
#include "segtypes.h"
#include "pv_alloc.h"
#include "segtype.h"
#include "text_import.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
@@ -31,7 +32,7 @@ typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct hash_table * pv_hash);
#define _read_int32(root, path, result) \
get_config_uint32(root, path, result)
get_config_uint32(root, path, (uint32_t *) result)
#define _read_uint32(root, path, result) \
get_config_uint32(root, path, result)
@@ -190,6 +191,7 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
}
list_init(&pv->tags);
list_init(&pv->segments);
/* Optional tags */
if ((cn = find_config_node(pvn, "tags")) &&
@@ -208,6 +210,11 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
@@ -216,12 +223,9 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
{
struct list *segh;
struct lv_segment *comp;
list_iterate(segh, &lv->segments) {
comp = list_item(segh, struct lv_segment);
list_iterate_items(comp, &lv->segments) {
if (comp->le > seg->le) {
list_add(&comp->list, &seg->list);
return;
@@ -283,19 +287,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
return 0;
}
if (!(seg = alloc_lv_segment(mem, area_count))) {
if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
extent_count, 0, 0, NULL, area_count,
extent_count, 0, 0, 0))) {
log_error("Segment allocation failed");
return 0;
}
seg->lv = lv;
seg->le = start_extent;
seg->len = extent_count;
seg->area_len = extent_count;
seg->status = 0u;
seg->segtype = segtype;
seg->extents_copied = 0u;
if (seg->segtype->ops->text_import &&
!seg->segtype->ops->text_import(seg, sn, pv_hash)) {
stack;
@@ -315,17 +313,18 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
*/
_insert_segment(lv, seg);
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
if (seg_is_mirrored(seg))
lv->status |= MIRRORED;
if (seg->segtype->flags & SEG_VIRTUAL)
if (seg_is_virtual(seg))
lv->status |= VIRTUAL;
return 1;
}
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
const struct config_node *cn, struct hash_table *pv_hash)
const struct config_node *cn, struct hash_table *pv_hash,
uint32_t flags)
{
unsigned int s;
struct config_value *cv;
@@ -361,19 +360,13 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
/* FIXME Cope if LV not yet read in */
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
seg->area[s].type = AREA_PV;
seg->area[s].u.pv.pv = pv;
seg->area[s].u.pv.pe = cv->next->v.i;
/*
* Adjust extent counts in the pv and vg.
*/
pv->pe_alloc_count += seg->area_len;
seg->lv->vg->free_count -= seg->area_len;
if (!set_lv_segment_area_pv(seg, s, pv, cv->next->v.i)) {
stack;
return 0;
}
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
seg->area[s].type = AREA_LV;
seg->area[s].u.lv.lv = lv1;
seg->area[s].u.lv.le = cv->next->v.i;
set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i,
flags);
} else {
log_error("Couldn't find volume '%s' "
"for segment '%s'.",
@@ -437,7 +430,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
/*
* Check there are no gaps or overlaps in the lv.
*/
if (!lv_check_segments(lv)) {
if (!check_lv_segments(lv)) {
stack;
return 0;
}
@@ -508,6 +501,8 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
lv->read_ahead = 0;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
@@ -561,24 +556,29 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
/* Skip this for now for snapshots */
if (!(lv->status & SNAPSHOT)) {
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read minor number for logical "
"volume %s.", lv->name);
return 0;
}
lv->major = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "major", &lv->major)) {
log_error("Couldn't read major number for logical "
"volume %s.", lv->name);
}
} else {
/*
* FIXME We now have 2 LVs for each snapshot. The real one was
* created by vg_add_snapshot from the segment text_import.
*/
if (lv->status & SNAPSHOT) {
vg->lv_count--;
list_del(&lvl->list);
return 1;
}
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read minor number for logical "
"volume %s.", lv->name);
return 0;
}
lv->major = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "major", &lv->major)) {
log_error("Couldn't read major number for logical "
"volume %s.", lv->name);
}
return 1;
@@ -736,7 +736,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
/* Optional tags */

View File

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

View File

@@ -17,6 +17,7 @@
#define _LVM_TEXT_EXPORT_H
#define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0)
#define outnl(f) do {if (!f->nl(f)) {stack; return 0;}} while (0)
struct formatter;
struct lv_segment;

View File

@@ -20,6 +20,7 @@ struct lv_segment;
struct config_node;
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
const struct config_node *cn, struct hash_table *pv_hash);
const struct config_node *cn, struct hash_table *pv_hash,
uint32_t flags);
#endif

View File

@@ -39,7 +39,6 @@ static int _write(struct label *label, char *buf)
struct pv_header *pvhdr;
struct lvmcache_info *info;
struct disk_locn *pvh_dlocn_xl;
struct list *mdash, *dash;
struct metadata_area *mda;
struct mda_context *mdac;
struct data_area_list *da;
@@ -57,9 +56,7 @@ static int _write(struct label *label, char *buf)
pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
/* List of data areas (holding PEs) */
list_iterate(dash, &info->das) {
da = list_item(dash, struct data_area_list);
list_iterate_items(da, &info->das) {
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
pvh_dlocn_xl++;
@@ -71,8 +68,7 @@ static int _write(struct label *label, char *buf)
pvh_dlocn_xl++;
/* List of metadata area header locations */
list_iterate(mdash, &info->mdas) {
mda = list_item(mdash, struct metadata_area);
list_iterate_items(mda, &info->mdas) {
mdac = (struct mda_context *) mda->metadata_locn;
if (mdac->area.dev != info->dev)
@@ -198,7 +194,6 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
struct lvmcache_info *info;
struct disk_locn *dlocn_xl;
uint64_t offset;
struct list *mdah;
struct metadata_area *mda;
char vgnamebuf[NAME_LEN + 2];
struct mda_context *mdac;
@@ -235,8 +230,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
dlocn_xl++;
}
list_iterate(mdah, &info->mdas) {
mda = list_item(mdah, struct metadata_area);
list_iterate_items(mda, &info->mdas) {
mdac = (struct mda_context *) mda->metadata_locn;
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
sizeof(vgnamebuf))) {

View File

@@ -98,14 +98,11 @@ int label_register_handler(const char *name, struct labeller *handler)
struct labeller *label_get_handler(const char *name)
{
struct list *lih;
struct labeller_i *li;
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
list_iterate_items(li, &_labellers)
if (!strcmp(li->name, name))
return li->l;
}
return NULL;
}
@@ -113,16 +110,20 @@ struct labeller *label_get_handler(const char *name)
static struct labeller *_find_labeller(struct device *dev, char *buf,
uint64_t *label_sector)
{
struct list *lih;
struct labeller_i *li;
struct labeller *r = NULL;
struct label_header *lh;
struct lvmcache_info *info;
uint64_t sector;
int found = 0;
char readbuf[LABEL_SCAN_SIZE];
if (!dev_open(dev)) {
stack;
if ((info = info_from_pvid(dev->pvid)))
lvmcache_update_vgname(info, ORPHAN);
return NULL;
}
@@ -161,8 +162,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
continue;
}
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
list_iterate_items(li, &_labellers) {
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
log_very_verbose("%s: %s label detected",
dev_name(dev), li->name);
@@ -182,10 +182,13 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
}
}
if (!found)
log_very_verbose("%s: No label detected", dev_name(dev));
out:
if (!found) {
if ((info = info_from_pvid(dev->pvid)))
lvmcache_update_vgname(info, ORPHAN);
log_very_verbose("%s: No label detected", dev_name(dev));
}
if (!dev_close(dev))
stack;
@@ -200,7 +203,6 @@ int label_remove(struct device *dev)
int r = 1;
uint64_t sector;
int wipe;
struct list *lih;
struct labeller_i *li;
struct label_header *lh;
@@ -236,8 +238,7 @@ int label_remove(struct device *dev)
if (xlate64(lh->sector_xl) == sector)
wipe = 1;
} else {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
list_iterate_items(li, &_labellers) {
if (li->l->ops->can_handle(li->l, (char *) lh,
sector)) {
wipe = 1;
@@ -279,7 +280,7 @@ int label_read(struct device *dev, struct label **result)
return 0;
}
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
(*result)->sector = sector;
return r;
@@ -309,7 +310,7 @@ int label_write(struct device *dev, struct label *label)
lh->sector_xl = xlate64(label->sector);
lh->offset_xl = xlate32(sizeof(*lh));
if (!label->labeller->ops->write(label, buf)) {
if (!(label->labeller->ops->write)(label, buf)) {
stack;
return 0;
}

View File

@@ -22,9 +22,7 @@ LIB_SHARED = liblvm2clusterlock.so
include $(top_srcdir)/make.tmpl
.PHONY: install
install: liblvm2clusterlock.so
install install_cluster: liblvm2clusterlock.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2clusterlock.so.$(LIB_VERSION)
$(LN_S) -f liblvm2clusterlock.so.$(LIB_VERSION) \

View File

@@ -139,8 +139,7 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
/* Read the returned values */
off = 1; /* we've already read the first byte */
while (off < outheader->arglen && len > 0) {
while (off <= outheader->arglen && len > 0) {
len = read(_clvmd_sock, outheader->args + off,
buflen - off - offsetof(struct clvm_header, args));
if (len > 0)
@@ -148,10 +147,16 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
}
/* Was it an error ? */
if (outheader->status < 0) {
errno = -outheader->status;
log_error("cluster send request failed: %s", strerror(errno));
return 0;
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)) {
log_error("cluster request failed: %s", strerror(errno));
return 0;
}
}
return 1;
@@ -322,19 +327,20 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
args = alloca(len);
strcpy(args + 2, name);
args[0] = flags & 0xBF; /* Maskoff LOCAL flag */
args[1] = 0; /* Not used now */
args[0] = flags & 0x7F; /* Maskoff lock flags */
args[1] = flags & 0xC0; /* Bitmap flags */
/*
* VG locks are just that: locks, and have no side effects
* so we only need to do them on the local node because all
* locks are cluster-wide.
* Also, if the lock is exclusive it makes no sense to try to
* Also, if the lock is exclusive it makes no sense to try to
* acquire it on all nodes, so just do that on the local node too.
*/
if (cmd == CLVMD_CMD_LOCK_VG ||
(flags & LCK_TYPE_MASK) == LCK_EXCL ||
(flags & LCK_LOCAL))
(flags & LCK_LOCAL) ||
!(flags & LCK_CLUSTER_VG))
node = ".";
status = _cluster_request(cmd, node, args, len,
@@ -342,10 +348,11 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
/* If any nodes were down then display them and return an error */
for (i = 0; i < num_responses; i++) {
if (response[i].status == -EHOSTDOWN) {
if (response[i].status == EHOSTDOWN) {
log_error("clvmd not running on node %s",
response[i].node);
status = 0;
errno = response[i].status;
} else if (response[i].status) {
log_error("Error locking on node %s: %s",
response[i].node,
@@ -353,6 +360,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
response[i].response :
strerror(response[i].status));
status = 0;
errno = response[i].status;
}
}
@@ -439,7 +447,7 @@ int init_cluster_locking(struct locking_type *locking, struct config_tree *cft)
locking->lock_resource = _lock_resource;
locking->fin_locking = _locking_end;
locking->reset_locking = _reset_locking;
locking->flags = LCK_PRE_MEMLOCK;
locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
_clvmd_sock = _open_local_sock();
if (_clvmd_sock == -1)
@@ -456,6 +464,7 @@ int locking_init(int type, struct config_tree *cf, uint32_t *flags)
/* Ask LVM to lock memory before calling us */
*flags |= LCK_PRE_MEMLOCK;
*flags |= LCK_CLUSTERED;
return 1;
}

View File

@@ -41,7 +41,7 @@ static char _lock_dir[NAME_LEN];
static sig_t _oldhandler;
static sigset_t _fullsigset, _intsigset;
static int _handler_installed;
static volatile sig_atomic_t _handler_installed;
static int _release_lock(const char *file, int unlock)
{
@@ -95,38 +95,40 @@ static void _reset_file_locking(void)
static void _remove_ctrl_c_handler()
{
siginterrupt(SIGINT, 0);
if (!_handler_installed || _oldhandler == SIG_ERR)
if (!_handler_installed)
return;
_handler_installed = 0;
sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
if (signal(SIGINT, _oldhandler) == SIG_ERR)
log_sys_error("signal", "_remove_ctrl_c_handler");
_handler_installed = 0;
}
static void _trap_ctrl_c(int sig)
{
_remove_ctrl_c_handler();
log_error("CTRL-c detected: giving up waiting for lock");
return;
}
static void _install_ctrl_c_handler()
{
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
_handler_installed = 1;
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
_handler_installed = 0;
return;
}
sigprocmask(SIG_SETMASK, &_intsigset, NULL);
siginterrupt(SIGINT, 1);
_handler_installed = 1;
}
static int _lock_file(const char *file, int flags)
{
int operation;
int r = 1;
int old_errno;
struct lock_list *ll;
struct stat buf1, buf2;
@@ -176,10 +178,12 @@ static int _lock_file(const char *file, int flags)
_install_ctrl_c_handler();
r = flock(ll->lf, operation);
old_errno = errno;
if (!(flags & LCK_NONBLOCK))
_remove_ctrl_c_handler();
if (r) {
errno = old_errno;
log_sys_error("flock", ll->res);
goto err;
}
@@ -239,7 +243,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
break;
case LCK_READ:
log_debug("Locking LV %s (R)", resource);
if (!lv_activate_with_filter(cmd, resource))
if (!lv_activate_with_filter(cmd, resource, 0))
return 0;
break;
case LCK_WRITE:
@@ -249,7 +253,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
break;
case LCK_EXCL:
log_debug("Locking LV %s (EX)", resource);
if (!lv_activate_with_filter(cmd, resource))
if (!lv_activate_with_filter(cmd, resource, 1))
return 0;
break;
default:

View File

@@ -124,6 +124,8 @@ static inline void _update_vg_lock_count(int flags)
*/
int init_locking(int type, struct config_tree *cft)
{
init_lockingfailed(0);
switch (type) {
case 0:
init_no_locking(&_locking, cft);
@@ -165,6 +167,7 @@ int init_locking(int type, struct config_tree *cft)
log_verbose("Locking disabled - only read operations permitted.");
init_no_locking(&_locking, cft);
init_lockingfailed(1);
return 1;
}
@@ -262,13 +265,10 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
/* Unlock list of LVs */
int resume_lvs(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
resume_lv(cmd, lv->lvid.s);
}
list_iterate_items(lvl, lvs)
resume_lv(cmd, lvl->lv);
return 1;
}
@@ -277,15 +277,14 @@ int resume_lvs(struct cmd_context *cmd, struct list *lvs)
int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!suspend_lv(cmd, lv->lvid.s)) {
log_error("Failed to suspend %s", lv->name);
list_uniterate(lvh, lvs, lvh) {
lv = list_item(lvh, struct lv_list)->lv;
resume_lv(cmd, lv->lvid.s);
list_iterate_items(lvl, lvs) {
if (!suspend_lv(cmd, lvl->lv)) {
log_error("Failed to suspend %s", lvl->lv->name);
list_uniterate(lvh, lvs, &lvl->list) {
lvl = list_item(lvh, struct lv_list);
resume_lv(cmd, lvl->lv);
}
return 0;
@@ -299,15 +298,14 @@ int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!activate_lv_excl(cmd, lv->lvid.s)) {
log_error("Failed to activate %s", lv->name);
list_uniterate(lvh, lvs, lvh) {
lv = list_item(lvh, struct lv_list)->lv;
activate_lv(cmd, lv->lvid.s);
list_iterate_items(lvl, lvs) {
if (!activate_lv_excl(cmd, lvl->lv)) {
log_error("Failed to activate %s", lvl->lv->name);
list_uniterate(lvh, lvs, &lvl->list) {
lvl = list_item(lvh, struct lv_list);
activate_lv(cmd, lvl->lv);
}
return 0;
@@ -321,3 +319,9 @@ int vg_write_lock_held(void)
{
return _vg_write_lock_held;
}
int locking_is_clustered(void)
{
return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
}

View File

@@ -20,6 +20,7 @@ int init_locking(int type, struct config_tree *cf);
void fin_locking(void);
void reset_locking(void);
int vg_write_lock_held(void);
int locking_is_clustered(void);
/*
* LCK_VG:
@@ -64,6 +65,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define LCK_NONBLOCK 0x00000010 /* Don't block waiting for lock? */
#define LCK_HOLD 0x00000020 /* Hold lock when lock_vol returns? */
#define LCK_LOCAL 0x00000040 /* Don't propagate to other nodes */
#define LCK_CLUSTER_VG 0x00000080 /* VG is clustered */
/*
* Common combinations
@@ -78,22 +80,27 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ | LCK_NONBLOCK)
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_NULL | LCK_NONBLOCK)
#define LCK_LV_CLUSTERED(lv) \
(((lv)->vg->status & CLUSTERED) ? LCK_CLUSTER_VG : 0)
#define lock_lv_vol(cmd, lv, flags) \
lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv))
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
#define resume_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_RESUME)
#define suspend_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_SUSPEND | LCK_HOLD)
#define deactivate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_DEACTIVATE)
#define activate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD)
#define activate_lv_excl(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_EXCLUSIVE | LCK_HOLD)
#define activate_lv_local(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL)
#define deactivate_lv_local(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_DEACTIVATE | LCK_LOCAL)
#define resume_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME)
#define suspend_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD)
#define deactivate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE)
#define activate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD)
#define activate_lv_excl(cmd, lv) \
lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD)
#define activate_lv_local(cmd, lv) \
lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL)
#define deactivate_lv_local(cmd, lv) \
lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE | LCK_LOCAL)
/* Process list of LVs */
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);

View File

@@ -23,6 +23,7 @@ typedef void (*fin_lock_fn) (void);
typedef void (*reset_lock_fn) (void);
#define LCK_PRE_MEMLOCK 0x00000001 /* Is memlock() needed before calls? */
#define LCK_CLUSTERED 0x00000002
struct locking_type {
uint32_t flags;
@@ -40,4 +41,5 @@ int init_no_locking(struct locking_type *locking, struct config_tree *cf);
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);

View File

@@ -58,11 +58,11 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
case LCK_UNLOCK:
return lv_resume_if_active(cmd, resource);
case LCK_READ:
return lv_activate_with_filter(cmd, resource);
return lv_activate_with_filter(cmd, resource, 0);
case LCK_WRITE:
return lv_suspend_if_active(cmd, resource);
case LCK_EXCL:
return lv_activate_with_filter(cmd, resource);
return lv_activate_with_filter(cmd, resource, 1);
default:
break;
}

View File

@@ -28,7 +28,9 @@ static struct str_list _log_dev_alias;
static int _verbose_level = VERBOSE_BASE_LEVEL;
static int _test = 0;
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 _debug_level = 0;
static int _syslog = 0;
static int _log_to_file = 0;
@@ -38,6 +40,7 @@ static int _indent = 1;
static int _log_cmd_name = 0;
static int _log_suppress = 0;
static int _ignorelockingfailure = 0;
static int _lockingfailed = 0;
static int _security_level = SECURITY_LEVEL;
static char _cmd_name[30] = "";
static char _msg_prefix[30] = " ";
@@ -69,7 +72,7 @@ void init_log_direct(const char *log_file, int append)
{
int open_flags = append ? 0 : O_TRUNC;
dev_create_file(log_file, &_log_dev, &_log_dev_alias);
dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1);
if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0))
return;
@@ -138,16 +141,31 @@ void init_partial(int level)
_partial = level;
}
void init_md_filtering(int level)
{
_md_filtering = level;
}
void init_pvmove(int level)
{
_pvmove = level;
}
void init_full_scan_done(int level)
{
_full_scan_done = level;
}
void init_ignorelockingfailure(int level)
{
_ignorelockingfailure = level;
}
void init_lockingfailed(int level)
{
_lockingfailed = level;
}
void init_security_level(int level)
{
_security_level = level;
@@ -187,11 +205,26 @@ int partial_mode()
return _partial;
}
int md_filtering()
{
return _md_filtering;
}
int pvmove_mode()
{
return _pvmove;
}
int full_scan_done()
{
return _full_scan_done;
}
int lockingfailed()
{
return _lockingfailed;
}
int ignorelockingfailure()
{
return _ignorelockingfailure;
@@ -215,7 +248,7 @@ int debug_level()
void print_log(int level, const char *file, int line, const char *format, ...)
{
va_list ap;
char buf[1024], buf2[4096];
char buf[1024], buf2[4096], locn[4096];
int bufused, n;
const char *message;
const char *trformat; /* Translated format string */
@@ -243,36 +276,46 @@ 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 ",
file, line);
else
locn[0] = '\0';
va_start(ap, format);
switch (level) {
case _LOG_DEBUG:
if (!strcmp("<backtrace>", format))
if (!strcmp("<backtrace>", format) &&
_verbose_level <= _LOG_DEBUG)
break;
if (_verbose_level >= _LOG_DEBUG) {
printf("%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
if (_indent)
printf(" ");
vprintf(trformat, ap);
putchar('\n');
fprintf(stderr, " ");
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
break;
case _LOG_INFO:
if (_verbose_level >= _LOG_INFO) {
printf("%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
if (_indent)
printf(" ");
vprintf(trformat, ap);
putchar('\n');
fprintf(stderr, " ");
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
break;
case _LOG_NOTICE:
if (_verbose_level >= _LOG_NOTICE) {
printf("%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
if (_indent)
printf(" ");
vprintf(trformat, ap);
putchar('\n');
fprintf(stderr, " ");
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
break;
case _LOG_WARN:
@@ -284,7 +327,8 @@ void print_log(int level, const char *file, int line, const char *format, ...)
break;
case _LOG_ERR:
if (_verbose_level >= _LOG_ERR) {
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
@@ -292,7 +336,8 @@ void print_log(int level, const char *file, int line, const char *format, ...)
case _LOG_FATAL:
default:
if (_verbose_level >= _LOG_FATAL) {
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}

View File

@@ -63,21 +63,27 @@ void fin_syslog(void);
void init_verbose(int level);
void init_test(int level);
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_debug(int level);
void init_cmd_name(int status);
void init_msg_prefix(const char *prefix);
void init_indent(int indent);
void init_ignorelockingfailure(int level);
void init_lockingfailed(int level);
void init_security_level(int level);
void set_cmd_name(const char *cmd_name);
int test_mode(void);
int partial_mode(void);
int md_filtering(void);
int pvmove_mode(void);
int full_scan_done(void);
int debug_level(void);
int ignorelockingfailure(void);
int lockingfailed(void);
int security_level(void);
/* Suppress messages to stdout/stderr */

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