1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-13 11:33:16 +03:00

Compare commits

...

163 Commits

Author SHA1 Message Date
Alasdair Kergon
4049c1e480 Backwards compatibility fix for version1 suspend/resume. 2003-07-05 23:20:43 +00:00
Alasdair Kergon
8449314da2 Another sync point - numerous fixes & clean ups. 2003-07-04 22:34:56 +00:00
Alasdair Kergon
63ad057028 Synchronise repository / 2.4.21 support 2003-07-04 19:38:49 +00:00
Alasdair Kergon
e720464330 Support for v4 interface 2003-07-01 21:20:58 +00:00
Alasdair Kergon
24036afef9 move functions 2003-05-06 12:22:24 +00:00
Alasdair Kergon
c78fa1a1bc remove global pvmove lock & poll for completion 2003-05-06 12:20:11 +00:00
Alasdair Kergon
faa8b9022c Check for locked LVs/pvmoves. 2003-05-06 12:14:36 +00:00
Alasdair Kergon
729bafef7a unsigned 2003-05-06 12:13:19 +00:00
Alasdair Kergon
590b028632 Prevent renaming active VGs for now. 2003-05-06 12:11:46 +00:00
Alasdair Kergon
8150d00f36 Don't process locked LVs 2003-05-06 12:10:18 +00:00
Alasdair Kergon
060065926f Store argv 2003-05-06 12:09:28 +00:00
Alasdair Kergon
70babe8a28 --abort --background 2003-05-06 12:08:58 +00:00
Alasdair Kergon
c36e09664f move fields 2003-05-06 12:06:02 +00:00
Alasdair Kergon
a9672246f3 reset_locking() 2003-05-06 12:03:13 +00:00
Alasdair Kergon
ff571884e9 Move fields. 2003-05-06 12:02:36 +00:00
Alasdair Kergon
475138bceb list_next 2003-05-06 12:01:13 +00:00
Alasdair Kergon
4a8af199c2 Add argv 2003-05-06 12:00:51 +00:00
Alasdair Kergon
bdabf5db72 Distinguish between visible & top level devices. 2003-05-06 12:00:29 +00:00
Alasdair Kergon
6a5f21b34e Missing 'make install' dependency. 2003-05-06 11:58:55 +00:00
Alasdair Kergon
d608be103c Update 2003-04-30 16:49:27 +00:00
Alasdair Kergon
374bb5d18a Don't move snapshots 2003-04-30 15:58:09 +00:00
Alasdair Kergon
031d6c25ff Add pvmove 2003-04-30 15:28:17 +00:00
Alasdair Kergon
223fb7b075 add region size & interval 2003-04-30 15:27:48 +00:00
Alasdair Kergon
a746741971 configurable region size 2003-04-30 15:26:54 +00:00
Alasdair Kergon
120faf2a58 pvmove support 2003-04-30 15:26:25 +00:00
Alasdair Kergon
990bca0dc6 use pvmove flag 2003-04-30 15:25:34 +00:00
Alasdair Kergon
3406472db7 Add mirror.c 2003-04-30 15:24:49 +00:00
Alasdair Kergon
1bd733c9f6 Outline pvmove man page 2003-04-30 15:24:08 +00:00
Alasdair Kergon
238c7f982e basic pvmove support 2003-04-30 15:23:43 +00:00
Alasdair Kergon
fcb81147cb pvmove flag 2003-04-30 15:22:52 +00:00
Alasdair Kergon
1915b73783 mirror type 2003-04-30 15:22:36 +00:00
Alasdair Kergon
ee79e621fb mirror display type 2003-04-30 15:21:43 +00:00
Alasdair Kergon
d203275a3b Add comment 2003-04-30 15:21:10 +00:00
Alasdair Kergon
9e8a996222 Up interface to major version number 4. 2003-04-30 13:48:53 +00:00
Alasdair Kergon
0126b0b3ed Up interface to major version number 4. 2003-04-29 22:52:11 +00:00
Alasdair Kergon
458928612c Display event number. 2003-04-29 11:34:40 +00:00
Alasdair Kergon
e33f88e28d Event number support. 2003-04-29 11:34:23 +00:00
Alasdair Kergon
be570bbf9e Try alternative syncs if BLKFLSBUF fails. 2003-04-28 16:20:39 +00:00
Alasdair Kergon
f59b4be110 Extra metadata-reading debug message. 2003-04-28 12:18:53 +00:00
Alasdair Kergon
37336e41be Revert to data_start 2003-04-28 11:55:58 +00:00
Alasdair Kergon
d24a1a3f0a Version 1.95.17 (new <PV>:<PE range list> allocation restriction feature). 2003-04-24 22:52:14 +00:00
Alasdair Kergon
f7258955bd Update segment area length when merging consecutive segments. 2003-04-24 22:46:47 +00:00
Alasdair Kergon
2a1eae5d6f o Metadata area struct change.
o Support physical extent restrictions on PV lists for allocations
    e.g. lvcreate -l 200 vg1 /dev/sda1:100-199:300-399
2003-04-24 22:23:24 +00:00
Alasdair Kergon
50ee0a4adb Stop more gracefully when in test mode. 2003-04-24 22:13:48 +00:00
Alasdair Kergon
955a26584e stripe filler parameter 2003-04-24 22:10:56 +00:00
Alasdair Kergon
1d3e407c8f o Rejig activation code device dependencies to make things a bit more robust
and further reduce the number of ioctl calls made.
o Metadata area struct change.
o Make config file accessible to activation functions & get stripe_filler
  from it.
o Allow kernel to return snapshot status as a fraction or a percentage.
2003-04-24 22:09:13 +00:00
Alasdair Kergon
cb809c4596 indent 2003-04-24 22:00:29 +00:00
Alasdair Kergon
53bbe2888e fix optind after last change to it 2003-04-24 21:59:42 +00:00
Alasdair Kergon
7246f476a5 Add pool_strndup 2003-04-24 21:58:34 +00:00
Alasdair Kergon
0785d1c390 DM_EXISTS_FLAG replaced by ENXIO 2003-04-24 16:08:18 +00:00
Alasdair Kergon
85d2c49d14 Some ioctl code tidying: removing duplicate internal buffers; making bounds
checks clearer (incl. variable renaming); using a flag to indicate when
output data doesn't fit into supplied buffer instead of returning an error etc.
2003-04-22 21:22:04 +00:00
Alasdair Kergon
8b77d62b7f Improve message for pvcreate of empty device. 2003-04-22 16:09:11 +00:00
Alasdair Kergon
373058a32a Improve build robustness. 2003-04-15 13:24:42 +00:00
Alasdair Kergon
e6293c2c8c Abort if any filter creation fails. 2003-04-15 13:22:43 +00:00
Alasdair Kergon
eff181c959 Cope with intentionally missing /proc. 2003-04-15 13:21:38 +00:00
Alasdair Kergon
54752c2305 Support snapshot status fraction. 2003-04-15 13:20:16 +00:00
Alasdair Kergon
b4753c044f Display read-only state. 2003-04-15 12:30:44 +00:00
Alasdair Kergon
26493424ae alignment fixes 2003-04-08 21:20:31 +00:00
Alasdair Kergon
0282fd1332 Add major arg 2003-04-04 13:22:58 +00:00
Alasdair Kergon
b9a019a08b Allow for specification of major number as well as minor. 2003-04-02 19:14:43 +00:00
Alasdair Kergon
66f6a0e687 size_t tidying 2003-04-02 19:11:23 +00:00
Alasdair Kergon
2dd1b9f97d Allow device major to be set too. 2003-04-02 19:03:00 +00:00
Alasdair Kergon
89615f3045 Reinstate lost vg_write() in lvchange --permission. 2003-04-02 13:01:04 +00:00
Alasdair Kergon
7e46192f67 Proposed changes to the ioctl interface to fix alignment issues on some
architectures and specify an explicit width for every numeric field.
2003-03-28 18:58:59 +00:00
Alasdair Kergon
e78d985cdf Avoid report segfault with non-partial inconsistent VG. 2003-03-24 18:22:48 +00:00
Alasdair Kergon
e8c4bf56fe Tidy various pre-processing incl. making libdl optional. 2003-03-24 18:08:53 +00:00
Alasdair Kergon
e6aa7d323d Fix incomplete munmap. (pjc) 2003-03-20 14:29:28 +00:00
Alasdair Kergon
fca8e25929 Fix typo. 2003-03-03 12:57:27 +00:00
Joe Thornber
8e8ac286b4 HAT_CHAR and DOLLAR_CHAR were defined to the same value ! 2003-02-20 14:53:56 +00:00
Alasdair Kergon
7d9770b9a2 Fix table output bug in last commit. 2003-02-20 13:30:03 +00:00
Andres Salomon
1996230460 Update packages. 2003-02-16 22:12:28 +00:00
Alasdair Kergon
de7897a864 LV name validation 2003-02-03 20:09:58 +00:00
Alasdair Kergon
e2884dcdb7 Identifiers may now start with digits etc. 2003-02-03 20:08:45 +00:00
Alasdair Kergon
544a53a42b Allow strings in single quotes too 2003-01-28 17:20:11 +00:00
Alasdair Kergon
2e4787bfc8 Treat 'section{' as equivalent to 'section {' 2003-01-28 16:07:04 +00:00
Alasdair Kergon
1829eeb171 merge back accidentally overwritten r1.2 change 2003-01-25 13:34:35 +00:00
Alasdair Kergon
c7488e3c4a Prepare for ioctl version number change. 2003-01-21 21:27:36 +00:00
Alasdair Kergon
3bf9606383 Allow optional verbose logging. 2003-01-21 21:25:51 +00:00
Alasdair Kergon
4f43f18f0a Allow optional verbose logging 2003-01-21 21:25:11 +00:00
Alasdair Kergon
5b7f197397 Add --enable-debug --disable-compat 2003-01-21 21:22:55 +00:00
Alasdair Kergon
018141c97f Indicate full (dropped) snapshot. 2003-01-21 18:50:50 +00:00
Alasdair Kergon
4d7813e57c vgreduce --removemissing to remove missing PVs & deps & make VG consistent 2003-01-17 21:04:26 +00:00
Alasdair Kergon
605c60208f Add success message; validate given VG name. 2003-01-17 21:02:04 +00:00
Alasdair Kergon
884fafcc30 Activation commands now return success in test mode. 2003-01-17 20:16:23 +00:00
Alasdair Kergon
56baa90320 Update 2003-01-10 22:51:18 +00:00
Alasdair Kergon
6bb20ee09e Fix (rare) cache bug on machines with large /dev directories. 2003-01-10 19:14:01 +00:00
Alasdair Kergon
541356430c Fix segfault in uuid display (substitution missed during bulk change) 2003-01-09 19:35:17 +00:00
Alasdair Kergon
2f4d91fd69 configure --disable-devmapper if you don't have libdevmapper 2003-01-08 22:44:07 +00:00
Alasdair Kergon
f58c5e6b30 o Additional device/filter-level debugging messages + duplicate alias fix
o 32/64-bit size_t fix (pjc)
2003-01-08 16:41:22 +00:00
Alasdair Kergon
0311d0132c Update date. 2003-01-07 17:06:58 +00:00
Alasdair Kergon
c946c97402 Detect duplicate PV uuids - select the one on an md device if appropriate. 2003-01-06 21:10:43 +00:00
Alasdair Kergon
84a6f51318 Ignore filter cache at startup if config file is newer than cache. 2003-01-06 21:09:04 +00:00
Alasdair Kergon
24a1501b0d More docn for filter changes. 2003-01-06 21:07:27 +00:00
Alasdair Kergon
383b6f5fcc Correct error message for non-snapshot activation failure. 2003-01-06 21:06:43 +00:00
Alasdair Kergon
633dd7ff9b When there are device name aliases, choose the "nicest" to display. 2003-01-03 21:11:23 +00:00
Alasdair Kergon
580624fad6 Also lock memory during LV updates. 2003-01-03 21:10:28 +00:00
Alasdair Kergon
a8190f7efa When activating an LV, remove any stray LVM1 /dev nodes and group file. 2003-01-03 13:50:47 +00:00
Alasdair Kergon
dd2157534b Default stripesize 64k & config file setting for it;
Clear many compiler warnings (i386) & associated bugs - hopefully without
introducing too many new bugs:-)  (Same exercise required for other archs.)
Default compilation has optimisation - or else use ./configure --enable-debug
2002-12-19 23:25:55 +00:00
Alasdair Kergon
38a90e7669 New column-based reporting tools: lvs, pvs & vgs. 2002-12-12 20:55:49 +00:00
Andres Salomon
6bfc526dcd close another bug 2002-12-09 08:59:34 +00:00
Andres Salomon
aadb8a7405 it's about that time again 2002-12-09 08:37:58 +00:00
Alasdair Kergon
27082bf77e Use sync_dir(). 2002-12-05 22:56:22 +00:00
Alasdair Kergon
a2903c80cd Add sync_dir() 2002-12-05 22:51:15 +00:00
Alasdair Kergon
9a77c5369c Fix display alignment of zero. 2002-12-05 22:42:31 +00:00
Alasdair Kergon
3c30741a19 Remove an unused .h file. 2002-12-05 22:37:36 +00:00
Alasdair Kergon
7028ad4ec0 Fix long arg processing. 2002-12-05 22:35:15 +00:00
Alasdair Kergon
8de750c6aa Maintain snapshot_count correctly. 2002-12-05 22:30:39 +00:00
Alasdair Kergon
04f98de9ee Keep certain versions of ld happy. 2002-12-05 22:28:18 +00:00
Alasdair Kergon
a1a019784b Keep some ld versions happy. 2002-12-05 22:27:43 +00:00
Alasdair Kergon
4aeeae77bd New devices/types config file entry to add new types of block devices. 2002-12-03 16:20:38 +00:00
Alasdair Kergon
651cfc2b78 tidy 2002-12-03 13:27:23 +00:00
Alasdair Kergon
2ef8af25e2 Show PV uuid; single stripe is 'linear'; suppress snapshot fields for origin. 2002-12-03 13:26:17 +00:00
Alasdair Kergon
0b13852a5b More restore hints. 2002-12-03 13:25:09 +00:00
Alasdair Kergon
13427578c9 Default size unit normally MB not KB. 2002-12-03 13:24:38 +00:00
Alasdair Kergon
d89ca2087e Suppress a (normally) unnecessary warning. 2002-12-03 13:23:50 +00:00
Alasdair Kergon
8b0ea9fba6 Further help text tidying & support for -?. 2002-11-29 15:02:57 +00:00
Heinz Mauelshagen
9f0b653d5a tiny tidying 2002-11-28 15:27:59 +00:00
Heinz Mauelshagen
659a339233 Corrected lvcreate synopsis.
Added --ignorelockingflag to synopsis where missing.
2002-11-28 15:27:29 +00:00
Alasdair Kergon
4c29f177a0 Show stripesize in KB. 2002-11-26 21:56:57 +00:00
Alasdair Kergon
d664e63d55 Skip config file reload attempt if no config file location. 2002-11-26 12:14:37 +00:00
Alasdair Kergon
2493509dbe Fix snapshot lvcreate activation check. 2002-11-22 14:19:56 +00:00
Alasdair Kergon
1c8b27f554 Remove 2 TB LV size restriction message. 2002-11-18 16:21:00 +00:00
Alasdair Kergon
68297b7186 Missing sector->k conversion in "logical volumes cannot be larger than" mesg. 2002-11-18 16:08:45 +00:00
Alasdair Kergon
34dd8d0a91 Some new features. 2002-11-18 14:04:08 +00:00
Alasdair Kergon
81c44790d5 Refactoring. 2002-11-18 14:01:16 +00:00
Alasdair Kergon
d557b335cf A new cache. 2002-11-18 13:53:58 +00:00
Alasdair Kergon
e2adc28cff Only functions listed in libdevmapper.h should get exported. 2002-11-14 19:26:28 +00:00
Alasdair Kergon
0fef6a6ecc Fix includes after DM_DIR definition move. 2002-11-14 14:44:42 +00:00
Alasdair Kergon
f2fd4b8a1f Don't let LVM2 access a VG if the original LVM driver appears to be using it. 2002-11-01 19:57:25 +00:00
Alasdair Kergon
95bd5605a8 Improve missing-kernel-driver error message. 2002-11-01 16:16:42 +00:00
Andres Salomon
497cca7eca agk, I recall you saying you had a massive commit pending; if you need me
to back this out so you can do that commit, let me know.  Also, if there's
an issue with the error message that's displayed, just change it in tools.h.

This causes a "device-mapper driver/module not loaded?" error message to
be displayed for the commands that require dm-mod, if the tools can't get
the driver version.  It's not done for commands that don't require dm-mod.
This should clear up some problems people have had attempting to use lvm2
without rtfm'ing.
2002-10-27 21:04:03 +00:00
Andres Salomon
54f78feedd synch w/ debian 2002-10-27 18:40:35 +00:00
Andres Salomon
76408e53ae Wow, learn something new every day. Apparently, the signed-ness of char is
implementation-dependent; some archs (s390, arm, and ppc) default to
an unsigned char.
2002-10-08 20:16:44 +00:00
Alasdair Kergon
be19e74d30 Support alternative lvrename syntax. 2002-09-05 12:49:23 +00:00
Andres Salomon
dac578a775 update, synch w/ debian 2002-09-01 23:08:17 +00:00
Joe Thornber
04732ce74b o inline _step_matcher 2002-08-29 15:05:16 +00:00
Joe Thornber
a6c95a2374 o Give an example filter that uses anchors. 2002-08-29 14:47:06 +00:00
Joe Thornber
f68622abe9 o Anchor support for the regex engine. 2002-08-29 14:46:30 +00:00
AJ Lewis
83a9a7bdb2 o This resolves bug #79
o added -D_REENTRANT to the CFLAGS so clvmd works properly with liblvm
   (I saw this problem with Redhat 7.3)
2002-08-15 15:31:33 +00:00
Patrick Caulfield
6500afc0ca Remove O_DIRECT as it causes problems with some systems.
Harumph.
2002-08-14 14:58:00 +00:00
Joe Thornber
c69b7ecc96 o Remove e2fsadm to stop people waiting expectantly for something that isn't going
to arrive.
2002-08-08 07:54:57 +00:00
Joe Thornber
615ef1e2d2 o Make sure the status parsing code can deal with an empty array. 2002-08-01 12:51:48 +00:00
Joe Thornber
cf69a0cd7f o Added new value type CFG_EMPTY_ARRAY, to indicate '[]', useful since we use
the arrays to hold a symbolic set of flags.
2002-08-01 12:46:52 +00:00
Joe Thornber
06e892fb33 o 0 was used rather than NULL in a couple of places.
o  Indent output with tabs rather than single spaces.
2002-08-01 08:22:09 +00:00
Joe Thornber
e6c5dd6865 o Test program for the config unit. Just reads a config and then writes it
out again.
2002-08-01 08:18:54 +00:00
Patrick Caulfield
247efdebdb Rename lock_resource to file_lock_resource to avoid name clashes 2002-07-25 09:04:30 +00:00
Patrick Caulfield
76f3792287 Use O_DIRECT for writing to devices.
Doesn't work on HPPA due to a kernel bug but other archs shuld be OK.
2002-07-22 08:10:54 +00:00
Alasdair Kergon
64d8e2c727 Remove hard-coded extent_size from snapshot target (field no longer used). 2002-07-17 17:00:54 +00:00
Alasdair Kergon
ead0bd9cb0 Improved snapshot-related arg validation 2002-07-17 16:04:05 +00:00
Joe Thornber
66fc13b2ec i) Add the VISIBLE flag to the text format. (Other changes are pending
for lib/activate.)
2002-07-11 15:28:49 +00:00
Joe Thornber
f3af4128b0 i) Added a little macro to aid defining the status flags. 2002-07-11 14:36:45 +00:00
Joe Thornber
0e43107c87 i) There's now a seperate field in struct logical_volume that stores the
allocation policy.  This can currently take one of three values:

   typedef enum {
        ALLOC_NEXT_FREE,
        ALLOC_STRICT,
        ALLOC_CONTIGUOUS
   } alloc_policy_t;

    Notice that 'SIMPLE' has turned into the slightly more meaningful NEXT_FREE.

ii) Put code into display.[hc] for converting one of these enums to a
    text representation and back again.

ii) Updated the text format so this also has the alloc_policy field.
2002-07-11 14:21:49 +00:00
Alasdair Kergon
1ee3e7997e tidy 2002-07-11 14:09:26 +00:00
Alasdair Kergon
50fd61d91f Add get_config_str 2002-07-11 14:07:43 +00:00
Patrick Caulfield
e4cdc051a9 Don't log an error if we can't write the cache file because the FS is read-only.
Gets rid of that annoying error at shutdown.
2002-07-11 09:23:29 +00:00
Alasdair Kergon
778e846e96 Add --ignorelockingfailure 2002-07-10 20:43:32 +00:00
Alasdair Kergon
a27759b647 Merge adjacent "Missing" segments. 2002-07-10 13:54:17 +00:00
Joe Thornber
b75eceab41 o Add version number to text format. 2002-07-02 18:47:43 +00:00
Alasdair Kergon
e748a5d5f4 Tidy up for another release: updated documentation; removed old files;
module build fix.
2002-06-26 21:50:53 +00:00
Patrick Caulfield
99c5a3ae46 Flush on open as well as close. 2002-06-25 14:02:28 +00:00
Alasdair Kergon
51da710f5a o Long-awaited ioctl interface clean-up. *** Not backwardly compatible ***
o Various other kernel side tidy-ups.
o Version number changes so we have the option of adding new ioctl commands
  in future without affecting the use of existing ones should you later
  revert to an older kernel but not revert the userspace library/tools.
o Better separation of kernel/userspace elements in the build process to
  prepare for independent distribution of the kernel driver.
2002-06-19 13:07:05 +00:00
Joe Thornber
569d69b3d2 o Knock the version check out of the makefile, Alasdair will no doubt put it back :)
o  Change to new ioctl names.
2002-06-17 15:50:17 +00:00
Patrick Caulfield
059a6b1d90 Get rid of compile warnings on 64bit platforms. 2002-06-07 08:37:07 +00:00
226 changed files with 19544 additions and 8061 deletions

21
INSTALL
View File

@@ -6,8 +6,8 @@ LVM2 installation
Ensure the device-mapper has been installed on the machine. Ensure the device-mapper has been installed on the machine.
The device-mapper should be in the kernel (look for 'device-mapper' The device-mapper should be in the kernel (look for 'device-mapper'
messages in the kernel logs) and /usr/include/libdevmapper.h should messages in the kernel logs) and /usr/include/libdevmapper.h
be present. and libdevmapper.so should be present.
The device-mapper is available from: The device-mapper is available from:
ftp://ftp.sistina.com/pub/LVM2/device-mapper/ ftp://ftp.sistina.com/pub/LVM2/device-mapper/
@@ -17,9 +17,15 @@ LVM2 installation
Run the 'configure' script from the top directory. Run the 'configure' script from the top directory.
If you do not have GNU readline (http://www.gnu.org/directory/readline.html) If you wish to use the built-in LVM2 shell and have GNU readline
installed use installed (http://www.gnu.org/directory/readline.html) use:
./configure --disable-readline ./configure --enable-readline
If you don't want to include the LVM1 backwards-compatibility code use:
./configure --with-lvm1=none
To separate the LVM1 support into a shared library loaded by lvm.conf use:
./configure --with-lvm1=shared
3) Build and install LVM2. 3) Build and install LVM2.
@@ -31,6 +37,9 @@ LVM2 installation
The tools will work fine without a configuration file being The tools will work fine without a configuration file being
present, but you ought to review the example file in doc/example.conf. present, but you ought to review the example file in doc/example.conf.
For example, specifying the devices that LVM2 is to use should For example, specifying the devices that LVM2 is to use can
make the tools run more efficiently - and avoid scanning /dev/cdrom! make the tools run more efficiently - and avoid scanning /dev/cdrom!
Please also refer to the WHATS_NEW file and the manual pages for the
individual commands.

18
INTRO
View File

@@ -1,18 +0,0 @@
An introduction to LVM2
=======================
Background
Compatibility with LVM1
New features
Missing features
Future enhancements

View File

@@ -23,7 +23,8 @@ VPATH = @srcdir@
SUBDIRS = include man lib tools SUBDIRS = include man lib tools
ifeq ($(MAKECMDGOALS),distclean) ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += test/mm test/device test/format1 test/regex test/filters SUBDIRS += lib/format1 \
test/mm test/device test/format1 test/regex test/filters
endif endif
include make.tmpl include make.tmpl

4
README
View File

@@ -1,10 +1,10 @@
This directory contains a beta release of LMV2, the new version of This directory contains a beta release of LVM2, the new version of
the userland LVM tools designed for the new device-mapper for the userland LVM tools designed for the new device-mapper for
the Linux kernel. the Linux kernel.
The device-mapper needs to be installed before compiling these LVM2 tools. The device-mapper needs to be installed before compiling these LVM2 tools.
For more information about LVM2 read the INTRO file. For more information about LVM2 read the WHATS_NEW file.
Installation instructions are in INSTALL. Installation instructions are in INSTALL.
This is beta-quality software, released for testing purposes only. This is beta-quality software, released for testing purposes only.

28
TODO
View File

@@ -1,28 +0,0 @@
before 2.0
-----------
vgexport
vgimport
snapshots
pvmove
device-mapper support for 2.5 kernel series
review FIXMEs
extra validation & full consistency checks in format1 with LVM1
partial activation (aka VG quorum)
error message review
locking during metadata changes
format2 with atomic transactions
bidirectional format1/format2 migration tool
persistent minors
statistics target and tool support
review tool exit codes for LVM1 compatibility
before 2.1
----------
e2fsadm
lvmsadc
lvmsar
pvdata
vgsplit
vgmknodes

View File

@@ -1 +1 @@
1.95.10-cvs (2002-05-31) 2.00.00-cvs (2003-07-04)

93
WHATS_NEW Normal file
View File

@@ -0,0 +1,93 @@
Wednesday 30th April 2003
=========================
A pvmove implementation is now available for the new metadata format.
When running a command that allocates space (e.g. lvcreate), you can now
restrict not only which disk(s) may be used but also the Physical Extents
on those disks. e.g. lvcreate -L 10 vg1 /dev/hda6:1000-2000:3000-4000
Monday 18th November 2002
========================
The new format of LVM metadata is ready for you to test!
We expect it to be more efficient and more robust than the original format.
It's more compact and supports transactional changes and replication.
Should things go wrong on a system, it's human-readable (and editable).
Please report any problems you find to the mailing list,
linux-lvm@sistina.com. The software has NOT yet been thoroughly
tested and so quite possibly there'll still be some bugs in it.
Be aware of the disclaimer in the COPYING file.
While testing, we recommend turning logging on in the configuration file
to provide us with diagnostic information:
log {
file="/tmp/lvm2.log"
level=7
}
You should schedule regular backups of your configuration file and
metadata backups and archives (normally kept under /etc/lvm).
Please read docs/example.conf and "man lvm.conf" to find out more about
the configuration file.
To convert an existing volume group called vg1 to the new format using
the default settings, use "vgconvert -M2 vg1". See "man vgconvert".
-M (or --metadatatype in its long form) is a new flag to indicate which
format of metadata the command should use for anything it creates.
Currently, the valid types are "lvm1" and "lvm2" and they can be
abbreviated to "1" and "2" respectively. The default value for this
flag can be changed in the global section in the config file.
Backwards-compatible support for the original LVM1 metadata format is
maintained, but it can be moved into a shared library or removed
completely with configure's --with-lvm1 option.
Under LVM2, the basic unit of metadata is the volume group. Different
volume groups can use different formats of metadata - vg1 could use
the original LVM1 format while vg2 used the new format - but you can't
mix formats within a volume group. So to add a PV to an LVM2-format
volume group you must run "pvcreate -M2" on it, followed by "vgextend".
With LVM2-format metadata, lvextend will let you specify striping
parameters. So an LV could consist of two or more "segments" - the
first segment could have 3 stripes while the second segment has just 2.
LVM2 maintains a backup of the current metadata for each volume group
in /etc/lvm/backup, and puts copies of previous versions in
/etc/lvm/archive. "vgcfgbackup" and "vgcfgrestore" can be used to
create and restore from these files. If you fully understand what
you're doing, metadata can be changed by editing a copy of a current
backup file and using vgcfgrestore to reload it.
Please read the pvcreate man page for more information on the new
format for metadata.
All tools that can change things have a --test flag which can be used
to check the effect of a set of cmdline args without really making the
changes.
What's not finished?
====================
The internal cache. If you turn on debugging output you'll see lots of
repeated messages, many of which will eventually get optimised out.
--test sometimes causes a command to fail (e.g. vgconvert --test) even
though the real command would work: again, fixing this is waiting for
the work on the cache.
Several of the tools do not yet contain the logic to handle full
recovery: combinations of pvcreate and vgcfgrestore may sometimes be
needed to restore metadata if a tool gets interrupted or crashes or
finds something unexpected. This applies particularly to tools that
work on more than one volume group at once (e.g. vgsplit).
Display output. Some metadata information cannot yet be displayed.
Recovery tools to salvage "lost" metadata directly from the disks:
but we hope the new format will mean such tools are hardly ever needed!

777
autoconf/config.guess vendored

File diff suppressed because it is too large Load Diff

373
autoconf/config.sub vendored
View File

@@ -1,6 +1,10 @@
#! /bin/sh #! /bin/sh
# Configuration validation subroutine script, version 1.1. # Configuration validation subroutine script.
# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
# Free Software Foundation, Inc.
timestamp='2001-09-07'
# This file is (in principle) common to ALL GNU software. # This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software # The presence of a machine in this file suggests that SOME GNU software
# can handle that machine. It does not imply ALL GNU software can. # can handle that machine. It does not imply ALL GNU software can.
@@ -25,6 +29,8 @@
# configuration script generated by Autoconf, you may include it under # configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program. # the same distribution terms that you use for the rest of that program.
# Please send patches to <config-patches@gnu.org>.
#
# Configuration subroutine to validate and canonicalize a configuration type. # Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument. # Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1. # If it is invalid, we print an error message on stderr and exit with code 1.
@@ -45,30 +51,73 @@
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification. # It is wrong to echo any other type of specification.
if [ x$1 = x ] me=`echo "$0" | sed -e 's,.*/,,'`
then
echo Configuration name missing. 1>&2
echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
echo "or $0 ALIAS" 1>&2
echo where ALIAS is a recognized configuration type. 1>&2
exit 1
fi
# First pass through any local machine types. usage="\
case $1 in Usage: $0 [OPTION] CPU-MFR-OPSYS
*local*) $0 [OPTION] ALIAS
echo $1
exit 0 Canonicalize a configuration name.
;;
*) Operation modes:
;; -h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
Try \`$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
echo "$timestamp" ; exit 0 ;;
--version | -v )
echo "$version" ; exit 0 ;;
--help | --h* | -h )
echo "$usage"; exit 0 ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
break ;;
-* )
echo "$me: invalid option $1$help"
exit 1 ;;
*local*)
# First pass through any local machine types.
echo $1
exit 0;;
* )
break ;;
esac
done
case $# in
0) echo "$me: missing argument$help" >&2
exit 1;;
1) ;;
*) echo "$me: too many arguments$help" >&2
exit 1;;
esac esac
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations. # Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in case $maybe_os in
linux-gnu*) nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
os=-$maybe_os os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;; ;;
@@ -94,7 +143,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple) -apple | -axis)
os= os=
basic_machine=$1 basic_machine=$1
;; ;;
@@ -105,9 +154,17 @@ case $os in
-scout) -scout)
;; ;;
-wrs) -wrs)
os=vxworks os=-vxworks
basic_machine=$1 basic_machine=$1
;; ;;
-chorusos*)
os=-chorusos
basic_machine=$1
;;
-chorusrdb)
os=-chorusrdb
basic_machine=$1
;;
-hiux*) -hiux*)
os=-hiuxwe2 os=-hiuxwe2
;; ;;
@@ -156,33 +213,60 @@ case $os in
-psos*) -psos*)
os=-psos os=-psos
;; ;;
-mint | -mint[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
esac esac
# Decode aliases for certain CPU-COMPANY combinations. # Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in case $basic_machine in
# Recognize the basic CPU types without company name. # Recognize the basic CPU types without company name.
# Some are omitted here because they have special meanings below. # Some are omitted here because they have special meanings below.
tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ 1750a | 580 \
| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ | a29k \
| 580 | i960 | h8300 \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \ | c4x | clipper \
| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ | d10v | d30v | dsp16xx \
| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ | fr30 \
| mips64orion | mips64orionel | mipstx39 | mipstx39el \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ | i370 | i860 | i960 | ia64 \
| mips64vr5000 | miprs64vr5000el | mcore \ | m32r | m68000 | m68k | m88k | mcore \
| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \
| thumb | d10v) | mips64vr4100 | mips64vr4100el | mips64vr4300 \
| mips64vr4300el | mips64vr5000 | mips64vr5000el \
| mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \
| mipsisa32 \
| mn10200 | mn10300 \
| ns16k | ns32k \
| openrisc \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| s390 | s390x \
| sh | sh[34] | sh[34]eb | shbe | shle \
| sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \
| stormy16 | strongarm \
| tahoe | thumb | tic80 | tron \
| v850 \
| we32k \
| x86 | xscale \
| z8k)
basic_machine=$basic_machine-unknown basic_machine=$basic_machine-unknown
;; ;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65) m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
basic_machine=$basic_machine-unknown
os=-none
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;; ;;
# We use `pc' rather than `unknown' # We use `pc' rather than `unknown'
# because (1) that's what they normally are, and # because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users. # (2) the word "unknown" tends to confuse beginning users.
i[34567]86) i*86 | x86_64)
basic_machine=$basic_machine-pc basic_machine=$basic_machine-pc
;; ;;
# Object if more than one company name word. # Object if more than one company name word.
@@ -191,24 +275,43 @@ case $basic_machine in
exit 1 exit 1
;; ;;
# Recognize the basic CPU types with company name. # Recognize the basic CPU types with company name.
# FIXME: clean up the formatting here. 580-* \
vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ | a29k-* \
| m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ | alphapca5[67]-* | arc-* \
| power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ | arm-* | armbe-* | armle-* | armv*-* \
| xmp-* | ymp-* \ | bs2000-* \
| hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ | c[123]* | c30-* | [cjt]90-* | c54x-* \
| alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \ | clipper-* | cray2-* | cydra-* \
| we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ | d10v-* | d30v-* \
| clipper-* | orion-* \ | elxsi-* \
| sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ | f30[01]-* | f700-* | fr30-* | fx80-* \
| sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ | h8300-* | h8500-* \
| mips64el-* | mips64orion-* | mips64orionel-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ | i*86-* | i860-* | i960-* | ia64-* \
| mipstx39-* | mipstx39el-* | mcore-* \ | m32r-* \
| f301-* | armv*-* | t3e-* \ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ | m88110-* | m88k-* | mcore-* \
| thumb-* | v850-* | d30v-* | tic30-* | c30-* ) | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \
| mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \
| mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| s390-* | s390x-* \
| sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \
| sparc-* | sparc64-* | sparc86x-* | sparclite-* \
| sparcv9-* | sparcv9b-* | stormy16-* | strongarm-* | sv1-* \
| t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
| v850-* | vax-* \
| we32k-* \
| x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \
| ymp-* \
| z8k-*)
;; ;;
# Recognize the various machine names and aliases which stand # Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS. # for a CPU type and a company and sometimes even an OS.
@@ -245,14 +348,14 @@ case $basic_machine in
os=-sysv os=-sysv
;; ;;
amiga | amiga-*) amiga | amiga-*)
basic_machine=m68k-cbm basic_machine=m68k-unknown
;; ;;
amigaos | amigados) amigaos | amigados)
basic_machine=m68k-cbm basic_machine=m68k-unknown
os=-amigaos os=-amigaos
;; ;;
amigaunix | amix) amigaunix | amix)
basic_machine=m68k-cbm basic_machine=m68k-unknown
os=-sysv4 os=-sysv4
;; ;;
apollo68) apollo68)
@@ -299,13 +402,16 @@ case $basic_machine in
basic_machine=cray2-cray basic_machine=cray2-cray
os=-unicos os=-unicos
;; ;;
[ctj]90-cray) [cjt]90)
basic_machine=c90-cray basic_machine=${basic_machine}-cray
os=-unicos os=-unicos
;; ;;
crds | unos) crds | unos)
basic_machine=m68k-crds basic_machine=m68k-crds
;; ;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
da30 | da30-*) da30 | da30-*)
basic_machine=m68k-da30 basic_machine=m68k-da30
;; ;;
@@ -353,6 +459,10 @@ case $basic_machine in
basic_machine=tron-gmicro basic_machine=tron-gmicro
os=-sysv os=-sysv
;; ;;
go32)
basic_machine=i386-pc
os=-go32
;;
h3050r* | hiux*) h3050r* | hiux*)
basic_machine=hppa1.1-hitachi basic_machine=hppa1.1-hitachi
os=-hiuxwe2 os=-hiuxwe2
@@ -426,22 +536,21 @@ case $basic_machine in
;; ;;
i370-ibm* | ibm*) i370-ibm* | ibm*)
basic_machine=i370-ibm basic_machine=i370-ibm
os=-mvs
;; ;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2? # I'm not sure what "Sysv32" means. Should this be sysv3.2?
i[34567]86v32) i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32 os=-sysv32
;; ;;
i[34567]86v4*) i*86v4*)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4 os=-sysv4
;; ;;
i[34567]86v) i*86v)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv os=-sysv
;; ;;
i[34567]86sol2) i*86sol2)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2 os=-solaris2
;; ;;
@@ -453,14 +562,6 @@ case $basic_machine in
basic_machine=i386-unknown basic_machine=i386-unknown
os=-vsta os=-vsta
;; ;;
i386-go32 | go32)
basic_machine=i386-unknown
os=-go32
;;
i386-mingw32 | mingw32)
basic_machine=i386-unknown
os=-mingw32
;;
iris | iris4d) iris | iris4d)
basic_machine=mips-sgi basic_machine=mips-sgi
case $os in case $os in
@@ -486,10 +587,14 @@ case $basic_machine in
basic_machine=ns32k-utek basic_machine=ns32k-utek
os=-sysv os=-sysv
;; ;;
mingw32)
basic_machine=i386-pc
os=-mingw32
;;
miniframe) miniframe)
basic_machine=m68000-convergent basic_machine=m68000-convergent
;; ;;
*mint | *MiNT) *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
basic_machine=m68k-atari basic_machine=m68k-atari
os=-mint os=-mint
;; ;;
@@ -507,14 +612,22 @@ case $basic_machine in
mips3*) mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;; ;;
mmix*)
basic_machine=mmix-knuth
os=-mmixware
;;
monitor) monitor)
basic_machine=m68k-rom68k basic_machine=m68k-rom68k
os=-coff os=-coff
;; ;;
msdos) msdos)
basic_machine=i386-unknown basic_machine=i386-pc
os=-msdos os=-msdos
;; ;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
ncr3000) ncr3000)
basic_machine=i486-ncr basic_machine=i486-ncr
os=-sysv4 os=-sysv4
@@ -524,7 +637,7 @@ case $basic_machine in
os=-netbsd os=-netbsd
;; ;;
netwinder) netwinder)
basic_machine=armv4l-corel basic_machine=armv4l-rebel
os=-linux os=-linux
;; ;;
news | news700 | news800 | news900) news | news700 | news800 | news900)
@@ -572,9 +685,16 @@ case $basic_machine in
basic_machine=i960-intel basic_machine=i960-intel
os=-mon960 os=-mon960
;; ;;
nonstopux)
basic_machine=mips-compaq
os=-nonstopux
;;
np1) np1)
basic_machine=np1-gould basic_machine=np1-gould
;; ;;
nsr-tandem)
basic_machine=nsr-tandem
;;
op50n-* | op60c-*) op50n-* | op60c-*)
basic_machine=hppa1.1-oki basic_machine=hppa1.1-oki
os=-proelf os=-proelf
@@ -604,28 +724,28 @@ case $basic_machine in
pc532 | pc532-*) pc532 | pc532-*)
basic_machine=ns32k-pc532 basic_machine=ns32k-pc532
;; ;;
pentium | p5 | k5 | k6 | nexen) pentium | p5 | k5 | k6 | nexgen)
basic_machine=i586-pc basic_machine=i586-pc
;; ;;
pentiumpro | p6 | 6x86) pentiumpro | p6 | 6x86 | athlon)
basic_machine=i686-pc basic_machine=i686-pc
;; ;;
pentiumii | pentium2) pentiumii | pentium2)
basic_machine=i786-pc basic_machine=i686-pc
;; ;;
pentium-* | p5-* | k5-* | k6-* | nexen-*) pentium-* | p5-* | k5-* | k6-* | nexgen-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentiumpro-* | p6-* | 6x86-*) pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentiumii-* | pentium2-*) pentiumii-* | pentium2-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pn) pn)
basic_machine=pn-gould basic_machine=pn-gould
;; ;;
power) basic_machine=rs6000-ibm power) basic_machine=power-ibm
;; ;;
ppc) basic_machine=powerpc-unknown ppc) basic_machine=powerpc-unknown
;; ;;
@@ -637,9 +757,23 @@ case $basic_machine in
ppcle-* | powerpclittle-*) ppcle-* | powerpclittle-*)
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64) basic_machine=powerpc64-unknown
;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppc64le | powerpc64little | ppc64-le | powerpc64-little)
basic_machine=powerpc64le-unknown
;;
ppc64le-* | powerpc64little-*)
basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ps2) ps2)
basic_machine=i386-ibm basic_machine=i386-ibm
;; ;;
pw32)
basic_machine=i586-unknown
os=-pw32
;;
rom68k) rom68k)
basic_machine=m68k-rom68k basic_machine=m68k-rom68k
os=-coff os=-coff
@@ -719,6 +853,10 @@ case $basic_machine in
sun386 | sun386i | roadrunner) sun386 | sun386i | roadrunner)
basic_machine=i386-sun basic_machine=i386-sun
;; ;;
sv1)
basic_machine=sv1-cray
os=-unicos
;;
symmetry) symmetry)
basic_machine=i386-sequent basic_machine=i386-sequent
os=-dynix os=-dynix
@@ -727,6 +865,10 @@ case $basic_machine in
basic_machine=t3e-cray basic_machine=t3e-cray
os=-unicos os=-unicos
;; ;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tx39) tx39)
basic_machine=mipstx39-unknown basic_machine=mipstx39-unknown
;; ;;
@@ -779,6 +921,10 @@ case $basic_machine in
basic_machine=hppa1.1-winbond basic_machine=hppa1.1-winbond
os=-proelf os=-proelf
;; ;;
windows32)
basic_machine=i386-pc
os=-windows32-msvcrt
;;
xmp) xmp)
basic_machine=xmp-cray basic_machine=xmp-cray
os=-unicos os=-unicos
@@ -822,13 +968,20 @@ case $basic_machine in
vax) vax)
basic_machine=vax-dec basic_machine=vax-dec
;; ;;
pdp10)
# there are many clones, so DEC is not a safe bet
basic_machine=pdp10-unknown
;;
pdp11) pdp11)
basic_machine=pdp11-dec basic_machine=pdp11-dec
;; ;;
we32k) we32k)
basic_machine=we32k-att basic_machine=we32k-att
;; ;;
sparc | sparcv9) sh3 | sh4 | sh3eb | sh4eb)
basic_machine=sh-unknown
;;
sparc | sparcv9 | sparcv9b)
basic_machine=sparc-sun basic_machine=sparc-sun
;; ;;
cydra) cydra)
@@ -850,6 +1003,9 @@ case $basic_machine in
basic_machine=c4x-none basic_machine=c4x-none
os=-coff os=-coff
;; ;;
*-unknown)
# Make sure to match an already-canonicalized machine name.
;;
*) *)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1 exit 1
@@ -906,14 +1062,30 @@ case $os in
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*) | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos*)
# Remember, each alternative MUST END IN *, to match a version number. # Remember, each alternative MUST END IN *, to match a version number.
;; ;;
-qnx*)
case $basic_machine in
x86-* | i*86-*)
;;
*)
os=-nto$os
;;
esac
;;
-nto*)
os=-nto-qnx
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
| -macos* | -mpw* | -magic* | -mon960* | -lnews*) | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;; ;;
-mac*) -mac*)
os=`echo $os | sed -e 's|mac|macos|'` os=`echo $os | sed -e 's|mac|macos|'`
@@ -927,6 +1099,12 @@ case $os in
-sunos6*) -sunos6*)
os=`echo $os | sed -e 's|sunos6|solaris3|'` os=`echo $os | sed -e 's|sunos6|solaris3|'`
;; ;;
-opened*)
os=-openedition
;;
-wince*)
os=-wince
;;
-osfrose*) -osfrose*)
os=-osfrose os=-osfrose
;; ;;
@@ -951,6 +1129,9 @@ case $os in
-ns2 ) -ns2 )
os=-nextstep2 os=-nextstep2
;; ;;
-nsk*)
os=-nsk
;;
# Preserve the version number of sinix5. # Preserve the version number of sinix5.
-sinix5.*) -sinix5.*)
os=`echo $os | sed -e 's|sinix|sysv|'` os=`echo $os | sed -e 's|sinix|sysv|'`
@@ -985,7 +1166,7 @@ case $os in
-xenix) -xenix)
os=-xenix os=-xenix
;; ;;
-*mint | -*MiNT) -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint os=-mint
;; ;;
-none) -none)
@@ -1013,12 +1194,15 @@ case $basic_machine in
*-acorn) *-acorn)
os=-riscix1.2 os=-riscix1.2
;; ;;
arm*-corel) arm*-rebel)
os=-linux os=-linux
;; ;;
arm*-semi) arm*-semi)
os=-aout os=-aout
;; ;;
pdp10-*)
os=-tops20
;;
pdp11-*) pdp11-*)
os=-none os=-none
;; ;;
@@ -1127,7 +1311,7 @@ case $basic_machine in
*-masscomp) *-masscomp)
os=-rtu os=-rtu
;; ;;
f301-fujitsu) f30[01]-fujitsu | f700-fujitsu)
os=-uxpv os=-uxpv
;; ;;
*-rom68k) *-rom68k)
@@ -1187,7 +1371,7 @@ case $basic_machine in
-genix*) -genix*)
vendor=ns vendor=ns
;; ;;
-mvs*) -mvs* | -opened*)
vendor=ibm vendor=ibm
;; ;;
-ptx*) -ptx*)
@@ -1205,12 +1389,23 @@ case $basic_machine in
-mpw* | -macos*) -mpw* | -macos*)
vendor=apple vendor=apple
;; ;;
-*mint | -*MiNT) -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
vendor=atari vendor=atari
;; ;;
-vos*)
vendor=stratus
;;
esac esac
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;; ;;
esac esac
echo $basic_machine$os echo $basic_machine$os
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:

443
configure vendored
View File

@@ -16,13 +16,20 @@ ac_help="$ac_help
--with-user=USER Set the owner of installed files " --with-user=USER Set the owner of installed files "
ac_help="$ac_help ac_help="$ac_help
--with-group=GROUP Set the group owner of installed files " --with-group=GROUP Set the group owner of installed files "
ac_help="$ac_help
--with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] "
ac_help="$ac_help ac_help="$ac_help
--enable-jobs=NUM Number of jobs to run simultaneously" --enable-jobs=NUM Number of jobs to run simultaneously"
ac_help="$ac_help ac_help="$ac_help
--enable-static_link Use this to link the tools to the liblvm library --enable-static_link Use this to link the tools to the liblvm library
statically. Default is dynamic linking" statically. Default is dynamic linking"
ac_help="$ac_help ac_help="$ac_help
--disable-readline Disable readline support" --enable-readline Enable readline support"
ac_help="$ac_help
--enable-debug Enable debugging"
ac_help="$ac_help
--disable-devmapper Disable device-mapper interaction"
# Initialize some variables set by options. # Initialize some variables set by options.
# The variables have the same names as the options, with # The variables have the same names as the options, with
@@ -559,7 +566,7 @@ do
# Extract the first word of "$ac_prog", so it can be a program name with args. # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2 set dummy $ac_prog; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:563: checking for $ac_word" >&5 echo "configure:570: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -591,7 +598,7 @@ done
# Extract the first word of "gcc", so it can be a program name with args. # Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2 set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:595: checking for $ac_word" >&5 echo "configure:602: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -621,7 +628,7 @@ if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args. # Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2 set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:625: checking for $ac_word" >&5 echo "configure:632: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -672,7 +679,7 @@ fi
# Extract the first word of "cl", so it can be a program name with args. # Extract the first word of "cl", so it can be a program name with args.
set dummy cl; ac_word=$2 set dummy cl; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:676: checking for $ac_word" >&5 echo "configure:683: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -704,7 +711,7 @@ fi
fi fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
echo "configure:708: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 echo "configure:715: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -715,12 +722,12 @@ cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext << EOF cat > conftest.$ac_ext << EOF
#line 719 "configure" #line 726 "configure"
#include "confdefs.h" #include "confdefs.h"
main(){return(0);} main(){return(0);}
EOF EOF
if { (eval echo configure:724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
ac_cv_prog_cc_works=yes ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler. # If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then if (./conftest; exit) 2>/dev/null; then
@@ -746,12 +753,12 @@ if test $ac_cv_prog_cc_works = no; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "configure:757: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
echo "configure:755: checking whether we are using GNU C" >&5 echo "configure:762: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -760,7 +767,7 @@ else
yes; yes;
#endif #endif
EOF EOF
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:764: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:771: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes ac_cv_prog_gcc=yes
else else
ac_cv_prog_gcc=no ac_cv_prog_gcc=no
@@ -779,7 +786,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
ac_save_CFLAGS="$CFLAGS" ac_save_CFLAGS="$CFLAGS"
CFLAGS= CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
echo "configure:783: checking whether ${CC-cc} accepts -g" >&5 echo "configure:790: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -822,7 +829,7 @@ fi
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh. # ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
echo "configure:826: checking for a BSD compatible install" >&5 echo "configure:833: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
@@ -875,7 +882,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
echo "configure:879: checking whether ln -s works" >&5 echo "configure:886: checking whether ln -s works" >&5
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -896,7 +903,7 @@ else
fi fi
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
echo "configure:900: checking whether ${MAKE-make} sets \${MAKE}" >&5 echo "configure:907: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
@@ -925,7 +932,7 @@ fi
# Extract the first word of "ranlib", so it can be a program name with args. # Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2 set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:929: checking for $ac_word" >&5 echo "configure:936: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
@@ -958,12 +965,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
do do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
echo "configure:962: checking for $ac_hdr that defines DIR" >&5 echo "configure:969: checking for $ac_hdr that defines DIR" >&5
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 967 "configure" #line 974 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#include <$ac_hdr> #include <$ac_hdr>
@@ -971,7 +978,7 @@ int main() {
DIR *dirp = 0; DIR *dirp = 0;
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:975: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:982: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_header_dirent_$ac_safe=yes" eval "ac_cv_header_dirent_$ac_safe=yes"
else else
@@ -996,7 +1003,7 @@ done
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
if test $ac_header_dirent = dirent.h; then if test $ac_header_dirent = dirent.h; then
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
echo "configure:1000: checking for opendir in -ldir" >&5 echo "configure:1007: checking for opendir in -ldir" >&5
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
@@ -1004,7 +1011,7 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-ldir $LIBS" LIBS="-ldir $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1008 "configure" #line 1015 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
@@ -1015,7 +1022,7 @@ int main() {
opendir() opendir()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:1026: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
@@ -1037,7 +1044,7 @@ fi
else else
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
echo "configure:1041: checking for opendir in -lx" >&5 echo "configure:1048: checking for opendir in -lx" >&5
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
@@ -1045,7 +1052,7 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-lx $LIBS" LIBS="-lx $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1049 "configure" #line 1056 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
@@ -1056,7 +1063,7 @@ int main() {
opendir() opendir()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:1067: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
@@ -1079,7 +1086,7 @@ fi
fi fi
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
echo "configure:1083: checking how to run the C preprocessor" >&5 echo "configure:1090: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory. # On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then if test -n "$CPP" && test -d "$CPP"; then
CPP= CPP=
@@ -1094,13 +1101,13 @@ else
# On the NeXT, cc -E runs the code through the compiler's parser, # On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. # not just through cpp.
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1098 "configure" #line 1105 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <assert.h> #include <assert.h>
Syntax Error Syntax Error
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:1111: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
: :
@@ -1111,13 +1118,13 @@ else
rm -rf conftest* rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp" CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1115 "configure" #line 1122 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <assert.h> #include <assert.h>
Syntax Error Syntax Error
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1121: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:1128: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
: :
@@ -1128,13 +1135,13 @@ else
rm -rf conftest* rm -rf conftest*
CPP="${CC-cc} -nologo -E" CPP="${CC-cc} -nologo -E"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1132 "configure" #line 1139 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <assert.h> #include <assert.h>
Syntax Error Syntax Error
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1138: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:1145: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
: :
@@ -1159,12 +1166,12 @@ fi
echo "$ac_t""$CPP" 1>&6 echo "$ac_t""$CPP" 1>&6
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
echo "configure:1163: checking for ANSI C header files" >&5 echo "configure:1170: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1168 "configure" #line 1175 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
@@ -1172,7 +1179,7 @@ else
#include <float.h> #include <float.h>
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1176: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:1183: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
rm -rf conftest* rm -rf conftest*
@@ -1189,7 +1196,7 @@ rm -f conftest*
if test $ac_cv_header_stdc = yes; then if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI. # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1193 "configure" #line 1200 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <string.h> #include <string.h>
EOF EOF
@@ -1207,7 +1214,7 @@ fi
if test $ac_cv_header_stdc = yes; then if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1211 "configure" #line 1218 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <stdlib.h> #include <stdlib.h>
EOF EOF
@@ -1228,7 +1235,7 @@ if test "$cross_compiling" = yes; then
: :
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1232 "configure" #line 1239 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <ctype.h> #include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1239,7 +1246,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); } exit (0); }
EOF EOF
if { (eval echo configure:1243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null if { (eval echo configure:1250: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then then
: :
else else
@@ -1266,17 +1273,17 @@ for ac_hdr in fcntl.h malloc.h sys/ioctl.h unistd.h
do do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:1270: checking for $ac_hdr" >&5 echo "configure:1277: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1275 "configure" #line 1282 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <$ac_hdr> #include <$ac_hdr>
EOF EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1280: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } { (eval echo configure:1287: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then if test -z "$ac_err"; then
rm -rf conftest* rm -rf conftest*
@@ -1304,12 +1311,12 @@ done
echo $ac_n "checking for working const""... $ac_c" 1>&6 echo $ac_n "checking for working const""... $ac_c" 1>&6
echo "configure:1308: checking for working const" >&5 echo "configure:1315: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1313 "configure" #line 1320 "configure"
#include "confdefs.h" #include "confdefs.h"
int main() { int main() {
@@ -1358,7 +1365,7 @@ ccp = (char const *const *) p;
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1362: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:1369: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
ac_cv_c_const=yes ac_cv_c_const=yes
else else
@@ -1379,21 +1386,21 @@ EOF
fi fi
echo $ac_n "checking for inline""... $ac_c" 1>&6 echo $ac_n "checking for inline""... $ac_c" 1>&6
echo "configure:1383: checking for inline" >&5 echo "configure:1390: checking for inline" >&5
if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
ac_cv_c_inline=no ac_cv_c_inline=no
for ac_kw in inline __inline__ __inline; do for ac_kw in inline __inline__ __inline; do
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1390 "configure" #line 1397 "configure"
#include "confdefs.h" #include "confdefs.h"
int main() { int main() {
} int $ac_kw foo() { } int $ac_kw foo() {
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1397: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:1404: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
ac_cv_c_inline=$ac_kw; break ac_cv_c_inline=$ac_kw; break
else else
@@ -1419,12 +1426,12 @@ EOF
esac esac
echo $ac_n "checking for off_t""... $ac_c" 1>&6 echo $ac_n "checking for off_t""... $ac_c" 1>&6
echo "configure:1423: checking for off_t" >&5 echo "configure:1430: checking for off_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1428 "configure" #line 1435 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#if STDC_HEADERS #if STDC_HEADERS
@@ -1452,12 +1459,12 @@ EOF
fi fi
echo $ac_n "checking for pid_t""... $ac_c" 1>&6 echo $ac_n "checking for pid_t""... $ac_c" 1>&6
echo "configure:1456: checking for pid_t" >&5 echo "configure:1463: checking for pid_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1461 "configure" #line 1468 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#if STDC_HEADERS #if STDC_HEADERS
@@ -1485,12 +1492,12 @@ EOF
fi fi
echo $ac_n "checking for size_t""... $ac_c" 1>&6 echo $ac_n "checking for size_t""... $ac_c" 1>&6
echo "configure:1489: checking for size_t" >&5 echo "configure:1496: checking for size_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1494 "configure" #line 1501 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#if STDC_HEADERS #if STDC_HEADERS
@@ -1518,12 +1525,12 @@ EOF
fi fi
echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6 echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
echo "configure:1522: checking for st_rdev in struct stat" >&5 echo "configure:1529: checking for st_rdev in struct stat" >&5
if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1527 "configure" #line 1534 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -1531,7 +1538,7 @@ int main() {
struct stat s; s.st_rdev; struct stat s; s.st_rdev;
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:1542: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
ac_cv_struct_st_rdev=yes ac_cv_struct_st_rdev=yes
else else
@@ -1552,12 +1559,12 @@ EOF
fi fi
echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
echo "configure:1556: checking whether time.h and sys/time.h may both be included" >&5 echo "configure:1563: checking whether time.h and sys/time.h may both be included" >&5
if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1561 "configure" #line 1568 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
@@ -1566,7 +1573,7 @@ int main() {
struct tm *tp; struct tm *tp;
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1570: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:1577: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
ac_cv_header_time=yes ac_cv_header_time=yes
else else
@@ -1588,6 +1595,101 @@ fi
# Do some error checking and defaulting for the host and target type.
# The inputs are:
# configure --host=HOST --target=TARGET --build=BUILD NONOPT
#
# The rules are:
# 1. You are not allowed to specify --host, --target, and nonopt at the
# same time.
# 2. Host defaults to nonopt.
# 3. If nonopt is not specified, then host defaults to the current host,
# as determined by config.guess.
# 4. Target and build default to nonopt.
# 5. If nonopt is not specified, then target and build default to host.
# The aliases save the names the user supplied, while $host etc.
# will get canonicalized.
case $host---$target---$nonopt in
NONE---*---* | *---NONE---* | *---*---NONE) ;;
*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
esac
# Make sure we can run config.sub.
if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
fi
echo $ac_n "checking host system type""... $ac_c" 1>&6
echo "configure:1626: checking host system type" >&5
host_alias=$host
case "$host_alias" in
NONE)
case $nonopt in
NONE)
if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
fi ;;
*) host_alias=$nonopt ;;
esac ;;
esac
host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$host" 1>&6
echo $ac_n "checking target system type""... $ac_c" 1>&6
echo "configure:1647: checking target system type" >&5
target_alias=$target
case "$target_alias" in
NONE)
case $nonopt in
NONE) target_alias=$host_alias ;;
*) target_alias=$nonopt ;;
esac ;;
esac
target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$target" 1>&6
echo $ac_n "checking build system type""... $ac_c" 1>&6
echo "configure:1665: checking build system type" >&5
build_alias=$build
case "$build_alias" in
NONE)
case $nonopt in
NONE) build_alias=$host_alias ;;
*) build_alias=$nonopt ;;
esac ;;
esac
build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$build" 1>&6
test "$host_alias" != "$target_alias" &&
test "$program_prefix$program_suffix$program_transform_name" = \
NONENONEs,x,x, &&
program_prefix=${target_alias}-
case "$host_os" in
linux*)
CFLAGS= ;;
esac
# Check whether --with-user or --without-user was given. # Check whether --with-user or --without-user was given.
if test "${with_user+set}" = set; then if test "${with_user+set}" = set; then
@@ -1607,12 +1709,31 @@ else
fi fi
# Check whether --with-lvm1 or --without-lvm1 was given.
if test "${with_lvm1+set}" = set; then
withval="$with_lvm1"
LVM1="$withval"
else
LVM1="internal"
fi
if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
then { echo "configure: error: --with-lvm1 parameter invalid
" 1>&2; exit 1; }
exit
fi;
if test x$LVM1 = xinternal; then
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
fi
# Check whether --enable-jobs or --disable-jobs was given. # Check whether --enable-jobs or --disable-jobs was given.
if test "${enable_jobs+set}" = set; then if test "${enable_jobs+set}" = set; then
enableval="$enable_jobs" enableval="$enable_jobs"
JOBS=-j$enableval JOBS=-j$enableval
else else
JOBS= JOBS=-j2
fi fi
@@ -1631,23 +1752,51 @@ if test "${enable_readline+set}" = set; then
\ \
READLINE=$enableval READLINE=$enableval
else else
READLINE=yes READLINE=no
fi fi
if test x$READLINE = xyes; then
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
fi
# Check whether --enable-debug or --disable-debug was given.
if test "${enable_debug+set}" = set; then
enableval="$enable_debug"
\
DEBUG=yes
else
DEBUG=no
fi
# Check whether --enable-devmapper or --disable-devmapper was given.
if test "${enable_devmapper+set}" = set; then
enableval="$enable_devmapper"
\
DEVMAPPER=no
else
DEVMAPPER=yes
fi
if test x$DEVMAPPER = xyes; then
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
fi
if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]; if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ];
then exec_prefix=""; then exec_prefix="";
fi; fi;
if test $ac_cv_prog_gcc = yes; then if test $ac_cv_prog_gcc = yes; then
echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
echo "configure:1645: checking whether ${CC-cc} needs -traditional" >&5 echo "configure:1794: checking whether ${CC-cc} needs -traditional" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
ac_pattern="Autoconf.*'x'" ac_pattern="Autoconf.*'x'"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1651 "configure" #line 1800 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sgtty.h> #include <sgtty.h>
Autoconf TIOCGETP Autoconf TIOCGETP
@@ -1665,7 +1814,7 @@ rm -f conftest*
if test $ac_cv_prog_gcc_traditional = no; then if test $ac_cv_prog_gcc_traditional = no; then
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1669 "configure" #line 1818 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <termio.h> #include <termio.h>
Autoconf TCGETA Autoconf TCGETA
@@ -1687,12 +1836,12 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
fi fi
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
echo "configure:1691: checking return type of signal handlers" >&5 echo "configure:1840: checking return type of signal handlers" >&5
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1696 "configure" #line 1845 "configure"
#include "confdefs.h" #include "confdefs.h"
#include <sys/types.h> #include <sys/types.h>
#include <signal.h> #include <signal.h>
@@ -1709,7 +1858,7 @@ int main() {
int i; int i;
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1713: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if { (eval echo configure:1862: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest* rm -rf conftest*
ac_cv_type_signal=void ac_cv_type_signal=void
else else
@@ -1728,12 +1877,12 @@ EOF
echo $ac_n "checking for vprintf""... $ac_c" 1>&6 echo $ac_n "checking for vprintf""... $ac_c" 1>&6
echo "configure:1732: checking for vprintf" >&5 echo "configure:1881: checking for vprintf" >&5
if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1737 "configure" #line 1886 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char vprintf(); below. */ which can conflict with char vprintf(); below. */
@@ -1756,7 +1905,7 @@ vprintf();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:1909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_vprintf=yes" eval "ac_cv_func_vprintf=yes"
else else
@@ -1780,12 +1929,12 @@ fi
if test "$ac_cv_func_vprintf" != yes; then if test "$ac_cv_func_vprintf" != yes; then
echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
echo "configure:1784: checking for _doprnt" >&5 echo "configure:1933: checking for _doprnt" >&5
if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1789 "configure" #line 1938 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char _doprnt(); below. */ which can conflict with char _doprnt(); below. */
@@ -1808,7 +1957,7 @@ _doprnt();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:1961: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func__doprnt=yes" eval "ac_cv_func__doprnt=yes"
else else
@@ -1835,12 +1984,12 @@ fi
for ac_func in mkdir rmdir uname for ac_func in mkdir rmdir uname
do do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:1839: checking for $ac_func" >&5 echo "configure:1988: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1844 "configure" #line 1993 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */ which can conflict with char $ac_func(); below. */
@@ -1863,7 +2012,7 @@ $ac_func();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1867: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:2016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_$ac_func=yes" eval "ac_cv_func_$ac_func=yes"
else else
@@ -1891,14 +2040,14 @@ done
if test x$READLINE = xyes; then if test x$READLINE = xyes; then
echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6 echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6
echo "configure:1895: checking for library containing tgetent" >&5 echo "configure:2044: checking for library containing tgetent" >&5
if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
ac_func_search_save_LIBS="$LIBS" ac_func_search_save_LIBS="$LIBS"
ac_cv_search_tgetent="no" ac_cv_search_tgetent="no"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1902 "configure" #line 2051 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
@@ -1909,7 +2058,7 @@ int main() {
tgetent() tgetent()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:2062: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
ac_cv_search_tgetent="none required" ac_cv_search_tgetent="none required"
else else
@@ -1920,7 +2069,7 @@ rm -f conftest*
test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do
LIBS="-l$i $ac_func_search_save_LIBS" LIBS="-l$i $ac_func_search_save_LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1924 "configure" #line 2073 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
@@ -1931,7 +2080,7 @@ int main() {
tgetent() tgetent()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:2084: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
ac_cv_search_tgetent="-l$i" ac_cv_search_tgetent="-l$i"
break break
@@ -1963,9 +2112,97 @@ Note: (n)curses also seems to work as a substitute for termcap. This was
fi fi
fi fi
echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
echo "configure:2117: checking for dlopen in -ldl" >&5
ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_save_LIBS="$LIBS"
LIBS="-ldl $LIBS"
cat > conftest.$ac_ext <<EOF
#line 2125 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char dlopen();
int main() {
dlopen()
; return 0; }
EOF
if { (eval echo configure:2136: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=no"
fi
rm -f conftest*
LIBS="$ac_save_LIBS"
fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
echo "$ac_t""yes" 1>&6
HAVE_LIBDL=yes
else
echo "$ac_t""no" 1>&6
HAVE_LIBDL=no
fi
if test x$HAVE_LIBDL = xyes; then
CFLAGS="$CFLAGS -DHAVE_LIBDL"
LIBS="-ldl $LIBS"
fi
for ac_hdr in getopt.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:2167: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2172 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2177: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
eval "ac_cv_header_$ac_safe=yes"
else
echo "$ac_err" >&5
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
eval "ac_cv_header_$ac_safe=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
cat >> confdefs.h <<EOF
#define $ac_tr_hdr 1
EOF
CFLAGS="$CFLAGS -DHAVE_GETOPTLONG"
else
echo "$ac_t""no" 1>&6
fi
done
if test x$READLINE = xyes; then if test x$READLINE = xyes; then
echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
echo "configure:1969: checking for readline in -lreadline" >&5 echo "configure:2206: checking for readline in -lreadline" >&5
ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
@@ -1973,7 +2210,7 @@ else
ac_save_LIBS="$LIBS" ac_save_LIBS="$LIBS"
LIBS="-lreadline $LIBS" LIBS="-lreadline $LIBS"
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 1977 "configure" #line 2214 "configure"
#include "confdefs.h" #include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */ /* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2 /* We use char because int might match the return type of a gcc2
@@ -1984,7 +2221,7 @@ int main() {
readline() readline()
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:2225: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes" eval "ac_cv_lib_$ac_lib_var=yes"
else else
@@ -2021,12 +2258,12 @@ package as well (which may be called readline-devel or something similar).
fi fi
echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6 echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6
echo "configure:2025: checking for rl_completion_matches" >&5 echo "configure:2262: checking for rl_completion_matches" >&5
if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6 echo $ac_n "(cached) $ac_c" 1>&6
else else
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 2030 "configure" #line 2267 "configure"
#include "confdefs.h" #include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes, /* System header to define __stub macros and hopefully few prototypes,
which can conflict with char rl_completion_matches(); below. */ which can conflict with char rl_completion_matches(); below. */
@@ -2049,7 +2286,7 @@ rl_completion_matches();
; return 0; } ; return 0; }
EOF EOF
if { (eval echo configure:2053: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then if { (eval echo configure:2290: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest* rm -rf conftest*
eval "ac_cv_func_rl_completion_matches=yes" eval "ac_cv_func_rl_completion_matches=yes"
else else
@@ -2063,12 +2300,12 @@ fi
if eval "test \"`echo '$ac_cv_func_'rl_completion_matches`\" = yes"; then if eval "test \"`echo '$ac_cv_func_'rl_completion_matches`\" = yes"; then
echo "$ac_t""yes" 1>&6 echo "$ac_t""yes" 1>&6
HAVE_RL_COMPLETION_MATCHES=yes CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES"
else else
echo "$ac_t""no" 1>&6 echo "$ac_t""no" 1>&6
HAVE_RL_COMPLETION_MATCHES=no
fi fi
fi fi
if test "-f VERSION"; then if test "-f VERSION"; then
@@ -2085,6 +2322,9 @@ fi
trap '' 1 2 15 trap '' 1 2 15
cat > confcache <<\EOF cat > confcache <<\EOF
# This file is a shell script that caches the results of configure # This file is a shell script that caches the results of configure
@@ -2203,6 +2443,7 @@ Makefile \
make.tmpl \ make.tmpl \
include/Makefile \ include/Makefile \
lib/Makefile \ lib/Makefile \
lib/format1/Makefile \
man/Makefile \ man/Makefile \
tools/Makefile \ tools/Makefile \
tools/version.h \ tools/version.h \
@@ -2252,13 +2493,30 @@ s%@LN_S@%$LN_S%g
s%@SET_MAKE@%$SET_MAKE%g s%@SET_MAKE@%$SET_MAKE%g
s%@RANLIB@%$RANLIB%g s%@RANLIB@%$RANLIB%g
s%@CPP@%$CPP%g s%@CPP@%$CPP%g
s%@host@%$host%g
s%@host_alias@%$host_alias%g
s%@host_cpu@%$host_cpu%g
s%@host_vendor@%$host_vendor%g
s%@host_os@%$host_os%g
s%@target@%$target%g
s%@target_alias@%$target_alias%g
s%@target_cpu@%$target_cpu%g
s%@target_vendor@%$target_vendor%g
s%@target_os@%$target_os%g
s%@build@%$build%g
s%@build_alias@%$build_alias%g
s%@build_cpu@%$build_cpu%g
s%@build_vendor@%$build_vendor%g
s%@build_os@%$build_os%g
s%@JOBS@%$JOBS%g s%@JOBS@%$JOBS%g
s%@STATIC_LINK@%$STATIC_LINK%g s%@STATIC_LINK@%$STATIC_LINK%g
s%@READLINE@%$READLINE%g s%@LVM1@%$LVM1%g
s%@HAVE_RL_COMPLETION_MATCHES@%$HAVE_RL_COMPLETION_MATCHES%g
s%@OWNER@%$OWNER%g s%@OWNER@%$OWNER%g
s%@GROUP@%$GROUP%g s%@GROUP@%$GROUP%g
s%@LVM_VERSION@%$LVM_VERSION%g s%@LVM_VERSION@%$LVM_VERSION%g
s%@DEBUG@%$DEBUG%g
s%@DEVMAPPER@%$DEVMAPPER%g
s%@HAVE_LIBDL@%$HAVE_LIBDL%g
CEOF CEOF
EOF EOF
@@ -2305,6 +2563,7 @@ Makefile \
make.tmpl \ make.tmpl \
include/Makefile \ include/Makefile \
lib/Makefile \ lib/Makefile \
lib/format1/Makefile \
man/Makefile \ man/Makefile \
tools/Makefile \ tools/Makefile \
tools/version.h \ tools/version.h \

View File

@@ -46,6 +46,14 @@ AC_TYPE_SIZE_T
AC_STRUCT_ST_RDEV AC_STRUCT_ST_RDEV
AC_HEADER_TIME AC_HEADER_TIME
dnl Get system type
AC_CANONICAL_SYSTEM
case "$host_os" in
linux*)
CFLAGS= ;;
esac
dnl -- prefix is /usr by default, the exec_prefix default is setup later dnl -- prefix is /usr by default, the exec_prefix default is setup later
AC_PREFIX_DEFAULT(/usr) AC_PREFIX_DEFAULT(/usr)
@@ -61,15 +69,49 @@ AC_ARG_WITH(group,
[ GROUP="$withval" ], [ GROUP="$withval" ],
[ GROUP="root" ]) [ GROUP="root" ])
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=) dnl -- format1 inclusion type
AC_ARG_WITH(lvm1,
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] ],
[ LVM1="$withval" ],
[ LVM1="internal" ])
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
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
fi
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
dnl Enables staticly linked tools dnl Enables staticly linked tools
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no) statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
dnl Disable readline dnl Enable readline
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \ AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
READLINE=$enableval, READLINE=yes) READLINE=$enableval, READLINE=no)
if test x$READLINE = xyes; then
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
fi
dnl Enable Debugging
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging], \
DEBUG=yes, DEBUG=no)
dnl Disable devmapper
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction], \
DEVMAPPER=no, DEVMAPPER=yes)
if test x$DEVMAPPER = xyes; then
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
fi
dnl Mess with default exec_prefix dnl Mess with default exec_prefix
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]]; if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -99,6 +141,17 @@ Note: (n)curses also seems to work as a substitute for termcap. This was
) )
fi fi
dnl Check for dlopen
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
if test x$HAVE_LIBDL = xyes; then
CFLAGS="$CFLAGS -DHAVE_LIBDL"
LIBS="-ldl $LIBS"
fi
dnl Check for getopt
AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG")
dnl Check for readline (Shamelessly copied from parted 1.4.17) dnl Check for readline (Shamelessly copied from parted 1.4.17)
if test x$READLINE = xyes; then if test x$READLINE = xyes; then
AC_CHECK_LIB(readline, readline, , AC_CHECK_LIB(readline, readline, ,
@@ -112,8 +165,8 @@ package as well (which may be called readline-devel or something similar).
) )
exit exit
) )
AC_CHECK_FUNC(rl_completion_matches, HAVE_RL_COMPLETION_MATCHES=yes, AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
HAVE_RL_COMPLETION_MATCHES=no)
fi fi
if test "-f VERSION"; then if test "-f VERSION"; then
@@ -124,12 +177,15 @@ fi
AC_SUBST(JOBS) AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK) AC_SUBST(STATIC_LINK)
AC_SUBST(READLINE) AC_SUBST(LVM1)
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
AC_SUBST(OWNER) AC_SUBST(OWNER)
AC_SUBST(GROUP) AC_SUBST(GROUP)
AC_SUBST(CFLAGS)
AC_SUBST(LIBS) AC_SUBST(LIBS)
AC_SUBST(LVM_VERSION) AC_SUBST(LVM_VERSION)
AC_SUBST(DEBUG)
AC_SUBST(DEVMAPPER)
AC_SUBST(HAVE_LIBDL)
dnl First and last lines should not contain files to generate in order to dnl First and last lines should not contain files to generate in order to
dnl keep utility scripts running properly dnl keep utility scripts running properly
AC_OUTPUT( \ AC_OUTPUT( \
@@ -137,6 +193,7 @@ Makefile \
make.tmpl \ make.tmpl \
include/Makefile \ include/Makefile \
lib/Makefile \ lib/Makefile \
lib/format1/Makefile \
man/Makefile \ man/Makefile \
tools/Makefile \ tools/Makefile \
tools/version.h \ tools/version.h \

6
debian/README.Debian vendored Normal file
View File

@@ -0,0 +1,6 @@
LVM2 requires the device-mapper kernel module (dm-mod). This is
available as a kernel patch for 2.4 (in kernel-patch-device-mapper), and
is distributed with linux 2.5 and above. The LVM1 kernel module (lvm-mod)
will not work with lvm2 packages. dm-mod and lvm-mod may both be loaded
in the kernel at the same time with no problems. Without dm-mod, this
package is pretty useless.

38
debian/changelog vendored
View File

@@ -1,8 +1,40 @@
lvm2 (1.95.08-1) unstable; urgency=low lvm2 (1.95.15-1) unstable; urgency=low
* New upstream release.
* Remove undocumented manpage symlinks.
* Update description to be more informative. (Closes: #173499)
* Add kernel-patch-device-mapper suggestion.
* Update standards version.
* New upstream release (Beta3). -- Andres Salomon <dilinger@mp3revolution.net> Sun, 16 Feb 2002 04:21:26 -0400
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 23 May 2002 03:46:37 -0500 lvm2 (1.95.11-1) unstable; urgency=low
* New upstream release. (Closes: #171436)
* Removed TODO and INTRO from debian/docs; added WHATS_NEW.
* Remove vgcfgrestore.8 undocumented symlink.
* Added a README.Debian, mentioning the device-mapper kernel module
requirement that lvm2 has. (Closes: #171674, #163020)
* Get rid of debian/conffiles (debhelper's smart enough to figure that out).
* debian/copyright fix to appease lintian.
* Fix typo in tools/commands.h that caused /usr/sbin/; to be created.
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 9 Dec 2002 02:51:02 -0400
lvm2 (1.95.10-2) unstable; urgency=low
* Fix software raid problems by ensuring lvm init script runs after
raidtools init script. (Closes: #152569)
-- Andres Salomon <dilinger@mp3revolution.net> Tue, 3 Sep 2002 04:05:43 -0400
lvm2 (1.95.10-1) unstable; urgency=low
* New upstream release (Beta 3.2).
* Change all references to /dev/device-mapper/control to
/dev/mapper/control.
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 1 Sep 2002 18:55:12 -0400
lvm2 (0.95.05-3) unstable; urgency=low lvm2 (0.95.05-3) unstable; urgency=low

2
debian/conffiles vendored
View File

@@ -1,2 +0,0 @@
/etc/lvm/lvm.conf
/etc/init.d/lvm2

10
debian/control vendored
View File

@@ -2,8 +2,8 @@ Source: lvm2
Section: admin Section: admin
Priority: optional Priority: optional
Maintainer: Andres Salomon <dilinger@mp3revolution.net> Maintainer: Andres Salomon <dilinger@mp3revolution.net>
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
Standards-Version: 3.5.2 Standards-Version: 3.5.8.0
Package: lvm2 Package: lvm2
Architecture: any Architecture: any
@@ -11,10 +11,14 @@ Depends: ${shlibs:Depends}
Conflicts: lvm10, lvm-common Conflicts: lvm10, lvm-common
Replaces: lvm10, lvm-common Replaces: lvm10, lvm-common
Provides: lvm-binaries Provides: lvm-binaries
Suggests: dmsetup Suggests: dmsetup, kernel-patch-device-mapper
Description: The Linux Logical Volume Manager Description: The Linux Logical Volume Manager
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
supports enterprise level volume management of disk and disk subsystems supports enterprise level volume management of disk and disk subsystems
by grouping arbitrary disks into volume groups. The total capacity of by grouping arbitrary disks into volume groups. The total capacity of
volume groups can be allocated to logical volumes, which are accessed as volume groups can be allocated to logical volumes, which are accessed as
regular block devices. regular block devices.
.
LVM2 is currently stable, but has some unimplemented features (most notably,
pvmove and e2fsadm). It is not yet recommended for production use. It is
backwards-compatible with LVM1 (lvm10), and requires Linux kernel 2.4.

2
debian/copyright vendored
View File

@@ -3,7 +3,7 @@ Wed, 20 Feb 2002 03:17:25 -0500.
It was downloaded from http://www.sistina.com/products_lvm.htm It was downloaded from http://www.sistina.com/products_lvm.htm
Upstream Author(s): LVM Development Team Upstream Author: LVM Development Team
Copyright (c) 2001-2002 LVM Development Team Copyright (c) 2001-2002 LVM Development Team

3
debian/docs vendored
View File

@@ -1,6 +1,5 @@
BUGS BUGS
INTRO
README README
TODO
VERSION VERSION
WHATS_NEW
doc/* doc/*

8
debian/init.d vendored
View File

@@ -14,7 +14,7 @@ modprobe dm-mod >/dev/null 2>&1
# Create necessary files in /dev for device-mapper # Create necessary files in /dev for device-mapper
create_devfiles() { create_devfiles() {
DIR="/dev/device-mapper" DIR="/dev/mapper"
FILE="$DIR/control" FILE="$DIR/control"
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//') major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//') minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
@@ -33,6 +33,12 @@ case "$1" in
echo -n "Initializing $DESC: " echo -n "Initializing $DESC: "
create_devfiles create_devfiles
vgchange -a y vgchange -a y
# # Mount all LVM devices
# for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do
# MTPT=$( grep $vg /etc/fstab | awk '{print $2}' )
# mount $MTPT
# done
echo "$NAME." echo "$NAME."
;; ;;
stop) stop)

3
debian/rules vendored
View File

@@ -98,11 +98,10 @@ binary-arch: build install
# dh_installemacsen -a # dh_installemacsen -a
# dh_installpam -a # dh_installpam -a
# dh_installmime -a # dh_installmime -a
dh_installinit --update-rcd-params="start 25 S . start 50 0 6 ." dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
dh_installcron dh_installcron
dh_installman dh_installman
dh_installinfo dh_installinfo
dh_undocumented
dh_installchangelogs dh_installchangelogs
dh_strip dh_strip
dh_link dh_link

14
debian/undocumented vendored
View File

@@ -1,14 +0,0 @@
e2fsadm.8
lvmdiskscan.8
lvmsadc.8
lvmsar.8
lvresize.8
pvdata.8
pvmove.8
pvresize.8
version.8
vgcfgrestore.8
vgexport.8
vgimport.8
vgmknodes.8
vgsplit.8

View File

@@ -1,74 +1,94 @@
# This is an example configuration file for the LVM2 system. It # This is an example configuration file for the LVM2 system.
# contains the default settings that would be used if there was no # It contains the default settings that would be used if there was no
# /etc/lvm/lvm.conf file. # /etc/lvm/lvm.conf file.
# Refer to 'man lvm.conf' for further information. #
# Refer to 'man lvm.conf' for further information including the file layout.
#
# To put this file in a different directory and override /etc/lvm set
# the environment variable LVM_SYSTEM_DIR before running the tools.
# This section allows the user to configure which block devices should # This section allows you to configure which block devices should
# be used by the LVM system. # be used by the LVM system.
devices { devices {
# where do you want your volume groups to appear ? # Where do you want your volume groups to appear ?
dir = "/dev" dir = "/dev"
# An array of directories that contain the device nodes you wish # An array of directories that contain the device nodes you wish
# to use with LVM2. # to use with LVM2.
scan = "/dev" scan = [ "/dev" ]
# A very important option, that allows you to tune the LVM2 system
# to just look at a restricted set of devices that you're
# interested in.
# A filter that tells LVM2 to only use a restricted set of devices.
# The filter consists of an array of regular expressions. These # The filter consists of an array of regular expressions. These
# expressions can be delimited by a character of your choice, and # expressions can be delimited by a character of your choice, and
# prefixed with either an 'a' (for accept) or 'r' (for reject). # prefixed with either an 'a' (for accept) or 'r' (for reject).
# ATM you cannot use anchors (^ or $) in your regular expression. # The first expression found to match a device name determines if
# 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. # If using RAID md devices as physical volumes, you should
# set up a filter here to reject the constituent devices.
# Remember to run vgscan after you change this parameter to ensure
# that the cache file gets regenerated (see below).
# By default we accept every block device: # By default we accept every block device:
filter = "a/.*/" filter = [ "a/.*/" ]
# Exclude the cdrom drive
# filter = [ "r|/dev/cdrom|" ]
# When testing I like to work with just loopback devices: # When testing I like to work with just loopback devices:
# filter = ["a/loop/", "r/.*/"] # filter = [ "a/loop/", "r/.*/" ]
# Or maybe all loops and ide drives except hdc: # Or maybe all loops and ide drives except hdc:
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"] # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
# The results of all the filtering are cached on disk to avoid # Use anchors if you want to be really specific
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
# The results of the filtering are cached on disk to avoid
# rescanning dud devices (which can take a very long time). By # rescanning dud devices (which can take a very long time). By
# default this cache file is hidden in the /etc/lvm directory, it # default this cache file is hidden in the /etc/lvm directory.
# is human readable to aid filter debugging. # It is safe to delete this file: the tools regenerate it.
cache = "/etc/lvm/.cache" cache = "/etc/lvm/.cache"
# You can turn off writing this cache file by setting this to 0. # You can turn off writing this cache file by setting this to 0.
write_cache_state = 1 write_cache_state = 1
# An advanced setting.
# List of pairs of additional acceptable block device types found
# in /proc/devices with maximum (non-zero) number of partitions.
# types = [ "fd", 16 ]
} }
# A section that allows the user to configure the nature of the # This section that allows you to configure the nature of the
# information that LVM2 reports. # information that LVM2 reports.
log { log {
# Where should the log of error and debug messages go ? By # Controls the messages sent to stdout or stderr.
# default there is no log. # There are three levels of verbosity, 3 being the most verbose.
#file = "/var/log/lvm2.log"
# Should we overwrite the last log. By default we append.
overwrite = 0
# There are 9 log levels, with 9 being the most verbose.
level = 3
# Controls the messages sent to stdout or stderr while running
# LVM2. There are three levels of verbosity, 3 being the most
# verbose.
verbose = 0 verbose = 0
# Should we send log messages through syslog? # Should we send log messages through syslog?
# 1 is yes; 0 is no. # 1 is yes; 0 is no.
syslog = 1 syslog = 1
# Choose format of output messages # Should we log error and debug messages to a file?
# By default there is no log file.
#file = "/var/log/lvm2.log"
# Should we overwrite the log file each time the program is run?
# By default we append.
overwrite = 0
# What level of log messages should we send to the log file and/or syslog?
# There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
# 7 is the most verbose (LOG_DEBUG).
level = 0
# Format of output messages
# Whether or not (1 or 0) to indent messages according to their severity # Whether or not (1 or 0) to indent messages according to their severity
indent = 1 indent = 1
@@ -76,13 +96,18 @@ log {
command_names = 0 command_names = 0
# A prefix to use before the message text (but after the command name, # A prefix to use before the message text (but after the command name,
# if selected) # if selected). Default is two spaces, so you can see/grep the severity
# of each message.
prefix = " " prefix = " "
# To make the messages look similar to the original LVM use: # To make the messages look similar to the original LVM tools use:
# indent = 0 # indent = 0
# command_names = 1 # command_names = 1
# prefix = " -- " # prefix = " -- "
# Set this if you want log messages during activation.
# Don't use this in low memory situations (can deadlock).
# activation = 0
} }
# Configuration of metadata backups and archiving. In LVM2 when we # Configuration of metadata backups and archiving. In LVM2 when we
@@ -93,19 +118,20 @@ backup {
# Should we maintain a backup of the current metadata configuration ? # Should we maintain a backup of the current metadata configuration ?
# Use 1 for Yes; 0 for No. # Use 1 for Yes; 0 for No.
# Think very hard before turning this off. # Think very hard before turning this off!
backup = 1 backup = 1
# Where shall we keep it ? # Where shall we keep it ?
# Remember to back up this directory regularly!
backup_dir = "/etc/lvm/backup" backup_dir = "/etc/lvm/backup"
# Should we maintain an archive of old metadata configurations. # Should we maintain an archive of old metadata configurations.
# Use 1 for Yes; 0 for No. # Use 1 for Yes; 0 for No.
# On by default. Think very hard before turning this off. # On by default. Think very hard before turning this off.
archive = 1 archive = 1
# Where should archived files go ? # Where should archived files go ?
# Remember to back up this directory regularly!
archive_dir = "/etc/lvm/archive" archive_dir = "/etc/lvm/archive"
# What is the minimum number of archive files you wish to keep ? # What is the minimum number of archive files you wish to keep ?
@@ -115,20 +141,15 @@ backup {
retain_days = 30 retain_days = 30
} }
# Settings for the running LVM2 in shell mode. # Settings for the running LVM2 in shell (readline) mode.
shell { shell {
# Number of lines of history to store in ~/.lvm_history # Number of lines of history to store in ~/.lvm_history
history_size = 100 history_size = 100
} }
# Metadata settings
metadata {
# List of directories holding copies of text format metadata
dirs = [ "/etc/lvm/metadata" ]
}
# Miscellaneous global settings # Miscellaneous global LVM2 settings
global { global {
# The file creation mask for any files and directories created. # The file creation mask for any files and directories created.
@@ -143,10 +164,94 @@ global {
# command. Defaults to off. # command. Defaults to off.
test = 0 test = 0
# Default metadata format commands use - "lvm1" (default) or "text" # Whether or not to communicate with the kernel device-mapper.
format = "lvm1" # Set to 0 if you want to use the tools to manipulate LVM metadata
# without activating any logical volumes.
# If the device-mapper kernel driver is not present in your kernel
# setting this to 0 should suppress the error messages.
activation = 1
# The default metadata format that commands should use - "lvm1" or "lvm2".
# The command line override is -M1 or -M2.
# Defaults to "lvm1" if compiled in, else "lvm2".
# format = "lvm1"
# Location of proc filesystem # Location of proc filesystem
proc = "/proc" proc = "/proc"
# Type of locking to use. Defaults to file-based locking (1).
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
# if LVM2 commands get run concurrently).
locking_type = 1
# Local non-LV directory that holds file-based locks while commands are
# in progress. A directory like /tmp that may get wiped on reboot is OK.
locking_dir = "/var/lock/lvm"
# Other entries can go here to allow you to load shared libraries
# e.g. if support for LVM1 metadata was compiled as a shared library use
# format_libraries = "liblvm2format1.so"
# Full pathnames can be given.
# Search this directory first for shared libraries.
# library_dir = "/lib"
} }
activation {
# Device used in place of missing stripes if activating incomplete volume.
# For now, you need to set this up yourself first (e.g. with 'dmsetup')
# For example, you could make it return I/O errors using the 'error'
# target or make it return zeros.
missing_stripe_filler = "/dev/ioerror"
# Size (in KB) of each copy operation when mirroring
mirror_region_size = 512
# How much stack (in KB) to reserve for use while devices suspended
reserved_stack = 256
# How much memory (in KB) to reserve for use while devices suspended
reserved_memory = 8192
# Nice value used while devices suspended
process_priority = -18
}
####################
# Advanced section #
####################
# Metadata settings
#
# 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
# when running pvcreate on new PVs which are to be added to large VGs.
# pvmetadatacopies = 2
# Approximate default size of on-disk metadata areas in sectors.
# You should increase this if you have large volume groups or
# you want to retain a large on-disk history of your metadata changes.
# pvmetadatasize = 255
# List of directories holding live copies of text format metadata.
# These directories must not be on logical volumes!
# It's possible to use LVM2 with a couple of directories here,
# preferably on different (non-LV) filesystems, and with no other
# on-disk metadata (pvmetadatacopies = 0). Or this can be in
# addition to on-disk metadata areas.
# The feature was originally added to simplify testing and is not
# supported under low memory situations - the machine could lock up.
#
# Never edit any files in these directories by hand unless you
# you are absolutely sure you know what you are doing! Use
# the supplied toolset to make changes (e.g. vgcfgrestore).
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
#}

View File

@@ -1,4 +1,5 @@
../lib/activate/activate.h ../lib/activate/activate.h
../lib/cache/lvmcache.h
../lib/commands/errors.h ../lib/commands/errors.h
../lib/commands/toolcontext.h ../lib/commands/toolcontext.h
../lib/config/config.h ../lib/config/config.h
@@ -16,18 +17,21 @@
../lib/filters/filter-regex.h ../lib/filters/filter-regex.h
../lib/filters/filter.h ../lib/filters/filter.h
../lib/format1/format1.h ../lib/format1/format1.h
../lib/format1/lvm1_label.h ../lib/format1/lvm1-label.h
../lib/format_text/format-text.h ../lib/format_text/format-text.h
../lib/label/label.h ../lib/label/label.h
../lib/label/uuid-map.h
../lib/locking/locking.h ../lib/locking/locking.h
../lib/log/log.h ../lib/log/log.h
../lib/metadata/metadata.h ../lib/metadata/metadata.h
../lib/mm/dbg_malloc.h ../lib/mm/dbg_malloc.h
../lib/mm/memlock.h
../lib/mm/pool.h ../lib/mm/pool.h
../lib/mm/xlate.h ../lib/mm/xlate.h
../lib/misc/crc.h
../lib/misc/lib.h
../lib/misc/lvm-file.h ../lib/misc/lvm-file.h
../lib/misc/lvm-string.h ../lib/misc/lvm-string.h
../lib/misc/sharedlib.h
../lib/regex/matcher.h ../lib/regex/matcher.h
../lib/report/report.h
../lib/uuid/uuid.h ../lib/uuid/uuid.h
../lib/vgcache/vgcache.h

View File

@@ -8,10 +8,14 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
ifeq ("@LVM1@", "shared")
SUBDIRS = format1
endif
SOURCES=\ SOURCES=\
activate/activate.c \ activate/activate.c \
activate/dev_manager.c \ cache/lvmcache.c \
activate/fs.c \ commands/toolcontext.c \
config/config.c \ config/config.c \
datastruct/bitset.c \ datastruct/bitset.c \
datastruct/btree.c \ datastruct/btree.c \
@@ -24,21 +28,14 @@ SOURCES=\
filters/filter-persistent.c \ filters/filter-persistent.c \
filters/filter-regex.c \ filters/filter-regex.c \
filters/filter.c \ filters/filter.c \
format1/disk-rep.c \
format1/format1.c \
format1/import-export.c \
format1/import-extents.c \
format1/layout.c \
format1/lvm1_label.c \
format1/vg_number.c \
format_text/archive.c \ format_text/archive.c \
format_text/export.c \ format_text/export.c \
format_text/flags.c \ format_text/flags.c \
format_text/format-text.c \ format_text/format-text.c \
format_text/import.c \ format_text/import.c \
format_text/import_vsn1.c \
format_text/text_label.c \
label/label.c \ label/label.c \
label/uuid-map.c \
locking/external_locking.c \
locking/file_locking.c \ locking/file_locking.c \
locking/locking.c \ locking/locking.c \
locking/no_locking.c \ locking/no_locking.c \
@@ -46,16 +43,47 @@ SOURCES=\
metadata/lv_manip.c \ metadata/lv_manip.c \
metadata/merge.c \ metadata/merge.c \
metadata/metadata.c \ metadata/metadata.c \
metadata/mirror.c \
metadata/pv_map.c \ metadata/pv_map.c \
metadata/snapshot_manip.c \ metadata/snapshot_manip.c \
misc/crc.c \
misc/lvm-file.c \ misc/lvm-file.c \
mm/dbg_malloc.c \ misc/lvm-string.c \
mm/memlock.c \
mm/pool.c \ mm/pool.c \
regex/matcher.c \ regex/matcher.c \
regex/parse_rx.c \ regex/parse_rx.c \
regex/ttree.c \ regex/ttree.c \
uuid/uuid.c \ report/report.c \
vgcache/vgcache.c uuid/uuid.c
ifeq ("@LVM1@", "internal")
SOURCES+=\
format1/disk-rep.c \
format1/format1.c \
format1/import-export.c \
format1/import-extents.c \
format1/layout.c \
format1/lvm1-label.c \
format1/vg_number.c
endif
ifeq ("@DEBUG@", "yes")
SOURCES+=\
mm/dbg_malloc.c
endif
ifeq ("@DEVMAPPER@", "yes")
SOURCES+=\
activate/dev_manager.c \
activate/fs.c
endif
ifeq ("@HAVE_LIBDL@", "yes")
SOURCES+=\
locking/external_locking.c \
misc/sharedlib.c
endif
TARGETS=liblvm.a TARGETS=liblvm.a

View File

@@ -4,27 +4,112 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "metadata.h" #include "metadata.h"
#include "activate.h" #include "activate.h"
#include "memlock.h"
#include "display.h" #include "display.h"
#include "log.h"
#include "fs.h" #include "fs.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "pool.h" #include "pool.h"
#include "toolcontext.h" #include "toolcontext.h"
#include "dev_manager.h" #include "dev_manager.h"
/* FIXME Temporary */
#include "vgcache.h"
#include <limits.h> #include <limits.h>
#include <linux/kdev_t.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
#ifndef DEVMAPPER_SUPPORT
void set_activation(int act)
{
if (act)
log_error("Compiled without libdevmapper support. "
"Can't enable activation.");
}
int activation(void)
{
return 0;
}
int library_version(char *version, size_t size) int library_version(char *version, size_t size)
{ {
return 0;
}
int driver_version(char *version, size_t size)
{
return 0;
}
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
{
return 0;
}
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
{
return 0;
}
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
uint32_t *event_nr)
{
return 0;
}
int lvs_in_vg_activated(struct volume_group *vg)
{
return 0;
}
int lvs_in_vg_opened(struct volume_group *vg)
{
return 0;
}
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
{
return 1;
}
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
{
return 1;
}
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
{
return 1;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
{
return 1;
}
void activation_exit(void)
{
return;
}
#else /* DEVMAPPER_SUPPORT */
static int _activation = 1;
void set_activation(int act)
{
if (act == _activation)
return;
_activation = act;
if (_activation)
log_verbose("Activation enabled. Device-mapper kernel "
"driver will be used.");
else
log_verbose("Activation disabled. No device-mapper "
"interaction will be attempted.");
}
int activation(void)
{
return _activation;
}
int library_version(char *version, size_t size)
{
if (!activation())
return 0;
if (!dm_get_library_version(version, size)) if (!dm_get_library_version(version, size))
return 0; return 0;
return 1; return 1;
@@ -35,6 +120,9 @@ int driver_version(char *version, size_t size)
int r = 0; int r = 0;
struct dm_task *dmt; struct dm_task *dmt;
if (!activation())
return 0;
log_very_verbose("Getting driver version"); log_very_verbose("Getting driver version");
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) { if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
stack; stack;
@@ -58,19 +146,30 @@ int driver_version(char *version, size_t size)
/* /*
* Returns 1 if info structure populated, else 0 on failure. * Returns 1 if info structure populated, else 0 on failure.
*/ */
int lv_info(struct logical_volume *lv, struct dm_info *info) int lv_info(const struct logical_volume *lv, struct lvinfo *info)
{ {
int r; int r;
struct dev_manager *dm; struct dev_manager *dm;
struct dm_info dminfo;
if (!(dm = dev_manager_create(lv->vg->name))) { if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack; stack;
return 0; return 0;
} }
if (!(r = dev_manager_info(dm, lv, info))) if (!(r = dev_manager_info(dm, lv, &dminfo)))
stack; stack;
info->exists = dminfo.exists;
info->suspended = dminfo.suspended;
info->open_count = dminfo.open_count;
info->major = dminfo.major;
info->minor = dminfo.minor;
info->read_only = dminfo.read_only;
dev_manager_destroy(dm); dev_manager_destroy(dm);
return r; return r;
} }
@@ -83,7 +182,10 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
int r; int r;
struct dev_manager *dm; struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) { if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack; stack;
return 0; return 0;
} }
@@ -96,9 +198,32 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
return r; return r;
} }
/* FIXME Merge with snapshot_percent */
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
uint32_t *event_nr)
{
int r;
struct dev_manager *dm;
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
stack;
dev_manager_destroy(dm);
return r;
}
static int _lv_active(struct logical_volume *lv) static int _lv_active(struct logical_volume *lv)
{ {
struct dm_info info; struct lvinfo info;
if (!lv_info(lv, &info)) { if (!lv_info(lv, &info)) {
stack; stack;
@@ -110,7 +235,7 @@ static int _lv_active(struct logical_volume *lv)
static int _lv_open_count(struct logical_volume *lv) static int _lv_open_count(struct logical_volume *lv)
{ {
struct dm_info info; struct lvinfo info;
if (!lv_info(lv, &info)) { if (!lv_info(lv, &info)) {
stack; stack;
@@ -126,7 +251,7 @@ static int _lv_activate(struct logical_volume *lv)
int r; int r;
struct dev_manager *dm; struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) { if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack; stack;
return 0; return 0;
} }
@@ -143,7 +268,7 @@ static int _lv_deactivate(struct logical_volume *lv)
int r; int r;
struct dev_manager *dm; struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) { if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack; stack;
return 0; return 0;
} }
@@ -160,7 +285,7 @@ static int _lv_suspend(struct logical_volume *lv)
int r; int r;
struct dev_manager *dm; struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) { if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack; stack;
return 0; return 0;
} }
@@ -182,6 +307,9 @@ int lvs_in_vg_activated(struct volume_group *vg)
struct logical_volume *lv; struct logical_volume *lv;
int count = 0; int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) { list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv; lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_active(lv) == 1); count += (_lv_active(lv) == 1);
@@ -196,6 +324,9 @@ int lvs_in_vg_opened(struct volume_group *vg)
struct logical_volume *lv; struct logical_volume *lv;
int count = 0; int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) { list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv; lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_open_count(lv) == 1); count += (_lv_open_count(lv) == 1);
@@ -204,119 +335,21 @@ int lvs_in_vg_opened(struct volume_group *vg)
return count; return count;
} }
static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
const char *lvid_s)
{
struct lv_list *lvl;
struct volume_group *vg;
union lvid *lvid;
lvid = (union lvid *) lvid_s;
log_very_verbose("Finding volume group for uuid %s", lvid_s);
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
log_error("Volume group for uuid not found: %s", lvid_s);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
log_very_verbose("Can't find logical volume id %s", lvid_s);
return NULL;
}
return lvl->lv;
}
/* These return success if the device is not active */ /* These return success if the device is not active */
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s) int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
{ {
struct logical_volume *lv; struct logical_volume *lv;
struct dm_info info; struct lvinfo info;
if (!(lv = _lv_from_lvid(cmd, lvid_s))) if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0; return 0;
if (test_mode()) { if (test_mode()) {
_skip("Suspending '%s'.", lv->name); _skip("Suspending '%s'.", lv->name);
return 0; return 1;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && !info.suspended)
return _lv_suspend(lv);
return 1;
}
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Resuming '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && info.suspended)
return _lv_activate(lv);
return 1;
}
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Deactivating '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists)
return _lv_deactivate(lv);
return 1;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Activating '%s'.", lv->name);
return 0;
} }
if (!lv_info(lv, &info)) { if (!lv_info(lv, &info)) {
@@ -325,7 +358,119 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s)
} }
if (!info.exists || info.suspended) if (!info.exists || info.suspended)
return _lv_activate(lv); return 1;
memlock_inc();
if (!_lv_suspend(lv)) {
memlock_dec();
fs_unlock();
return 0;
}
return 1; return 1;
} }
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct lvinfo info;
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Resuming '%s'.", lv->name);
return 1;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (!info.exists || !info.suspended)
return 1;
if (!_lv_activate(lv))
return 0;
memlock_dec();
fs_unlock();
return 1;
}
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct lvinfo info;
int r;
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Deactivating '%s'.", lv->name);
return 1;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (!info.exists)
return 1;
memlock_inc();
r = _lv_deactivate(lv);
memlock_dec();
fs_unlock();
return r;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct lvinfo info;
int r;
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Activating '%s'.", lv->name);
return 1;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && !info.suspended)
return 1;
memlock_inc();
r = _lv_activate(lv);
memlock_dec();
fs_unlock();
return r;
}
void activation_exit(void)
{
dev_manager_exit();
}
#endif

View File

@@ -7,33 +7,44 @@
#ifndef LVM_ACTIVATE_H #ifndef LVM_ACTIVATE_H
#define LVM_ACTIVATE_H #define LVM_ACTIVATE_H
#include <libdevmapper.h> #include "metadata.h"
#ifdef DEVMAPPER_SUPPORT
# include <libdevmapper.h>
#endif
struct lvinfo {
int exists;
int suspended;
unsigned int open_count;
int major;
int minor;
int read_only;
};
void set_activation(int activation);
int activation(void);
int driver_version(char *version, size_t size); int driver_version(char *version, size_t size);
int library_version(char *version, size_t size); int library_version(char *version, size_t size);
/* void activation_exit(void);
* Returns 1 if info structure has been populated, else 0.
*/
int lv_info(struct logical_volume *lv, struct dm_info *info);
/*
* Returns 1 if percent has been set, else 0.
*/
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
/*
* These should eventually use config file
* to determine whether or not to activate
*/
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s); int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_resume_if_active(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(struct cmd_context *cmd, const char *lvid_s);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s); int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
/* /*
* FIXME: * Returns 1 if info structure has been populated, else 0.
* I don't like the *lvs_in_vg* function names.
*/ */
int lv_info(const struct logical_volume *lv, struct lvinfo *info);
/*
* Returns 1 if percent has been set, else 0.
*/
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
uint32_t *event_nr);
/* /*
* Return number of LVs in the VG that are active. * Return number of LVs in the VG that are active.

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,18 @@
#define _LVM_DEV_MANAGER_H #define _LVM_DEV_MANAGER_H
#include "metadata.h" #include "metadata.h"
#include "config.h"
#include <libdevmapper.h>
struct dev_manager; struct dev_manager;
struct dm_info;
/* /*
* Constructor and destructor. * Constructor and destructor.
*/ */
struct dev_manager *dev_manager_create(const char *vg_name); struct dev_manager *dev_manager_create(const char *vg_name,
struct config_tree *cf);
void dev_manager_destroy(struct dev_manager *dm); void dev_manager_destroy(struct dev_manager *dm);
void dev_manager_exit(void);
/* /*
* The device handler is responsible for creating all the layered * The device handler is responsible for creating all the layered
@@ -25,10 +27,13 @@ void dev_manager_destroy(struct dev_manager *dm);
* (eg, an origin is created before its snapshot, but is not * (eg, an origin is created before its snapshot, but is not
* unsuspended until the snapshot is also created.) * unsuspended until the snapshot is also created.)
*/ */
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv, int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
struct dm_info *info); struct dm_info *info);
int dev_manager_snapshot_percent(struct dev_manager *dm, int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent); struct logical_volume *lv, float *percent);
int dev_manager_mirror_percent(struct dev_manager *dm,
struct logical_volume *lv, int wait,
float *percent, uint32_t *event_nr);
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv); int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv); int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv); int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);

View File

@@ -4,28 +4,26 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "fs.h" #include "fs.h"
#include "log.h"
#include "toolcontext.h" #include "toolcontext.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "lvm-file.h" #include "lvm-file.h"
#include "memlock.h"
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <dirent.h>
#include <string.h>
#include <libdevmapper.h> #include <libdevmapper.h>
static int _mk_dir(struct volume_group *vg) static int _mk_dir(const char *dev_dir, const char *vg_name)
{ {
char vg_path[PATH_MAX]; char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s", if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
vg->cmd->dev_dir, vg->name) == -1) { dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume " log_error("Couldn't construct name of volume "
"group directory."); "group directory.");
return 0; return 0;
@@ -43,12 +41,12 @@ static int _mk_dir(struct volume_group *vg)
return 1; return 1;
} }
static int _rm_dir(struct volume_group *vg) static int _rm_dir(const char *dev_dir, const char *vg_name)
{ {
char vg_path[PATH_MAX]; char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s", if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
vg->cmd->dev_dir, vg->name) == -1) { dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume " log_error("Couldn't construct name of volume "
"group directory."); "group directory.");
return 0; return 0;
@@ -62,32 +60,100 @@ static int _rm_dir(struct volume_group *vg)
return 1; return 1;
} }
static int _mk_link(struct logical_volume *lv, const char *dev) static void _rm_blks(const char *dir)
{ {
char lv_path[PATH_MAX], link_path[PATH_MAX]; const char *name;
char path[PATH_MAX];
struct dirent *dirent;
struct stat buf;
DIR *d;
if (!(d = opendir(dir))) {
log_sys_error("opendir", dir);
return;
}
while ((dirent = readdir(d))) {
name = dirent->d_name;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
log_error("Couldn't create path for %s", name);
continue;
}
if (!lstat(path, &buf)) {
if (!S_ISBLK(buf.st_mode))
continue;
log_very_verbose("Removing %s", path);
if (unlink(path) < 0)
log_sys_error("unlink", path);
}
}
}
static int _mk_link(const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev)
{
char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
char vg_path[PATH_MAX];
struct stat buf; struct stat buf;
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s", if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
lv->vg->cmd->dev_dir, lv->vg->name, lv->name) == -1) { dev_dir, vg_name) == -1) {
log_error("Couldn't create path for volume group dir %s",
vg_name);
return 0;
}
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
lv_name) == -1) {
log_error("Couldn't create source pathname for " log_error("Couldn't create source pathname for "
"logical volume link %s", lv->name); "logical volume link %s", lv_name);
return 0; return 0;
} }
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s", if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
dm_dir(), dev) == -1) { dm_dir(), dev) == -1) {
log_error("Couldn't create destination pathname for " log_error("Couldn't create destination pathname for "
"logical volume link for %s", lv->name); "logical volume link for %s", lv_name);
return 0; return 0;
} }
if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
vg_path) == -1) {
log_error("Couldn't create pathname for LVM1 group file for %s",
vg_name);
return 0;
}
/* To reach this point, the VG must have been locked.
* As locking fails if the VG is active under LVM1, it's
* now safe to remove any LVM1 devices we find here
* (as well as any existing LVM2 symlink). */
if (!lstat(lvm1_group_path, &buf)) {
if (!S_ISCHR(buf.st_mode)) {
log_error("Non-LVM1 character device found at %s",
lvm1_group_path);
} else {
_rm_blks(vg_path);
log_very_verbose("Removing %s", lvm1_group_path);
if (unlink(lvm1_group_path) < 0)
log_sys_error("unlink", lvm1_group_path);
}
}
if (!lstat(lv_path, &buf)) { if (!lstat(lv_path, &buf)) {
if (!S_ISLNK(buf.st_mode)) { if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) {
log_error("Symbolic link %s not created: file exists", log_error("Symbolic link %s not created: file exists",
link_path); link_path);
return 0; return 0;
} }
log_very_verbose("Removing %s", lv_path);
if (unlink(lv_path) < 0) { if (unlink(lv_path) < 0) {
log_sys_error("unlink", lv_path); log_sys_error("unlink", lv_path);
return 0; return 0;
@@ -103,23 +169,24 @@ static int _mk_link(struct logical_volume *lv, const char *dev)
return 1; return 1;
} }
static int _rm_link(struct logical_volume *lv, const char *lv_name) static int _rm_link(const char *dev_dir, const char *vg_name,
const char *lv_name)
{ {
struct stat buf; struct stat buf;
char lv_path[PATH_MAX]; char lv_path[PATH_MAX];
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s", if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) { dev_dir, vg_name, lv_name) == -1) {
log_error("Couldn't determine link pathname."); log_error("Couldn't determine link pathname.");
return 0; return 0;
} }
log_very_verbose("Removing link %s", lv_path);
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) { if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
log_error("%s not symbolic link - not removing", lv_path); log_error("%s not symbolic link - not removing", lv_path);
return 0; return 0;
} }
log_very_verbose("Removing link %s", lv_path);
if (unlink(lv_path) < 0) { if (unlink(lv_path) < 0) {
log_sys_error("unlink", lv_path); log_sys_error("unlink", lv_path);
return 0; return 0;
@@ -128,35 +195,143 @@ static int _rm_link(struct logical_volume *lv, const char *lv_name)
return 1; return 1;
} }
int fs_add_lv(struct logical_volume *lv, const char *dev) typedef enum {
FS_ADD,
FS_DEL,
FS_RENAME
} fs_op_t;
static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev,
const char *old_lv_name)
{ {
if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) { switch (type) {
stack; case FS_ADD:
return 0; if (!_mk_dir(dev_dir, vg_name) ||
!_mk_link(dev_dir, vg_name, lv_name, dev)) {
stack;
return 0;
}
break;
case FS_DEL:
if (!_rm_link(dev_dir, vg_name, lv_name) ||
!_rm_dir(dev_dir, vg_name)) {
stack;
return 0;
}
break;
/* FIXME Use rename() */
case FS_RENAME:
if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name))
stack;
if (!_mk_link(dev_dir, vg_name, lv_name, dev))
stack;
} }
return 1; return 1;
} }
static LIST_INIT(_fs_ops);
struct fs_op_parms {
struct list list;
fs_op_t type;
char *dev_dir;
char *vg_name;
char *lv_name;
char *dev;
char *old_lv_name;
char names[0];
};
static void _store_str(char **pos, char **ptr, const char *str)
{
strcpy(*pos, str);
*ptr = *pos;
*pos += strlen(*ptr) + 1;
}
static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev,
const char *old_lv_name)
{
struct fs_op_parms *fsp;
size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
strlen(dev) + strlen(old_lv_name) + 5;
char *pos;
if (!(fsp = dbg_malloc(sizeof(*fsp) + len))) {
log_error("No space to stack fs operation");
return 0;
}
pos = fsp->names;
fsp->type = type;
_store_str(&pos, &fsp->dev_dir, dev_dir);
_store_str(&pos, &fsp->vg_name, vg_name);
_store_str(&pos, &fsp->lv_name, lv_name);
_store_str(&pos, &fsp->dev, dev);
_store_str(&pos, &fsp->old_lv_name, old_lv_name);
list_add(&_fs_ops, &fsp->list);
return 1;
}
static void _pop_fs_ops(void)
{
struct list *fsph, *fspht;
struct fs_op_parms *fsp;
list_iterate_safe(fsph, fspht, &_fs_ops) {
fsp = list_item(fsph, struct fs_op_parms);
_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
fsp->dev, fsp->old_lv_name);
list_del(&fsp->list);
dbg_free(fsp);
}
}
static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev, const char *old_lv_name)
{
if (memlock()) {
if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
old_lv_name)) {
stack;
return 0;
}
return 1;
}
return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name);
}
int fs_add_lv(struct logical_volume *lv, const char *dev)
{
return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
dev, "");
}
int fs_del_lv(struct logical_volume *lv) int fs_del_lv(struct logical_volume *lv)
{ {
if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) { return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
stack; "", "");
return 0;
}
return 1;
} }
/* FIXME Use rename() */
int fs_rename_lv(struct logical_volume *lv, int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name) const char *dev, const char *old_name)
{ {
if (old_name && !_rm_link(lv, old_name)) return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
stack; dev, old_name);
}
if (!_mk_link(lv, dev))
stack; void fs_unlock(void)
{
return 1; if (!memlock()) {
dm_lib_release();
_pop_fs_ops();
}
} }

View File

@@ -18,6 +18,6 @@ int fs_add_lv(struct logical_volume *lv, const char *dev);
int fs_del_lv(struct logical_volume *lv); int fs_del_lv(struct logical_volume *lv);
int fs_rename_lv(struct logical_volume *lv, int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name); const char *dev, const char *old_name);
void fs_unlock(void);
#endif #endif

580
lib/cache/lvmcache.c vendored Normal file
View File

@@ -0,0 +1,580 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "lib.h"
#include "lvmcache.h"
#include "hash.h"
#include "toolcontext.h"
#include "dev-cache.h"
#include "metadata.h"
#include "filter.h"
#include "memlock.h"
static struct hash_table *_pvid_hash = NULL;
static struct hash_table *_vgid_hash = NULL;
static struct hash_table *_vgname_hash = NULL;
static struct hash_table *_lock_hash = NULL;
static struct list _vginfos;
static int _has_scanned = 0;
static int _vgs_locked = 0;
int lvmcache_init(void)
{
list_init(&_vginfos);
if (!(_vgname_hash = hash_create(128)))
return 0;
if (!(_vgid_hash = hash_create(128)))
return 0;
if (!(_pvid_hash = hash_create(128)))
return 0;
if (!(_lock_hash = hash_create(128)))
return 0;
return 1;
}
void lvmcache_lock_vgname(const char *vgname, int read_only)
{
if (!_lock_hash && !lvmcache_init()) {
log_error("Internal cache initialisation failed");
return;
}
if (!hash_insert(_lock_hash, vgname, (void *) 1))
log_error("Cache locking failure for %s", vgname);
_vgs_locked++;
}
static int _vgname_is_locked(const char *vgname) __attribute__ ((unused));
static int _vgname_is_locked(const char *vgname)
{
if (!_lock_hash)
return 0;
return hash_lookup(_lock_hash, vgname) ? 1 : 0;
}
void lvmcache_unlock_vgname(const char *vgname)
{
/* FIXME: Clear all CACHE_LOCKED flags in this vg */
hash_remove(_lock_hash, vgname);
/* FIXME Do this per-VG */
if (!--_vgs_locked)
dev_close_all();
}
int vgs_locked(void)
{
return _vgs_locked;
}
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
{
struct lvmcache_vginfo *vginfo;
if (!_vgname_hash)
return NULL;
if (!(vginfo = hash_lookup(_vgname_hash, vgname)))
return NULL;
return vginfo;
}
const struct format_type *fmt_from_vgname(const char *vgname)
{
struct lvmcache_vginfo *vginfo;
if (!(vginfo = vginfo_from_vgname(vgname)))
return NULL;
return vginfo->fmt;
}
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
{
struct lvmcache_vginfo *vginfo;
char id[ID_LEN + 1];
if (!_vgid_hash || !vgid)
return NULL;
/* vgid not necessarily NULL-terminated */
strncpy(&id[0], vgid, ID_LEN);
id[ID_LEN] = '\0';
if (!(vginfo = hash_lookup(_vgid_hash, id)))
return NULL;
return vginfo;
}
struct lvmcache_info *info_from_pvid(const char *pvid)
{
struct lvmcache_info *info;
char id[ID_LEN + 1];
if (!_pvid_hash || !pvid)
return NULL;
strncpy(&id[0], pvid, ID_LEN);
id[ID_LEN] = '\0';
if (!(info = hash_lookup(_pvid_hash, id)))
return NULL;
return info;
}
static void _rescan_entry(struct lvmcache_info *info)
{
struct label *label;
if (info->status & CACHE_INVALID)
label_read(info->dev, &label);
}
static int _scan_invalid(void)
{
hash_iter(_pvid_hash, (iterate_fn) _rescan_entry);
return 1;
}
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;
int r = 0;
/* Avoid recursion when a PVID can't be found! */
if (_scanning_in_progress)
return 0;
_scanning_in_progress = 1;
if (!_vgname_hash && !lvmcache_init()) {
log_error("Internal cache initialisation failed");
goto out;
}
if (_has_scanned && !full_scan) {
r = _scan_invalid();
goto out;
}
if (!(iter = dev_iter_create(cmd->filter))) {
log_error("dev_iter creation failed");
goto out;
}
while ((dev = dev_iter_get(iter)))
label_read(dev, &label);
dev_iter_destroy(iter);
_has_scanned = 1;
/* Perform any format-specific scanning e.g. text files */
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
if (fmt->ops->scan && !fmt->ops->scan(fmt))
goto out;
}
r = 1;
out:
_scanning_in_progress = 0;
return r;
}
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
{
struct list *vgih, *vgnames;
struct str_list *sl;
lvmcache_label_scan(cmd, full_scan);
if (!(vgnames = pool_alloc(cmd->mem, sizeof(struct list)))) {
log_error("vgnames list allocation failed");
return NULL;
}
list_init(vgnames);
list_iterate(vgih, &_vginfos) {
if (!(sl = pool_alloc(cmd->mem, sizeof(*sl)))) {
log_error("strlist allocation failed");
return NULL;
}
if (!(sl->str = pool_strdup(cmd->mem,
list_item(vgih,
struct lvmcache_vginfo)->
vgname))) {
log_error("vgname allocation failed");
return NULL;
}
list_add(vgnames, &sl->list);
}
return vgnames;
}
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
{
struct label *label;
struct lvmcache_info *info;
/* Already cached ? */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct lvmcache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
lvmcache_label_scan(cmd, 0);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct lvmcache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
if (memlock())
return NULL;
lvmcache_label_scan(cmd, 1);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct lvmcache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
return NULL;
}
static void _drop_vginfo(struct lvmcache_info *info)
{
if (!list_empty(&info->list)) {
list_del(&info->list);
list_init(&info->list);
}
if (info->vginfo && list_empty(&info->vginfo->infos)) {
hash_remove(_vgname_hash, info->vginfo->vgname);
if (info->vginfo->vgname)
dbg_free(info->vginfo->vgname);
if (*info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
list_del(&info->vginfo->list);
dbg_free(info->vginfo);
}
info->vginfo = NULL;
}
/* Unused
void lvmcache_del(struct lvmcache_info *info)
{
if (info->dev->pvid[0] && _pvid_hash)
hash_remove(_pvid_hash, info->dev->pvid);
_drop_vginfo(info);
info->label->labeller->ops->destroy_label(info->label->labeller,
info->label);
dbg_free(info);
return;
} */
static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
{
if (!strcmp(info->dev->pvid, pvid))
return 1;
if (*info->dev->pvid) {
hash_remove(_pvid_hash, info->dev->pvid);
}
strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
if (!hash_insert(_pvid_hash, pvid, info)) {
log_error("_lvmcache_update: pvid insertion failed: %s", pvid);
return 0;
}
return 1;
}
static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
{
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
sizeof(info->vginfo->vgid)))
return 1;
if (info->vginfo && *info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
if (!vgid)
return 1;
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
if (!hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) {
log_error("_lvmcache_update: vgid hash insertion failed: %s",
info->vginfo->vgid);
return 0;
}
return 1;
}
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
{
struct lvmcache_vginfo *vginfo;
/* If vgname is NULL and we don't already have a vgname,
* assume ORPHAN - we want every entry to have a vginfo
* attached for scanning reasons.
*/
if (!vgname && !info->vginfo)
vgname = ORPHAN;
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
return 1;
/* Remove existing vginfo entry */
_drop_vginfo(info);
/* Get existing vginfo or create new one */
if (!(vginfo = vginfo_from_vgname(vgname))) {
if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
log_error("lvmcache_update_vgname: list alloc failed");
return 0;
}
memset(vginfo, 0, sizeof(*vginfo));
if (!(vginfo->vgname = dbg_strdup(vgname))) {
dbg_free(vginfo);
log_error("cache vgname alloc failed for %s", vgname);
return 0;
}
list_init(&vginfo->infos);
if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
log_error("cache_update: vg hash insertion failed: %s",
vginfo->vgname);
dbg_free(vginfo->vgname);
dbg_free(vginfo);
return 0;
}
/* Ensure orphans appear last on list_iterate */
if (!*vgname)
list_add(&_vginfos, &vginfo->list);
else
list_add_h(&_vginfos, &vginfo->list);
}
info->vginfo = vginfo;
list_add(&vginfo->infos, &info->list);
/* FIXME Check consistency of list! */
vginfo->fmt = info->fmt;
return 1;
}
int lvmcache_update_vg(struct volume_group *vg)
{
struct list *pvh;
struct physical_volume *pv;
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? */
if ((info = info_from_pvid(pvid_s))) {
lvmcache_update_vgname(info, vg->name);
if (!vgid_updated) {
_lvmcache_update_vgid(info, (char *) &vg->id);
vgid_updated = 1;
}
}
}
return 1;
}
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid)
{
struct label *label;
struct lvmcache_info *existing, *info;
char pvid_s[ID_LEN + 1];
if (!_vgname_hash && !lvmcache_init()) {
log_error("Internal cache initialisation failed");
return NULL;
}
strncpy(pvid_s, pvid, sizeof(pvid_s));
pvid_s[sizeof(pvid_s) - 1] = '\0';
if (!(existing = info_from_pvid(pvid_s)) &&
!(existing = info_from_pvid(dev->pvid))) {
if (!(label = label_create(labeller))) {
stack;
return NULL;
}
if (!(info = dbg_malloc(sizeof(*info)))) {
log_error("lvmcache_info allocation failed");
label_destroy(label);
return NULL;
}
memset(info, 0, sizeof(*info));
label->info = info;
info->label = label;
list_init(&info->list);
info->dev = dev;
} else {
if (existing->dev != dev) {
/* Is the existing entry a duplicate pvid e.g. md ? */
if (MAJOR(existing->dev->dev) == md_major() &&
MAJOR(dev->dev) != md_major()) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s - using md %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
log_error("Found duplicate PV %s: using %s not "
"%s", pvid, dev_name(dev),
dev_name(existing->dev));
}
info = existing;
/* Has labeller changed? */
if (info->label->labeller != labeller) {
label_destroy(info->label);
if (!(info->label = label_create(labeller))) {
/* FIXME leaves info without label! */
stack;
return NULL;
}
info->label->info = info;
}
label = info->label;
}
info->fmt = (const struct format_type *) labeller->private;
info->status |= CACHE_INVALID;
if (!_lvmcache_update_pvid(info, pvid_s)) {
if (!existing) {
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!lvmcache_update_vgname(info, vgname)) {
if (!existing) {
hash_remove(_pvid_hash, pvid_s);
strcpy(info->dev->pvid, "");
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!_lvmcache_update_vgid(info, vgid))
/* Non-critical */
stack;
return info;
}
static void _lvmcache_destroy_entry(struct lvmcache_info *info)
{
if (!list_empty(&info->list))
list_del(&info->list);
strcpy(info->dev->pvid, "");
label_destroy(info->label);
dbg_free(info);
}
static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
{
if (vginfo->vgname)
dbg_free(vginfo->vgname);
dbg_free(vginfo);
}
static void _lvmcache_destroy_lockname(int present)
{
/* Nothing to do */
}
void lvmcache_destroy(void)
{
_has_scanned = 0;
if (_vgid_hash) {
hash_destroy(_vgid_hash);
_vgid_hash = NULL;
}
if (_pvid_hash) {
hash_iter(_pvid_hash, (iterate_fn) _lvmcache_destroy_entry);
hash_destroy(_pvid_hash);
_pvid_hash = NULL;
}
if (_vgname_hash) {
hash_iter(_vgname_hash,
(iterate_fn) _lvmcache_destroy_vgnamelist);
hash_destroy(_vgname_hash);
_vgname_hash = NULL;
}
if (_lock_hash) {
hash_iter(_lock_hash, (iterate_fn) _lvmcache_destroy_lockname);
hash_destroy(_lock_hash);
_lock_hash = NULL;
}
list_init(&_vginfos);
}

75
lib/cache/lvmcache.h vendored Normal file
View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#ifndef _LVM_CACHE_H
#define _LVM_CACHE_H
#include "dev-cache.h"
#include "uuid.h"
#include "label.h"
#include "metadata.h"
#define ORPHAN ""
#define CACHE_INVALID 0x00000001
#define CACHE_LOCKED 0x00000002
/* LVM specific per-volume info */
/* Eventual replacement for struct physical_volume perhaps? */
struct lvmcache_vginfo {
struct list list; /* Join these vginfos together */
struct list infos; /* List head for lvmcache_infos */
char *vgname; /* "" == orphan */
char vgid[ID_LEN + 1];
const struct format_type *fmt;
};
struct lvmcache_info {
struct list list; /* Join VG members together */
struct list mdas; /* list head for metadata areas */
struct list das; /* list head for data areas */
struct lvmcache_vginfo *vginfo; /* NULL == unknown */
struct label *label;
const struct format_type *fmt;
struct device *dev;
uint64_t device_size; /* Bytes */
uint32_t status;
};
int lvmcache_init(void);
void lvmcache_destroy(void);
/* Set full_scan to 1 to reread every filtered device label */
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
/* Add/delete a device */
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid);
void lvmcache_del(struct lvmcache_info *info);
/* Update things */
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname);
int lvmcache_update_vg(struct volume_group *vg);
void lvmcache_lock_vgname(const char *vgname, int read_only);
void lvmcache_unlock_vgname(const char *vgname);
/* Queries */
const struct format_type *fmt_from_vgname(const char *vgname);
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname);
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
struct lvmcache_info *info_from_pvid(const char *pvid);
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
int vgs_locked(void);
/* Returns list of struct str_lists containing pool-allocated copy of vgnames */
/* Set full_scan to 1 to reread every filtered device label */
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan);
#endif

View File

@@ -13,4 +13,3 @@
#define ECMD_FAILED 5 #define ECMD_FAILED 5
#endif #endif

521
lib/commands/toolcontext.c Normal file
View File

@@ -0,0 +1,521 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "lib.h"
#include "toolcontext.h"
#include "pool.h"
#include "metadata.h"
#include "defaults.h"
#include "lvm-string.h"
#include "activate.h"
#include "filter.h"
#include "filter-composite.h"
#include "filter-persistent.h"
#include "filter-regex.h"
#include "label.h"
#include "lvm-file.h"
#include "format-text.h"
#include "display.h"
#include "memlock.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
#endif
#ifdef LVM1_INTERNAL
#include "format1.h"
#endif
#include <locale.h>
#include <sys/stat.h>
#include <syslog.h>
#include <time.h>
#ifdef linux
# include <malloc.h>
#endif
static FILE *_log;
static int _get_env_vars(struct cmd_context *cmd)
{
const char *e;
/* Set to "" to avoid using any system directory */
if ((e = getenv("LVM_SYSTEM_DIR"))) {
if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
"%s", e) < 0) {
log_error("LVM_SYSTEM_DIR environment variable "
"is too long.");
return 0;
}
}
return 1;
}
static void _init_logging(struct cmd_context *cmd)
{
int append = 1;
time_t t;
const char *log_file;
/* Syslog */
cmd->default_settings.syslog =
find_config_int(cmd->cf->root, "log/syslog", '/', DEFAULT_SYSLOG);
if (cmd->default_settings.syslog != 1)
fin_syslog();
if (cmd->default_settings.syslog > 1)
init_syslog(cmd->default_settings.syslog);
/* Debug level for log file output */
cmd->default_settings.debug =
find_config_int(cmd->cf->root, "log/level", '/', DEFAULT_LOGLEVEL);
init_debug(cmd->default_settings.debug);
/* Verbose level for tty output */
cmd->default_settings.verbose =
find_config_int(cmd->cf->root, "log/verbose", '/', DEFAULT_VERBOSE);
init_verbose(cmd->default_settings.verbose);
/* Log message formatting */
init_indent(find_config_int(cmd->cf->root, "log/indent", '/',
DEFAULT_INDENT));
cmd->default_settings.msg_prefix = find_config_str(cmd->cf->root,
"log/prefix", '/',
DEFAULT_MSG_PREFIX);
init_msg_prefix(cmd->default_settings.msg_prefix);
cmd->default_settings.cmd_name = find_config_int(cmd->cf->root,
"log/command_names",
'/', DEFAULT_CMD_NAME);
init_cmd_name(cmd->default_settings.cmd_name);
/* Test mode */
cmd->default_settings.test =
find_config_int(cmd->cf->root, "global/test", '/', 0);
/* Settings for logging to file */
if (find_config_int(cmd->cf->root, "log/overwrite", '/',
DEFAULT_OVERWRITE))
append = 0;
log_file = find_config_str(cmd->cf->root, "log/file", '/', 0);
if (log_file)
init_log_file(log_file, append);
log_file = find_config_str(cmd->cf->root, "log/activate_file", '/', 0);
if (log_file)
init_log_direct(log_file, append);
init_log_while_suspended(find_config_int(cmd->cf->root,
"log/activation", '/', 0));
t = time(NULL);
log_verbose("Logging initialised at %s", ctime(&t));
/* Tell device-mapper about our logging */
#ifdef DEVMAPPER_SUPPORT
dm_log_init(print_log);
#endif
}
static int _process_config(struct cmd_context *cmd)
{
mode_t old_umask;
/* umask */
cmd->default_settings.umask = find_config_int(cmd->cf->root,
"global/umask", '/',
DEFAULT_UMASK);
if ((old_umask = umask((mode_t) cmd->default_settings.umask)) !=
(mode_t) cmd->default_settings.umask)
log_verbose("Set umask to %04o", cmd->default_settings.umask);
/* dev dir */
if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
find_config_str(cmd->cf->root, "devices/dir",
'/', DEFAULT_DEV_DIR)) < 0) {
log_error("Device directory given in config file too long");
return 0;
}
#ifdef DEVMAPPER_SUPPORT
dm_set_dev_dir(cmd->dev_dir);
#endif
/* proc dir */
if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
find_config_str(cmd->cf->root, "global/proc",
'/', DEFAULT_PROC_DIR)) < 0) {
log_error("Device directory given in config file too long");
return 0;
}
/* activation? */
cmd->default_settings.activation = find_config_int(cmd->cf->root,
"global/activation",
'/',
DEFAULT_ACTIVATION);
set_activation(cmd->default_settings.activation);
cmd->default_settings.suffix = find_config_int(cmd->cf->root,
"global/suffix",
'/', DEFAULT_SUFFIX);
if (!(cmd->default_settings.unit_factor =
units_to_bytes(find_config_str(cmd->cf->root,
"global/units",
'/',
DEFAULT_UNITS),
&cmd->default_settings.unit_type))) {
log_error("Invalid units specification");
return 0;
}
return 1;
}
/* Find and read config file */
static int _init_config(struct cmd_context *cmd)
{
struct stat info;
char config_file[PATH_MAX] = "";
if (!(cmd->cf = create_config_tree())) {
stack;
return 0;
}
/* No config file if LVM_SYSTEM_DIR is empty */
if (!*cmd->sys_dir)
return 1;
if (lvm_snprintf(config_file, sizeof(config_file),
"%s/lvm.conf", cmd->sys_dir) < 0) {
log_error("LVM_SYSTEM_DIR was too long");
destroy_config_tree(cmd->cf);
return 0;
}
/* Is there a config file? */
if (stat(config_file, &info) == -1) {
if (errno == ENOENT)
return 1;
log_sys_error("stat", config_file);
destroy_config_tree(cmd->cf);
return 0;
}
if (!read_config_file(cmd->cf, config_file)) {
log_error("Failed to load config file %s", config_file);
destroy_config_tree(cmd->cf);
return 0;
}
return 1;
}
static int _init_dev_cache(struct cmd_context *cmd)
{
struct config_node *cn;
struct config_value *cv;
if (!dev_cache_init()) {
stack;
return 0;
}
if (!(cn = find_config_node(cmd->cf->root, "devices/scan", '/'))) {
if (!dev_cache_add_dir("/dev")) {
log_error("Failed to add /dev to internal "
"device cache");
return 0;
}
log_verbose("device/scan not in config file: "
"Defaulting to /dev");
return 1;
}
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"devices/scan");
return 0;
}
if (!dev_cache_add_dir(cv->v.str)) {
log_error("Failed to add %s to internal device cache",
cv->v.str);
return 0;
}
}
return 1;
}
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
{
struct config_node *cn;
struct dev_filter *f1, *f2, *f3;
cn = find_config_node(cmd->cf->root, "devices/types", '/');
if (!(f2 = lvm_type_filter_create(cmd->proc_dir, cn)))
return NULL;
if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/'))) {
log_debug("devices/filter not found in config file: no regex "
"filter installed");
return f2;
}
if (!(f1 = regex_filter_create(cn->v))) {
log_error("Failed to create regex device filter");
return NULL;
}
if (!(f3 = composite_filter_create(2, f1, f2))) {
log_error("Failed to create composite device filter");
return NULL;
}
return f3;
}
static int _init_filters(struct cmd_context *cmd)
{
const char *dev_cache;
struct dev_filter *f3, *f4;
struct stat st;
char cache_file[PATH_MAX];
cmd->dump_filter = 0;
if (!(f3 = _init_filter_components(cmd)))
return 0;
if (lvm_snprintf(cache_file, sizeof(cache_file),
"%s/.cache", cmd->sys_dir) < 0) {
log_error("Persistent cache filename too long ('%s/.cache').",
cmd->sys_dir);
return 0;
}
dev_cache =
find_config_str(cmd->cf->root, "devices/cache", '/', cache_file);
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
log_error("Failed to create persistent device filter");
return 0;
}
/* Should we ever dump persistent filter state? */
if (find_config_int(cmd->cf->root, "devices/write_cache_state", '/', 1))
cmd->dump_filter = 1;
if (!*cmd->sys_dir)
cmd->dump_filter = 0;
if (!stat(dev_cache, &st) &&
(st.st_mtime > config_file_timestamp(cmd->cf)) &&
!persistent_filter_load(f4))
log_verbose("Failed to load existing device cache from %s",
dev_cache);
cmd->filter = f4;
return 1;
}
static int _init_formats(struct cmd_context *cmd)
{
const char *format;
struct format_type *fmt;
struct list *fmth;
#ifdef HAVE_LIBDL
struct config_node *cn;
#endif
label_init();
#ifdef LVM1_INTERNAL
if (!(fmt = init_lvm1_format(cmd)))
return 0;
fmt->library = NULL;
list_add(&cmd->formats, &fmt->list);
#endif
#ifdef HAVE_LIBDL
/* Load any formats in shared libs */
if ((cn = find_config_node(cmd->cf->root, "global/format_libraries",
'/'))) {
struct config_value *cv;
struct format_type *(*init_format_fn) (struct cmd_context *);
void *lib;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"global/format_libraries");
return 0;
}
if (!(lib = load_shared_library(cmd->cf, cv->v.str,
"format"))) {
stack;
return 0;
}
if (!(init_format_fn = dlsym(lib, "init_format"))) {
log_error("Shared library %s does not contain "
"format functions", cv->v.str);
dlclose(lib);
return 0;
}
if (!(fmt = init_format_fn(cmd)))
return 0;
fmt->library = lib;
list_add(&cmd->formats, &fmt->list);
}
}
#endif
if (!(fmt = create_text_format(cmd)))
return 0;
fmt->library = NULL;
list_add(&cmd->formats, &fmt->list);
cmd->fmt_backup = fmt;
format = find_config_str(cmd->cf->root, "global/format", '/',
DEFAULT_FORMAT);
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
if (!strcasecmp(fmt->name, format) ||
(fmt->alias && !strcasecmp(fmt->alias, format))) {
cmd->default_settings.fmt = fmt;
return 1;
}
}
log_error("_init_formats: Default format (%s) not found", format);
return 0;
}
/* Entry point */
struct cmd_context *create_toolcontext(struct arg *the_args)
{
struct cmd_context *cmd;
#ifdef M_MMAP_MAX
mallopt(M_MMAP_MAX, 0);
#endif
if (!setlocale(LC_ALL, ""))
log_error("setlocale failed");
init_syslog(DEFAULT_LOG_FACILITY);
if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
log_error("Failed to allocate command context");
return NULL;
}
memset(cmd, 0, sizeof(*cmd));
cmd->args = the_args;
list_init(&cmd->formats);
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
if (!_get_env_vars(cmd))
goto error;
/* Create system directory if it doesn't already exist */
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
goto error;
if (!_init_config(cmd))
goto error;
_init_logging(cmd);
if (!_process_config(cmd))
goto error;
if (!_init_dev_cache(cmd))
goto error;
if (!_init_filters(cmd))
goto error;
if (!(cmd->mem = pool_create(4 * 1024))) {
log_error("Command memory pool creation failed");
return 0;
}
memlock_init(cmd);
if (!_init_formats(cmd))
goto error;
cmd->current_settings = cmd->default_settings;
return cmd;
error:
dbg_free(cmd);
return NULL;
}
static void _destroy_formats(struct list *formats)
{
struct list *fmtl, *tmp;
struct format_type *fmt;
void *lib;
list_iterate_safe(fmtl, tmp, formats) {
fmt = list_item(fmtl, struct format_type);
list_del(&fmt->list);
lib = fmt->library;
fmt->ops->destroy(fmt);
#ifdef HAVE_LIBDL
if (lib)
dlclose(lib);
#endif
}
}
void destroy_toolcontext(struct cmd_context *cmd)
{
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
activation_exit();
lvmcache_destroy();
label_exit();
_destroy_formats(&cmd->formats);
cmd->filter->destroy(cmd->filter);
pool_destroy(cmd->mem);
dev_cache_exit();
destroy_config_tree(cmd->cf);
dbg_free(cmd);
release_log_memory();
dump_memory();
fin_log();
fin_syslog();
if (_log)
fclose(_log);
}

View File

@@ -13,25 +13,61 @@
#include "pool.h" #include "pool.h"
#include "metadata.h" #include "metadata.h"
#include <stdio.h>
#include <limits.h>
/*
* Config options that can be changed while commands are processed
*/
struct config_info {
int debug;
int verbose;
int test;
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 ? */
struct format_type *fmt;
mode_t umask;
};
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */ /* command-instance-related variables needed by library */
struct cmd_context { struct cmd_context {
/* format handler allocates all objects from here */ /* format handler allocates all objects from here */
struct pool *mem; struct pool *mem;
struct format_type *fmt; /* Current format to use by default */ const struct format_type *fmt; /* Current format to use by default */
struct format_type *fmt_backup; /* Format to use for backups */
/* FIXME Move into dynamic list */ struct list formats; /* Available formats */
struct format_type *fmt1; /* Format1 */
struct format_type *fmtt; /* Format_text */
char *cmd_line; char *cmd_line;
char *dev_dir;
struct dev_filter *filter;
struct config_file *cf;
struct command *command; struct command *command;
struct uuid_map *um;
struct arg *args; struct arg *args;
char **argv;
struct dev_filter *filter;
int dump_filter; /* Dump filter when exiting? */
struct config_tree *cf;
struct config_info default_settings;
struct config_info current_settings;
char sys_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
}; };
struct cmd_context *create_toolcontext(struct arg *the_args);
void destroy_toolcontext(struct cmd_context *cmd);
#endif #endif

View File

@@ -4,18 +4,17 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include <sys/types.h> #include "lib.h"
#include "config.h"
#include "crc.h"
#include "pool.h"
#include "device.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <ctype.h> #include <ctype.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#include "pool.h"
#include "log.h"
enum { enum {
TOK_INT, TOK_INT,
@@ -32,10 +31,10 @@ enum {
}; };
struct parser { struct parser {
const char *fb, *fe; /* file limits */ char *fb, *fe; /* file limits */
int t; /* token limits and type */ int t; /* token limits and type */
const char *tb, *te; char *tb, *te;
int fd; /* descriptor for file being parsed */ int fd; /* descriptor for file being parsed */
int line; /* line number we are on */ int line; /* line number we are on */
@@ -44,11 +43,13 @@ struct parser {
}; };
struct cs { struct cs {
struct config_file cf; struct config_tree cf;
struct pool *mem; struct pool *mem;
time_t timestamp;
char *filename;
}; };
static void _get_token(struct parser *p); static void _get_token(struct parser *p, int tok_prev);
static void _eat_space(struct parser *p); static void _eat_space(struct parser *p);
static struct config_node *_file(struct parser *p); static struct config_node *_file(struct parser *p);
static struct config_node *_section(struct parser *p); static struct config_node *_section(struct parser *p);
@@ -81,7 +82,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
/* /*
* public interface * public interface
*/ */
struct config_file *create_config_file(void) struct config_tree *create_config_tree(void)
{ {
struct cs *c; struct cs *c;
struct pool *mem = pool_create(10 * 1024); struct pool *mem = pool_create(10 * 1024);
@@ -99,20 +100,25 @@ struct config_file *create_config_file(void)
c->mem = mem; c->mem = mem;
c->cf.root = (struct config_node *) NULL; c->cf.root = (struct config_node *) NULL;
c->timestamp = 0;
c->filename = NULL;
return &c->cf; return &c->cf;
} }
void destroy_config_file(struct config_file *cf) void destroy_config_tree(struct config_tree *cf)
{ {
pool_destroy(((struct cs *) cf)->mem); pool_destroy(((struct cs *) cf)->mem);
} }
int read_config(struct config_file *cf, const char *file) int read_config_fd(struct config_tree *cf, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum)
{ {
struct cs *c = (struct cs *) cf; struct cs *c = (struct cs *) cf;
struct parser *p; struct parser *p;
struct stat info; int r = 0;
int r = 1, fd; int use_mmap = 1;
off_t mmap_offset = 0;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) { if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack; stack;
@@ -120,50 +126,195 @@ int read_config(struct config_file *cf, const char *file)
} }
p->mem = c->mem; p->mem = c->mem;
/* memory map the file */ /* Only use mmap with regular files */
if (stat(file, &info) || S_ISDIR(info.st_mode)) { if (!(dev->flags & DEV_REGULAR) || size2)
use_mmap = 0;
if (use_mmap) {
mmap_offset = offset % getpagesize();
/* memory map the file */
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", dev_name(dev));
goto out;
}
p->fb = p->fb + mmap_offset;
} else {
if (!(p->fb = dbg_malloc(size + size2))) {
stack;
return 0;
}
if (!dev_read(dev, (uint64_t) offset, size, p->fb)) {
log_error("Read from %s failed", dev_name(dev));
goto out;
}
if (size2) {
if (!dev_read(dev, (uint64_t) offset2, size2,
p->fb + size)) {
log_error("Circular read from %s failed",
dev_name(dev));
goto out;
}
}
}
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
p->fb + size, size2))) {
log_error("%s: Checksum error", dev_name(dev));
goto out;
}
p->fe = p->fb + size + size2;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p, TOK_SECTION_E);
if (!(cf->root = _file(p))) {
stack;
goto out;
}
r = 1;
out:
if (!use_mmap)
dbg_free(p->fb);
else {
/* unmap the file */
if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
log_sys_error("munmap", dev_name(dev));
r = 0;
}
}
return r;
}
int read_config_file(struct config_tree *cf, const char *file)
{
struct cs *c = (struct cs *) cf;
struct stat info;
struct device *dev;
int r = 1;
if (stat(file, &info)) {
log_sys_error("stat", file); log_sys_error("stat", file);
return 0; return 0;
} }
if (!S_ISREG(info.st_mode)) {
log_error("%s is not a regular file", file);
return 0;
}
if (info.st_size == 0) { if (info.st_size == 0) {
log_verbose("%s is empty", file); log_verbose("%s is empty", file);
return 1; return 1;
} }
if ((fd = open(file, O_RDONLY)) < 0) { if (!(dev = dev_create_file(file, NULL, NULL))) {
log_sys_error("open", file);
return 0;
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack; stack;
r = 0; return 0;
} }
/* unmap the file */ if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
if (munmap((char *) p->fb, info.st_size)) { stack;
log_sys_error("munmap", file); return 0;
r = 0;
} }
close(fd); r = read_config_fd(cf, dev, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0);
dev_close(dev);
c->timestamp = info.st_mtime;
c->filename = pool_strdup(c->mem, file);
return r; return r;
} }
static void _write_value(FILE * fp, struct config_value *v) time_t config_file_timestamp(struct config_tree *cf)
{
struct cs *c = (struct cs *) cf;
return c->timestamp;
}
/*
* Returns 1 if config file reloaded
*/
int reload_config_file(struct config_tree **cf)
{
struct config_tree *new_cf;
struct cs *c = (struct cs *) *cf;
struct cs *new_cs;
struct stat info;
struct device *dev;
int r;
if (!c->filename)
return 0;
if (stat(c->filename, &info) == -1) {
if (errno == ENOENT)
return 1;
log_sys_error("stat", c->filename);
log_error("Failed to reload configuration file");
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("Configuration file %s is not a regular file",
c->filename);
return 0;
}
/* Unchanged? */
if (c->timestamp == info.st_mtime)
return 0;
log_verbose("Detected config file change: Reloading %s", c->filename);
if (info.st_size == 0) {
log_verbose("Config file reload: %s is empty", c->filename);
return 0;
}
if (!(new_cf = create_config_tree())) {
log_error("Allocation of new config_tree failed");
return 0;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
stack;
return 0;
}
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
r = read_config_fd(new_cf, dev, 0, (size_t) info.st_size,
0, 0, (checksum_fn_t) NULL, 0);
dev_close(dev);
if (r) {
new_cs = (struct cs *) new_cf;
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
new_cs->timestamp = info.st_mtime;
destroy_config_tree(*cf);
*cf = new_cf;
}
return r;
}
static void _write_value(FILE *fp, struct config_value *v)
{ {
switch (v->type) { switch (v->type) {
case CFG_STRING: case CFG_STRING:
@@ -177,10 +328,18 @@ static void _write_value(FILE * fp, struct config_value *v)
case CFG_INT: case CFG_INT:
fprintf(fp, "%d", v->v.i); fprintf(fp, "%d", v->v.i);
break; break;
case CFG_EMPTY_ARRAY:
fprintf(fp, "[]");
break;
default:
log_error("_write_value: Unknown value type: %d", v->type);
} }
} }
static int _write_config(struct config_node *n, FILE * fp, int level) static int _write_config(struct config_node *n, FILE *fp, int level)
{ {
char space[MAX_INDENT + 1]; char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT; int l = (level < MAX_INDENT) ? level : MAX_INDENT;
@@ -190,7 +349,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
return 1; return 1;
for (i = 0; i < l; i++) for (i = 0; i < l; i++)
space[i] = ' '; space[i] = '\t';
space[i] = '\0'; space[i] = '\0';
while (n) { while (n) {
@@ -223,7 +382,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
return 1; return 1;
} }
int write_config(struct config_file *cf, const char *file) int write_config_file(struct config_tree *cf, const char *file)
{ {
int r = 1; int r = 1;
FILE *fp = fopen(file, "w"); FILE *fp = fopen(file, "w");
@@ -306,7 +465,7 @@ static struct config_node *_section(struct parser *p)
static struct config_value *_value(struct parser *p) static struct config_value *_value(struct parser *p)
{ {
/* '[' TYPE* ']' | TYPE */ /* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0; struct config_value *h = NULL, *l, *ll = NULL;
if (p->t == TOK_ARRAY_B) { if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B); match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) { while (p->t != TOK_ARRAY_E) {
@@ -325,6 +484,16 @@ static struct config_value *_value(struct parser *p)
match(TOK_COMMA); match(TOK_COMMA);
} }
match(TOK_ARRAY_E); match(TOK_ARRAY_E);
/*
* Special case for an empty array.
*/
if (!h) {
if (!(h = _create_value(p)))
return NULL;
h->type = CFG_EMPTY_ARRAY;
}
} else } else
h = _type(p); h = _type(p);
@@ -336,16 +505,19 @@ static struct config_value *_type(struct parser *p)
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */ /* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p); struct config_value *v = _create_value(p);
if (!v)
return NULL;
switch (p->t) { switch (p->t) {
case TOK_INT: case TOK_INT:
v->type = CFG_INT; v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */ v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
match(TOK_INT); match(TOK_INT);
break; break;
case TOK_FLOAT: case TOK_FLOAT:
v->type = CFG_FLOAT; v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */ v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
match(TOK_FLOAT); match(TOK_FLOAT);
break; break;
@@ -373,22 +545,29 @@ static int _match_aux(struct parser *p, int t)
if (p->t != t) if (p->t != t)
return 0; return 0;
_get_token(p); _get_token(p, t);
return 1; return 1;
} }
/* /*
* tokeniser * tokeniser
*/ */
static void _get_token(struct parser *p) static void _get_token(struct parser *p, int tok_prev)
{ {
int values_allowed = 0;
p->tb = p->te; p->tb = p->te;
_eat_space(p); _eat_space(p);
if (p->tb == p->fe) { if (p->tb == p->fe || !*p->tb) {
p->t = TOK_EOF; p->t = TOK_EOF;
return; return;
} }
/* Should next token be interpreted as value instead of identifier? */
if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
tok_prev == TOK_COMMA)
values_allowed = 1;
p->t = TOK_INT; /* fudge so the fall through for p->t = TOK_INT; /* fudge so the fall through for
floats works */ floats works */
switch (*p->te) { switch (*p->te) {
@@ -425,13 +604,24 @@ static void _get_token(struct parser *p)
case '"': case '"':
p->t = TOK_STRING; p->t = TOK_STRING;
p->te++; p->te++;
while ((p->te != p->fe) && (*p->te != '"')) { while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe)) if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
*(p->te + 1))
p->te++; p->te++;
p->te++; p->te++;
} }
if (p->te != p->fe) if ((p->te != p->fe) && (*p->te))
p->te++;
break;
case '\'':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
p->te++;
if ((p->te != p->fe) && (*p->te))
p->te++; p->te++;
break; break;
@@ -447,22 +637,25 @@ static void _get_token(struct parser *p)
case '7': case '7':
case '8': case '8':
case '9': case '9':
p->te++; if (values_allowed) {
while (p->te != p->fe) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++; p->te++;
while ((p->te != p->fe) && (*p->te)) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++;
}
break;
} }
break;
default: default:
p->t = TOK_IDENTIFIER; p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) && while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '=')) (*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
(*p->te != '}'))
p->te++; p->te++;
break; break;
} }
@@ -470,15 +663,15 @@ static void _get_token(struct parser *p)
static void _eat_space(struct parser *p) static void _eat_space(struct parser *p)
{ {
while (p->tb != p->fe) { while ((p->tb != p->fe) && (*p->tb)) {
if (*p->te == '#') { if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n')) while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
p->te++; p->te++;
p->line++; p->line++;
} }
else if (isspace(*p->te)) { else if (isspace(*p->te)) {
while ((p->te != p->fe) && isspace(*p->te)) { while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
if (*p->te == '\n') if (*p->te == '\n')
p->line++; p->line++;
p->te++; p->te++;
@@ -511,7 +704,7 @@ static struct config_node *_create_node(struct parser *p)
static char *_dup_tok(struct parser *p) static char *_dup_tok(struct parser *p)
{ {
int len = p->te - p->tb; size_t len = p->te - p->tb;
char *str = pool_alloc(p->mem, len + 1); char *str = pool_alloc(p->mem, len + 1);
if (!str) { if (!str) {
stack; stack;
@@ -526,7 +719,7 @@ static char *_dup_tok(struct parser *p)
* utility functions * utility functions
*/ */
struct config_node *find_config_node(struct config_node *cn, struct config_node *find_config_node(struct config_node *cn,
const char *path, char sep) const char *path, const int sep)
{ {
const char *e; const char *e;
@@ -558,7 +751,7 @@ struct config_node *find_config_node(struct config_node *cn,
} }
const char *find_config_str(struct config_node *cn, const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail) const char *path, const int sep, const char *fail)
{ {
struct config_node *n = find_config_node(cn, path, sep); struct config_node *n = find_config_node(cn, path, sep);
@@ -575,7 +768,7 @@ const char *find_config_str(struct config_node *cn,
} }
int find_config_int(struct config_node *cn, const char *path, int find_config_int(struct config_node *cn, const char *path,
char sep, int fail) const int sep, int fail)
{ {
struct config_node *n = find_config_node(cn, path, sep); struct config_node *n = find_config_node(cn, path, sep);
@@ -590,7 +783,7 @@ int find_config_int(struct config_node *cn, const char *path,
} }
float find_config_float(struct config_node *cn, const char *path, float find_config_float(struct config_node *cn, const char *path,
char sep, float fail) const int sep, float fail)
{ {
struct config_node *n = find_config_node(cn, path, sep); struct config_node *n = find_config_node(cn, path, sep);
@@ -633,7 +826,7 @@ static int _str_to_bool(const char *str, int fail)
} }
int find_config_bool(struct config_node *cn, const char *path, int find_config_bool(struct config_node *cn, const char *path,
char sep, int fail) const int sep, int fail)
{ {
struct config_node *n = find_config_node(cn, path, sep); struct config_node *n = find_config_node(cn, path, sep);
struct config_value *v; struct config_value *v;
@@ -655,7 +848,7 @@ int find_config_bool(struct config_node *cn, const char *path,
} }
int get_config_uint32(struct config_node *cn, const char *path, int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t * result) const int sep, uint32_t *result)
{ {
struct config_node *n; struct config_node *n;
@@ -669,7 +862,7 @@ int get_config_uint32(struct config_node *cn, const char *path,
} }
int get_config_uint64(struct config_node *cn, const char *path, int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t * result) const int sep, uint64_t *result)
{ {
struct config_node *n; struct config_node *n;
@@ -682,3 +875,17 @@ int get_config_uint64(struct config_node *cn, const char *path,
*result = (uint64_t) n->v->v.i; *result = (uint64_t) n->v->v.i;
return 1; return 1;
} }
int get_config_str(struct config_node *cn, const char *path,
const int sep, char **result)
{
struct config_node *n;
n = find_config_node(cn, path, sep);
if (!n || !n->v || n->v->type != CFG_STRING)
return 0;
*result = n->v->v.str;
return 1;
}

View File

@@ -7,66 +7,75 @@
#ifndef _LVM_CONFIG_H #ifndef _LVM_CONFIG_H
#define _LVM_CONFIG_H #define _LVM_CONFIG_H
#include <inttypes.h> #include "device.h"
enum { enum {
CFG_STRING, CFG_STRING,
CFG_FLOAT, CFG_FLOAT,
CFG_INT, CFG_INT,
CFG_EMPTY_ARRAY
}; };
struct config_value { struct config_value {
int type; int type;
union { union {
int i; int i;
float r; float r;
char *str; char *str;
} v; } v;
struct config_value *next; /* for arrays */ struct config_value *next; /* for arrays */
}; };
struct config_node { struct config_node {
char *key; char *key;
struct config_node *sib, *child; struct config_node *sib, *child;
struct config_value *v; struct config_value *v;
}; };
struct config_file { struct config_tree {
struct config_node *root; struct config_node *root;
}; };
struct config_file *create_config_file(void); struct config_tree *create_config_tree(void);
void destroy_config_file(struct config_file *cf); void destroy_config_tree(struct config_tree *cf);
int read_config(struct config_file *cf, const char *file); typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
int write_config(struct config_file *cf, const char *file);
int read_config_fd(struct config_tree *cf, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum);
int read_config_file(struct config_tree *cf, const char *file);
int write_config_file(struct config_tree *cf, const char *file);
int reload_config_file(struct config_tree **cf);
time_t config_file_timestamp(struct config_tree *cf);
struct config_node *find_config_node(struct config_node *cn, struct config_node *find_config_node(struct config_node *cn,
const char *path, char seperator); const char *path, const int separator);
const char *find_config_str(struct config_node *cn, const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail); const char *path, const int sep, const char *fail);
int find_config_int(struct config_node *cn, const char *path, int find_config_int(struct config_node *cn, const char *path,
char sep, int fail); const int sep, int fail);
float find_config_float(struct config_node *cn, const char *path, float find_config_float(struct config_node *cn, const char *path,
char sep, float fail); const int sep, float fail);
/* /*
* Understands (0, ~0), (y, n), (yes, no), (on, * Understands (0, ~0), (y, n), (yes, no), (on,
* off), (true, false). * off), (true, false).
*/ */
int find_config_bool(struct config_node *cn, const char *path, int find_config_bool(struct config_node *cn, const char *path,
char sep, int fail); const int sep, int fail);
int get_config_uint32(struct config_node *cn, const char *path, int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t *result); const int sep, uint32_t *result);
int get_config_uint64(struct config_node *cn, const char *path, int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t *result); const int sep, uint64_t *result);
int get_config_str(struct config_node *cn, const char *path,
const int sep, char **result);
#endif #endif

View File

@@ -7,9 +7,6 @@
#ifndef _LVM_DEFAULTS_H #ifndef _LVM_DEFAULTS_H
#define _LVM_DEFAULTS_H #define _LVM_DEFAULTS_H
#define DEFAULT_SYS_DIR "/etc/lvm"
#define DEFAULT_ARCHIVE_ENABLED 1 #define DEFAULT_ARCHIVE_ENABLED 1
#define DEFAULT_BACKUP_ENABLED 1 #define DEFAULT_BACKUP_ENABLED 1
@@ -19,22 +16,76 @@
#define DEFAULT_ARCHIVE_DAYS 30 #define DEFAULT_ARCHIVE_DAYS 30
#define DEFAULT_ARCHIVE_NUMBER 10 #define DEFAULT_ARCHIVE_NUMBER 10
#define DEFAULT_SYS_DIR "/etc/lvm"
#define DEFAULT_DEV_DIR "/dev" #define DEFAULT_DEV_DIR "/dev"
#define DEFAULT_PROC_DIR "/proc" #define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_LOCK_DIR "/var/lock/lvm" #define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
#define DEFAULT_UMASK 0077 #define DEFAULT_UMASK 0077
#define DEFAULT_FORMAT "lvm1" #ifdef LVM1_SUPPORT
# define DEFAULT_FORMAT "lvm1"
#define DEFAULT_MSG_PREFIX " " #else
# define DEFAULT_FORMAT "lvm2"
#define DEFAULT_CMD_NAME 0
#ifdef READLINE_SUPPORT
#define DEFAULT_MAX_HISTORY 100
#endif #endif
#define DEFAULT_STRIPESIZE 64 /* KB */
#define DEFAULT_PVMETADATASIZE 255
#define DEFAULT_PVMETADATACOPIES 1
#define DEFAULT_LABELSECTOR UINT64_C(1)
#endif /* _LVM_DEFAULTS_H */ #define DEFAULT_MSG_PREFIX " "
#define DEFAULT_CMD_NAME 0
#define DEFAULT_OVERWRITE 0
#ifndef DEFAULT_LOG_FACILITY
# define DEFAULT_LOG_FACILITY LOG_USER
#endif
#define DEFAULT_SYSLOG 1
#define DEFAULT_VERBOSE 0
#define DEFAULT_LOGLEVEL 0
#define DEFAULT_INDENT 1
#define DEFAULT_UNITS "h"
#define DEFAULT_SUFFIX 1
#ifdef DEVMAPPER_SUPPORT
# define DEFAULT_ACTIVATION 1
# define DEFAULT_RESERVED_MEMORY 8192
# define DEFAULT_RESERVED_STACK 256
# define DEFAULT_PROCESS_PRIORITY -18
#else
# define DEFAULT_ACTIVATION 0
#endif
#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
#define DEFAULT_MIRROR_REGION_SIZE 512 /* KB */
#define DEFAULT_INTERVAL 15
#ifdef READLINE_SUPPORT
# define DEFAULT_MAX_HISTORY 100
#endif
#define DEFAULT_REP_ALIGNED 1
#define DEFAULT_REP_BUFFERED 1
#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,move_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_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,move_percent,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_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
#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"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -4,18 +4,16 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "bitset.h" #include "bitset.h"
#include "dbg_malloc.h"
#include <stdlib.h>
/* FIXME: calculate this. */ /* FIXME: calculate this. */
#define INT_SHIFT 5 #define INT_SHIFT 5
bitset_t bitset_create(struct pool * mem, unsigned num_bits) bitset_t bitset_create(struct pool *mem, unsigned num_bits)
{ {
int n = (num_bits / BITS_PER_INT) + 2; unsigned n = (num_bits / BITS_PER_INT) + 2;
int size = sizeof(int) * n; size_t size = sizeof(int) * n;
unsigned *bs = pool_zalloc(mem, size); unsigned *bs = pool_zalloc(mem, size);
if (!bs) if (!bs)

View File

@@ -7,22 +7,19 @@
#ifndef _LVM_BITSET_H #ifndef _LVM_BITSET_H
#define _LVM_BITSET_H #define _LVM_BITSET_H
#include "lvm-types.h"
#include "pool.h" #include "pool.h"
#include <limits.h> #include <limits.h>
#include <string.h>
typedef uint32_t *bitset_t; typedef uint32_t *bitset_t;
bitset_t bitset_create(struct pool *mem, unsigned num_bits); bitset_t bitset_create(struct pool *mem, unsigned num_bits);
void bitset_destroy(bitset_t bs);
void bit_union(bitset_t out, bitset_t in1, bitset_t in2); void bit_union(bitset_t out, bitset_t in1, bitset_t in2);
int bit_get_first(bitset_t bs); int bit_get_first(bitset_t bs);
int bit_get_next(bitset_t bs, int last_bit); int bit_get_next(bitset_t bs, int last_bit);
#define BITS_PER_INT (sizeof(int) * CHAR_BIT) #define BITS_PER_INT (sizeof(int) * CHAR_BIT)
#define bit(bs, i) \ #define bit(bs, i) \

View File

@@ -4,8 +4,8 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "btree.h" #include "btree.h"
#include "log.h"
struct node { struct node {
uint32_t key; uint32_t key;
@@ -46,7 +46,7 @@ static uint32_t _shuffle(uint32_t k)
#endif #endif
} }
struct node **_lookup(struct node **c, uint32_t key, struct node **p) static struct node **_lookup(struct node **c, uint32_t key, struct node **p)
{ {
*p = NULL; *p = NULL;
while (*c) { while (*c) {

View File

@@ -7,7 +7,6 @@
#ifndef _LVM_BTREE_H #ifndef _LVM_BTREE_H
#define _LVM_BTREE_H #define _LVM_BTREE_H
#include "lvm-types.h"
#include "pool.h" #include "pool.h"
struct btree; struct btree;

View File

@@ -4,9 +4,8 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "dbg_malloc.h" #include "lib.h"
#include "hash.h" #include "hash.h"
#include "log.h"
struct hash_node { struct hash_node {
struct hash_node *next; struct hash_node *next;
@@ -26,26 +25,26 @@ static unsigned char _nums[] = {
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65, 87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28, 49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172, 12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
144, 144,
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254, 176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54, 178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
221, 221,
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93, 102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189, 166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185, 121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
194, 194,
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232, 193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
139, 139,
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112, 6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196, 84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
43, 43,
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231, 249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
71, 71,
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47, 230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
109, 109,
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184, 44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120, 163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
209 209
}; };
static struct hash_node *_create_node(const char *str) static struct hash_node *_create_node(const char *str)
@@ -62,7 +61,7 @@ static struct hash_node *_create_node(const char *str)
static unsigned _hash(const char *str) static unsigned _hash(const char *str)
{ {
unsigned long int h = 0, g; unsigned long h = 0, g;
while (*str) { while (*str) {
h <<= 4; h <<= 4;
h += _nums[(int) *str++]; h += _nums[(int) *str++];
@@ -209,7 +208,7 @@ void *hash_get_data(struct hash_table *t, struct hash_node *n)
return n->data; return n->data;
} }
static struct hash_node *_next_slot(struct hash_table *t, unsigned int s) static struct hash_node *_next_slot(struct hash_table *t, unsigned s)
{ {
struct hash_node *c = NULL; struct hash_node *c = NULL;
int i; int i;
@@ -227,6 +226,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n) struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
{ {
unsigned int h = _hash(n->key) & (t->num_slots - 1); unsigned h = _hash(n->key) & (t->num_slots - 1);
return n->next ? n->next : _next_slot(t, h + 1); return n->next ? n->next : _next_slot(t, h + 1);
} }

View File

@@ -10,13 +10,14 @@
struct hash_table; struct hash_table;
struct hash_node; struct hash_node;
typedef void (*iterate_fn)(void *data); typedef void (*iterate_fn) (void *data);
struct hash_table *hash_create(unsigned size_hint); struct hash_table *hash_create(unsigned size_hint);
void hash_destroy(struct hash_table *t); void hash_destroy(struct hash_table *t);
void hash_wipe(struct hash_table *t); void hash_wipe(struct hash_table *t);
void *hash_lookup(struct hash_table *t, const char *key); void *hash_lookup(struct hash_table *t, const char *key);
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len);
int hash_insert(struct hash_table *t, const char *key, void *data); int hash_insert(struct hash_table *t, const char *key, void *data);
void hash_remove(struct hash_table *t, const char *key); void hash_remove(struct hash_table *t, const char *key);
@@ -33,4 +34,3 @@ struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
v = hash_get_next(h, v)) v = hash_get_next(h, v))
#endif #endif

View File

@@ -13,11 +13,15 @@ struct list {
struct list *n, *p; struct list *n, *p;
}; };
static inline void list_init(struct list *head) { #define LIST_INIT(name) struct list name = { &(name), &(name) }
static inline void list_init(struct list *head)
{
head->n = head->p = head; head->n = head->p = head;
} }
static inline void list_add(struct list *head, struct list *elem) { static inline void list_add(struct list *head, struct list *elem)
{
assert(head->n); assert(head->n);
elem->n = head; elem->n = head;
@@ -27,7 +31,8 @@ static inline void list_add(struct list *head, struct list *elem) {
head->p = elem; head->p = elem;
} }
static inline void list_add_h(struct list *head, struct list *elem) { static inline void list_add_h(struct list *head, struct list *elem)
{
assert(head->n); assert(head->n);
elem->n = head->n; elem->n = head->n;
@@ -37,27 +42,43 @@ static inline void list_add_h(struct list *head, struct list *elem) {
head->n = elem; head->n = elem;
} }
static inline void list_del(struct list *elem) { static inline void list_del(struct list *elem)
{
elem->n->p = elem->p; elem->n->p = elem->p;
elem->p->n = elem->n; elem->p->n = elem->n;
} }
static inline int list_empty(struct list *head) { static inline int list_empty(struct list *head)
{
return head->n == head; return head->n == head;
} }
static inline int list_end(struct list *head, struct list *elem)
{
return elem->n == head;
}
static inline struct list *list_next(struct list *head, struct list *elem)
{
return (list_end(head, elem) ? NULL : elem->n);
}
#define list_iterate(v, head) \ #define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n) for (v = (head)->n; v != head; v = v->n)
#define list_uniterate(v, head, start) \
for (v = (start)->p; v != head; v = v->p)
#define list_iterate_safe(v, t, head) \ #define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n) for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
static inline int list_size(struct list *head) { static inline unsigned int list_size(const struct list *head)
int s = 0; {
struct list *v; unsigned int s = 0;
const struct list *v;
list_iterate(v, head) list_iterate(v, head)
s++; s++;
return s; return s;
} }
@@ -65,8 +86,14 @@ static inline int list_size(struct list *head) {
#define list_item(v, t) \ #define list_item(v, t) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list)) ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
/* Given a known element in a known structure, locate the struct list */ #define list_struct_base(v, t, h) \
#define list_head(v, t, e) \ ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->list)
/* Given a known element in a known structure, locate another */
#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 */
#define list_head(v, t, e) struct_field(v, t, e, list)
#endif #endif

View File

@@ -12,9 +12,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <inttypes.h> #include <inttypes.h>
/* Define some portable printing types */
#define PRIsize_t "Zu"
struct str_list { struct str_list {
struct list list; struct list list;
char *str; const char *str;
}; };
#endif #endif

View File

@@ -4,27 +4,18 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "dev-cache.h" #include "dev-cache.h"
#include "log.h"
#include "pool.h" #include "pool.h"
#include "hash.h" #include "hash.h"
#include "list.h" #include "list.h"
#include "lvm-types.h" #include "lvm-types.h"
#include "btree.h" #include "btree.h"
#include "dbg_malloc.h" #include "filter.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <sys/param.h> #include <sys/param.h>
#include <dirent.h> #include <dirent.h>
#include <linux/kdev_t.h>
/*
* FIXME: really need to seperate names from the devices since
* multiple names can point to the same device.
*/
struct dev_iter { struct dev_iter {
struct btree_iter *current; struct btree_iter *current;
@@ -51,36 +42,163 @@ static struct {
static int _insert(const char *path, int rec); static int _insert(const char *path, int rec);
static struct device *_create_dev(dev_t d) struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias)
{
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);
}
return NULL;
}
dev->flags = DEV_REGULAR;
if (allocate)
dev->flags |= DEV_ALLOCED;
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;
memset(dev->pvid, 0, sizeof(dev->pvid));
list_init(&dev->open_list);
return dev;
}
static struct device *_dev_create(dev_t d)
{ {
struct device *dev; struct device *dev;
if (!(dev = _alloc(sizeof(*dev)))) { if (!(dev = _alloc(sizeof(*dev)))) {
stack; log_error("struct device allocation failed");
return NULL; return NULL;
} }
dev->flags = 0;
list_init(&dev->aliases); list_init(&dev->aliases);
dev->dev = d; dev->dev = d;
dev->fd = -1; dev->fd = -1;
dev->open_count = 0;
dev->end = UINT64_C(0);
memset(dev->pvid, 0, sizeof(dev->pvid));
list_init(&dev->open_list);
return dev; return dev;
} }
/* Return 1 if we prefer path1 else return 0 */
static int _compare_paths(const char *path0, const char *path1)
{
int slash0 = 0, slash1 = 0;
const char *p;
char p0[PATH_MAX], p1[PATH_MAX];
char *s0, *s1;
struct stat stat0, stat1;
/* Return the path with fewer slashes */
for (p = path0; p++; p = (const char *) strchr(p, '/'))
slash0++;
for (p = path1; p++; p = (const char *) strchr(p, '/'))
slash1++;
if (slash0 < slash1)
return 0;
if (slash1 < slash0)
return 1;
strncpy(p0, path0, PATH_MAX);
strncpy(p1, path1, PATH_MAX);
s0 = &p0[0] + 1;
s1 = &p1[0] + 1;
/* We prefer symlinks - they exist for a reason!
* So we prefer a shorter path before the first symlink in the name.
* FIXME Configuration option to invert this? */
while (s0) {
s0 = strchr(s0, '/');
s1 = strchr(s1, '/');
if (s0) {
*s0 = '\0';
*s1 = '\0';
}
if (lstat(p0, &stat0)) {
log_sys_error("lstat", p0);
return 1;
}
if (lstat(p1, &stat1)) {
log_sys_error("lstat", p1);
return 0;
}
if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
return 0;
if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
return 1;
if (s0) {
*s0++ = '/';
*s1++ = '/';
}
}
/* ASCII comparison */
if (strcmp(path0, path1) < 0)
return 0;
else
return 1;
}
static int _add_alias(struct device *dev, const char *path) static int _add_alias(struct device *dev, const char *path)
{ {
struct str_list *sl = _alloc(sizeof(*sl)); struct str_list *sl = _alloc(sizeof(*sl));
struct list *ah;
const char *oldpath;
int prefer_old = 1;
if (!sl) { if (!sl) {
stack; stack;
return 0; return 0;
} }
/* Is name already there? */
list_iterate(ah, &dev->aliases) {
if (!strcmp(list_item(ah, struct str_list)->str, path)) {
stack;
return 1;
}
}
if (!(sl->str = pool_strdup(_cache.mem, path))) { if (!(sl->str = pool_strdup(_cache.mem, path))) {
stack; stack;
return 0; return 0;
} }
list_add(&dev->aliases, &sl->list); if (!list_empty(&dev->aliases)) {
oldpath = list_item(dev->aliases.n, struct str_list)->str;
prefer_old = _compare_paths(path, oldpath);
log_debug("%s: Aliased to %s in device cache%s",
path, oldpath, prefer_old ? "" : " (preferred name)");
} else
log_debug("%s: Added to device cache", path);
if (prefer_old)
list_add(&dev->aliases, &sl->list);
else
list_add_h(&dev->aliases, &sl->list);
return 1; return 1;
} }
@@ -93,14 +211,15 @@ static int _insert_dev(const char *path, dev_t d)
struct device *dev; struct device *dev;
/* is this device already registered ? */ /* is this device already registered ? */
if (!(dev = (struct device *) btree_lookup(_cache.devices, d))) { if (!(dev = (struct device *) btree_lookup(_cache.devices,
(uint32_t) d))) {
/* create new device */ /* create new device */
if (!(dev = _create_dev(d))) { if (!(dev = _dev_create(d))) {
stack; stack;
return 0; return 0;
} }
if (!(btree_insert(_cache.devices, d, dev))) { if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
log_err("Couldn't insert device into binary tree."); log_err("Couldn't insert device into binary tree.");
_free(dev); _free(dev);
return 0; return 0;
@@ -122,7 +241,7 @@ static int _insert_dev(const char *path, dev_t d)
static char *_join(const char *dir, const char *name) static char *_join(const char *dir, const char *name)
{ {
int len = strlen(dir) + strlen(name) + 2; size_t len = strlen(dir) + strlen(name) + 2;
char *r = dbg_malloc(len); char *r = dbg_malloc(len);
if (r) if (r)
snprintf(r, len, "%s/%s", dir, name); snprintf(r, len, "%s/%s", dir, name);
@@ -229,6 +348,21 @@ static void _full_scan(void)
_cache.has_scanned = 1; _cache.has_scanned = 1;
} }
int dev_cache_has_scanned(void)
{
return _cache.has_scanned;
}
void dev_cache_scan(int do_scan)
{
if (!do_scan)
_cache.has_scanned = 1;
else {
_cache.has_scanned = 0;
_full_scan();
}
}
int dev_cache_init(void) int dev_cache_init(void)
{ {
_cache.names = NULL; _cache.names = NULL;
@@ -259,7 +393,7 @@ int dev_cache_init(void)
return 0; return 0;
} }
void _check_closed(struct device *dev) static void _check_closed(struct device *dev)
{ {
if (dev->fd >= 0) if (dev->fd >= 0)
log_err("Device '%s' has been left open.", dev_name(dev)); log_err("Device '%s' has been left open.", dev_name(dev));
@@ -295,8 +429,10 @@ int dev_cache_add_dir(const char *path)
return 1; return 1;
} }
if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
log_error("dir_list allocation failed");
return 0; return 0;
}
strcpy(dl->dir, path); strcpy(dl->dir, path);
list_add(&_cache.dirs, &dl->list); list_add(&_cache.dirs, &dl->list);
@@ -305,20 +441,31 @@ int dev_cache_add_dir(const char *path)
/* Check cached device name is still valid before returning it */ /* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */ /* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
/* FIXME Make rest of code pass/cache struct device instead of dev_name */ /* FIXME Make rest of code pass/cache struct device instead of dev_name */
const char *dev_name_confirmed(struct device *dev) const char *dev_name_confirmed(struct device *dev, int quiet)
{ {
struct stat buf; struct stat buf;
char *name; const char *name;
int r; int r;
while ((r = stat(name = list_item(dev->aliases.n, while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) || struct str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) { (buf.st_rdev != dev->dev)) {
if (r < 0) if (r < 0) {
log_sys_error("stat", name); if (quiet)
log_error("Path %s no longer valid for device(%d,%d)", log_sys_debug("stat", name);
name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev)); else
log_sys_error("stat", name);
}
if (quiet)
log_debug("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev),
(int) MINOR(dev->dev));
else
log_error("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev),
(int) MINOR(dev->dev));
/* Remove the incorrect hash entry */ /* Remove the incorrect hash entry */
hash_remove(_cache.names, name); hash_remove(_cache.names, name);
@@ -364,8 +511,10 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
{ {
struct dev_iter *di = dbg_malloc(sizeof(*di)); struct dev_iter *di = dbg_malloc(sizeof(*di));
if (!di) if (!di) {
log_error("dev_iter allocation failed");
return NULL; return NULL;
}
_full_scan(); _full_scan();
di->current = btree_first(_cache.devices); di->current = btree_first(_cache.devices);

View File

@@ -7,7 +7,6 @@
#ifndef _LVM_DEV_CACHE_H #ifndef _LVM_DEV_CACHE_H
#define _LVM_DEV_CACHE_H #define _LVM_DEV_CACHE_H
#include <sys/types.h>
#include "lvm-types.h" #include "lvm-types.h"
#include "device.h" #include "device.h"
@@ -15,22 +14,24 @@
* predicate for devices. * predicate for devices.
*/ */
struct dev_filter { struct dev_filter {
int (*passes_filter)(struct dev_filter *f, struct device *dev); int (*passes_filter) (struct dev_filter * f, struct device * dev);
void (*destroy)(struct dev_filter *f); void (*destroy) (struct dev_filter * f);
void *private; void *private;
}; };
/* /*
* The global device cache. * The global device cache.
*/ */
int dev_cache_init(void); int dev_cache_init(void);
void dev_cache_exit(void); void dev_cache_exit(void);
/* Trigger(1) or avoid(0) a scan */
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_dir(const char *path);
struct device *dev_cache_get(const char *name, struct dev_filter *f); struct device *dev_cache_get(const char *name, struct dev_filter *f);
/* /*
* Object for iterating through the cache. * Object for iterating through the cache.
*/ */

View File

@@ -4,21 +4,206 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "device.h" #include "lib.h"
#include "lvm-types.h" #include "lvm-types.h"
#include "log.h" #include "device.h"
#include "metadata.h"
#include "lvmcache.h"
#include "memlock.h"
#include <sys/types.h> #include <limits.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/fs.h> // UGH!!! for BLKSSZGET
int dev_get_size(struct device *dev, uint64_t * size) #ifdef linux
# define u64 uint64_t /* Missing without __KERNEL__ */
# undef WNOHANG /* Avoid redefinition */
# undef WUNTRACED /* Avoid redefinition */
# include <linux/fs.h> /* For block ioctl definitions */
# define BLKSIZE_SHIFT SECTOR_SHIFT
#else
# include <sys/disk.h>
# define BLKBSZGET DKIOCGETBLOCKSIZE
# define BLKSSZGET DKIOCGETBLOCKSIZE
# define BLKGETSIZE64 DKIOCGETBLOCKCOUNT
# define BLKFLSBUF DKIOCSYNCHRONIZECACHE
# define BLKSIZE_SHIFT 0
# ifndef O_DIRECT
# define O_DIRECT 0
# endif
#endif
/* FIXME Use _llseek for 64-bit
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);
if (_llseek((unsigned) fd, (ulong) (offset >> 32), (ulong) (offset & 0xFFFFFFFF), &pos, SEEK_SET) < 0) {
*/
static LIST_INIT(_open_devices);
/*-----------------------------------------------------------------
* The standard io loop that keeps submitting an io until it's
* all gone.
*---------------------------------------------------------------*/
static int _io(struct device_area *where, void *buffer, int should_write)
{
int fd = dev_fd(where->dev);
ssize_t n = 0;
size_t total = 0;
if (fd < 0) {
log_error("Attempt to read an unopened device (%s).",
dev_name(where->dev));
return 0;
}
/*
* Skip all writes in test mode.
*/
if (should_write && test_mode())
return 1;
if (where->size > SSIZE_MAX) {
log_error("Read size too large: %" PRIu64, where->size);
return 0;
}
if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) {
log_sys_error("lseek", dev_name(where->dev));
return 0;
}
while (total < (size_t) where->size) {
do
n = should_write ?
write(fd, buffer, (size_t) where->size - total) :
read(fd, buffer, (size_t) where->size - total);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n <= 0)
break;
total += n;
buffer += n;
}
return (total == (size_t) where->size);
}
/*-----------------------------------------------------------------
* LVM2 uses O_DIRECT when performing metadata io, which requires
* block size aligned accesses. If any io is not aligned we have
* to perform the io via a bounce buffer, obviously this is quite
* inefficient.
*---------------------------------------------------------------*/
/*
* Get the sector size from an _open_ device.
*/
static int _get_block_size(struct device *dev, unsigned int *size)
{
int s;
if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) {
log_sys_error("ioctl BLKBSZGET", dev_name(dev));
return 0;
}
*size = (unsigned int) s;
return 1;
}
/*
* Widens a region to be an aligned region.
*/
static void _widen_region(unsigned int block_size, struct device_area *region,
struct device_area *result)
{
uint64_t mask = block_size - 1, delta;
memcpy(result, region, sizeof(*result));
/* adjust the start */
delta = result->start & mask;
if (delta) {
result->start -= delta;
result->size += delta;
}
/* adjust the end */
delta = (result->start + result->size) & mask;
if (delta)
result->size += block_size - delta;
}
static int _aligned_io(struct device_area *where, void *buffer,
int should_write)
{
void *bounce;
unsigned int block_size = 0;
uintptr_t mask;
struct device_area widened;
if (!(where->dev->flags & DEV_REGULAR) &&
!_get_block_size(where->dev, &block_size)) {
stack;
return 0;
}
if (!block_size)
block_size = SECTOR_SIZE * 2;
_widen_region(block_size, where, &widened);
/* Do we need to use a bounce buffer? */
mask = block_size - 1;
if (!memcmp(where, &widened, sizeof(widened)) &&
!((uintptr_t) buffer & mask))
return _io(where, buffer, should_write);
/* Allocate a bounce buffer with an extra block */
if (!(bounce = alloca((size_t) widened.size + block_size))) {
log_error("Bounce buffer alloca failed");
return 0;
}
/*
* Realign start of bounce buffer (using the extra sector)
*/
if (((uintptr_t) bounce) & mask)
bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask);
/* channel the io through the bounce buffer */
if (!_io(&widened, bounce, 0)) {
if (!should_write) {
stack;
return 0;
}
/* FIXME pre-extend the file */
memset(bounce, '\n', widened.size);
}
if (should_write) {
memcpy(bounce + (where->start - widened.start), buffer,
(size_t) where->size);
/* ... then we write */
return _io(&widened, bounce, 1);
}
memcpy(buffer, bounce + (where->start - widened.start),
(size_t) where->size);
return 1;
}
/*-----------------------------------------------------------------
* Public functions
*---------------------------------------------------------------*/
int dev_get_size(struct device *dev, uint64_t *size)
{ {
int fd; int fd;
long s;
const char *name = dev_name(dev); const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name); log_very_verbose("Getting size of %s", name);
@@ -27,19 +212,18 @@ int dev_get_size(struct device *dev, uint64_t * size)
return 0; return 0;
} }
/* FIXME: add 64 bit ioctl */ if (ioctl(fd, BLKGETSIZE64, size) < 0) {
if (ioctl(fd, BLKGETSIZE, &s) < 0) { log_sys_error("ioctl BLKGETSIZE64", name);
log_sys_error("ioctl BLKGETSIZE", name);
close(fd); close(fd);
return 0; return 0;
} }
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
close(fd); close(fd);
*size = (uint64_t) s;
return 1; return 1;
} }
int dev_get_sectsize(struct device *dev, uint32_t * size) int dev_get_sectsize(struct device *dev, uint32_t *size)
{ {
int fd; int fd;
int s; int s;
@@ -62,45 +246,104 @@ int dev_get_sectsize(struct device *dev, uint32_t * size)
return 1; return 1;
} }
int dev_open(struct device *dev, int flags) void dev_flush(struct device *dev)
{
if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0)
return;
if (fsync(dev->fd) >= 0)
return;
sync();
}
int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
{ {
struct stat buf; struct stat buf;
const char *name = dev_name_confirmed(dev); const char *name;
if (!name) { if (dev->fd >= 0) {
dev->open_count++;
return 1;
}
if (memlock())
log_error("WARNING: dev_open(%s) called while suspended",
dev_name(dev));
if (dev->flags & DEV_REGULAR)
name = dev_name(dev);
else if (!(name = dev_name_confirmed(dev, quiet))) {
stack; stack;
return 0; return 0;
} }
if (dev->fd >= 0) { if (!(dev->flags & DEV_REGULAR) &&
log_error("Device '%s' has already been opened", name); ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) {
return 0;
}
if ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev)) {
log_error("%s: stat failed: Has device name changed?", name); log_error("%s: stat failed: Has device name changed?", name);
return 0; return 0;
} }
if ((dev->fd = open(name, flags)) < 0) { if (direct)
flags |= O_DIRECT;
if ((dev->fd = open(name, flags, 0777)) < 0) {
log_sys_error("open", name); log_sys_error("open", name);
return 0; return 0;
} }
if ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev)) { dev->open_count = 1;
dev->flags &= ~DEV_ACCESSED_W;
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); log_error("%s: fstat failed: Has device name changed?", name);
dev_close(dev); dev_close(dev);
dev->fd = -1;
return 0; return 0;
} }
#if !O_DIRECT
if (!(dev->flags & DEV_REGULAR))
dev_flush(dev);
#endif
dev->flags = 0; 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));
return 1; return 1;
} }
static void _flush(int fd) int dev_open_quiet(struct device *dev)
{ {
ioctl(fd, BLKFLSBUF, 0); /* FIXME Open O_RDONLY if vg read lock? */
return dev_open_flags(dev, O_RDWR, 1, 1);
}
int dev_open(struct device *dev)
{
/* FIXME Open O_RDONLY if vg read lock? */
return dev_open_flags(dev, O_RDWR, 1, 0);
}
static void _close(struct device *dev)
{
if (close(dev->fd))
log_sys_error("close", dev_name(dev));
dev->fd = -1;
list_del(&dev->open_list);
log_debug("Closed %s", dev_name(dev));
if (dev->flags & DEV_ALLOCED) {
dbg_free((void *) list_item(dev->aliases.n, struct str_list)->
str);
dbg_free(dev->aliases.n);
dbg_free(dev);
}
} }
int dev_close(struct device *dev) int dev_close(struct device *dev)
@@ -110,140 +353,115 @@ int dev_close(struct device *dev)
"which is not open.", dev_name(dev)); "which is not open.", dev_name(dev));
return 0; return 0;
} }
#if !O_DIRECT
if (dev->flags & DEV_ACCESSED_W) if (dev->flags & DEV_ACCESSED_W)
_flush(dev->fd); dev_flush(dev);
#endif
if (close(dev->fd)) /* FIXME lookup device in cache to get vgname and see if it's locked? */
log_sys_error("close", dev_name(dev)); if (--dev->open_count < 1 && !vgs_locked())
_close(dev);
dev->fd = -1;
return 1; return 1;
} }
/* void dev_close_all(void)
* FIXME: factor common code out. {
struct list *doh, *doht;
struct device *dev;
list_iterate_safe(doh, doht, &_open_devices) {
dev = list_struct_base(doh, struct device, open_list);
if (dev->open_count < 1)
_close(dev);
}
}
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
{
struct device_area where;
if (!dev->open_count)
return 0;
where.dev = dev;
where.start = offset;
where.size = len;
return _aligned_io(&where, buffer, 0);
}
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
* But fails if concurrent processes writing
*/ */
int _read(int fd, void *buf, size_t count)
/* FIXME pre-extend the file */
int dev_append(struct device *dev, size_t len, void *buffer)
{ {
size_t n = 0; int r;
int tot = 0;
while (tot < count) { if (!dev->open_count)
do return 0;
n = read(fd, buf, count - tot);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n <= 0) r = dev_write(dev, dev->end, len, buffer);
return tot ? tot : n; dev->end += (uint64_t) len;
tot += n; #if !O_DIRECT
buf += n; dev_flush(dev);
} #endif
return r;
return tot;
} }
int64_t dev_read(struct device * dev, uint64_t offset, int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
int64_t len, void *buffer)
{ {
const char *name = dev_name(dev); struct device_area where;
int fd = dev->fd;
if (fd < 0) { if (!dev->open_count)
log_err("Attempt to read an unopened device (%s).", name);
return 0; return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) { where.dev = dev;
log_sys_error("lseek", name); where.start = offset;
return 0; where.size = len;
}
return _read(fd, buffer, len);
}
int _write(int fd, const void *buf, size_t count)
{
size_t n = 0;
int tot = 0;
/* Skip all writes */
if (test_mode())
return count;
while (tot < count) {
do
n = write(fd, buf, count - tot);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n <= 0)
return tot ? tot : n;
tot += n;
buf += n;
}
return tot;
}
int64_t dev_write(struct device * dev, uint64_t offset,
int64_t len, void *buffer)
{
const char *name = dev_name(dev);
int fd = dev->fd;
if (fd < 0) {
log_error("Attempt to write to unopened device %s", name);
return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", name);
return 0;
}
dev->flags |= DEV_ACCESSED_W; dev->flags |= DEV_ACCESSED_W;
return _write(fd, buffer, len); return _aligned_io(&where, buffer, 1);
} }
int dev_zero(struct device *dev, uint64_t offset, int64_t len) int dev_zero(struct device *dev, uint64_t offset, size_t len)
{ {
int64_t r, s; size_t s;
char buffer[4096]; char buffer[4096];
const char *name = dev_name(dev);
int fd = dev->fd;
if (fd < 0) { if (!dev_open(dev)) {
log_error("Attempt to zero part of an unopened device %s", stack;
name);
return 0; return 0;
} }
if (lseek(fd, offset, SEEK_SET) < 0) { if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
log_sys_error("lseek", name); log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t,
return 0; dev_name(dev), offset, len);
} else
log_debug("Wiping %s at sector %" PRIu64 " length %" PRIsize_t
" sectors", dev_name(dev), offset >> SECTOR_SHIFT,
len >> SECTOR_SHIFT);
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
while (1) { while (1) {
s = len > sizeof(buffer) ? sizeof(buffer) : len; s = len > sizeof(buffer) ? sizeof(buffer) : len;
r = _write(fd, buffer, s); if (!dev_write(dev, offset, s, buffer))
if (r <= 0)
break; break;
len -= r; len -= s;
if (!len) { if (!len)
r = 1;
break; break;
}
} }
dev->flags |= DEV_ACCESSED_W; dev->flags |= DEV_ACCESSED_W;
if (!dev_close(dev))
stack;
/* FIXME: Always display error */ /* FIXME: Always display error */
return (len == 0); return (len == 0);
} }

View File

@@ -17,16 +17,19 @@
* MA 02111-1307, USA * MA 02111-1307, USA
*/ */
#include <sys/types.h> #if 0
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <ctype.h> #include <ctype.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/genhd.h>
#include "dbg_malloc.h" #include "dbg_malloc.h"
#include "log.h" #include "log.h"
@@ -34,11 +37,6 @@
#include "metadata.h" #include "metadata.h"
#include "device.h" #include "device.h"
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/genhd.h>
#if 0
int _get_partition_type(struct dev_filter *filter, struct device *d); 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(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))

View File

@@ -7,22 +7,29 @@
#ifndef _LVM_DEVICE_H #ifndef _LVM_DEVICE_H
#define _LVM_DEVICE_H #define _LVM_DEVICE_H
#include "lvm-types.h" #include "uuid.h"
#include "list.h" #include <fcntl.h>
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */ #define DEV_ACCESSED_W 0x00000001 /* Device written to? */
#define DEV_REGULAR 0x00000002 /* Regular file? */
#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */
/* /*
* All devices in LVM will be represented by one of these. * All devices in LVM will be represented by one of these.
* pointer comparisons are valid. * pointer comparisons are valid.
*/ */
struct device { struct device {
struct list aliases; /* struct str_list from lvm-types.h */ struct list aliases; /* struct str_list from lvm-types.h */
dev_t dev; dev_t dev;
/* private */ /* private */
int fd; int fd;
int open_count;
uint32_t flags; uint32_t flags;
uint64_t end;
struct list open_list;
char pvid[ID_LEN + 1];
}; };
struct device_list { struct device_list {
@@ -30,33 +37,57 @@ struct device_list {
struct device *dev; struct device *dev;
}; };
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
uint64_t size; /* Bytes */
};
/* /*
* All io should use these routines. * All io should use these routines.
*/ */
int dev_get_size(struct device *dev, uint64_t *size); int dev_get_size(struct device *dev, uint64_t *size);
int dev_get_sectsize(struct device *dev, uint32_t *size); int dev_get_sectsize(struct device *dev, uint32_t *size);
int dev_open(struct device *dev, int flags); /* 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_close(struct device *dev); int dev_close(struct device *dev);
void dev_close_all(void);
int64_t dev_read(struct device *dev, static inline int dev_fd(struct device *dev)
uint64_t offset, int64_t len, void *buffer); {
int64_t dev_write(struct device *dev, return dev->fd;
uint64_t offset, int64_t len, void *buffer); }
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
int dev_append(struct device *dev, size_t len, void *buffer);
int dev_zero(struct device *dev, uint64_t offset, size_t len);
void dev_flush(struct device *dev);
static inline const char *dev_name(struct device *dev) { struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias);
static inline const char *dev_name(const struct device *dev)
{
return (dev) ? list_item(dev->aliases.n, struct str_list)->str : return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
"unknown device"; "unknown device";
} }
/* Return a valid device name from the alias list; NULL otherwise */ /* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev); const char *dev_name_confirmed(struct device *dev, int quiet);
static inline int is_lvm_partition(const char *name) { /* FIXME Check partition type if appropriate */
#define is_lvm_partition(a) 1
/*
static inline int is_lvm_partition(const char *name)
{
return 1; return 1;
} }
*/
#endif #endif

View File

@@ -18,48 +18,206 @@
* *
*/ */
#include "lib.h"
#include "metadata.h" #include "metadata.h"
#include "dbg_malloc.h"
#include "log.h"
#include "display.h" #include "display.h"
#include "activate.h" #include "activate.h"
#include "uuid.h"
#include "toolcontext.h" #include "toolcontext.h"
#include <sys/types.h>
#include <string.h>
#define SIZE_BUF 128 #define SIZE_BUF 128
char *display_size(uint64_t size, size_len_t sl) static struct {
alloc_policy_t alloc;
const char *str;
} _policies[] = {
{
ALLOC_NEXT_FREE, "next free"}, {
ALLOC_CONTIGUOUS, "contiguous"}, {
ALLOC_DEFAULT, "next free (default)"}
};
static struct {
segment_type_t segtype;
const char *str;
} _segtypes[] = {
{
SEG_STRIPED, "striped"}, {
SEG_MIRRORED, "mirror"}, {
SEG_SNAPSHOT, "snapshot"}
};
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
uint64_t units_to_bytes(const char *units, char *unit_type)
{
char *ptr = NULL;
uint64_t v;
if (isdigit(*units)) {
v = (uint64_t) strtod(units, &ptr);
if (ptr == units)
return 0;
units = ptr;
} else
v = 1;
if (v == 1)
*unit_type = *units;
else
*unit_type = 'U';
switch (*units) {
case 'h':
case 'H':
v = UINT64_C(1);
*unit_type = *units;
break;
case 's':
v *= SECTOR_SIZE;
break;
case 'b':
case 'B':
v *= UINT64_C(1);
break;
#define KILO UINT64_C(1024)
case 'k':
v *= KILO;
break;
case 'm':
v *= KILO * KILO;
break;
case 'g':
v *= KILO * KILO * KILO;
break;
case 't':
v *= KILO * KILO * KILO * KILO;
break;
#undef KILO
#define KILO UINT64_C(1000)
case 'K':
v *= KILO;
break;
case 'M':
v *= KILO * KILO;
break;
case 'G':
v *= KILO * KILO * KILO;
break;
case 'T':
v *= KILO * KILO * KILO * KILO;
break;
#undef KILO
default:
return 0;
}
if (*(units + 1))
return 0;
return v;
}
const char *get_alloc_string(alloc_policy_t alloc)
{
int i;
for (i = 0; i < _num_policies; i++)
if (_policies[i].alloc == alloc)
return _policies[i].str;
return NULL;
}
const char *get_segtype_string(segment_type_t segtype)
{
int i;
for (i = 0; i < _num_segtypes; i++)
if (_segtypes[i].segtype == segtype)
return _segtypes[i].str;
return "unknown";
}
alloc_policy_t get_alloc_from_string(const char *str)
{
int i;
for (i = 0; i < _num_policies; i++)
if (!strcmp(_policies[i].str, str))
return _policies[i].alloc;
log_error("Unrecognised allocation policy - using default");
return ALLOC_DEFAULT;
}
segment_type_t get_segtype_from_string(const char *str)
{
int i;
for (i = 0; i < _num_segtypes; i++)
if (!strcmp(_segtypes[i].str, str))
return _segtypes[i].segtype;
log_error("Unrecognised segment type - using default (striped)");
return SEG_STRIPED;
}
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
{ {
int s; int s;
ulong byte = 1024 * 1024 * 1024; int suffix = 1;
uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024);
char *size_buf = NULL; char *size_buf = NULL;
char *size_str[][2] = { const char *size_str[][3] = {
{"Terabyte", "TB"}, {" Terabyte", " TB", "T"},
{"Gigabyte", "GB"}, {" Gigabyte", " GB", "G"},
{"Megabyte", "MB"}, {" Megabyte", " MB", "M"},
{"Kilobyte", "KB"}, {" Kilobyte", " KB", "K"},
{"", ""} {"", "", ""},
{" Byte ", " B ", "B"},
{" Units ", " Un", "U"},
{" Sectors ", " Se", "S"},
{" ", " ", " "},
}; };
if (!(size_buf = dbg_malloc(SIZE_BUF))) { if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
log_error("no memory for size display buffer"); log_error("no memory for size display buffer");
return NULL; return "";
} }
if (size == 0LL) suffix = cmd->current_settings.suffix;
sprintf(size_buf, "0");
else { for (s = 0; s < 8; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[s][2])
break;
if (size == UINT64_C(0)) {
sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : "");
return size_buf;
}
if (s < 8) {
byte = cmd->current_settings.unit_factor;
size *= UINT64_C(1024);
} else {
suffix = 1;
if (cmd->current_settings.unit_type == 'H')
units = UINT64_C(1000);
else
units = UINT64_C(1024);
byte = units * units * units;
s = 0; s = 0;
while (size_str[s] && size < byte) while (size_str[s] && size < byte)
s++, byte /= 1024; s++, byte /= units;
snprintf(size_buf, SIZE_BUF - 1,
"%.2f %s", (float) size / byte, size_str[s][sl]);
} }
/* Caller to deallocate */ snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
suffix ? size_str[s][sl] : "");
return size_buf; return size_buf;
} }
@@ -75,7 +233,7 @@ void pvdisplay_colons(struct physical_volume *pv)
return; return;
} }
log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu64 ":%u:%u:%u:%s", log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu32 ":%u:%u:%u:%s",
dev_name(pv->dev), pv->vg_name, pv->size, dev_name(pv->dev), pv->vg_name, pv->size,
/* FIXME pv->pv_number, Derive or remove? */ /* FIXME pv->pv_number, Derive or remove? */
pv->status, /* FIXME Support old or new format here? */ pv->status, /* FIXME Support old or new format here? */
@@ -89,12 +247,14 @@ void pvdisplay_colons(struct physical_volume *pv)
return; return;
} }
void pvdisplay_full(struct physical_volume *pv) /* FIXME Include label fields */
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
void *handle)
{ {
char uuid[64]; char uuid[64];
char *size, *size1; /*, *size2; */ const char *size;
uint64_t pe_free; uint32_t pe_free;
if (!pv) if (!pv)
return; return;
@@ -104,49 +264,30 @@ void pvdisplay_full(struct physical_volume *pv)
return; return;
} }
/* Compat */
if(!pv->pe_size) {
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
log_print("\"%s\" is a new physical volume of %s", dev_name(pv->dev), size);
dbg_free(size);
return;
}
set_cmd_name("");
init_msg_prefix("");
/****** FIXME Do we really need this conditional here? */
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW "); log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
log_print("PV Name %s", dev_name(pv->dev)); log_print("PV Name %s", dev_name(pv->dev));
log_print("VG Name %s%s", pv->vg_name, log_print("VG Name %s%s", pv->vg_name,
pv->status & EXPORTED_VG ? " (exported)" : ""); pv->status & EXPORTED_VG ? " (exported)" : "");
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT); size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
if (pv->pe_size && pv->pe_count) { if (pv->pe_size && pv->pe_count) {
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
/ 2, SIZE_SHORT);
/******** FIXME display LVM on-disk data size - static for now... /******** FIXME display LVM on-disk data size
size2 = display_size(pv->size / 2, SIZE_SHORT); size2 = display_size(pv->size / 2, SIZE_SHORT);
********/ ********/
log_print("PV Size %s [%llu secs]" " / not " log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
"usable %s [LVM: %s]", size, display_size(cmd,
size, (uint64_t) pv->size, size1, "151 KB"); (pv->size -
/* , size2); */ pv->pe_count * pv->pe_size) / 2,
SIZE_SHORT));
dbg_free(size1);
/* dbg_free(size2); */
} else } else
log_print("PV Size %s", size); log_print("PV Size %s", size);
dbg_free(size);
/******** FIXME anytime this *isn't* available? */ /* PV number not part of LVM2 design
log_print("PV Status available"); log_print("PV# %u", pv->pv_number);
*/
/*********FIXME Anything use this?
log_print("PV# %u", pv->pv_number);
**********/
pe_free = pv->pe_count - pv->pe_alloc_count; pe_free = pv->pe_count - pv->pe_alloc_count;
if (pv->pe_count && (pv->status & ALLOCATABLE_PV)) if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
@@ -155,18 +296,13 @@ void pvdisplay_full(struct physical_volume *pv)
else else
log_print("Allocatable NO"); log_print("Allocatable NO");
/*********FIXME Erm...where is this stored? /* LV count is no longer available when displaying PV
log_print("Cur LV %u", vg->lv_count); log_print("Cur LV %u", vg->lv_count);
*/ */
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2); log_print("PE Size (KByte) %" PRIu32, pv->pe_size / 2);
log_print("Total PE %u", pv->pe_count); log_print("Total PE %u", pv->pe_count);
log_print("Free PE %" PRIu64, pe_free); log_print("Free PE %" PRIu32, pe_free);
log_print("Allocated PE %u", pv->pe_alloc_count); log_print("Allocated PE %u", pv->pe_alloc_count);
#ifdef LVM_FUTURE
printf("Stale PE %u", pv->pe_stale);
#endif
log_print("PV UUID %s", *uuid ? uuid : "none"); log_print("PV UUID %s", *uuid ? uuid : "none");
log_print(" "); log_print(" ");
@@ -174,13 +310,21 @@ void pvdisplay_full(struct physical_volume *pv)
} }
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv) struct physical_volume *pv, void *handle)
{ {
char uuid[64];
if (!pv) if (!pv)
return 0; return 0;
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
stack;
return 0;
}
log_print("PV Name %s ", dev_name(pv->dev)); log_print("PV Name %s ", dev_name(pv->dev));
/* FIXME pv->pv_number); */ /* FIXME pv->pv_number); */
log_print("PV UUID %s", *uuid ? uuid : "none");
log_print("PV Status %sallocatable", log_print("PV Status %sallocatable",
(pv->status & ALLOCATABLE_PV) ? "" : "NOT "); (pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
log_print("Total PE / Free PE %u / %u", log_print("Total PE / Free PE %u / %u",
@@ -190,12 +334,10 @@ int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
return 0; return 0;
} }
void lvdisplay_colons(struct logical_volume *lv) void lvdisplay_colons(struct logical_volume *lv)
{ {
int inkernel; int inkernel;
struct dm_info info; struct lvinfo info;
inkernel = lv_info(lv, &info) && info.exists; inkernel = lv_info(lv, &info) && info.exists;
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d", log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
@@ -207,25 +349,20 @@ void lvdisplay_colons(struct logical_volume *lv)
/* FIXME lv->lv_number, */ /* FIXME lv->lv_number, */
inkernel ? info.open_count : 0, lv->size, lv->le_count, inkernel ? info.open_count : 0, lv->size, lv->le_count,
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */ /* FIXME Add num allocated to struct! lv->lv_allocated_le, */
((lv->status & ALLOC_STRICT) + (lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
inkernel ? info.major : -1, inkernel ? info.minor : -1); inkernel ? info.major : -1, inkernel ? info.minor : -1);
return; return;
} }
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv) int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{ {
char *size; struct lvinfo info;
uint32_t alloc; int inkernel, snap_active;
struct dm_info info;
int inkernel;
char uuid[64]; char uuid[64];
struct snapshot *snap; struct snapshot *snap = NULL;
struct stripe_segment *seg; struct list *slh, *snaplist;
struct list *lvseg; float snap_percent; /* fused, fsize; */
struct logical_volume *origin;
float snap_percent;
int snap_active;
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) { if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
stack; stack;
@@ -234,170 +371,103 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
inkernel = lv_info(lv, &info) && info.exists; inkernel = lv_info(lv, &info) && info.exists;
set_cmd_name("");
init_msg_prefix("");
log_print("--- Logical volume ---"); log_print("--- Logical volume ---");
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir, log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
lv->vg->name, lv->name); lv->vg->name, lv->name);
log_print("VG Name %s", lv->vg->name); log_print("VG Name %s", lv->vg->name);
/* Not in LVM1 format
log_print("LV UUID %s", uuid); log_print("LV UUID %s", uuid);
**/
log_print("LV Write Access %s", log_print("LV Write Access %s",
(lv->status & LVM_WRITE) ? "read/write" : "read only"); (lv->status & LVM_WRITE) ? "read/write" : "read only");
/* see if this LV is an origin for a snapshot */ if (lv_is_origin(lv)) {
if ((snap = find_origin(lv))) {
struct list *slh, *snaplist = find_snapshots(lv);
log_print("LV snapshot status source of"); log_print("LV snapshot status source of");
snaplist = find_snapshots(lv);
list_iterate(slh, snaplist) { list_iterate(slh, snaplist) {
snap = list_item(slh, struct snapshot_list)->snapshot; snap = list_item(slh, struct snapshot_list)->snapshot;
snap_active = lv_snapshot_percent(snap->cow, snap_active = lv_snapshot_percent(snap->cow,
&snap_percent); &snap_percent);
log_print(" %s%s/%s [%s]", log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name, lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name, snap->cow->name,
(snap_active > 0) ? "active" : "INACTIVE"); (snap_active > 0) ? "active" : "INACTIVE");
} }
/* reset so we don't try to use this to display other snapshot
* related information. */
snap = NULL; snap = NULL;
snap_active = 0; } else if ((snap = find_cow(lv))) {
}
/* Check to see if this LV is a COW target for a snapshot */
else if ((snap = find_cow(lv))) {
snap_active = lv_snapshot_percent(lv, &snap_percent); snap_active = lv_snapshot_percent(lv, &snap_percent);
log_print("LV snapshot status %s destination for %s%s/%s", log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE", (snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name, lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name); snap->origin->name);
} }
if (inkernel && info.suspended) if (inkernel && info.suspended)
log_print("LV Status suspended"); log_print("LV Status suspended");
else else
log_print("LV Status %savailable", log_print("LV Status %savailable",
!inkernel || (snap && (snap_active < 1)) inkernel ? "" : "NOT ");
? "NOT " : "");
/********* FIXME lv_number - not sure that we're going to bother with this /********* FIXME lv_number
log_print("LV # %u", lv->lv_number + 1); log_print("LV # %u", lv->lv_number + 1);
************/ ************/
/* LVM1 lists the number of LVs open in this field, therefore, so do we. */
log_print("# open %u", lvs_in_vg_opened(lv->vg));
/* We're not going to use this count ATM, 'cause it's not what LVM1 does
if (inkernel) if (inkernel)
log_print("# open %u", info.open_count); log_print("# open %u", info.open_count);
*/
/********
#ifdef LVM_FUTURE
printf("Mirror copies %u\n", lv->lv_mirror_copies);
printf("Consistency recovery ");
if (lv->lv_recovery | LV_BADBLOCK_ON)
printf("bad blocks\n");
else
printf("none\n");
printf("Schedule %u\n", lv->lv_schedule);
#endif
********/
if(snap) log_print("LV Size %s",
origin = snap->origin; display_size(cmd,
else snap ? snap->origin->size / 2 : lv->size / 2,
origin = lv; SIZE_SHORT));
size = display_size(origin->size / 2, SIZE_SHORT);
log_print("LV Size %s", size);
dbg_free(size);
log_print("Current LE %u", origin->le_count); log_print("Current LE %u",
snap ? snap->origin->le_count : lv->le_count);
/********** FIXME allocation - is there anytime the allocated LEs will not
* equal the current LEs? */
log_print("Allocated LE %u", origin->le_count);
/**********/
list_iterate(lvseg, &lv->segments) { /********** FIXME allocation
seg = list_item(lvseg, struct stripe_segment); log_print("Allocated LE %u", lv->allocated_le);
if(seg->stripes > 1) { **********/
log_print("Stripes %u", seg->stripes);
log_print("Stripe size (KByte) %u",
seg->stripe_size/2);
}
/* only want the first segment for LVM1 format output */
break;
}
if(snap) {
float fused, fsize;
if(snap_percent == -1)
snap_percent=100;
size = display_size(snap->chunk_size / 2, SIZE_SHORT);
log_print("snapshot chunk size %s", size);
dbg_free(size);
size = display_size(lv->size / 2, SIZE_SHORT);
sscanf(size, "%f", &fsize);
fused = fsize * ( snap_percent / 100 );
log_print("Allocated to snapshot %2.2f%% [%2.2f/%s]",
snap_percent, fused, size);
dbg_free(size);
/* FIXME: Think this'll make them wonder?? */
log_print("Allocated to COW-table %s", "00.01 KB");
}
/** Not in LVM1 format output **
log_print("Segments %u", list_size(&lv->segments)); log_print("Segments %u", list_size(&lv->segments));
***/
/********* FIXME Stripes & stripesize for each segment /********* FIXME Stripes & stripesize for each segment
log_print("Stripe size (KByte) %u", lv->stripesize / 2); log_print("Stripe size (KByte) %u", lv->stripesize / 2);
***********/ ***********/
/************** if (snap) {
#ifdef LVM_FUTURE if (snap_percent == -1)
printf("Bad block "); snap_percent = 100;
if (lv->lv_badblock == LV_BADBLOCK_ON)
printf("on\n");
else
printf("off\n");
#endif
***************/
/* FIXME next free == ALLOC_SIMPLE */ log_print("Snapshot chunk size %s",
alloc = lv->status & (ALLOC_STRICT | ALLOC_CONTIGUOUS); display_size(cmd, (uint64_t) snap->chunk_size / 2,
log_print("Allocation %s%s%s%s", SIZE_SHORT));
!(alloc & (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "next free" :
"", (alloc == ALLOC_STRICT) ? "strict" : "",
(alloc == ALLOC_CONTIGUOUS) ? "contiguous" : "",
(alloc ==
(ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "strict/contiguous" :
"");
/*
size = display_size(lv->size / 2, 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); log_print("Read ahead sectors %u", lv->read_ahead);
if (lv->status & FIXED_MINOR) if (lv->status & FIXED_MINOR) {
if (lv->major >= 0)
log_print("Persistent major %d", lv->major);
log_print("Persistent minor %d", lv->minor); log_print("Persistent minor %d", lv->minor);
}
/****************
#ifdef LVM_FUTURE
printf("IO Timeout (seconds) ");
if (lv->lv_io_timeout == 0)
printf("default\n\n");
else
printf("%lu\n\n", lv->lv_io_timeout);
#endif
*************/
if (inkernel) if (inkernel)
log_print("Block device %d:%d", info.major, log_print("Block device %d:%d", info.major,
@@ -408,45 +478,80 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
return 0; return 0;
} }
void _display_stripe(struct stripe_segment *seg, int s, const char *pre) static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
{ {
uint32_t len = seg->len / seg->stripes; switch (seg->area[s].type) {
case AREA_PV:
log_print("%sPhysical volume\t%s", pre,
seg->area[s].u.pv.pv ?
dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
log_print("%sphysical volume\t%s", pre, if (seg->area[s].u.pv.pv)
seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing"); 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);
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");
if (seg->area[s].pv) if (seg->area[s].u.lv.lv)
log_print("%sphysical extents\t%d to %d", pre, log_print("%sLogical extents\t%d to %d", pre,
seg->area[s].pe, seg->area[s].pe + len - 1); seg->area[s].u.lv.le,
seg->area[s].u.lv.le + seg->area_len - 1);
}
} }
int lvdisplay_segments(struct logical_volume *lv) int lvdisplay_segments(struct logical_volume *lv)
{ {
int s; uint32_t s;
struct list *segh; struct list *segh;
struct stripe_segment *seg; struct lv_segment *seg;
log_print("--- Segments ---"); log_print("--- Segments ---");
list_iterate(segh, &lv->segments) { list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment); seg = list_item(segh, struct lv_segment);
log_print("logical extent %d to %d:", log_print("Logical extent %u to %u:",
seg->le, seg->le + seg->len - 1); seg->le, seg->le + seg->len - 1);
if (seg->stripes == 1) if (seg->type == SEG_STRIPED && seg->area_count == 1)
_display_stripe(seg, 0, " "); log_print(" Type\t\tlinear");
else
log_print(" Type\t\t%s",
get_segtype_string(seg->type));
else { switch (seg->type) {
log_print(" stripes\t\t%d", seg->stripes); case SEG_STRIPED:
log_print(" stripe size\t\t%d", seg->stripe_size); if (seg->area_count == 1)
_display_stripe(seg, 0, " ");
else {
log_print(" Stripes\t\t%u", seg->area_count);
log_print(" Stripe size\t\t%u KB",
seg->stripe_size / 2);
for (s = 0; s < seg->stripes; s++) { for (s = 0; s < seg->area_count; s++) {
log_print(" stripe %d:", s); log_print(" Stripe %d:", s);
_display_stripe(seg, s, " "); _display_stripe(seg, s, " ");
}
} }
log_print(" ");
break;
case SEG_SNAPSHOT:
break;
case SEG_MIRRORED:
log_print(" Mirrors\t\t%u", seg->area_count);
log_print(" Mirror size\t\t%u", seg->area_len);
log_print(" Mirror original:");
_display_stripe(seg, 0, " ");
log_print(" Mirror destination:");
_display_stripe(seg, 1, " ");
log_print(" ");
break;
} }
log_print(" ");
} }
log_print(" "); log_print(" ");
@@ -461,29 +566,23 @@ void vgdisplay_extents(struct volume_group *vg)
void vgdisplay_full(struct volume_group *vg) void vgdisplay_full(struct volume_group *vg)
{ {
uint32_t access; uint32_t access;
char *s1;
char uuid[64];
uint32_t active_pvs; uint32_t active_pvs;
struct list *pvlist; char uuid[64];
set_cmd_name(""); if (vg->status & PARTIAL_VG)
init_msg_prefix(""); active_pvs = list_size(&vg->pvs);
/* get the number of active PVs */
if(vg->status & PARTIAL_VG) {
active_pvs=0;
list_iterate(pvlist, &(vg->pvs)) {
active_pvs++;
}
}
else else
active_pvs=vg->pv_count; active_pvs = vg->pv_count;
log_print("--- Volume group ---"); log_print("--- Volume group ---");
log_print("VG Name %s", vg->name); log_print("VG Name %s", vg->name);
/****** Not in LVM1 output, so we aren't outputing it here:
log_print("System ID %s", vg->system_id); log_print("System ID %s", vg->system_id);
*******/ log_print("Format %s", vg->fid->fmt->name);
if (vg->fid->fmt->features & FMT_MDAS) {
log_print("Metadata Areas %d",
list_size(&vg->fid->metadata_areas));
log_print("Metadata Sequence No %d", vg->seqno);
}
access = vg->status & (LVM_READ | LVM_WRITE); access = vg->status & (LVM_READ | LVM_WRITE);
log_print("VG Access %s%s%s%s", log_print("VG Access %s%s%s%s",
access == (LVM_READ | LVM_WRITE) ? "read/write" : "", access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
@@ -491,49 +590,56 @@ void vgdisplay_full(struct volume_group *vg)
access == LVM_WRITE ? "write" : "", access == LVM_WRITE ? "write" : "",
access == 0 ? "error" : ""); access == 0 ? "error" : "");
log_print("VG Status %s%sresizable", log_print("VG Status %s%sresizable",
vg->status & EXPORTED_VG ? "exported/" : "available/", vg->status & EXPORTED_VG ? "exported/" : "",
vg->status & RESIZEABLE_VG ? "" : "NOT "); vg->status & RESIZEABLE_VG ? "" : "NOT ");
/* vg number not part of LVM2 design
log_print ("VG # %u\n", vg->vg_number);
*/
if (vg->status & CLUSTERED) { if (vg->status & CLUSTERED) {
log_print("Clustered yes"); log_print("Clustered yes");
log_print("Shared %s", log_print("Shared %s",
vg->status & SHARED ? "yes" : "no"); vg->status & SHARED ? "yes" : "no");
} }
/****** FIXME VG # - we aren't implementing this because people should
* use the UUID for this anyway
log_print("VG # %u", vg->vg_number);
*******/
log_print("MAX LV %u", vg->max_lv); log_print("MAX LV %u", vg->max_lv);
log_print("Cur LV %u", vg->lv_count); log_print("Cur LV %u", vg->lv_count);
log_print("Open LV %u", lvs_in_vg_opened(vg)); log_print("Open LV %u", lvs_in_vg_opened(vg));
log_print("MAX LV Size 256 TB"); /****** FIXME Max LV Size
log_print ( "MAX LV Size %s",
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
free ( s1);
*********/
log_print("Max PV %u", vg->max_pv); log_print("Max PV %u", vg->max_pv);
log_print("Cur PV %u", vg->pv_count); log_print("Cur PV %u", vg->pv_count);
log_print("Act PV %u", active_pvs); log_print("Act PV %u", active_pvs);
s1 = log_print("VG Size %s",
display_size((uint64_t) vg->extent_count * (vg->extent_size / 2), display_size(vg->cmd,
SIZE_SHORT); (uint64_t) vg->extent_count * (vg->extent_size /
log_print("VG Size %s", s1); 2), SIZE_SHORT));
dbg_free(s1);
s1 = display_size(vg->extent_size / 2, SIZE_SHORT); log_print("PE Size %s",
log_print("PE Size %s", s1); display_size(vg->cmd, (uint64_t) vg->extent_size / 2,
dbg_free(s1); SIZE_SHORT));
log_print("Total PE %u", vg->extent_count); log_print("Total PE %u", vg->extent_count);
s1 = display_size(((uint64_t)
vg->extent_count - vg->free_count) *
(vg->extent_size / 2), SIZE_SHORT);
log_print("Alloc PE / Size %u / %s", log_print("Alloc PE / Size %u / %s",
vg->extent_count - vg->free_count, s1); vg->extent_count - vg->free_count, display_size(vg->cmd,
dbg_free(s1); ((uint64_t)
vg->
extent_count
-
vg->
free_count) *
(vg->
extent_size /
2),
SIZE_SHORT));
s1 = log_print("Free PE / Size %u / %s", vg->free_count,
display_size((uint64_t) vg->free_count * (vg->extent_size / 2), display_size(vg->cmd,
SIZE_SHORT); (uint64_t) vg->free_count * (vg->extent_size /
log_print("Free PE / Size %u / %s", vg->free_count, s1); 2), SIZE_SHORT));
dbg_free(s1);
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) { if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
stack; stack;
@@ -553,17 +659,17 @@ void vgdisplay_colons(struct volume_group *vg)
void vgdisplay_short(struct volume_group *vg) void vgdisplay_short(struct volume_group *vg)
{ {
char *s1, *s2, *s3;
s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
s2 =
display_size((vg->extent_count - vg->free_count) * vg->extent_size /
2, SIZE_SHORT);
s3 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name, log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
/********* FIXME if "open" print "/used" else print "/idle"??? ******/ /********* FIXME if "open" print "/used" else print "/idle"??? ******/
s1, s2, s3); display_size(vg->cmd, (uint64_t) vg->extent_count *
dbg_free(s1); vg->extent_size / 2, SIZE_SHORT),
dbg_free(s2); display_size(vg->cmd,
dbg_free(s3); ((uint64_t) vg->extent_count -
vg->free_count) * vg->extent_size / 2,
SIZE_SHORT), display_size(vg->cmd,
(uint64_t) vg->
free_count *
vg->extent_size / 2,
SIZE_SHORT));
return; return;
} }

View File

@@ -25,23 +25,40 @@
#include <stdint.h> #include <stdint.h>
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t; typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
uint64_t units_to_bytes(const char *units, char *unit_type);
/* Specify size in KB */ /* Specify size in KB */
char *display_size(uint64_t size, size_len_t sl); const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
char *display_uuid(char *uuidstr); char *display_uuid(char *uuidstr);
void pvdisplay_colons(struct physical_volume *pv); void pvdisplay_colons(struct physical_volume *pv);
void pvdisplay_full(struct physical_volume *pv); void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv); void *handle);
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle);
void lvdisplay_colons(struct logical_volume *lv); void lvdisplay_colons(struct logical_volume *lv);
int lvdisplay_segments(struct logical_volume *lv); int lvdisplay_segments(struct logical_volume *lv);
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv); int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle);
void vgdisplay_extents(struct volume_group *vg); void vgdisplay_extents(struct volume_group *vg);
void vgdisplay_full(struct volume_group *vg); void vgdisplay_full(struct volume_group *vg);
void vgdisplay_colons(struct volume_group *vg); void vgdisplay_colons(struct volume_group *vg);
void vgdisplay_short(struct volume_group *vg); void vgdisplay_short(struct volume_group *vg);
/*
* Allocation policy display conversion routines.
*/
const char *get_alloc_string(alloc_policy_t alloc);
alloc_policy_t get_alloc_from_string(const char *str);
/*
* Segment type display conversion routines.
*/
segment_type_t get_segtype_from_string(const char *str);
const char *get_segtype_string(segment_type_t segtype);
#endif #endif

View File

@@ -4,9 +4,8 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "filter-composite.h" #include "filter-composite.h"
#include "dbg_malloc.h"
#include "log.h"
#include <stdarg.h> #include <stdarg.h>
@@ -20,6 +19,8 @@ static int _and_p(struct dev_filter *f, struct device *dev)
filters++; filters++;
} }
log_debug("Using %s", dev_name(dev));
return 1; return 1;
} }

View File

@@ -4,14 +4,12 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "config.h" #include "config.h"
#include "dev-cache.h" #include "dev-cache.h"
#include "hash.h" #include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "filter-persistent.h" #include "filter-persistent.h"
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
@@ -34,8 +32,12 @@ static int _init_hash(struct pfilter *pf)
if (pf->devices) if (pf->devices)
hash_destroy(pf->devices); hash_destroy(pf->devices);
pf->devices = hash_create(128); if (!(pf->devices = hash_create(128))) {
return pf->devices ? 1 : 0; stack;
return 0;
}
return 1;
} }
int persistent_filter_wipe(struct dev_filter *f) int persistent_filter_wipe(struct dev_filter *f)
@@ -43,10 +45,13 @@ int persistent_filter_wipe(struct dev_filter *f)
struct pfilter *pf = (struct pfilter *) f->private; struct pfilter *pf = (struct pfilter *) f->private;
hash_wipe(pf->devices); hash_wipe(pf->devices);
/* Trigger complete device scan */
dev_cache_scan(1);
return 1; return 1;
} }
static int _read_array(struct pfilter *pf, struct config_file *cf, static int _read_array(struct pfilter *pf, struct config_tree *cf,
const char *path, void *data) const char *path, void *data)
{ {
struct config_node *cn; struct config_node *cn;
@@ -72,6 +77,8 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
if (!hash_insert(pf->devices, cv->v.str, data)) if (!hash_insert(pf->devices, cv->v.str, data))
log_verbose("Couldn't add '%s' to filter ... ignoring", log_verbose("Couldn't add '%s' to filter ... ignoring",
cv->v.str); cv->v.str);
/* Populate dev_cache ourselves */
dev_cache_get(cv->v.str, NULL);
} }
return 1; return 1;
} }
@@ -81,32 +88,39 @@ int persistent_filter_load(struct dev_filter *f)
struct pfilter *pf = (struct pfilter *) f->private; struct pfilter *pf = (struct pfilter *) f->private;
int r = 0; int r = 0;
struct config_file *cf; struct config_tree *cf;
if (!(cf = create_config_file())) { if (!(cf = create_config_tree())) {
stack; stack;
return 0; return 0;
} }
if (!read_config(cf, pf->file)) { if (!read_config_file(cf, pf->file)) {
stack; stack;
goto out; goto out;
} }
_read_array(pf, cf, "persistent_filter_cache/valid_devices", _read_array(pf, cf, "persistent_filter_cache/valid_devices",
PF_GOOD_DEVICE); PF_GOOD_DEVICE);
_read_array(pf, cf, "persistent_filter_cache/invalid_devices", /* We don't gain anything by holding invalid devices */
PF_BAD_DEVICE); /* _read_array(pf, cf, "persistent_filter_cache/invalid_devices",
PF_BAD_DEVICE); */
if (hash_get_num_entries(pf->devices)) /* Did we find anything? */
if (hash_get_num_entries(pf->devices)) {
/* We populated dev_cache ourselves */
dev_cache_scan(0);
r = 1; r = 1;
}
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out: out:
destroy_config_file(cf); destroy_config_tree(cf);
return r; return r;
} }
static void _write_array(struct pfilter *pf, FILE * fp, const char *path, static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
void *data) void *data)
{ {
void *d; void *d;
@@ -147,11 +161,18 @@ int persistent_filter_dump(struct dev_filter *f)
"- not writing to %s", pf->file); "- not writing to %s", pf->file);
return 0; return 0;
} }
if (!dev_cache_has_scanned()) {
log_very_verbose("Device cache incomplete - not writing "
"to %s", pf->file);
return 0;
}
log_very_verbose("Dumping persistent device cache to %s", pf->file); log_very_verbose("Dumping persistent device cache to %s", pf->file);
fp = fopen(pf->file, "w"); fp = fopen(pf->file, "w");
if (!fp) { if (!fp) {
log_sys_error("fopen", pf->file); if (errno != EROFS)
log_sys_error("fopen", pf->file);
return 0; return 0;
} }
@@ -159,7 +180,8 @@ int persistent_filter_dump(struct dev_filter *f)
fprintf(fp, "persistent_filter_cache {\n"); fprintf(fp, "persistent_filter_cache {\n");
_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE); _write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
_write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); /* We don't gain anything by remembering invalid devices */
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
fprintf(fp, "}\n"); fprintf(fp, "}\n");
fclose(fp); fclose(fp);
@@ -183,7 +205,11 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
} }
} }
return l == PF_GOOD_DEVICE; if (l == PF_BAD_DEVICE) {
log_debug("%s: Skipping (cached)", dev_name(dev));
return 0;
} else
return 1;
} }
static void _destroy(struct dev_filter *f) static void _destroy(struct dev_filter *f)

View File

@@ -4,12 +4,12 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "pool.h" #include "pool.h"
#include "filter-regex.h" #include "filter-regex.h"
#include "matcher.h" #include "matcher.h"
#include "device.h" #include "device.h"
#include "bitset.h" #include "bitset.h"
#include "log.h"
#include "list.h" #include "list.h"
struct rfilter { struct rfilter {
@@ -19,7 +19,7 @@ struct rfilter {
}; };
static int _extract_pattern(struct pool *mem, const char *pat, static int _extract_pattern(struct pool *mem, const char *pat,
char **regex, bitset_t accept, int index) char **regex, bitset_t accept, int ix)
{ {
char sep, *r, *ptr; char sep, *r, *ptr;
@@ -28,11 +28,11 @@ static int _extract_pattern(struct pool *mem, const char *pat,
*/ */
switch (*pat) { switch (*pat) {
case 'a': case 'a':
bit_set(accept, index); bit_set(accept, ix);
break; break;
case 'r': case 'r':
bit_clear(accept, index); bit_clear(accept, ix);
break; break;
default: default:
@@ -80,7 +80,7 @@ static int _extract_pattern(struct pool *mem, const char *pat,
} }
*ptr = '\0'; *ptr = '\0';
regex[index] = r; regex[ix] = r;
return 1; return 1;
} }
@@ -89,7 +89,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
struct pool *scratch; struct pool *scratch;
struct config_value *v; struct config_value *v;
char **regex; char **regex;
int count = 0, i, r = 0; unsigned count = 0;
int i, r = 0;
if (!(scratch = pool_create(1024))) { if (!(scratch = pool_create(1024))) {
stack; stack;
@@ -137,7 +138,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
* build the matcher. * build the matcher.
*/ */
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex, if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
count))) count)))
stack; stack;
r = 1; r = 1;
@@ -161,6 +162,8 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
if (bit(rf->accept, m)) { if (bit(rf->accept, m)) {
if (!first) { if (!first) {
log_debug("%s: New preferred name",
sl->str);
list_del(&sl->list); list_del(&sl->list);
list_add_h(&dev->aliases, &sl->list); list_add_h(&dev->aliases, &sl->list);
} }

View File

@@ -18,32 +18,34 @@
* *
*/ */
#include "dbg_malloc.h" #include "lib.h"
#include "log.h"
#include "dev-cache.h" #include "dev-cache.h"
#include "filter.h" #include "filter.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "config.h"
#include <stdlib.h>
#include <dirent.h> #include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/kdev_t.h> #include <limits.h>
#define NUMBER_OF_MAJORS 256 #define NUMBER_OF_MAJORS 256
typedef struct { typedef struct {
char *name; const char *name;
int max_partitions; const int max_partitions;
} device_info_t; } device_info_t;
static int _md_major = -1; static int _md_major = -1;
static device_info_t device_info[] = { int md_major(void)
{
return _md_major;
}
/* This list can be supplemented with devices/types in the config file */
static const device_info_t device_info[] = {
{"ide", 16}, /* IDE disk */ {"ide", 16}, /* IDE disk */
{"sd", 16}, /* SCSI disk */ {"sd", 16}, /* SCSI disk */
{"md", 16}, /* Multiple Disk driver (SoftRAID) */ {"md", 16}, /* Multiple Disk driver (SoftRAID) */
@@ -58,21 +60,23 @@ static device_info_t device_info[] = {
{NULL, 0} {NULL, 0}
}; };
static int *scan_proc_dev(const char *proc); static int _passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
static int passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
{ {
int fd; int fd;
const char *name = dev_name(dev); const char *name = dev_name(dev);
/* Is this a recognised device type? */ /* Is this a recognised device type? */
if (!(((int *) f->private)[MAJOR(dev->dev)])) if (!(((int *) f->private)[MAJOR(dev->dev)])) {
log_debug("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev));
return 0; return 0;
}
/* Check it's accessible */ /* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) { if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno)); log_debug("%s: Skipping: open failed: %s", name,
strerror(errno));
return 0; return 0;
} }
@@ -81,48 +85,18 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
return 1; return 1;
} }
struct dev_filter *lvm_type_filter_create(const char *proc) static int *_scan_proc_dev(const char *proc, struct config_node *cn)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
f->passes_filter = passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
if (!(f->private = scan_proc_dev(proc)))
return NULL;
return f;
}
int md_major(void)
{
return _md_major;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}
static int *scan_proc_dev(const char *proc)
{ {
char line[80]; char line[80];
char proc_devices[PATH_MAX]; char proc_devices[PATH_MAX];
FILE *pd = NULL; FILE *pd = NULL;
int ret = 0;
int i, j = 0; int i, j = 0;
int line_maj = 0; int line_maj = 0;
int blocksection = 0; int blocksection = 0;
int dev_len = 0; size_t dev_len = 0;
struct config_value *cv;
int *max_partitions_by_major; int *max_partitions_by_major;
char *name;
if (!(max_partitions_by_major = if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) { dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
@@ -130,6 +104,14 @@ static int *scan_proc_dev(const char *proc)
return NULL; 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;
}
if (lvm_snprintf(proc_devices, sizeof(proc_devices), if (lvm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) { "%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string"); log_error("Failed to create /proc/devices string");
@@ -173,12 +155,44 @@ static int *scan_proc_dev(const char *proc)
for (j = 0; device_info[j].name != NULL; j++) { for (j = 0; device_info[j].name != NULL; j++) {
dev_len = strlen(device_info[j].name); dev_len = strlen(device_info[j].name);
if (dev_len <= strlen(line + i) if (dev_len <= strlen(line + i) &&
&& !strncmp(device_info[j].name, line + i, dev_len) !strncmp(device_info[j].name, line + i, dev_len) &&
&& (line_maj < NUMBER_OF_MAJORS)) { (line_maj < NUMBER_OF_MAJORS)) {
max_partitions_by_major[line_maj] = max_partitions_by_major[line_maj] =
device_info[j].max_partitions; device_info[j].max_partitions;
ret++; break;
}
}
if (max_partitions_by_major[line_maj] || !cn)
continue;
/* Check devices/types for local variations */
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Expecting string in devices/types "
"in config file");
return NULL;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
cv = cv->next;
if (!cv || cv->type != CFG_INT) {
log_error("Max partition count missing for %s "
"in devices/types in config file",
name);
return NULL;
}
if (!cv->v.i) {
log_error("Zero partition count invalid for "
"%s in devices/types in config file",
name);
return NULL;
}
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;
break; break;
} }
} }
@@ -186,3 +200,31 @@ static int *scan_proc_dev(const char *proc)
fclose(pd); fclose(pd);
return max_partitions_by_major; return max_partitions_by_major;
} }
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
f->passes_filter = _passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
if (!(f->private = _scan_proc_dev(proc, cn))) {
stack;
return NULL;
}
return f;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}

View File

@@ -21,11 +21,23 @@
#ifndef _LVM_FILTER_H #ifndef _LVM_FILTER_H
#define _LVM_FILTER_H #define _LVM_FILTER_H
struct dev_filter *lvm_type_filter_create(const char *proc); #include "config.h"
#include <sys/stat.h>
#ifdef linux
# include <linux/kdev_t.h>
#else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
#endif
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn);
void lvm_type_filter_destroy(struct dev_filter *f); void lvm_type_filter_destroy(struct dev_filter *f);
int md_major(void); int md_major(void);
#endif #endif

7
lib/format1/.export.sym Normal file
View File

@@ -0,0 +1,7 @@
Base {
global:
init_format;
local:
*;
};

31
lib/format1/Makefile.in Normal file
View File

@@ -0,0 +1,31 @@
#
# Copyright (C) 2002 Sistina Software (UK) Limited.
#
# This file is released under the LGPL.
#
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES=\
disk-rep.c \
format1.c \
import-export.c \
import-extents.c \
layout.c \
lvm1-label.c \
vg_number.c
TARGETS=liblvm2format1.so
include ../../make.tmpl
install: libformat1.so
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2format1.so.$(LIB_VERSION)
$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so
.PHONY: install

View File

@@ -4,18 +4,14 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "disk-rep.h" #include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h" #include "pool.h"
#include "xlate.h" #include "xlate.h"
#include "log.h"
#include "vgcache.h"
#include "filter.h" #include "filter.h"
#include "lvmcache.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/kdev_t.h>
#define fail do {stack; return 0;} while(0) #define fail do {stack; return 0;} while(0)
#define xx16(v) disk->v = xlate16(disk->v) #define xx16(v) disk->v = xlate16(disk->v)
@@ -96,7 +92,7 @@ static void _xlate_vgd(struct vg_disk *disk)
xx32(pvg_total); xx32(pvg_total);
} }
static void _xlate_extents(struct pe_disk *extents, int count) static void _xlate_extents(struct pe_disk *extents, uint32_t count)
{ {
int i; int i;
@@ -116,12 +112,12 @@ static int _munge_formats(struct pv_disk *pvd)
switch (pvd->version) { switch (pvd->version) {
case 1: case 1:
pvd->pe_start = ((pvd->pe_on_disk.base + pvd->pe_start = ((pvd->pe_on_disk.base +
pvd->pe_on_disk.size) / SECTOR_SIZE); pvd->pe_on_disk.size) >> SECTOR_SHIFT);
break; break;
case 2: case 2:
pvd->version = 1; pvd->version = 1;
pe_start = pvd->pe_start * SECTOR_SIZE; pe_start = pvd->pe_start << SECTOR_SHIFT;
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
break; break;
@@ -132,9 +128,9 @@ static int _munge_formats(struct pv_disk *pvd)
return 1; return 1;
} }
int read_pvd(struct device *dev, struct pv_disk *pvd) static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{ {
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) { if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
log_very_verbose("Failed to read PV data from %s", log_very_verbose("Failed to read PV data from %s",
dev_name(dev)); dev_name(dev));
return 0; return 0;
@@ -143,23 +139,23 @@ int read_pvd(struct device *dev, struct pv_disk *pvd)
_xlate_pvd(pvd); _xlate_pvd(pvd);
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') { if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
log_very_verbose("%s does not have a valid PV identifier", log_very_verbose("%s does not have a valid LVM1 PV identifier",
dev_name(dev)); dev_name(dev));
return 0; return 0;
} }
if (!_munge_formats(pvd)) { if (!_munge_formats(pvd)) {
log_very_verbose("Unknown metadata version %d found on %s", log_very_verbose("format1: Unknown metadata version %d "
pvd->version, dev_name(dev)); "found on %s", pvd->version, dev_name(dev));
return 0; return 0;
} }
return 1; return 1;
} }
static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk) static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
{ {
if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk)) if (!dev_read(dev, pos, sizeof(*disk), disk))
fail; fail;
_xlate_lvd(disk); _xlate_lvd(disk);
@@ -170,8 +166,8 @@ static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
static int _read_vgd(struct disk_list *data) static int _read_vgd(struct disk_list *data)
{ {
struct vg_disk *vgd = &data->vgd; struct vg_disk *vgd = &data->vgd;
ulong pos = data->pvd.vg_on_disk.base; uint64_t pos = data->pvd.vg_on_disk.base;
if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd)) if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
fail; fail;
_xlate_vgd(vgd); _xlate_vgd(vgd);
@@ -184,12 +180,11 @@ static int _read_uuids(struct disk_list *data)
int num_read = 0; int num_read = 0;
struct uuid_list *ul; struct uuid_list *ul;
char buffer[NAME_LEN]; char buffer[NAME_LEN];
ulong pos = data->pvd.pv_uuidlist_on_disk.base; uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size; uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
while (pos < end && num_read < data->vgd.pv_cur) { while (pos < end && num_read < data->vgd.pv_cur) {
if (dev_read(data->dev, pos, sizeof(buffer), buffer) != if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
sizeof(buffer))
fail; fail;
if (!(ul = pool_alloc(data->mem, sizeof(*ul)))) if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
@@ -214,8 +209,8 @@ static inline int _check_lvd(struct lv_disk *lvd)
static int _read_lvs(struct disk_list *data) static int _read_lvs(struct disk_list *data)
{ {
int i, read = 0; unsigned int i, read = 0;
ulong pos; uint64_t pos;
struct lvd_list *ll; struct lvd_list *ll;
struct vg_disk *vgd = &data->vgd; struct vg_disk *vgd = &data->vgd;
@@ -243,12 +238,12 @@ static int _read_extents(struct disk_list *data)
{ {
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
struct pe_disk *extents = pool_alloc(data->mem, len); struct pe_disk *extents = pool_alloc(data->mem, len);
ulong pos = data->pvd.pe_on_disk.base; uint64_t pos = data->pvd.pe_on_disk.base;
if (!extents) if (!extents)
fail; fail;
if (dev_read(data->dev, pos, len, extents) != len) if (!dev_read(data->dev, pos, len, extents))
fail; fail;
_xlate_extents(extents, data->pvd.pe_total); _xlate_extents(extents, data->pvd.pe_total);
@@ -262,7 +257,8 @@ static int _read_extents(struct disk_list *data)
*/ */
static void _munge_exported_vg(struct disk_list *data) static void _munge_exported_vg(struct disk_list *data)
{ {
int l, s; int l;
size_t s;
/* Return if PV not in a VG or VG not exported */ /* Return if PV not in a VG or VG not exported */
if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED)) if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED))
@@ -276,12 +272,13 @@ static void _munge_exported_vg(struct disk_list *data)
data->pvd.pv_status |= VG_EXPORTED; data->pvd.pv_status |= VG_EXPORTED;
} }
static struct disk_list *__read_disk(struct format_type *fmt, static struct disk_list *__read_disk(const struct format_type *fmt,
struct device *dev, struct pool *mem, struct device *dev, struct pool *mem,
const char *vg_name) const char *vg_name)
{ {
struct disk_list *dl = pool_alloc(mem, sizeof(*dl)); struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
const char *name = dev_name(dev); const char *name = dev_name(dev);
struct lvmcache_info *info;
if (!dl) { if (!dl) {
stack; stack;
@@ -293,11 +290,20 @@ static struct disk_list *__read_disk(struct format_type *fmt,
list_init(&dl->uuids); list_init(&dl->uuids);
list_init(&dl->lvds); list_init(&dl->lvds);
if (!read_pvd(dev, &dl->pvd)) { if (!_read_pvd(dev, &dl->pvd)) {
stack; stack;
goto bad; goto bad;
} }
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
dl->pvd.vg_name, NULL)))
stack;
else {
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
list_init(&info->mdas);
info->status &= ~CACHE_INVALID;
}
/* /*
* is it an orphan ? * is it an orphan ?
*/ */
@@ -305,7 +311,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
log_very_verbose("%s is not a member of any format1 VG", name); log_very_verbose("%s is not a member of any format1 VG", name);
/* Update VG cache */ /* Update VG cache */
vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); /* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
return (vg_name) ? NULL : dl; return (vg_name) ? NULL : dl;
} }
@@ -319,7 +325,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
_munge_exported_vg(dl); _munge_exported_vg(dl);
/* Update VG cache with what we found */ /* Update VG cache with what we found */
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); /* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) { if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s", log_very_verbose("%s is not a member of the VG %s",
@@ -353,12 +359,12 @@ static struct disk_list *__read_disk(struct format_type *fmt,
return NULL; return NULL;
} }
struct disk_list *read_disk(struct format_type *fmt, struct device *dev, struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name) struct pool *mem, const char *vg_name)
{ {
struct disk_list *r; struct disk_list *r;
if (!dev_open(dev, O_RDONLY)) { if (!dev_open(dev)) {
stack; stack;
return NULL; return NULL;
} }
@@ -400,21 +406,22 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
* We keep track of the first object allocated form the pool * We keep track of the first object allocated form the pool
* so we can free off all the memory if something goes wrong. * so we can free off all the memory if something goes wrong.
*/ */
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name, int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_filter *filter, struct pool *mem, struct dev_filter *filter, struct pool *mem,
struct list *head) struct list *head)
{ {
struct dev_iter *iter; struct dev_iter *iter;
struct device *dev; struct device *dev;
struct disk_list *data = NULL; struct disk_list *data = NULL;
struct list *vgih;
struct list *pvdh, *pvdh2; struct lvmcache_vginfo *vginfo;
/* Fast path if we already saw this VG and cached the list of PVs */ /* Fast path if we already saw this VG and cached the list of PVs */
if ((pvdh = vgcache_find(vg_name))) { if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
list_iterate(pvdh2, pvdh) { vginfo->infos.n) {
dev = list_item(pvdh2, struct pvdev_list)->dev; list_iterate(vgih, &vginfo->infos) {
if (!(data = read_disk(fmt, dev, mem, vg_name))) dev = list_item(vgih, struct lvmcache_info)->dev;
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
break; break;
_add_pv_to_list(head, data); _add_pv_to_list(head, data);
} }
@@ -422,11 +429,12 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
/* Did we find the whole VG? */ /* Did we find the whole VG? */
if (!vg_name || !*vg_name || if (!vg_name || !*vg_name ||
(data && *data->pvd.vg_name && (data && *data->pvd.vg_name &&
list_size(head) == data->vgd.pv_cur)) return 1; list_size(head) == data->vgd.pv_cur))
return 1;
/* Something changed. Remove the hints. */ /* Failed */
list_init(head); list_init(head);
vgcache_del(vg_name); /* vgcache_del(vg_name); */
} }
if (!(iter = dev_iter_create(filter))) { if (!(iter = dev_iter_create(filter))) {
@@ -451,10 +459,10 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
static int _write_vgd(struct disk_list *data) static int _write_vgd(struct disk_list *data)
{ {
struct vg_disk *vgd = &data->vgd; struct vg_disk *vgd = &data->vgd;
ulong pos = data->pvd.vg_on_disk.base; uint64_t pos = data->pvd.vg_on_disk.base;
_xlate_vgd(vgd); _xlate_vgd(vgd);
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd)) if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
fail; fail;
_xlate_vgd(vgd); _xlate_vgd(vgd);
@@ -466,8 +474,8 @@ static int _write_uuids(struct disk_list *data)
{ {
struct uuid_list *ul; struct uuid_list *ul;
struct list *uh; struct list *uh;
ulong pos = data->pvd.pv_uuidlist_on_disk.base; uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size; uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
list_iterate(uh, &data->uuids) { list_iterate(uh, &data->uuids) {
if (pos >= end) { if (pos >= end) {
@@ -477,7 +485,7 @@ static int _write_uuids(struct disk_list *data)
} }
ul = list_item(uh, struct uuid_list); ul = list_item(uh, struct uuid_list);
if (dev_write(data->dev, pos, NAME_LEN, ul->uuid) != NAME_LEN) if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
fail; fail;
pos += NAME_LEN; pos += NAME_LEN;
@@ -486,10 +494,10 @@ static int _write_uuids(struct disk_list *data)
return 1; return 1;
} }
static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk) static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
{ {
_xlate_lvd(disk); _xlate_lvd(disk);
if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk)) if (!dev_write(dev, pos, sizeof(*disk), disk))
fail; fail;
_xlate_lvd(disk); _xlate_lvd(disk);
@@ -500,7 +508,7 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
static int _write_lvs(struct disk_list *data) static int _write_lvs(struct disk_list *data)
{ {
struct list *lvh; struct list *lvh;
ulong pos, offset; uint64_t pos, offset;
pos = data->pvd.lv_on_disk.base; pos = data->pvd.lv_on_disk.base;
@@ -514,8 +522,7 @@ static int _write_lvs(struct disk_list *data)
struct lvd_list *ll = list_item(lvh, struct lvd_list); struct lvd_list *ll = list_item(lvh, struct lvd_list);
offset = sizeof(struct lv_disk) * ll->lvd.lv_number; offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
if (offset + sizeof(struct lv_disk) > if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
data->pvd.lv_on_disk.size) {
log_error("lv_number %d too large", ll->lvd.lv_number); log_error("lv_number %d too large", ll->lvd.lv_number);
return 0; return 0;
} }
@@ -531,10 +538,10 @@ static int _write_extents(struct disk_list *data)
{ {
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
struct pe_disk *extents = data->extents; struct pe_disk *extents = data->extents;
ulong pos = data->pvd.pe_on_disk.base; uint64_t pos = data->pvd.pe_on_disk.base;
_xlate_extents(extents, data->pvd.pe_total); _xlate_extents(extents, data->pvd.pe_total);
if (dev_write(data->dev, pos, len, extents) != len) if (!dev_write(data->dev, pos, len, extents))
fail; fail;
_xlate_extents(extents, data->pvd.pe_total); _xlate_extents(extents, data->pvd.pe_total);
@@ -545,8 +552,8 @@ static int _write_extents(struct disk_list *data)
static int _write_pvd(struct disk_list *data) static int _write_pvd(struct disk_list *data)
{ {
char *buf; char *buf;
ulong pos = data->pvd.pv_on_disk.base; uint64_t pos = data->pvd.pv_on_disk.base;
ulong size = data->pvd.pv_on_disk.size; size_t size = data->pvd.pv_on_disk.size;
if (size < sizeof(struct pv_disk)) { if (size < sizeof(struct pv_disk)) {
log_error("Invalid PV structure size."); log_error("Invalid PV structure size.");
@@ -566,7 +573,7 @@ static int _write_pvd(struct disk_list *data)
memcpy(buf, &data->pvd, sizeof(struct pv_disk)); memcpy(buf, &data->pvd, sizeof(struct pv_disk));
_xlate_pvd((struct pv_disk *) buf); _xlate_pvd((struct pv_disk *) buf);
if (dev_write(data->dev, pos, size, buf) != size) { if (!dev_write(data->dev, pos, size, buf)) {
dbg_free(buf); dbg_free(buf);
fail; fail;
} }
@@ -578,7 +585,8 @@ static int _write_pvd(struct disk_list *data)
/* /*
* assumes the device has been opened. * assumes the device has been opened.
*/ */
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data) static int __write_all_pvd(const struct format_type *fmt,
struct disk_list *data)
{ {
const char *pv_name = dev_name(data->dev); const char *pv_name = dev_name(data->dev);
@@ -587,19 +595,19 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
return 0; return 0;
} }
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); /* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
/* /*
* Stop here for orphan pv's. * Stop here for orphan pv's.
*/ */
if (data->pvd.vg_name[0] == '\0') { if (data->pvd.vg_name[0] == '\0') {
if (!test_mode()) /* if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
return 1; return 1;
} }
if (!test_mode()) /* if (!test_mode())
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
fmt); fmt); */
if (!_write_vgd(data)) { if (!_write_vgd(data)) {
log_error("Failed to write VG data to %s", pv_name); log_error("Failed to write VG data to %s", pv_name);
@@ -627,11 +635,11 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
/* /*
* opens the device and hands to the above fn. * opens the device and hands to the above fn.
*/ */
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data) static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
{ {
int r; int r;
if (!dev_open(data->dev, O_WRONLY)) { if (!dev_open(data->dev)) {
stack; stack;
return 0; return 0;
} }
@@ -649,7 +657,7 @@ static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
* little sanity checking, so make sure correct * little sanity checking, so make sure correct
* data is passed to here. * data is passed to here.
*/ */
int write_disks(struct format_type *fmt, struct list *pvs) int write_disks(const struct format_type *fmt, struct list *pvs)
{ {
struct list *pvh; struct list *pvh;
struct disk_list *dl; struct disk_list *dl;

View File

@@ -11,21 +11,17 @@
#include "metadata.h" #include "metadata.h"
#include "pool.h" #include "pool.h"
#define SECTOR_SIZE 512
#define MAX_PV 256 #define MAX_PV 256
#define MAX_LV 256 #define MAX_LV 256
#define MAX_VG 99 #define MAX_VG 99
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */ #define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
#define MIN_PE_SIZE (8192L / SECTOR_SIZE) /* 8 KB in sectors */ #define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */
#define MAX_PE_SIZE (16L * 1024L * 1024L / SECTOR_SIZE * 1024) #define MAX_PE_SIZE (16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L)
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */ #define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */ #define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
#define MAX_PE_TOTAL ((uint32_t) -2) #define MAX_PE_TOTAL ((uint32_t) -2)
#define UNMAPPED_EXTENT 0 #define UNMAPPED_EXTENT 0
/* volume group */ /* volume group */
@@ -60,86 +56,84 @@
#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */ #define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */
#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */ #define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */
struct data_area { struct data_area {
uint32_t base; uint32_t base;
uint32_t size; uint32_t size;
}; } __attribute__ ((packed));
struct pv_disk { struct pv_disk {
uint8_t id[2]; uint8_t id[2];
uint16_t version; /* lvm version */ uint16_t version; /* lvm version */
struct data_area pv_on_disk; struct data_area pv_on_disk;
struct data_area vg_on_disk; struct data_area vg_on_disk;
struct data_area pv_uuidlist_on_disk; struct data_area pv_uuidlist_on_disk;
struct data_area lv_on_disk; struct data_area lv_on_disk;
struct data_area pe_on_disk; struct data_area pe_on_disk;
uint8_t pv_uuid[NAME_LEN]; uint8_t pv_uuid[NAME_LEN];
uint8_t vg_name[NAME_LEN]; uint8_t vg_name[NAME_LEN];
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
uint32_t pv_major; uint32_t pv_major;
uint32_t pv_number; uint32_t pv_number;
uint32_t pv_status; uint32_t pv_status;
uint32_t pv_allocatable; uint32_t pv_allocatable;
uint32_t pv_size; uint32_t pv_size;
uint32_t lv_cur; uint32_t lv_cur;
uint32_t pe_size; uint32_t pe_size;
uint32_t pe_total; uint32_t pe_total;
uint32_t pe_allocated; uint32_t pe_allocated;
/* only present on version == 2 pv's */ /* only present on version == 2 pv's */
uint32_t pe_start; uint32_t pe_start;
}; } __attribute__ ((packed));
struct lv_disk { struct lv_disk {
uint8_t lv_name[NAME_LEN]; uint8_t lv_name[NAME_LEN];
uint8_t vg_name[NAME_LEN]; uint8_t vg_name[NAME_LEN];
uint32_t lv_access; uint32_t lv_access;
uint32_t lv_status; uint32_t lv_status;
uint32_t lv_open; uint32_t lv_open;
uint32_t lv_dev; uint32_t lv_dev;
uint32_t lv_number; uint32_t lv_number;
uint32_t lv_mirror_copies; /* for future use */ uint32_t lv_mirror_copies; /* for future use */
uint32_t lv_recovery; /* " */ uint32_t lv_recovery; /* " */
uint32_t lv_schedule; /* " */ uint32_t lv_schedule; /* " */
uint32_t lv_size; uint32_t lv_size;
uint32_t lv_snapshot_minor; /* minor number of original */ uint32_t lv_snapshot_minor; /* minor number of original */
uint16_t lv_chunk_size; /* chunk size of snapshot */ uint16_t lv_chunk_size; /* chunk size of snapshot */
uint16_t dummy; uint16_t dummy;
uint32_t lv_allocated_le; uint32_t lv_allocated_le;
uint32_t lv_stripes; uint32_t lv_stripes;
uint32_t lv_stripesize; uint32_t lv_stripesize;
uint32_t lv_badblock; /* for future use */ uint32_t lv_badblock; /* for future use */
uint32_t lv_allocation; uint32_t lv_allocation;
uint32_t lv_io_timeout; /* for future use */ uint32_t lv_io_timeout; /* for future use */
uint32_t lv_read_ahead; uint32_t lv_read_ahead;
}; } __attribute__ ((packed));
struct vg_disk { struct vg_disk {
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */ uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */ uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
uint32_t vg_number; /* volume group number */ uint32_t vg_number; /* volume group number */
uint32_t vg_access; /* read/write */ uint32_t vg_access; /* read/write */
uint32_t vg_status; /* active or not */ uint32_t vg_status; /* active or not */
uint32_t lv_max; /* maximum logical volumes */ uint32_t lv_max; /* maximum logical volumes */
uint32_t lv_cur; /* current logical volumes */ uint32_t lv_cur; /* current logical volumes */
uint32_t lv_open; /* open logical volumes */ uint32_t lv_open; /* open logical volumes */
uint32_t pv_max; /* maximum physical volumes */ uint32_t pv_max; /* maximum physical volumes */
uint32_t pv_cur; /* current physical volumes FU */ uint32_t pv_cur; /* current physical volumes FU */
uint32_t pv_act; /* active physical volumes */ uint32_t pv_act; /* active physical volumes */
uint32_t dummy; uint32_t dummy;
uint32_t vgda; /* volume group descriptor arrays FU */ uint32_t vgda; /* volume group descriptor arrays FU */
uint32_t pe_size; /* physical extent size in sectors */ uint32_t pe_size; /* physical extent size in sectors */
uint32_t pe_total; /* total of physical extents */ uint32_t pe_total; /* total of physical extents */
uint32_t pe_allocated; /* allocated physical extents */ uint32_t pe_allocated; /* allocated physical extents */
uint32_t pvg_total; /* physical volume groups FU */ uint32_t pvg_total; /* physical volume groups FU */
}; } __attribute__ ((packed));
struct pe_disk { struct pe_disk {
uint16_t lv_num; uint16_t lv_num;
uint16_t le_num; uint16_t le_num;
}; } __attribute__ ((packed));
struct uuid_list { struct uuid_list {
struct list list; struct list list;
@@ -163,7 +157,6 @@ struct disk_list {
struct pe_disk *extents; struct pe_disk *extents;
}; };
/* /*
* Layout constants. * Layout constants.
*/ */
@@ -173,29 +166,26 @@ struct disk_list {
#define PV_SIZE 1024UL #define PV_SIZE 1024UL
#define VG_SIZE 4096UL #define VG_SIZE 4096UL
/* /*
* Functions to calculate layout info. * Functions to calculate layout info.
*/ */
int calculate_layout(struct disk_list *dl); int calculate_layout(struct disk_list *dl);
int calculate_extent_count(struct physical_volume *pv); int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
uint32_t max_extent_count);
/* /*
* Low level io routines which read/write * Low level io routines which read/write
* disk_lists. * disk_lists.
*/ */
int read_pvd(struct device *dev, struct pv_disk *pvd);
struct disk_list *read_disk(struct format_type *fmt, struct device *dev, struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name); struct pool *mem, const char *vg_name);
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name, int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_filter *filter, struct dev_filter *filter,
struct pool *mem, struct list *results); struct pool *mem, struct list *results);
int write_disks(struct format_type *fmt, struct list *pvds); int write_disks(const struct format_type *fmt, struct list *pvds);
/* /*
* Functions to translate to between disk and in * Functions to translate to between disk and in
@@ -208,27 +198,21 @@ int export_pv(struct pool *mem, struct volume_group *vg,
struct pv_disk *pvd, struct physical_volume *pv); struct pv_disk *pvd, struct physical_volume *pv);
int import_vg(struct pool *mem, int import_vg(struct pool *mem,
struct volume_group *vg, struct disk_list *dl, struct volume_group *vg, struct disk_list *dl, int partial);
int partial);
int export_vg(struct vg_disk *vgd, struct volume_group *vg); int export_vg(struct vg_disk *vgd, struct volume_group *vg);
int import_lv(struct pool *mem, struct logical_volume *lv, int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
struct lv_disk *lvd);
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
struct logical_volume *lv, const char *dev_dir);
int import_extents(struct pool *mem, struct volume_group *vg, int import_extents(struct pool *mem, struct volume_group *vg,
struct list *pvds); struct list *pvds);
int export_extents(struct disk_list *dl, int lv_num, int export_extents(struct disk_list *dl, uint32_t lv_num,
struct logical_volume *lv, struct logical_volume *lv, struct physical_volume *pv);
struct physical_volume *pv);
int import_pvs(struct format_instance *fid, struct pool *mem, int import_pvs(const struct format_type *fmt, struct pool *mem,
struct volume_group *vg, struct volume_group *vg,
struct list *pvds, struct list *results, int *count); struct list *pvds, struct list *results, int *count);
int import_lvs(struct pool *mem, struct volume_group *vg, int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds);
struct list *pvds);
int export_lvs(struct disk_list *dl, struct volume_group *vg, int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct physical_volume *pv, const char *dev_dir); struct physical_volume *pv, const char *dev_dir);
@@ -247,5 +231,4 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
int export_vg_number(struct format_instance *fid, struct list *pvds, int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter); const char *vg_name, struct dev_filter *filter);
#endif #endif

View File

@@ -4,15 +4,17 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "disk-rep.h" #include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h" #include "pool.h"
#include "hash.h" #include "hash.h"
#include "limits.h" #include "limits.h"
#include "list.h" #include "list.h"
#include "log.h"
#include "display.h" #include "display.h"
#include "toolcontext.h" #include "toolcontext.h"
#include "lvmcache.h"
#include "lvm1-label.h"
#include "format1.h"
/* VG consistency checks */ /* VG consistency checks */
static int _check_vgs(struct list *pvs, int *partial) static int _check_vgs(struct list *pvs, int *partial)
@@ -21,8 +23,9 @@ static int _check_vgs(struct list *pvs, int *partial)
struct disk_list *dl = NULL; struct disk_list *dl = NULL;
struct disk_list *first = NULL; struct disk_list *first = NULL;
int pv_count = 0; uint32_t pv_count = 0;
int exported = -1; uint32_t exported = 0;
int first_time = 1;
*partial = 0; *partial = 0;
@@ -34,8 +37,9 @@ static int _check_vgs(struct list *pvs, int *partial)
list_iterate(pvh, pvs) { list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list); dl = list_item(pvh, struct disk_list);
if (exported < 0) { if (first_time) {
exported = dl->pvd.pv_status & VG_EXPORTED; exported = dl->pvd.pv_status & VG_EXPORTED;
first_time = 0;
continue; continue;
} }
@@ -113,7 +117,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
if (!import_vg(mem, vg, dl, partial)) if (!import_vg(mem, vg, dl, partial))
goto bad; goto bad;
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count)) if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
goto bad; goto bad;
if (!import_lvs(mem, vg, pvs)) if (!import_lvs(mem, vg, pvs))
@@ -134,7 +138,8 @@ static struct volume_group *_build_vg(struct format_instance *fid,
} }
static struct volume_group *_vg_read(struct format_instance *fid, static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name, void *mda) const char *vg_name,
struct metadata_area *mda)
{ {
struct pool *mem = pool_create(1024 * 10); struct pool *mem = pool_create(1024 * 10);
struct list pvs; struct list pvs;
@@ -185,8 +190,7 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
if (!export_pv(mem, vg, &dl->pvd, pv) || if (!export_pv(mem, vg, &dl->pvd, pv) ||
!export_vg(&dl->vgd, vg) || !export_vg(&dl->vgd, vg) ||
!export_uuids(dl, vg) || !export_uuids(dl, vg) ||
!export_lvs(dl, vg, pv, dev_dir) || !export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
!calculate_layout(dl)) {
stack; stack;
pool_free(mem, dl); pool_free(mem, dl);
return NULL; return NULL;
@@ -227,7 +231,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
} }
static int _vg_write(struct format_instance *fid, struct volume_group *vg, static int _vg_write(struct format_instance *fid, struct volume_group *vg,
void *mdl) struct metadata_area *mda)
{ {
struct pool *mem = pool_create(1024 * 10); struct pool *mem = pool_create(1024 * 10);
struct list pvds; struct list pvds;
@@ -243,26 +247,28 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir, r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
fid->fmt->cmd->filter) && fid->fmt->cmd->filter) &&
write_disks(fid->fmt, &pvds)); write_disks(fid->fmt, &pvds));
lvmcache_update_vg(vg);
pool_destroy(mem); pool_destroy(mem);
return r; return r;
} }
int _pv_read(struct format_type *fmt, const char *name, static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv) struct physical_volume *pv, struct list *mdas)
{ {
struct pool *mem = pool_create(1024); struct pool *mem = pool_create(1024);
struct disk_list *dl; struct disk_list *dl;
struct device *dev; struct device *dev;
int r = 0; int r = 0;
log_very_verbose("Reading physical volume data %s from disk", name); log_very_verbose("Reading physical volume data %s from disk", pv_name);
if (!mem) { if (!mem) {
stack; stack;
return 0; return 0;
} }
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) { if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
stack; stack;
goto out; goto out;
} }
@@ -277,7 +283,7 @@ int _pv_read(struct format_type *fmt, const char *name,
goto out; goto out;
} }
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL); pv->fmt = fmt;
r = 1; r = 1;
@@ -286,130 +292,50 @@ int _pv_read(struct format_type *fmt, const char *name,
return r; return r;
} }
static struct list *_get_pvs(struct format_type *fmt, struct list *results) static int _pv_setup(const struct format_type *fmt,
uint64_t pe_start, uint32_t extent_count,
uint32_t extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas,
struct physical_volume *pv, struct volume_group *vg)
{ {
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
uint32_t count;
if (!mem) {
stack;
return NULL;
}
list_init(&pvs);
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
stack;
goto bad;
}
pool_destroy(mem);
return results;
bad:
pool_destroy(mem);
return NULL;
}
static int _find_vg_name(struct list *names, const char *vg)
{
struct list *nh;
struct name_list *nl;
list_iterate(nh, names) {
nl = list_item(nh, struct name_list);
if (!strcmp(nl->name, vg))
return 1;
}
return 0;
}
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct list *pvh;
struct list *pvs;
struct name_list *nl;
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
log_error("PV list allocation failed");
goto err;
}
list_init(pvs);
if (!_get_pvs(fmt, pvs)) {
stack;
goto err;
}
list_iterate(pvh, pvs) {
struct pv_list *pvl = list_item(pvh, struct pv_list);
if (!(*pvl->pv->vg_name) ||
_find_vg_name(names, pvl->pv->vg_name))
continue;
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
goto err;
}
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
stack;
goto err;
}
list_add(names, &nl->list);
}
if (list_empty(names))
pool_free(fmt->cmd->mem, pvs);
return names;
err:
pool_free(fmt->cmd->mem, pvs);
return NULL;
}
static int _pv_setup(struct format_instance *fid, struct physical_volume *pv,
struct volume_group *vg)
{
/* setup operations for the PV structure */
if (pv->size > MAX_PV_SIZE) if (pv->size > MAX_PV_SIZE)
pv->size--; pv->size--;
if (pv->size > MAX_PV_SIZE) { if (pv->size > MAX_PV_SIZE) {
/* FIXME Limit hardcoded */ log_error("Physical volumes cannot be bigger than %s",
log_error("Physical volumes cannot be bigger than 2TB"); display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE / 2,
SIZE_SHORT));
return 0; return 0;
} }
/* Nothing more to do if pe_size isn't known */ /* Nothing more to do if extent size isn't provided */
if (!vg) if (!extent_size)
return 1; return 1;
/* /*
* This works out pe_start and pe_count. * This works out pe_start and pe_count.
*/ */
if (!calculate_extent_count(pv)) { if (!calculate_extent_count(pv, extent_size, extent_count)) {
stack; stack;
return 0; return 0;
} }
/* Retain existing extent locations exactly */
/* FIXME Relax this so a non-overlapping existing pe_start can also
* be used in place of the calculated one */
if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
(extent_count && (extent_count != pv->pe_count))) {
log_error("Metadata would overwrite physical extents");
return 0;
}
return 1; return 1;
} }
static int _find_free_lvnum(struct logical_volume *lv) static uint32_t _find_free_lvnum(struct logical_volume *lv)
{ {
int lvnum_used[MAX_LV]; int lvnum_used[MAX_LV];
int i = 0; uint32_t i = 0;
struct list *lvh; struct list *lvh;
struct lv_list *lvl; struct lv_list *lvl;
@@ -439,29 +365,36 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
return 0; return 0;
} }
if (lv->size > max_size) { if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT); log_error("logical volumes cannot be larger than %s",
log_error("logical volumes cannot be larger than %s", dummy); display_size(fid->fmt->cmd, max_size / 2,
dbg_free(dummy); SIZE_SHORT));
return 0; return 0;
} }
return 1; return 1;
} }
static int _pv_write(struct format_instance *fid, struct physical_volume *pv, static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
void *mdl) struct list *mdas, int64_t sector)
{ {
struct pool *mem; struct pool *mem;
struct disk_list *dl; struct disk_list *dl;
struct list pvs; struct list pvs;
struct label *label;
struct lvmcache_info *info;
list_init(&pvs); if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
pv->vg_name, NULL))) {
if (*pv->vg_name || pv->pe_alloc_count) { stack;
log_error("Assertion failed: can't _pv_write non-orphan PV "
"(in VG %s)", pv->vg_name);
return 0; return 0;
} }
label = info->label;
info->device_size = pv->size << SECTOR_SHIFT;
info->fmt = fmt;
list_init(&info->mdas);
list_init(&pvs);
/* Ensure any residual PE structure is gone */ /* Ensure any residual PE structure is gone */
pv->pe_size = pv->pe_count = 0; pv->pe_size = pv->pe_count = 0;
@@ -488,10 +421,10 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
dev_write in order to make other disk tools happy */ dev_write in order to make other disk tools happy */
dl->pvd.pv_on_disk.base = METADATA_BASE; dl->pvd.pv_on_disk.base = METADATA_BASE;
dl->pvd.pv_on_disk.size = PV_SIZE; dl->pvd.pv_on_disk.size = PV_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN * SECTOR_SIZE; dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
list_add(&pvs, &dl->list); list_add(&pvs, &dl->list);
if (!write_disks(fid->fmt, &pvs)) { if (!write_disks(fmt, &pvs)) {
stack; stack;
goto bad; goto bad;
} }
@@ -504,7 +437,7 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
return 0; return 0;
} }
int _vg_setup(struct format_instance *fid, struct volume_group *vg) static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
{ {
/* just check max_pv and max_lv */ /* just check max_pv and max_lv */
if (vg->max_lv >= MAX_LV) if (vg->max_lv >= MAX_LV)
@@ -514,22 +447,22 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
vg->max_pv = MAX_PV - 1; vg->max_pv = MAX_PV - 1;
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) { if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
char *dummy, *dummy2;
log_error("Extent size must be between %s and %s", log_error("Extent size must be between %s and %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)), display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT))); / 2,
SIZE_SHORT), display_size(fid->fmt->cmd,
(uint64_t)
MAX_PE_SIZE
/ 2,
SIZE_SHORT));
dbg_free(dummy);
dbg_free(dummy2);
return 0; return 0;
} }
if (vg->extent_size % MIN_PE_SIZE) { if (vg->extent_size % MIN_PE_SIZE) {
char *dummy;
log_error("Extent size must be multiple of %s", log_error("Extent size must be multiple of %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT))); display_size(fid->fmt->cmd,
dbg_free(dummy); (uint64_t) MIN_PE_SIZE / 2, SIZE_SHORT));
return 0; return 0;
} }
@@ -542,8 +475,14 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
return 1; return 1;
} }
struct format_instance *_create_instance(struct format_type *fmt, static struct metadata_area_ops _metadata_format1_ops = {
const char *vgname, void *private) vg_read:_vg_read,
vg_write:_vg_write,
};
static struct format_instance *_create_instance(const struct format_type *fmt,
const char *vgname,
void *private)
{ {
struct format_instance *fid; struct format_instance *fid;
struct metadata_area *mda; struct metadata_area *mda;
@@ -563,38 +502,40 @@ struct format_instance *_create_instance(struct format_type *fmt,
return NULL; return NULL;
} }
mda->ops = &_metadata_format1_ops;
mda->metadata_locn = NULL; mda->metadata_locn = NULL;
list_add(&fid->metadata_areas, &mda->list); list_add(&fid->metadata_areas, &mda->list);
return fid; return fid;
} }
void _destroy_instance(struct format_instance *fid) static void _destroy_instance(struct format_instance *fid)
{ {
return; return;
} }
void _destroy(struct format_type *fmt) static void _destroy(const struct format_type *fmt)
{ {
dbg_free(fmt); dbg_free((void *) fmt);
} }
static struct format_handler _format1_ops = { static struct format_handler _format1_ops = {
get_vgs: _get_vgs, pv_read:_pv_read,
get_pvs: _get_pvs, pv_setup:_pv_setup,
pv_read: _pv_read, pv_write:_pv_write,
pv_setup: _pv_setup, lv_setup:_lv_setup,
pv_write: _pv_write, vg_setup:_vg_setup,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_setup: _vg_setup,
vg_write: _vg_write,
create_instance:_create_instance, create_instance:_create_instance,
destroy_instance:_destroy_instance, destroy_instance:_destroy_instance,
destroy: _destroy, destroy:_destroy,
}; };
struct format_type *create_lvm1_format(struct cmd_context *cmd) #ifdef LVM1_INTERNAL
struct format_type *init_lvm1_format(struct cmd_context *cmd)
#else /* Shared */
struct format_type *init_format(struct cmd_context *cmd);
struct format_type *init_format(struct cmd_context *cmd)
#endif
{ {
struct format_type *fmt = dbg_malloc(sizeof(*fmt)); struct format_type *fmt = dbg_malloc(sizeof(*fmt));
@@ -606,8 +547,19 @@ struct format_type *create_lvm1_format(struct cmd_context *cmd)
fmt->cmd = cmd; fmt->cmd = cmd;
fmt->ops = &_format1_ops; fmt->ops = &_format1_ops;
fmt->name = FMT_LVM1_NAME; fmt->name = FMT_LVM1_NAME;
fmt->alias = NULL;
fmt->features = 0; fmt->features = 0;
fmt->private = NULL; fmt->private = NULL;
if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
log_error("Couldn't create lvm1 label handler.");
return NULL;
}
if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
log_error("Couldn't register lvm1 label handler.");
return NULL;
}
return fmt; return fmt;
} }

View File

@@ -9,6 +9,10 @@
#include "metadata.h" #include "metadata.h"
struct format_type *create_lvm1_format(struct cmd_context *cmd); #define FMT_LVM1_NAME "lvm1"
#ifdef LVM1_INTERNAL
struct format_type *init_lvm1_format(struct cmd_context *cmd);
#endif
#endif #endif

View File

@@ -6,17 +6,16 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "disk-rep.h" #include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h" #include "pool.h"
#include "hash.h" #include "hash.h"
#include "list.h" #include "list.h"
#include "log.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "filter.h"
#include <time.h> #include <time.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <linux/kdev_t.h>
static int _check_vg_name(const char *name) static int _check_vg_name(const char *name)
{ {
@@ -57,9 +56,9 @@ int import_pv(struct pool *mem, struct device *dev,
if (vg && if (vg &&
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))) strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
log_very_verbose("System ID %s on %s differs from %s for " log_very_verbose("System ID %s on %s differs from %s for "
"volume group", pvd->system_id, "volume group", pvd->system_id,
dev_name(pv->dev), vg->system_id); dev_name(pv->dev), vg->system_id);
/* /*
* If exported, we still need to flag in pv->status too because * If exported, we still need to flag in pv->status too because
@@ -80,7 +79,7 @@ int import_pv(struct pool *mem, struct device *dev,
return 1; return 1;
} }
int _system_id(char *s, const char *prefix) static int _system_id(char *s, const char *prefix)
{ {
struct utsname uts; struct utsname uts;
@@ -163,7 +162,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
if (vg && if (vg &&
(!*vg->system_id || (!*vg->system_id ||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))) strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
strncpy(vg->system_id, pvd->system_id, NAME_LEN); strncpy(vg->system_id, pvd->system_id, NAME_LEN);
//pvd->pv_major = MAJOR(pv->dev); //pvd->pv_major = MAJOR(pv->dev);
@@ -172,7 +171,10 @@ int export_pv(struct pool *mem, struct volume_group *vg,
pvd->pv_size = pv->size; pvd->pv_size = pv->size;
pvd->lv_cur = 0; /* this is set when exporting the lv list */ pvd->lv_cur = 0; /* this is set when exporting the lv list */
pvd->pe_size = pv->pe_size; if (vg)
pvd->pe_size = vg->extent_size;
else
pvd->pe_size = pv->pe_size;
pvd->pe_total = pv->pe_count; pvd->pe_total = pv->pe_count;
pvd->pe_allocated = pv->pe_alloc_count; pvd->pe_allocated = pv->pe_alloc_count;
pvd->pe_start = pv->pe_start; pvd->pe_start = pv->pe_start;
@@ -278,14 +280,19 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
return 0; return 0;
} }
lv->status |= VISIBLE_LV;
if (lvd->lv_status & LV_SPINDOWN) if (lvd->lv_status & LV_SPINDOWN)
lv->status |= SPINDOWN_LV; lv->status |= SPINDOWN_LV;
if (lvd->lv_status & LV_PERSISTENT_MINOR) { if (lvd->lv_status & LV_PERSISTENT_MINOR) {
lv->status |= FIXED_MINOR; lv->status |= FIXED_MINOR;
lv->minor = MINOR(lvd->lv_dev); lv->minor = MINOR(lvd->lv_dev);
} else lv->major = MAJOR(lvd->lv_dev);
} else {
lv->major = -1;
lv->minor = -1; lv->minor = -1;
}
if (lvd->lv_access & LV_READ) if (lvd->lv_access & LV_READ)
lv->status |= LVM_READ; lv->status |= LVM_READ;
@@ -296,13 +303,11 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
if (lvd->lv_badblock) if (lvd->lv_badblock)
lv->status |= BADBLOCK_ON; lv->status |= BADBLOCK_ON;
if (lvd->lv_allocation & LV_STRICT) /* Drop the unused LV_STRICT here */
lv->status |= ALLOC_STRICT;
if (lvd->lv_allocation & LV_CONTIGUOUS) if (lvd->lv_allocation & LV_CONTIGUOUS)
lv->status |= ALLOC_CONTIGUOUS; lv->alloc = ALLOC_CONTIGUOUS;
else else
lv->status |= ALLOC_SIMPLE; lv->alloc = ALLOC_NEXT_FREE;
lv->read_ahead = lvd->lv_read_ahead; lv->read_ahead = lvd->lv_read_ahead;
lv->size = lvd->lv_size; lv->size = lvd->lv_size;
@@ -313,15 +318,13 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
return 1; return 1;
} }
void export_lv(struct lv_disk *lvd, struct volume_group *vg, static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
struct logical_volume *lv, const char *dev_dir) struct logical_volume *lv, const char *dev_dir)
{ {
memset(lvd, 0, sizeof(*lvd)); memset(lvd, 0, sizeof(*lvd));
snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s", snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
dev_dir, vg->name, lv->name); dev_dir, vg->name, lv->name);
/* FIXME: Add 'if' test */
_check_vg_name(vg->name);
strcpy(lvd->vg_name, vg->name); strcpy(lvd->vg_name, vg->name);
if (lv->status & LVM_READ) if (lv->status & LVM_READ)
@@ -335,14 +338,14 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
if (lv->status & FIXED_MINOR) { if (lv->status & FIXED_MINOR) {
lvd->lv_status |= LV_PERSISTENT_MINOR; lvd->lv_status |= LV_PERSISTENT_MINOR;
lvd->lv_dev = MKDEV(0, lv->minor); lvd->lv_dev = MKDEV(lv->major, lv->minor);
} }
lvd->lv_read_ahead = lv->read_ahead; lvd->lv_read_ahead = lv->read_ahead;
lvd->lv_stripes = list_item(lv->segments.n, lvd->lv_stripes =
struct stripe_segment)->stripes; list_item(lv->segments.n, struct lv_segment)->area_count;
lvd->lv_stripesize = list_item(lv->segments.n, lvd->lv_stripesize =
struct stripe_segment)->stripe_size; list_item(lv->segments.n, struct lv_segment)->stripe_size;
lvd->lv_size = lv->size; lvd->lv_size = lv->size;
lvd->lv_allocated_le = lv->le_count; lvd->lv_allocated_le = lv->le_count;
@@ -350,33 +353,40 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
if (lv->status & BADBLOCK_ON) if (lv->status & BADBLOCK_ON)
lvd->lv_badblock = LV_BADBLOCK_ON; lvd->lv_badblock = LV_BADBLOCK_ON;
if (lv->status & ALLOC_STRICT) if (lv->alloc == ALLOC_CONTIGUOUS)
lvd->lv_allocation |= LV_STRICT;
if (lv->status & ALLOC_CONTIGUOUS)
lvd->lv_allocation |= LV_CONTIGUOUS; lvd->lv_allocation |= LV_CONTIGUOUS;
} }
int export_extents(struct disk_list *dl, int lv_num, int export_extents(struct disk_list *dl, uint32_t lv_num,
struct logical_volume *lv, struct physical_volume *pv) struct logical_volume *lv, struct physical_volume *pv)
{ {
struct list *segh; struct list *segh;
struct pe_disk *ped; struct pe_disk *ped;
struct stripe_segment *seg; struct lv_segment *seg;
uint32_t pe, s; uint32_t pe, s;
list_iterate(segh, &lv->segments) { list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment); seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->stripes; s++) { for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].pv != pv) if (seg->type != SEG_STRIPED) {
log_error("Non-striped segment type in LV %s: "
"unsupported by format1", lv->name);
return 0;
}
if (seg->area[s].type != AREA_PV) {
log_error("LV stripe found in LV %s: "
"unsupported by format1", lv->name);
return 0;
}
if (seg->area[s].u.pv.pv != pv)
continue; /* not our pv */ continue; /* not our pv */
for (pe = 0; pe < (seg->len / seg->stripes); pe++) { for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
ped = &dl->extents[pe + seg->area[s].pe]; ped = &dl->extents[pe + seg->area[s].u.pv.pe];
ped->lv_num = lv_num; ped->lv_num = lv_num;
ped->le_num = (seg->le / seg->stripes) + pe + ped->le_num = (seg->le / seg->area_count) + pe +
s * (lv->le_count / seg->stripes); s * (lv->le_count / seg->area_count);
} }
} }
} }
@@ -384,7 +394,7 @@ int export_extents(struct disk_list *dl, int lv_num,
return 1; return 1;
} }
int import_pvs(struct format_instance *fid, struct pool *mem, int import_pvs(const struct format_type *fmt, struct pool *mem,
struct volume_group *vg, struct volume_group *vg,
struct list *pvds, struct list *results, int *count) struct list *pvds, struct list *results, int *count)
{ {
@@ -397,7 +407,7 @@ int import_pvs(struct format_instance *fid, struct pool *mem,
dl = list_item(pvdh, struct disk_list); dl = list_item(pvdh, struct disk_list);
if (!(pvl = pool_alloc(mem, sizeof(*pvl))) || if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) { !(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
stack; stack;
return 0; return 0;
@@ -408,7 +418,7 @@ int import_pvs(struct format_instance *fid, struct pool *mem,
return 0; return 0;
} }
pvl->pv->fid = fid; pvl->pv->fmt = fmt;
list_add(results, &pvl->list); list_add(results, &pvl->list);
(*count)++; (*count)++;
} }
@@ -474,9 +484,15 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct list *lvh, *sh; struct list *lvh, *sh;
struct lv_list *ll; struct lv_list *ll;
struct lvd_list *lvdl; struct lvd_list *lvdl;
int lv_num, len; size_t len;
uint32_t lv_num;
struct hash_table *lvd_hash; struct hash_table *lvd_hash;
if (!_check_vg_name(vg->name)) {
stack;
return 0;
}
if (!(lvd_hash = hash_create(32))) { if (!(lvd_hash = hash_create(32))) {
stack; stack;
return 0; return 0;
@@ -499,7 +515,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
goto out; goto out;
} }
export_lv(&lvdl->lvd, vg, ll->lv, dev_dir); _export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
lv_num = lvnum_from_lvid(&ll->lv->lvid); lv_num = lvnum_from_lvid(&ll->lv->lvid);
@@ -616,7 +632,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
continue; continue;
/* insert the snapshot */ /* insert the snapshot */
if (!vg_add_snapshot(org, cow, 1, lvd->lv_chunk_size)) { if (!vg_add_snapshot(org, cow, 1, NULL,
lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot."); log_err("Couldn't add snapshot.");
return 0; return 0;
} }

View File

@@ -4,10 +4,9 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "metadata.h" #include "metadata.h"
#include "hash.h" #include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "pool.h" #include "pool.h"
#include "disk-rep.h" #include "disk-rep.h"
@@ -192,9 +191,9 @@ static int _check_maps_are_complete(struct hash_table *maps)
return 1; return 1;
} }
static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes) static struct lv_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
{ {
struct stripe_segment *seg; struct lv_segment *seg;
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0])); uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) { if (!(seg = pool_zalloc(mem, len))) {
@@ -208,26 +207,30 @@ static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
static int _read_linear(struct pool *mem, struct lv_map *lvm) static int _read_linear(struct pool *mem, struct lv_map *lvm)
{ {
uint32_t le = 0; uint32_t le = 0;
struct stripe_segment *seg; struct lv_segment *seg;
while (le < lvm->lv->le_count) { while (le < lvm->lv->le_count) {
seg = _alloc_seg(mem, 1); seg = _alloc_seg(mem, 1);
seg->lv = lvm->lv; seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
seg->le = le; seg->le = le;
seg->len = 0; seg->len = 0;
seg->area_len = 0;
seg->stripe_size = 0; seg->stripe_size = 0;
seg->stripes = 1; seg->area_count = 1;
seg->area[0].pv = lvm->map[le].pv; seg->area[0].type = AREA_PV;
seg->area[0].pe = lvm->map[le].pe; seg->area[0].u.pv.pv = lvm->map[le].pv;
seg->area[0].u.pv.pe = lvm->map[le].pe;
do do {
seg->len++; seg->len++;
seg->area_len++;
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) && } while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
(lvm->map[le + seg->len].pe == seg->area[0].pe + (seg->area[0].u.pv.pv &&
seg->len)); lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
seg->len));
le += seg->len; le += seg->len;
@@ -237,7 +240,7 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
return 1; return 1;
} }
static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg, static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
uint32_t base_le, uint32_t len) uint32_t base_le, uint32_t len)
{ {
uint32_t le, st; uint32_t le, st;
@@ -247,9 +250,11 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
/* /*
* Is the next physical extent in every stripe adjacent to the last? * Is the next physical extent in every stripe adjacent to the last?
*/ */
for (st = 0; st < seg->stripes; st++) for (st = 0; st < seg->area_count; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].pv) || if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len)) (seg->area[st].u.pv.pv &&
lvm->map[le + st * len].pe !=
seg->area[st].u.pv.pe + seg->len))
return 0; return 0;
return 1; return 1;
@@ -258,7 +263,7 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
static int _read_stripes(struct pool *mem, struct lv_map *lvm) static int _read_stripes(struct pool *mem, struct lv_map *lvm)
{ {
uint32_t st, le = 0, len; uint32_t st, le = 0, len;
struct stripe_segment *seg; struct lv_segment *seg;
/* /*
* Work out overall striped length * Work out overall striped length
@@ -277,28 +282,32 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
} }
seg->lv = lvm->lv; seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
seg->stripe_size = lvm->stripe_size; seg->stripe_size = lvm->stripe_size;
seg->stripes = lvm->stripes; seg->area_count = lvm->stripes;
seg->le = seg->stripes * le; seg->le = seg->area_count * le;
seg->len = 1; seg->len = 1;
seg->area_len = 1;
/* /*
* Set up start positions of each stripe in this segment * Set up start positions of each stripe in this segment
*/ */
for (st = 0; st < seg->stripes; st++) { for (st = 0; st < seg->area_count; st++) {
seg->area[st].pv = lvm->map[le + st * len].pv; seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
seg->area[st].pe = lvm->map[le + st * len].pe; seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
} }
/* /*
* Find how many blocks are contiguous in all stripes * Find how many blocks are contiguous in all stripes
* and so can form part of this segment * and so can form part of this segment
*/ */
while (_check_stripe(lvm, seg, le, len)) while (_check_stripe(lvm, seg, le, len)) {
seg->len++; seg->len++;
seg->area_len++;
}
le += seg->len; le += seg->len;
seg->len *= seg->stripes; seg->len *= seg->area_count;
list_add(&lvm->lv->segments, &seg->list); list_add(&lvm->lv->segments, &seg->list);
} }

View File

@@ -4,20 +4,19 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "disk-rep.h" #include "disk-rep.h"
#include "log.h"
#include "dbg_malloc.h"
/* /*
* Only works with powers of 2. * Only works with powers of 2.
*/ */
static inline ulong _round_up(ulong n, ulong size) static inline uint32_t _round_up(uint32_t n, uint32_t size)
{ {
size--; size--;
return (n + size) & ~size; return (n + size) & ~size;
} }
static inline ulong _div_up(ulong n, ulong size) static inline uint32_t _div_up(uint32_t n, uint32_t size)
{ {
return _round_up(n, size) / size; return _round_up(n, size) / size;
} }
@@ -36,7 +35,7 @@ static uint32_t _next_base(struct data_area *area)
*/ */
static int _adjust_pe_on_disk(struct pv_disk *pvd) static int _adjust_pe_on_disk(struct pv_disk *pvd)
{ {
uint32_t pe_start = pvd->pe_start * SECTOR_SIZE; uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size) if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
return 0; return 0;
@@ -63,7 +62,7 @@ static void _calc_simple_layout(struct pv_disk *pvd)
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk); pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
} }
int _check_vg_limits(struct disk_list *dl) static int _check_vg_limits(struct disk_list *dl)
{ {
if (dl->vgd.lv_max > MAX_LV) { if (dl->vgd.lv_max > MAX_LV) {
log_error("MaxLogicalVolumes of %d exceeds format limit of %d " log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
@@ -103,11 +102,10 @@ int calculate_layout(struct disk_list *dl)
} }
/* /*
* It may seem strange to have a struct physical_volume in here, * The number of extents that can fit on a disk is metadata format dependant.
* but the number of extents that can fit on a disk *is* metadata
* format dependant.
*/ */
int calculate_extent_count(struct physical_volume *pv) int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
uint32_t max_extent_count)
{ {
struct pv_disk *pvd = dbg_malloc(sizeof(*pvd)); struct pv_disk *pvd = dbg_malloc(sizeof(*pvd));
uint32_t end; uint32_t end;
@@ -122,10 +120,13 @@ int calculate_extent_count(struct physical_volume *pv)
* one is going to be knocked off at the start of the * one is going to be knocked off at the start of the
* next loop. * next loop.
*/ */
pvd->pe_total = (pv->size / pv->pe_size); if (max_extent_count)
pvd->pe_total = max_extent_count + 1;
else
pvd->pe_total = (pv->size / extent_size);
if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) { if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
log_error("Insufficient space for extents on %s", log_error("Too few extents on %s. Try smaller extent size.",
dev_name(pv->dev)); dev_name(pv->dev));
dbg_free(pvd); dbg_free(pvd);
return 0; return 0;
@@ -135,11 +136,12 @@ int calculate_extent_count(struct physical_volume *pv)
pvd->pe_total--; pvd->pe_total--;
_calc_simple_layout(pvd); _calc_simple_layout(pvd);
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
SECTOR_SIZE - 1) / SECTOR_SIZE); SECTOR_SIZE - 1) >> SECTOR_SHIFT);
pvd->pe_start = _round_up(end, PE_ALIGN); pvd->pe_start = _round_up(end, PE_ALIGN);
} while ((pvd->pe_start + (pvd->pe_total * pv->pe_size)) > pv->size); } while ((pvd->pe_start + (pvd->pe_total * extent_size))
> pv->size);
if (pvd->pe_total > MAX_PE_TOTAL) { if (pvd->pe_total > MAX_PE_TOTAL) {
log_error("Metadata extent limit (%u) exceeded for %s - " log_error("Metadata extent limit (%u) exceeded for %s - "
@@ -151,6 +153,7 @@ int calculate_extent_count(struct physical_volume *pv)
pv->pe_count = pvd->pe_total; pv->pe_count = pvd->pe_total;
pv->pe_start = pvd->pe_start; pv->pe_start = pvd->pe_start;
/* We can't set pe_size here without breaking LVM1 compatibility */
dbg_free(pvd); dbg_free(pvd);
return 1; return 1;
} }

106
lib/format1/lvm1-label.c Normal file
View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "lvm1-label.h"
#include "disk-rep.h"
#include "label.h"
#include "metadata.h"
#include "xlate.h"
#include "lvmcache.h"
#include <sys/stat.h>
#include <fcntl.h>
static void _not_supported(const char *op)
{
log_err("The '%s' operation is not supported for the lvm1 labeller.",
op);
}
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
{
struct pv_disk *pvd = (struct pv_disk *) buf;
uint32_t version;
/* LVM1 label must always be in first sector */
if (sector)
return 0;
version = xlate16(pvd->version);
if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
(version == 1 || version == 2))
return 1;
return 0;
}
static int _write(struct label *label, char *buf)
{
_not_supported("write");
return 0;
}
static int _read(struct labeller *l, struct device *dev, char *buf,
struct label **label)
{
struct pv_disk *pvd = (struct pv_disk *) buf;
struct lvmcache_info *info;
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL)))
return 0;
*label = info->label;
info->device_size = xlate32(pvd->pv_size) << SECTOR_SHIFT;
list_init(&info->mdas);
info->status &= ~CACHE_INVALID;
return 1;
}
static int _initialise_label(struct labeller *l, struct label *label)
{
strcpy(label->type, "LVM1");
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
return;
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _lvm1_ops = {
can_handle:_can_handle,
write:_write,
read:_read,
verify:_can_handle,
initialise_label:_initialise_label,
destroy_label:_destroy_label,
destroy:_destroy
};
struct labeller *lvm1_labeller_create(struct format_type *fmt)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_lvm1_ops;
l->private = (const void *) fmt;
return l;
}

14
lib/format1/lvm1-label.h Normal file
View File

@@ -0,0 +1,14 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_LVM1_LABEL_H
#define _LVM_LVM1_LABEL_H
#include "metadata.h"
struct labeller *lvm1_labeller_create(struct format_type *fmt);
#endif

View File

@@ -1,143 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lvm1_label.h"
#include "dbg_malloc.h"
#include "disk-rep.h"
#include "log.h"
#include "label.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void _not_supported(const char *op)
{
log_err("The '%s' operation is not supported for the lvm1 labeller.",
op);
}
static int _can_handle(struct labeller *l, struct device *dev)
{
struct pv_disk pvd;
int r;
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
return r;
}
static int _write(struct labeller *l, struct device *dev, struct label *label)
{
_not_supported("write");
return 0;
}
static int _remove(struct labeller *l, struct device *dev)
{
_not_supported("remove");
return 0;
}
static struct label *_to_label(struct pv_disk *pvd)
{
struct label *l;
struct lvm_label_info *info;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate label.");
return NULL;
}
if (!(info = (struct lvm_label_info *) dbg_strdup(pvd->vg_name))) {
dbg_free(l);
return NULL;
}
memcpy(&l->id, &pvd->pv_uuid, sizeof(l->id));
strcpy(l->volume_type, "lvm");
l->version[0] = 1;
l->version[0] = 0;
l->version[0] = 0;
l->extra_info = info;
return l;
}
static int _read(struct labeller *l, struct device *dev, struct label **label)
{
struct pv_disk pvd;
int r = 0;
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
if (!r) {
stack;
return 0;
}
/*
* Convert the disk_list into a label structure.
*/
if (!(*label = _to_label(&pvd))) {
stack;
return 0;
}
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
dbg_free(label->extra_info);
dbg_free(label);
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _lvm1_ops = {
can_handle: _can_handle,
write: _write,
remove: _remove,
read: _read,
verify: _can_handle,
destroy_label: _destroy_label,
destroy: _destroy
};
struct labeller *lvm1_labeller_create(void)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_lvm1_ops;
l->private = NULL;
return l;
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_LVM1_LABEL_H
#define _LVM_LVM1_LABEL_H
/*
* This is what the 'extra_info' field of the label will point to
* if the label type is lvm1.
*/
struct lvm_label_info {
char volume_group[0];
};
struct labeller *lvm1_labeller_create(void);
#endif

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "log.h" #include "lib.h"
#include "pool.h" #include "pool.h"
#include "disk-rep.h" #include "disk-rep.h"

View File

@@ -4,9 +4,9 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "format-text.h" #include "format-text.h"
#include "log.h"
#include "pool.h" #include "pool.h"
#include "config.h" #include "config.h"
#include "hash.h" #include "hash.h"
@@ -17,7 +17,6 @@
#include <dirent.h> #include <dirent.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/file.h> #include <sys/file.h>
#include <fcntl.h> #include <fcntl.h>
@@ -52,23 +51,23 @@ struct archive_file {
* Extract vg name and version number from a filename. * Extract vg name and version number from a filename.
*/ */
static int _split_vg(const char *filename, char *vg, size_t vg_size, static int _split_vg(const char *filename, char *vg, size_t vg_size,
uint32_t * index) uint32_t *ix)
{ {
int len, vg_len; size_t len, vg_len;
char *dot, *underscore; const char *dot, *underscore;
len = strlen(filename); len = strlen(filename);
if (len < 7) if (len < 7)
return 0; return 0;
dot = (char *) (filename + len - 3); dot = (filename + len - 3);
if (strcmp(".vg", dot)) if (strcmp(".vg", dot))
return 0; return 0;
if (!(underscore = rindex(filename, '_'))) if (!(underscore = rindex(filename, '_')))
return 0; return 0;
if (sscanf(underscore + 1, "%u", index) != 1) if (sscanf(underscore + 1, "%u", ix) != 1)
return 0; return 0;
vg_len = underscore - filename; vg_len = underscore - filename;
@@ -84,7 +83,7 @@ static int _split_vg(const char *filename, char *vg, size_t vg_size,
static void _insert_file(struct list *head, struct archive_file *b) static void _insert_file(struct list *head, struct archive_file *b)
{ {
struct list *bh; struct list *bh;
struct archive_file *bf; struct archive_file *bf = NULL;
if (list_empty(head)) { if (list_empty(head)) {
list_add(head, &b->list); list_add(head, &b->list);
@@ -124,7 +123,7 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
static struct list *_scan_archive(struct pool *mem, static struct list *_scan_archive(struct pool *mem,
const char *vg, const char *dir) const char *vg, const char *dir)
{ {
int i, count, index; int i, count, ix;
char vg_name[64], *path; char vg_name[64], *path;
struct dirent **dirent; struct dirent **dirent;
struct archive_file *af; struct archive_file *af;
@@ -150,7 +149,7 @@ static struct list *_scan_archive(struct pool *mem,
/* check the name is the correct format */ /* check the name is the correct format */
if (!_split_vg(dirent[i]->d_name, vg_name, sizeof(vg_name), if (!_split_vg(dirent[i]->d_name, vg_name, sizeof(vg_name),
&index)) &ix))
continue; continue;
/* is it the vg we're interested in ? */ /* is it the vg we're interested in ? */
@@ -171,7 +170,7 @@ static struct list *_scan_archive(struct pool *mem,
goto out; goto out;
} }
af->index = index; af->index = ix;
af->path = path; af->path = path;
/* /*
@@ -202,7 +201,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
return; return;
/* Convert retain_days into the time after which we must retain */ /* Convert retain_days into the time after which we must retain */
retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY; retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
/* Assume list is ordered oldest first (by index) */ /* Assume list is ordered oldest first (by index) */
list_iterate(bh, archives) { list_iterate(bh, archives) {
@@ -232,7 +231,7 @@ int archive_vg(struct volume_group *vg,
uint32_t retain_days, uint32_t min_archive) uint32_t retain_days, uint32_t min_archive)
{ {
int i, fd, renamed = 0; int i, fd, renamed = 0;
unsigned int index = 0; unsigned int ix = 0;
struct archive_file *last; struct archive_file *last;
FILE *fp = NULL; FILE *fp = NULL;
char temp_file[PATH_MAX], archive_name[PATH_MAX]; char temp_file[PATH_MAX], archive_name[PATH_MAX];
@@ -252,7 +251,7 @@ int archive_vg(struct volume_group *vg,
return 0; return 0;
} }
if (!text_vg_export(fp, vg, desc)) { if (!text_vg_export_file(vg, desc, fp)) {
stack; stack;
fclose(fp); fclose(fp);
return 0; return 0;
@@ -269,15 +268,15 @@ int archive_vg(struct volume_group *vg,
} }
if (list_empty(archives)) if (list_empty(archives))
index = 0; ix = 0;
else { else {
last = list_item(archives->p, struct archive_file); last = list_item(archives->p, struct archive_file);
index = last->index + 1; ix = last->index + 1;
} }
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
if (lvm_snprintf(archive_name, sizeof(archive_name), if (lvm_snprintf(archive_name, sizeof(archive_name),
"%s/%s_%05d.vg", dir, vg->name, index) < 0) { "%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
log_error("Archive file name too long."); log_error("Archive file name too long.");
return 0; return 0;
} }
@@ -285,7 +284,7 @@ int archive_vg(struct volume_group *vg,
if ((renamed = lvm_rename(temp_file, archive_name))) if ((renamed = lvm_rename(temp_file, archive_name)))
break; break;
index++; ix++;
} }
if (!renamed) if (!renamed)
@@ -297,8 +296,7 @@ int archive_vg(struct volume_group *vg,
return 1; return 1;
} }
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um, static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
struct archive_file *af)
{ {
struct volume_group *vg = NULL; struct volume_group *vg = NULL;
struct format_instance *tf; struct format_instance *tf;
@@ -308,8 +306,9 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
log_print("path:\t\t%s", af->path); log_print("path:\t\t%s", af->path);
if (!(context = create_text_context(cmd->fmtt, af->path, NULL)) || if (!(context = create_text_context(cmd, af->path, NULL)) ||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) { !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
context))) {
log_error("Couldn't create text instance object."); log_error("Couldn't create text instance object.");
return; return;
} }
@@ -319,7 +318,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
* retrieve the archive time and description. * retrieve the archive time and description.
*/ */
/* FIXME Use variation on _vg_read */ /* FIXME Use variation on _vg_read */
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) { if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
log_print("Unable to read archive file."); log_print("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf); tf->fmt->ops->destroy_instance(tf);
return; return;
@@ -332,8 +331,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
tf->fmt->ops->destroy_instance(tf); tf->fmt->ops->destroy_instance(tf);
} }
int archive_list(struct cmd_context *cmd, struct uuid_map *um, int archive_list(struct cmd_context *cmd, const char *dir, const char *vg)
const char *dir, const char *vg)
{ {
struct list *archives, *ah; struct list *archives, *ah;
struct archive_file *af; struct archive_file *af;
@@ -349,7 +347,7 @@ int archive_list(struct cmd_context *cmd, struct uuid_map *um,
list_iterate(ah, archives) { list_iterate(ah, archives) {
af = list_item(ah, struct archive_file); af = list_item(ah, struct archive_file);
_display_archive(cmd, um, af); _display_archive(cmd, af);
log_print(" "); log_print(" ");
} }

View File

@@ -4,18 +4,22 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "import-export.h" #include "import-export.h"
#include "metadata.h" #include "metadata.h"
#include "log.h"
#include "hash.h" #include "hash.h"
#include "pool.h" #include "pool.h"
#include "dbg_malloc.h" #include "display.h"
#include "lvm-string.h" #include "lvm-string.h"
#include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <time.h> #include <time.h>
#include <sys/utsname.h>
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);
/* /*
* The first half of this file deals with * The first half of this file deals with
* exporting the vg, ie. writing it to a file. * exporting the vg, ie. writing it to a file.
@@ -24,22 +28,50 @@ struct formatter {
struct pool *mem; /* pv names allocated from here */ struct pool *mem; /* pv names allocated from here */
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */ struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
FILE *fp; /* where we're writing to */ union {
int indent; /* current level of indentation */ FILE *fp; /* where we're writing to */
struct {
char *buf;
uint32_t size;
uint32_t used;
} buf;
} data;
out_with_comment_fn out_with_comment;
nl_fn nl;
int indent; /* current level of indentation */
int error; int error;
int header; /* 1 => comments at start; 0 => end */
}; };
static struct utsname _utsname;
static void _init(void)
{
static int _initialised = 0;
if (_initialised)
return;
if (uname(&_utsname)) {
log_error("uname failed: %s", strerror(errno));
memset(&_utsname, 0, sizeof(_utsname));
}
_initialised = 1;
}
/* /*
* Formatting functions. * Formatting functions.
*/ */
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...) static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4))); __attribute__ ((format(printf, 3, 4)));
static void _out_hint(struct formatter *f, const char *fmt, ...) static int _out_hint(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3))); __attribute__ ((format(printf, 2, 3)));
static void _out(struct formatter *f, const char *fmt, ...) static int _out(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3))); __attribute__ ((format(printf, 2, 3)));
#define MAX_INDENT 5 #define MAX_INDENT 5
@@ -60,26 +92,39 @@ static void _dec_indent(struct formatter *f)
/* /*
* Newline function for prettier layout. * Newline function for prettier layout.
*/ */
static void _nl(struct formatter *f) static void _nl_file(struct formatter *f)
{ {
fprintf(f->fp, "\n"); fprintf(f->data.fp, "\n");
}
static void _nl_raw(struct formatter *f)
{
if (f->data.buf.used >= f->data.buf.size - 1)
return;
*f->data.buf.buf = '\n';
f->data.buf.buf += 1;
f->data.buf.used += 1;
*f->data.buf.buf = '\0';
return;
} }
#define COMMENT_TAB 6 #define COMMENT_TAB 6
static void _out_with_comment(struct formatter *f, const char *comment, static int _out_with_comment_file(struct formatter *f, const char *comment,
const char *fmt, va_list ap) const char *fmt, va_list ap)
{ {
int i; int i;
char white_space[MAX_INDENT + 1]; char white_space[MAX_INDENT + 1];
if (ferror(f->fp)) if (ferror(f->data.fp))
return; return 0;
for (i = 0; i < f->indent; i++) for (i = 0; i < f->indent; i++)
white_space[i] = '\t'; white_space[i] = '\t';
white_space[i] = '\0'; white_space[i] = '\0';
fprintf(f->fp, white_space); fprintf(f->data.fp, white_space);
i = vfprintf(f->fp, fmt, ap); i = vfprintf(f->data.fp, fmt, ap);
if (comment) { if (comment) {
/* /*
@@ -90,13 +135,34 @@ static void _out_with_comment(struct formatter *f, const char *comment,
i++; i++;
do do
fputc('\t', f->fp); fputc('\t', f->data.fp);
while (++i < COMMENT_TAB); while (++i < COMMENT_TAB);
fprintf(f->fp, comment); fprintf(f->data.fp, comment);
} }
fputc('\n', f->fp); fputc('\n', f->data.fp);
return 1;
}
static int _out_with_comment_raw(struct formatter *f, const char *comment,
const char *fmt, va_list ap)
{
int n;
n = vsnprintf(f->data.buf.buf, 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;
f->data.buf.buf += n;
f->data.buf.used += n;
f->nl(f);
return 1;
} }
/* /*
@@ -107,11 +173,11 @@ static void _out_with_comment(struct formatter *f, const char *comment,
*/ */
static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s) static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
{ {
static char *_units[] = { static const char *_units[] = {
"Kilobytes", "Kilobytes",
"Megabytes", "Megabytes",
"Gigabytes", "Gigabytes",
"Terrabytes", "Terabytes",
NULL NULL
}; };
@@ -131,43 +197,55 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
* Appends a comment giving a size in more easily * Appends a comment giving a size in more easily
* readable form (eg, 4M instead of 8096). * readable form (eg, 4M instead of 8096).
*/ */
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...) static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
{ {
char buffer[64]; char buffer[64];
va_list ap; va_list ap;
int r;
_sectors_to_units(size, buffer, sizeof(buffer)); if (!_sectors_to_units(size, buffer, sizeof(buffer)))
return 0;
va_start(ap, fmt); va_start(ap, fmt);
_out_with_comment(f, buffer, fmt, ap); r = f->out_with_comment(f, buffer, fmt, ap);
va_end(ap); va_end(ap);
return r;
} }
/* /*
* Appends a comment indicating that the line is * Appends a comment indicating that the line is
* only a hint. * only a hint.
*/ */
static void _out_hint(struct formatter *f, const char *fmt, ...) static int _out_hint(struct formatter *f, const char *fmt, ...)
{ {
va_list ap; va_list ap;
int r;
va_start(ap, fmt); va_start(ap, fmt);
_out_with_comment(f, "# Hint only", fmt, ap); r = f->out_with_comment(f, "# Hint only", fmt, ap);
va_end(ap); va_end(ap);
return r;
} }
/* /*
* The normal output function. * The normal output function.
*/ */
static void _out(struct formatter *f, const char *fmt, ...) static int _out(struct formatter *f, const char *fmt, ...)
{ {
va_list ap; va_list ap;
int r;
va_start(ap, fmt); va_start(ap, fmt);
_out_with_comment(f, NULL, fmt, ap); r = f->out_with_comment(f, NULL, fmt, ap);
va_end(ap); va_end(ap);
return r;
} }
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
static int _print_header(struct formatter *f, static int _print_header(struct formatter *f,
struct volume_group *vg, const char *desc) struct volume_group *vg, const char *desc)
{ {
@@ -175,12 +253,17 @@ static int _print_header(struct formatter *f,
t = time(NULL); t = time(NULL);
_out(f, _outf(f, "# Generated by LVM2: %s", ctime(&t));
"# This file was originally generated by the LVM2 library\n" _outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
"# Generated: %s\n", ctime(&t)); _outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
f->nl(f);
_out(f, "description = \"%s\"", desc); _outf(f, "description = \"%s\"", desc);
_out(f, "creation_time = %lu\n", t); f->nl(f);
_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
_utsname.sysname, _utsname.nodename, _utsname.release,
_utsname.version, _utsname.machine);
_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
return 1; return 1;
} }
@@ -194,20 +277,24 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
return 0; return 0;
} }
_out(f, "id = \"%s\"", buffer); _outf(f, "id = \"%s\"", buffer);
_out(f, "seqno = %u", vg->seqno); _outf(f, "seqno = %u", vg->seqno);
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) { if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
stack; stack;
return 0; return 0;
} }
_out(f, "status = %s", buffer); _outf(f, "status = %s", buffer);
if (vg->system_id && *vg->system_id) if (vg->system_id && *vg->system_id)
_out(f, "system_id = \"%s\"", vg->system_id); _outf(f, "system_id = \"%s\"", vg->system_id);
_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size); if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
_out(f, "max_lv = %u", vg->max_lv); vg->extent_size)) {
_out(f, "max_pv = %u", vg->max_pv); stack;
return 0;
}
_outf(f, "max_lv = %u", vg->max_lv);
_outf(f, "max_pv = %u", vg->max_pv);
return 1; return 1;
} }
@@ -230,7 +317,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
char buffer[256]; char buffer[256];
const char *name; const char *name;
_out(f, "physical_volumes {"); _outf(f, "physical_volumes {");
_inc_indent(f); _inc_indent(f);
list_iterate(pvh, &vg->pvs) { list_iterate(pvh, &vg->pvs) {
@@ -242,8 +329,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
return 0; return 0;
} }
_nl(f); f->nl(f);
_out(f, "%s {", name); _outf(f, "%s {", name);
_inc_indent(f); _inc_indent(f);
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) { if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
@@ -251,65 +338,109 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
return 0; return 0;
} }
_out(f, "id = \"%s\"", buffer); _outf(f, "id = \"%s\"", buffer);
_out_hint(f, "device = \"%s\"", dev_name(pv->dev)); if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
_nl(f); stack;
return 0;
}
f->nl(f);
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) { if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
stack; stack;
return 0; return 0;
} }
_out(f, "status = %s", buffer); _outf(f, "status = %s", buffer);
_out(f, "pe_start = %llu", pv->pe_start); _outf(f, "pe_start = %" PRIu64, pv->pe_start);
_out_size(f, vg->extent_size * (uint64_t) pv->pe_count, if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
"pe_count = %u", pv->pe_count); "pe_count = %u", pv->pe_count)) {
_dec_indent(f);
_out(f, "}");
}
_dec_indent(f);
_out(f, "}");
return 1;
}
static int _print_segment(struct formatter *f, struct volume_group *vg,
int count, struct stripe_segment *seg)
{
int s;
const char *name;
_out(f, "segment%u {", count);
_inc_indent(f);
_out(f, "start_extent = %u", seg->le);
_out_size(f, seg->len * vg->extent_size, "extent_count = %u", seg->len);
_out(f, "stripes = %u", seg->stripes);
if (seg->stripes > 1)
_out_size(f, seg->stripe_size,
"stripe_size = %u", seg->stripe_size);
_nl(f);
_out(f, "areas = [");
_inc_indent(f);
for (s = 0; s < seg->stripes; s++) {
if (!(name = _get_pv_name(f, seg->area[s].pv))) {
stack; stack;
return 0; return 0;
} }
_out(f, "\"%s\", %u%s", name, seg->area[s].pe, _dec_indent(f);
(s == seg->stripes - 1) ? "" : ","); _outf(f, "}");
} }
_dec_indent(f); _dec_indent(f);
_out(f, "]"); _outf(f, "}");
return 1;
}
static int _print_segment(struct formatter *f, struct volume_group *vg,
int count, struct lv_segment *seg)
{
unsigned int s;
const char *name;
const char *type;
_outf(f, "segment%u {", count);
_inc_indent(f);
_outf(f, "start_extent = %u", seg->le);
if (!_out_size(f, (uint64_t) seg->len * vg->extent_size,
"extent_count = %u", seg->len)) {
stack;
return 0;
}
f->nl(f);
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
switch (seg->type) {
case SEG_SNAPSHOT:
_outf(f, "chunk_size = %u", seg->chunk_size);
_outf(f, "origin = \"%s\"", seg->origin->name);
_outf(f, "cow_store = \"%s\"", seg->cow->name);
break;
case SEG_MIRRORED:
case SEG_STRIPED:
type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe";
_outf(f, "%s_count = %u%s", type, seg->area_count,
(seg->area_count == 1) ? "\t# linear" : "");
if ((seg->type == SEG_MIRRORED) && (seg->status & PVMOVE))
_out_size(f, (uint64_t) seg->extents_moved,
"extents_moved = %u", seg->extents_moved);
if ((seg->type == SEG_STRIPED) && (seg->area_count > 1))
_out_size(f, (uint64_t) seg->stripe_size,
"stripe_size = %u", seg->stripe_size);
f->nl(f);
_outf(f, "%ss = [", type);
_inc_indent(f);
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_PV:
if (!(name = _get_pv_name(f, seg->
area[s].u.pv.pv))) {
stack;
return 0;
}
_outf(f, "\"%s\", %u%s", name,
seg->area[s].u.pv.pe,
(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,
(s == seg->area_count - 1) ? "" : ",");
}
}
_dec_indent(f);
_outf(f, "]");
break;
}
_dec_indent(f); _dec_indent(f);
_out(f, "}"); _outf(f, "}");
return 1; return 1;
} }
@@ -325,83 +456,48 @@ static int _count_segments(struct logical_volume *lv)
return r; return r;
} }
static int _print_lvs(struct formatter *f, struct volume_group *vg) static int _print_snapshot(struct formatter *f, struct snapshot *snap,
unsigned int count)
{ {
struct list *lvh, *segh;
struct logical_volume *lv;
struct stripe_segment *seg;
char buffer[256]; char buffer[256];
int seg_count; struct lv_segment seg;
/* f->nl(f);
* Don't bother with an lv section if there are no lvs.
*/
if (list_empty(&vg->lvs))
return 1;
_out(f, "logical_volumes {"); _outf(f, "snapshot%u {", count);
_inc_indent(f); _inc_indent(f);
list_iterate(lvh, &vg->lvs) { if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
lv = list_item(lvh, struct lv_list)->lv; stack;
return 0;
}
_nl(f); _outf(f, "id = \"%s\"", buffer);
_out(f, "%s {", lv->name); if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
_inc_indent(f); buffer, sizeof(buffer))) {
stack;
return 0;
}
/* FIXME: Write full lvid */ _outf(f, "status = %s", buffer);
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) { _outf(f, "segment_count = 1");
stack;
return 0;
}
_out(f, "id = \"%s\"", buffer); f->nl(f);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) { seg.type = SEG_SNAPSHOT;
stack; seg.le = 0;
return 0; seg.len = snap->origin->le_count;
} seg.origin = snap->origin;
seg.cow = snap->cow;
seg.chunk_size = snap->chunk_size;
_out(f, "status = %s", buffer); if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
_out(f, "read_ahead = %u", lv->read_ahead); stack;
if (lv->minor >= 0) return 0;
_out(f, "minor = %d", lv->minor);
_out(f, "segment_count = %u", _count_segments(lv));
_nl(f);
seg_count = 1;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
stack;
return 0;
}
}
_dec_indent(f);
_out(f, "}");
} }
_dec_indent(f); _dec_indent(f);
_out(f, "}"); _outf(f, "}");
return 1;
}
static int _print_snapshot(struct formatter *f, struct snapshot *s,
unsigned int count)
{
_nl(f);
_out(f, "snapshot%u {", count);
_inc_indent(f);
_out(f, "chunk_size = %u", s->chunk_size);
_out(f, "origin = \"%s\"", s->origin->name);
_out(f, "cow_store = \"%s\"", s->cow->name);
_dec_indent(f);
_out(f, "}");
return 1; return 1;
} }
@@ -412,16 +508,6 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
struct snapshot *s; struct snapshot *s;
unsigned int count = 0; unsigned int count = 0;
/*
* Don't bother with a snapshot section if there are no
* snapshots.
*/
if (list_empty(&vg->snapshots))
return 1;
_out(f, "snapshots {");
_inc_indent(f);
list_iterate(sh, &vg->snapshots) { list_iterate(sh, &vg->snapshots) {
s = list_item(sh, struct snapshot_list)->snapshot; s = list_item(sh, struct snapshot_list)->snapshot;
@@ -431,8 +517,80 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
} }
} }
return 1;
}
static int _print_lvs(struct formatter *f, struct volume_group *vg)
{
struct list *lvh, *segh;
struct logical_volume *lv;
struct lv_segment *seg;
char buffer[256];
int seg_count;
/*
* Don't bother with an lv section if there are no lvs.
*/
if (list_empty(&vg->lvs))
return 1;
_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))) {
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 (lv->alloc != ALLOC_DEFAULT)
_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(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
stack;
return 0;
}
}
_dec_indent(f);
_outf(f, "}");
}
if (!_print_snapshots(f, vg)) {
stack;
return 0;
}
_dec_indent(f); _dec_indent(f);
_out(f, "}"); _outf(f, "}");
return 1; return 1;
} }
@@ -462,6 +620,7 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
list_iterate(pvh, &vg->pvs) { list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv; pv = list_item(pvh, struct pv_list)->pv;
/* FIXME But skip if there's already an LV called pv%d ! */
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) { if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
stack; stack;
goto bad; goto bad;
@@ -490,19 +649,10 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
return 0; return 0;
} }
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc) static int _text_vg_export(struct formatter *f,
struct volume_group *vg, const char *desc)
{ {
int r = 0; int r = 0;
struct formatter *f;
if (!(f = dbg_malloc(sizeof(*f)))) {
stack;
return 0;
}
memset(f, 0, sizeof(*f));
f->fp = fp;
f->indent = 0;
if (!_build_pv_names(f, vg)) { if (!_build_pv_names(f, vg)) {
stack; stack;
@@ -510,32 +660,34 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
} }
#define fail do {stack; goto out;} while(0) #define fail do {stack; goto out;} while(0)
if (!_print_header(f, vg, desc)) if (f->header && !_print_header(f, vg, desc))
fail;
if (!_out(f, "%s {", vg->name))
fail; fail;
_out(f, "%s {", vg->name);
_inc_indent(f); _inc_indent(f);
if (!_print_vg(f, vg)) if (!_print_vg(f, vg))
fail; fail;
_nl(f); f->nl(f);
if (!_print_pvs(f, vg)) if (!_print_pvs(f, vg))
fail; fail;
_nl(f); f->nl(f);
if (!_print_lvs(f, vg)) if (!_print_lvs(f, vg))
fail; fail;
_nl(f); _dec_indent(f);
if (!_print_snapshots(f, vg)) if (!_out(f, "}"))
fail;
if (!f->header && !_print_header(f, vg, desc))
fail; fail;
#undef fail #undef fail
r = 1;
_dec_indent(f);
_out(f, "}");
r = !ferror(f->fp);
out: out:
if (f->mem) if (f->mem)
@@ -544,6 +696,68 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
if (f->pv_names) if (f->pv_names)
hash_destroy(f->pv_names); hash_destroy(f->pv_names);
return r;
}
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
{
struct formatter *f;
int r;
_init();
if (!(f = dbg_malloc(sizeof(*f)))) {
stack;
return 0;
}
memset(f, 0, sizeof(*f));
f->data.fp = fp;
f->indent = 0;
f->header = 1;
f->out_with_comment = &_out_with_comment_file;
f->nl = &_nl_file;
r = _text_vg_export(f, vg, desc);
if (r)
r = !ferror(f->data.fp);
dbg_free(f); dbg_free(f);
return r; return r;
} }
/* 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)
{
struct formatter *f;
int r;
_init();
if (!(f = dbg_malloc(sizeof(*f)))) {
stack;
return 0;
}
memset(f, 0, sizeof(*f));
f->data.buf.buf = buf;
f->data.buf.size = size;
f->indent = 0;
f->header = 0;
f->out_with_comment = &_out_with_comment_raw;
f->nl = &_nl_raw;
if (!_text_vg_export(f, vg, desc)) {
stack;
r = 0;
goto out;
}
r = f->data.buf.used + 1;
out:
dbg_free(f);
return r;
}
#undef _outf

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "log.h" #include "lib.h"
#include "metadata.h" #include "metadata.h"
#include "import-export.h" #include "import-export.h"
#include "lvm-string.h" #include "lvm-string.h"
@@ -14,14 +14,15 @@
* converted into arrays of strings. * converted into arrays of strings.
*/ */
struct flag { struct flag {
int mask; const int mask;
char *description; const char *description;
}; };
static struct flag _vg_flags[] = { static struct flag _vg_flags[] = {
{EXPORTED_VG, "EXPORTED"}, {EXPORTED_VG, "EXPORTED"},
{RESIZEABLE_VG, "RESIZEABLE"}, {RESIZEABLE_VG, "RESIZEABLE"},
{PARTIAL_VG, "PARTIAL"}, {PARTIAL_VG, "PARTIAL"},
{PVMOVE, "PVMOVE"},
{LVM_READ, "READ"}, {LVM_READ, "READ"},
{LVM_WRITE, "WRITE"}, {LVM_WRITE, "WRITE"},
{CLUSTERED, "CLUSTERED"}, {CLUSTERED, "CLUSTERED"},
@@ -38,10 +39,10 @@ static struct flag _pv_flags[] = {
static struct flag _lv_flags[] = { static struct flag _lv_flags[] = {
{LVM_READ, "READ"}, {LVM_READ, "READ"},
{LVM_WRITE, "WRITE"}, {LVM_WRITE, "WRITE"},
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
{ALLOC_STRICT, "ALLOC_STRICT"},
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
{FIXED_MINOR, "FIXED_MINOR"}, {FIXED_MINOR, "FIXED_MINOR"},
{VISIBLE_LV, "VISIBLE"},
{PVMOVE, "PVMOVE"},
{LOCKED, "LOCKED"},
{0, NULL} {0, NULL}
}; };
@@ -62,9 +63,9 @@ static struct flag *_get_flags(int type)
return NULL; return NULL;
} }
static int _emit(char **buffer, size_t * size, const char *fmt, ...) static int _emit(char **buffer, size_t *size, const char *fmt, ...)
{ {
size_t n; int n;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@@ -124,7 +125,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
return 1; return 1;
} }
int read_flags(uint32_t * status, int type, struct config_value *cv) int read_flags(uint32_t *status, int type, struct config_value *cv)
{ {
int f; int f;
uint32_t s = 0; uint32_t s = 0;
@@ -135,6 +136,9 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
return 0; return 0;
} }
if (cv->type == CFG_EMPTY_ARRAY)
goto out;
while (cv) { while (cv) {
if (cv->type != CFG_STRING) { if (cv->type != CFG_STRING) {
log_err("Status value is not a string."); log_err("Status value is not a string.");
@@ -155,6 +159,7 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
cv = cv->next; cv = cv->next;
} }
out:
*status = s; *status = s;
return 1; return 1;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,10 @@
#include "lvm-types.h" #include "lvm-types.h"
#include "metadata.h" #include "metadata.h"
#include "uuid-map.h" #include "pool.h"
#define FMT_TEXT_NAME "lvm2"
#define FMT_TEXT_ALIAS "text"
/* /*
* Archives a vg config. 'retain_days' is the minimum number of * Archives a vg config. 'retain_days' is the minimum number of
@@ -19,21 +22,33 @@
*/ */
int archive_vg(struct volume_group *vg, int archive_vg(struct volume_group *vg,
const char *dir, const char *dir,
const char *desc, const char *desc, uint32_t retain_days, uint32_t min_archive);
uint32_t retain_days,
uint32_t min_archive);
/* /*
* Displays a list of vg backups in a particular archive directory. * Displays a list of vg backups in a particular archive directory.
*/ */
int archive_list(struct cmd_context *cmd, struct uuid_map *um, int archive_list(struct cmd_context *cmd, const char *dir, const char *vg);
const char *dir, const char *vg);
/* /*
* The text format can read and write a volume_group to a file. * The text format can read and write a volume_group to a file.
*/ */
struct format_type *create_text_format(struct cmd_context *cmd); struct format_type *create_text_format(struct cmd_context *cmd);
void *create_text_context(struct format_type *fmt, const char *path, void *create_text_context(struct cmd_context *cmd, const char *path,
const char *desc); const char *desc);
struct labeller *text_labeller_create(const struct format_type *fmt);
int pvhdr_read(struct device *dev, char *buf);
int add_da(const struct format_type *fmt, struct pool *mem, struct list *das,
uint64_t start, uint64_t size);
void del_das(struct list *das);
int add_mda(const struct format_type *fmt, struct pool *mem, struct list *mdas,
struct device *dev, uint64_t start, uint64_t size);
void del_mdas(struct list *mdas);
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
char *buf, uint32_t size);
#endif #endif

View File

@@ -10,24 +10,55 @@
#include "config.h" #include "config.h"
#include "lvm-types.h" #include "lvm-types.h"
#include "metadata.h" #include "metadata.h"
#include "uuid-map.h" #include "pool.h"
#include <stdio.h> #include <stdio.h>
/*
* Constants to identify files this code can parse.
*/
#define CONTENTS_FIELD "contents"
#define CONTENTS_VALUE "Text Format Volume Group"
#define FORMAT_VERSION_FIELD "version"
#define FORMAT_VERSION_VALUE 1
/*
* VGs, PVs and LVs all have status bitsets, we gather together
* common code for reading and writing them.
*/
enum { enum {
VG_FLAGS, VG_FLAGS,
PV_FLAGS, PV_FLAGS,
LV_FLAGS LV_FLAGS
}; };
struct text_vg_version_ops {
int (*check_version) (struct config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
struct config_tree * cf);
void (*read_desc) (struct pool * mem, struct config_tree * cf,
time_t *when, char **desc);
};
struct text_vg_version_ops *text_vg_vsn1_init(void);
int print_flags(uint32_t status, int type, char *buffer, size_t size); int print_flags(uint32_t status, int type, char *buffer, size_t size);
int read_flags(uint32_t *status, int type, struct config_value *cv); int read_flags(uint32_t *status, int type, struct config_value *cv);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc); int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
struct volume_group *text_vg_import(struct format_instance *fid, uint32_t size);
const char *file, struct volume_group *text_vg_import_file(struct format_instance *fid,
struct uuid_map *um, const char *file,
time_t *when, char **desc); time_t *when, char **desc);
struct volume_group *text_vg_import_fd(struct format_instance *fid,
const char *file,
struct device *dev,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
uint32_t checksum,
time_t *when, char **desc);
#endif #endif

View File

@@ -4,674 +4,79 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "metadata.h" #include "metadata.h"
#include "import-export.h" #include "import-export.h"
#include "pool.h" #include "pool.h"
#include "log.h" #include "display.h"
#include "uuid.h"
#include "hash.h" #include "hash.h"
#include "toolcontext.h" #include "toolcontext.h"
#include "lvmcache.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn, /* FIXME Use tidier inclusion method */
struct config_node * vgn, static struct text_vg_version_ops *(_text_vsn_list[2]);
struct hash_table * pv_hash, struct uuid_map * um);
struct volume_group *text_vg_import_fd(struct format_instance *fid,
#define _read_int32(root, path, result) \ const char *file,
get_config_uint32(root, path, '/', result) struct device *dev,
off_t offset, uint32_t size,
#define _read_uint32(root, path, result) \ off_t offset2, uint32_t size2,
get_config_uint32(root, path, '/', result) checksum_fn_t checksum_fn,
uint32_t checksum,
#define _read_int64(root, path, result) \ time_t *when, char **desc)
get_config_uint64(root, path, '/', result)
static int _read_id(struct id *id, struct config_node *cn, const char *path)
{
struct config_value *cv;
if (!(cn = find_config_node(cn, path, '/'))) {
log_err("Couldn't find uuid.");
return 0;
}
cv = cn->v;
if (!cv || !cv->v.str) {
log_err("uuid must be a string.");
return 0;
}
if (!id_read_format(id, cv->v.str)) {
log_err("Invalid uuid.");
return 0;
}
return 1;
}
static int _read_pv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn,
struct hash_table *pv_hash, struct uuid_map *um)
{
struct physical_volume *pv;
struct pv_list *pvl;
struct config_node *cn;
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
stack;
return 0;
}
pv = pvl->pv;
/*
* Add the pv to the pv hash for quick lookup when we read
* the lv segments.
*/
if (!hash_insert(pv_hash, pvn->key, pv)) {
stack;
return 0;
}
if (!(pvn = pvn->child)) {
log_err("Empty pv section.");
return 0;
}
if (!_read_id(&pv->id, pvn, "id")) {
log_err("Couldn't read uuid for volume group.");
return 0;
}
/*
* Use the uuid map to convert the uuid into a device.
*/
if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
char buffer[64];
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_err("Couldn't find device.");
else
log_err("Couldn't find device with uuid '%s'.", buffer);
if (partial_mode())
vg->status |= PARTIAL_VG;
else
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
stack;
return 0;
}
if (!(cn = find_config_node(pvn, "status", '/'))) {
log_err("Couldn't find status flags for physical volume.");
return 0;
}
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
log_err("Couldn't read status flags for physical volume.");
return 0;
}
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
log_err("Couldn't read extent size for volume group.");
return 0;
}
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
log_err("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
}
/* adjust the volume group. */
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
pv->pe_size = vg->extent_size;
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
pv->pe_alloc_count = 0;
pv->fid = fid;
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
return 1;
}
static void _insert_segment(struct logical_volume *lv,
struct stripe_segment *seg)
{
struct list *segh;
struct stripe_segment *comp;
list_iterate(segh, &lv->segments) {
comp = list_item(segh, struct stripe_segment);
if (comp->le > seg->le) {
list_add(&comp->list, &seg->list);
return;
}
}
lv->le_count += seg->len;
list_add(&lv->segments, &seg->list);
}
static int _read_segment(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *sn,
struct hash_table *pv_hash)
{
int s;
uint32_t stripes;
struct stripe_segment *seg;
struct config_node *cn;
struct config_value *cv;
const char *seg_name = sn->key;
if (!(sn = sn->child)) {
log_err("Empty segment section.");
return 0;
}
if (!_read_int32(sn, "stripes", &stripes)) {
log_err("Couldn't read 'stripes' for segment '%s'.", sn->key);
return 0;
}
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
(sizeof(seg->area[0]) * stripes)))) {
stack;
return 0;
}
seg->stripes = stripes;
seg->lv = lv;
if (!_read_int32(sn, "start_extent", &seg->le)) {
log_err("Couldn't read 'start_extent' for segment '%s'.",
sn->key);
return 0;
}
if (!_read_int32(sn, "extent_count", &seg->len)) {
log_err("Couldn't read 'extent_count' for segment '%s'.",
sn->key);
return 0;
}
if (seg->stripes == 0) {
log_err("Zero stripes is *not* allowed for segment '%s'.",
sn->key);
return 0;
}
if ((seg->stripes != 1) &&
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
log_err("Couldn't read 'stripe_size' for segment '%s'.",
sn->key);
return 0;
}
if (!(cn = find_config_node(sn, "areas", '/'))) {
log_err("Couldn't find 'areas' array for segment '%s'.",
sn->key);
return 0;
}
/*
* Read the stripes from the 'areas' array.
* FIXME: we could move this to a separate function.
*/
for (cv = cn->v, s = 0; cv && s < seg->stripes; s++, cv = cv->next) {
/* first we read the pv */
const char *bad = "Badly formed areas array for segment '%s'.";
struct physical_volume *pv;
uint32_t allocated;
if (cv->type != CFG_STRING) {
log_err(bad, sn->key);
return 0;
}
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
log_err("Couldn't find physical volume '%s' for "
"segment '%s'.",
cn->v->v.str ? cn->v->v.str : "NULL", seg_name);
return 0;
}
seg->area[s].pv = pv;
if (!(cv = cv->next)) {
log_err(bad, sn->key);
return 0;
}
if (cv->type != CFG_INT) {
log_err(bad, sn->key);
return 0;
}
seg->area[s].pe = cv->v.i;
/*
* Adjust the extent counts in the pv and vg.
*/
allocated = seg->len / seg->stripes;
pv->pe_alloc_count += allocated;
vg->free_count -= allocated;
}
/*
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->stripes)) {
log_err("Incorrect number of stripes in 'area' array "
"for segment '%s'.", seg_name);
return 0;
}
/*
* Insert into correct part of segment list.
*/
_insert_segment(lv, seg);
return 1;
}
static int _read_segments(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *lvn,
struct hash_table *pv_hash)
{
struct config_node *sn;
int count = 0, seg_count;
for (sn = lvn; sn; sn = sn->sib) {
/*
* All sub-sections are assumed to be segments.
*/
if (!sn->v) {
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
stack;
return 0;
}
count++;
}
}
if (!_read_int32(lvn, "segment_count", &seg_count)) {
log_err("Couldn't read segment count for logical volume.");
return 0;
}
if (seg_count != count) {
log_err("segment_count and actual number of segments "
"disagree.");
return 0;
}
/*
* Check there are no gaps or overlaps in the lv.
*/
if (!lv_check_segments(lv)) {
stack;
return 0;
}
/*
* Merge segments in case someones been editing things by hand.
*/
if (!lv_merge_segments(lv)) {
stack;
return 0;
}
return 1;
}
static int _read_lv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *lvn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um)
{
struct logical_volume *lv;
struct lv_list *lvl;
struct config_node *cn;
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
stack;
return 0;
}
lv = lvl->lv;
if (!(lv->name = pool_strdup(mem, lvn->key))) {
stack;
return 0;
}
if (!(lvn = lvn->child)) {
log_err("Empty logical volume section.");
return 0;
}
lv->vg = vg;
/* FIXME: read full lvid */
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
log_err("Couldn't read uuid for logical volume %s.", lv->name);
return 0;
}
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
if (!(cn = find_config_node(lvn, "status", '/'))) {
log_err("Couldn't find status flags for logical volume.");
return 0;
}
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
log_err("Couldn't read status flags for logical volume.");
return 0;
}
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read 'minor' value for logical volume.");
return 0;
}
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
log_err("Couldn't read 'read_ahead' value for "
"logical volume.");
return 0;
}
list_init(&lv->segments);
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
stack;
return 0;
}
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
vg->lv_count++;
list_add(&vg->lvs, &lvl->list);
return 1;
}
static int _read_snapshot(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *sn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um)
{
uint32_t chunk_size;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
if (!(sn = sn->child)) {
log_err("Empty snapshot section.");
return 0;
}
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_err("Couldn't read chunk size for snapshot.");
return 0;
}
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
log_err("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
log_err("Snapshot origin not specified.");
return 0;
}
if (!(cow = find_lv(vg, cow_name))) {
log_err("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_err("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, chunk_size)) {
stack;
return 0;
}
return 1;
}
static int _read_sections(struct format_instance *fid,
const char *section, section_fn fn,
struct pool *mem,
struct volume_group *vg, struct config_node *vgn,
struct hash_table *pv_hash,
struct uuid_map *um, int optional)
{
struct config_node *n;
if (!(n = find_config_node(vgn, section, '/'))) {
if (!optional) {
log_err("Couldn't find section '%s'.", section);
return 0;
}
return 1;
}
for (n = n->child; n; n = n->sib) {
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
stack;
return 0;
}
}
return 1;
}
static struct volume_group *_read_vg(struct format_instance *fid,
struct config_file *cf,
struct uuid_map *um)
{
struct config_node *vgn, *cn;
struct volume_group *vg;
struct hash_table *pv_hash = NULL;
struct pool *mem = fid->fmt->cmd->mem;
/* skip any top-level values */
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
if (!vgn) {
log_err("Couldn't find volume group in file.");
return NULL;
}
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
return NULL;
}
vg->cmd = fid->fmt->cmd;
/* FIXME Determine format type from file contents */
/* eg Set to instance of fmt1 here if reading a format1 backup? */
vg->fid = fid;
if (!(vg->name = pool_strdup(mem, vgn->key))) {
stack;
goto bad;
}
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
stack;
goto bad;
}
vgn = vgn->child;
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
if (!cn->v->v.str) {
log_error("system_id must be a string");
goto bad;
}
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
}
if (!_read_id(&vg->id, vgn, "id")) {
log_err("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
}
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
log_err("Couldn't read 'seqno' for volume group %s.", vg->name);
goto bad;
}
if (!(cn = find_config_node(vgn, "status", '/'))) {
log_err("Couldn't find status flags for volume group %s.",
vg->name);
goto bad;
}
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
log_err("Couldn't read status flags for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
log_err("Couldn't read extent size for volume group %s.",
vg->name);
goto bad;
}
/*
* 'extent_count' and 'free_count' get filled in
* implicitly when reading in the pv's and lv's.
*/
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
log_err("Couldn't read 'max_lv' for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
log_err("Couldn't read 'max_pv' for volume group %s.",
vg->name);
goto bad;
}
/*
* The pv hash memoises the pv section names -> pv
* structures.
*/
if (!(pv_hash = hash_create(32))) {
log_err("Couldn't create hash table.");
goto bad;
}
list_init(&vg->pvs);
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
vgn, pv_hash, um, 0)) {
log_err("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->lvs);
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->snapshots);
if (!_read_sections(fid, "snapshots", _read_snapshot, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all snapshots for volume group %s.",
vg->name);
goto bad;
}
hash_destroy(pv_hash);
if (vg->status & PARTIAL_VG) {
vg->status &= ~LVM_WRITE;
vg->status |= LVM_READ;
}
/*
* Finished.
*/
return vg;
bad:
if (pv_hash)
hash_destroy(pv_hash);
pool_free(mem, vg);
return NULL;
}
static void _read_desc(struct pool *mem,
struct config_file *cf, time_t * when, char **desc)
{
const char *d;
unsigned int u = 0u;
d = find_config_str(cf->root, "description", '/', "");
*desc = pool_strdup(mem, d);
get_config_uint32(cf->root, "creation_time", '/', &u);
*when = u;
}
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um,
time_t * when, char **desc)
{ {
struct volume_group *vg = NULL; struct volume_group *vg = NULL;
struct config_file *cf; struct config_tree *cf;
struct text_vg_version_ops **vsn;
static int _initialised = 0;
if (!_initialised) {
_text_vsn_list[0] = text_vg_vsn1_init();
_text_vsn_list[1] = NULL;
_initialised = 1;
}
*desc = NULL; *desc = NULL;
*when = 0; *when = 0;
if (!(cf = create_config_file())) { if (!(cf = create_config_tree())) {
stack; stack;
goto out; goto out;
} }
if (!read_config(cf, file)) { if ((!dev && !read_config_file(cf, file)) ||
log_error("Couldn't read volume group file."); (dev && !read_config_fd(cf, dev, offset, size,
offset2, size2, checksum_fn, checksum))) {
log_error("Couldn't read volume group metadata.");
goto out; goto out;
} }
if (!(vg = _read_vg(fid, cf, um))) { /*
stack; * Find a set of version functions that can read this file
goto out; */
} for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
if (!(*vsn)->check_version(cf))
continue;
_read_desc(fid->fmt->cmd->mem, cf, when, desc); if (!(vg = (*vsn)->read_vg(fid, cf))) {
stack;
goto out;
}
(*vsn)->read_desc(fid->fmt->cmd->mem, cf, when, desc);
break;
}
out: out:
destroy_config_file(cf); destroy_config_tree(cf);
return vg; return vg;
} }
struct volume_group *text_vg_import_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc)
{
return text_vg_import_fd(fid, file, NULL, 0, 0, 0, 0, NULL, 0,
when, desc);
}

View File

@@ -0,0 +1,810 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "pool.h"
#include "display.h"
#include "hash.h"
#include "toolcontext.h"
#include "lvmcache.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn,
struct config_node * vgn,
struct hash_table * pv_hash);
#define _read_int32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_uint32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_int64(root, path, result) \
get_config_uint64(root, path, '/', result)
/*
* Logs an attempt to read an invalid format file.
*/
static void _invalid_format(const char *str)
{
log_error("Can't process text format file - %s.", str);
}
/*
* Checks that the config file contains vg metadata, and that it
* we recognise the version number,
*/
static int _check_version(struct config_tree *cf)
{
struct config_node *cn;
struct config_value *cv;
/*
* Check the contents field.
*/
if (!(cn = find_config_node(cf->root, CONTENTS_FIELD, '/'))) {
_invalid_format("missing contents field");
return 0;
}
cv = cn->v;
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
_invalid_format("unrecognised contents field");
return 0;
}
/*
* Check the version number.
*/
if (!(cn = find_config_node(cf->root, FORMAT_VERSION_FIELD, '/'))) {
_invalid_format("missing version number");
return 0;
}
cv = cn->v;
if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
_invalid_format("unrecognised version number");
return 0;
}
return 1;
}
static int _read_id(struct id *id, struct config_node *cn, const char *path)
{
struct config_value *cv;
if (!(cn = find_config_node(cn, path, '/'))) {
log_error("Couldn't find uuid.");
return 0;
}
cv = cn->v;
if (!cv || !cv->v.str) {
log_error("uuid must be a string.");
return 0;
}
if (!id_read_format(id, cv->v.str)) {
log_error("Invalid uuid.");
return 0;
}
return 1;
}
static int _read_pv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn, struct hash_table *pv_hash)
{
struct physical_volume *pv;
struct pv_list *pvl;
struct config_node *cn;
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
stack;
return 0;
}
pv = pvl->pv;
/*
* Add the pv to the pv hash for quick lookup when we read
* the lv segments.
*/
if (!hash_insert(pv_hash, pvn->key, pv)) {
stack;
return 0;
}
if (!(pvn = pvn->child)) {
log_error("Empty pv section.");
return 0;
}
if (!_read_id(&pv->id, pvn, "id")) {
log_error("Couldn't read uuid for volume group.");
return 0;
}
/*
* Convert the uuid into a device.
*/
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
char buffer[64];
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_error("Couldn't find device.");
else
log_error("Couldn't find device with uuid '%s'.",
buffer);
if (partial_mode())
vg->status |= PARTIAL_VG;
else
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
stack;
return 0;
}
if (!(cn = find_config_node(pvn, "status", '/'))) {
log_error("Couldn't find status flags for physical volume.");
return 0;
}
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
log_error("Couldn't read status flags for physical volume.");
return 0;
}
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
log_error("Couldn't read extent size for volume group.");
return 0;
}
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
log_error("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
}
/* adjust the volume group. */
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
pv->pe_size = vg->extent_size;
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
return 1;
}
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);
if (comp->le > seg->le) {
list_add(&comp->list, &seg->list);
return;
}
}
lv->le_count += seg->len;
list_add(&lv->segments, &seg->list);
}
static int _read_segment(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *sn,
struct hash_table *pv_hash)
{
unsigned int s;
uint32_t area_count = 0;
struct lv_segment *seg;
struct config_node *cn;
struct config_value *cv;
const char *seg_name = sn->key;
uint32_t start_extent, extent_count;
uint32_t chunk_size, extents_moved = 0u, seg_status = 0u;
const char *org_name, *cow_name;
struct logical_volume *org, *cow, *lv1;
segment_type_t segtype;
if (!(sn = sn->child)) {
log_error("Empty segment section.");
return 0;
}
if (!_read_int32(sn, "start_extent", &start_extent)) {
log_error("Couldn't read 'start_extent' for segment '%s'.",
sn->key);
return 0;
}
if (!_read_int32(sn, "extent_count", &extent_count)) {
log_error("Couldn't read 'extent_count' for segment '%s'.",
sn->key);
return 0;
}
segtype = SEG_STRIPED; /* Default */
if ((cn = find_config_node(sn, "type", '/'))) {
cv = cn->v;
if (!cv || !cv->v.str) {
log_error("Segment type must be a string.");
return 0;
}
segtype = get_segtype_from_string(cv->v.str);
}
if (segtype == SEG_STRIPED) {
if (!_read_int32(sn, "stripe_count", &area_count)) {
log_error("Couldn't read 'stripe_count' for "
"segment '%s'.", sn->key);
return 0;
}
}
if (segtype == SEG_MIRRORED) {
if (!_read_int32(sn, "mirror_count", &area_count)) {
log_error("Couldn't read 'mirror_count' for "
"segment '%s'.", sn->key);
return 0;
}
if (find_config_node(sn, "extents_moved", '/')) {
if (_read_uint32(sn, "extents_moved", &extents_moved))
seg_status |= PVMOVE;
else {
log_error("Couldn't read 'extents_moved' for "
"segment '%s'.", sn->key);
return 0;
}
}
}
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
(sizeof(seg->area[0]) * area_count)))) {
stack;
return 0;
}
seg->lv = lv;
seg->le = start_extent;
seg->len = extent_count;
seg->area_len = extent_count;
seg->type = segtype;
seg->status = seg_status;
seg->extents_moved = extents_moved;
switch (segtype) {
case SEG_SNAPSHOT:
lv->status |= SNAPSHOT;
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_error("Couldn't read chunk size for snapshot.");
return 0;
}
log_suppress(1);
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
log_suppress(0);
log_error("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
log_suppress(0);
log_error("Snapshot origin not specified.");
return 0;
}
log_suppress(0);
if (!(cow = find_lv(vg, cow_name))) {
log_error("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_error("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
stack;
return 0;
}
break;
case SEG_STRIPED:
if ((area_count != 1) &&
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
log_error("Couldn't read stripe_size for segment '%s'.",
sn->key);
return 0;
}
if (!(cn = find_config_node(sn, "stripes", '/'))) {
log_error("Couldn't find stripes array for segment "
"'%s'.", sn->key);
return 0;
}
seg->area_len /= area_count;
case SEG_MIRRORED:
seg->area_count = area_count;
if (!seg->area_count) {
log_error("Zero areas not allowed for segment '%s'",
sn->key);
return 0;
}
if ((seg->type == SEG_MIRRORED) &&
!(cn = find_config_node(sn, "mirrors", '/'))) {
log_error("Couldn't find mirrors array for segment "
"'%s'.", sn->key);
return 0;
}
for (cv = cn->v, s = 0; cv && s < seg->area_count;
s++, cv = cv->next) {
/* first we read the pv */
const char *bad = "Badly formed areas array for "
"segment '%s'.";
struct physical_volume *pv;
if (cv->type != CFG_STRING) {
log_error(bad, sn->key);
return 0;
}
if (!cv->next) {
log_error(bad, sn->key);
return 0;
}
if (cv->next->type != CFG_INT) {
log_error(bad, sn->key);
return 0;
}
/* 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;
vg->free_count -= seg->area_len;
} else if ((lv1 = find_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;
} else {
log_error("Couldn't find volume '%s' "
"for segment '%s'.",
cv->v.str ? cv->v.str : "NULL",
seg_name);
return 0;
}
cv = cv->next;
}
/*
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->area_count)) {
log_error("Incorrect number of areas in area array "
"for segment '%s'.", seg_name);
return 0;
}
}
/*
* Insert into correct part of segment list.
*/
_insert_segment(lv, seg);
return 1;
}
static int _read_segments(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *lvn,
struct hash_table *pv_hash)
{
struct config_node *sn;
int count = 0, seg_count;
for (sn = lvn; sn; sn = sn->sib) {
/*
* All sub-sections are assumed to be segments.
*/
if (!sn->v) {
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
stack;
return 0;
}
count++;
}
/* FIXME Remove this restriction */
if ((lv->status & SNAPSHOT) && count > 1) {
log_error("Only one segment permitted for snapshot");
return 0;
}
}
if (!_read_int32(lvn, "segment_count", &seg_count)) {
log_error("Couldn't read segment count for logical volume.");
return 0;
}
if (seg_count != count) {
log_error("segment_count and actual number of segments "
"disagree.");
return 0;
}
/*
* Check there are no gaps or overlaps in the lv.
*/
if (!lv_check_segments(lv)) {
stack;
return 0;
}
/*
* Merge segments in case someones been editing things by hand.
*/
if (!lv_merge_segments(lv)) {
stack;
return 0;
}
return 1;
}
static int _read_lvnames(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *lvn,
struct config_node *vgn, struct hash_table *pv_hash)
{
struct logical_volume *lv;
struct lv_list *lvl;
struct config_node *cn;
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
stack;
return 0;
}
lv = lvl->lv;
if (!(lv->name = pool_strdup(mem, lvn->key))) {
stack;
return 0;
}
if (!(lvn = lvn->child)) {
log_error("Empty logical volume section.");
return 0;
}
if (!(cn = find_config_node(lvn, "status", '/'))) {
log_error("Couldn't find status flags for logical volume.");
return 0;
}
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
log_error("Couldn't read status flags for logical volume.");
return 0;
}
lv->alloc = ALLOC_DEFAULT;
if ((cn = find_config_node(lvn, "allocation_policy", '/'))) {
struct config_value *cv = cn->v;
if (!cv || !cv->v.str) {
log_error("allocation_policy must be a string.");
return 0;
}
lv->alloc = get_alloc_from_string(cv->v.str);
}
/* read_ahead defaults to 0 */
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
lv->read_ahead = 0;
list_init(&lv->segments);
lv->vg = vg;
vg->lv_count++;
list_add(&vg->lvs, &lvl->list);
return 1;
}
static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *lvn,
struct config_node *vgn, struct hash_table *pv_hash)
{
struct logical_volume *lv;
struct lv_list *lvl;
if (!(lvl = find_lv_in_vg(vg, lvn->key))) {
log_error("Lost logical volume reference %s", lvn->key);
return 0;
}
lv = lvl->lv;
if (!(lvn = lvn->child)) {
log_error("Empty logical volume section.");
return 0;
}
/* FIXME: read full lvid */
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
log_error("Couldn't read uuid for logical volume %s.",
lv->name);
return 0;
}
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
stack;
return 0;
}
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 {
vg->lv_count--;
list_del(&lvl->list);
}
return 1;
}
static int _read_sections(struct format_instance *fid,
const char *section, section_fn fn,
struct pool *mem,
struct volume_group *vg, struct config_node *vgn,
struct hash_table *pv_hash, int optional)
{
struct config_node *n;
if (!(n = find_config_node(vgn, section, '/'))) {
if (!optional) {
log_error("Couldn't find section '%s'.", section);
return 0;
}
return 1;
}
for (n = n->child; n; n = n->sib) {
if (!fn(fid, mem, vg, n, vgn, pv_hash)) {
stack;
return 0;
}
}
return 1;
}
static struct volume_group *_read_vg(struct format_instance *fid,
struct config_tree *cf)
{
struct config_node *vgn, *cn;
struct volume_group *vg;
struct hash_table *pv_hash = NULL;
struct pool *mem = fid->fmt->cmd->mem;
/* skip any top-level values */
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
if (!vgn) {
log_error("Couldn't find volume group in file.");
return NULL;
}
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
return NULL;
}
vg->cmd = fid->fmt->cmd;
/* FIXME Determine format type from file contents */
/* eg Set to instance of fmt1 here if reading a format1 backup? */
vg->fid = fid;
if (!(vg->name = pool_strdup(mem, vgn->key))) {
stack;
goto bad;
}
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
stack;
goto bad;
}
vgn = vgn->child;
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
if (!cn->v->v.str) {
log_error("system_id must be a string");
goto bad;
}
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
}
if (!_read_id(&vg->id, vgn, "id")) {
log_error("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
}
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
log_error("Couldn't read 'seqno' for volume group %s.",
vg->name);
goto bad;
}
if (!(cn = find_config_node(vgn, "status", '/'))) {
log_error("Couldn't find status flags for volume group %s.",
vg->name);
goto bad;
}
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
log_error("Couldn't read status flags for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
log_error("Couldn't read extent size for volume group %s.",
vg->name);
goto bad;
}
/*
* 'extent_count' and 'free_count' get filled in
* implicitly when reading in the pv's and lv's.
*/
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
log_error("Couldn't read 'max_lv' for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
log_error("Couldn't read 'max_pv' for volume group %s.",
vg->name);
goto bad;
}
/*
* The pv hash memoises the pv section names -> pv
* structures.
*/
if (!(pv_hash = hash_create(32))) {
log_error("Couldn't create hash table.");
goto bad;
}
list_init(&vg->pvs);
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
vgn, pv_hash, 0)) {
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->lvs);
list_init(&vg->snapshots);
if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg,
vgn, pv_hash, 1)) {
log_error("Couldn't read all logical volume names for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "logical_volumes", _read_lvsegs, mem, vg,
vgn, pv_hash, 1)) {
log_error("Couldn't read all logical volumes for "
"volume group %s.", vg->name);
goto bad;
}
hash_destroy(pv_hash);
if (vg->status & PARTIAL_VG) {
vg->status &= ~LVM_WRITE;
vg->status |= LVM_READ;
}
/*
* Finished.
*/
return vg;
bad:
if (pv_hash)
hash_destroy(pv_hash);
pool_free(mem, vg);
return NULL;
}
static void _read_desc(struct pool *mem,
struct config_tree *cf, time_t *when, char **desc)
{
const char *d;
unsigned int u = 0u;
log_suppress(1);
d = find_config_str(cf->root, "description", '/', "");
log_suppress(0);
*desc = pool_strdup(mem, d);
get_config_uint32(cf->root, "creation_time", '/', &u);
*when = u;
}
static struct text_vg_version_ops _vsn1_ops = {
check_version:_check_version,
read_vg:_read_vg,
read_desc:_read_desc
};
struct text_vg_version_ops *text_vg_vsn1_init(void)
{
return &_vsn1_ops;
};

76
lib/format_text/layout.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_TEXT_LAYOUT_H
#define _LVM_TEXT_LAYOUT_H
#include "config.h"
#include "lvm-types.h"
#include "metadata.h"
#include "uuid.h"
/* On disk */
struct disk_locn {
uint64_t offset; /* Offset in bytes to start sector */
uint64_t size; /* Bytes */
} __attribute__ ((packed));
/* Data areas (holding PEs) */
struct data_area_list {
struct list list;
struct disk_locn disk_locn;
};
/* Fields with the suffix _xl should be xlate'd wherever they appear */
/* On disk */
struct pv_header {
uint8_t pv_uuid[ID_LEN];
uint64_t device_size_xl; /* Bytes */
/* NULL-terminated list of data areas followed by */
/* NULL-terminated list of metadata area headers */
struct disk_locn disk_areas_xl[0]; /* Two lists */
} __attribute__ ((packed));
/* On disk */
struct raw_locn {
uint64_t offset; /* Offset in bytes to start sector */
uint64_t size; /* Bytes */
uint32_t checksum;
uint32_t filler;
} __attribute__ ((packed));
/* On disk */
/* Structure size limited to one sector */
struct mda_header {
uint32_t checksum_xl; /* Checksum of rest of mda_header */
uint8_t magic[16]; /* To aid scans for metadata */
uint32_t version;
uint64_t start; /* Absolute start byte of mda_header */
uint64_t size; /* Size of metadata area */
struct raw_locn raw_locns[0]; /* NULL-terminated list */
} __attribute__ ((packed));
struct mda_lists {
struct list dirs;
struct list raws;
struct metadata_area_ops *file_ops;
struct metadata_area_ops *raw_ops;
};
struct mda_context {
struct device_area area;
struct raw_locn rlocn; /* Store inbetween write and commit */
};
/* FIXME Convert this at runtime */
#define FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
#define FMTT_VERSION 1
#define MDA_HEADER_SIZE 512
#define LVM2_LABEL "LVM2 001"
#endif

View File

@@ -1,67 +0,0 @@
# An example volume group
# YYYY-MM-DD HH:MM:SS
output_date = "2001-12-11 11:35:12"
sample_volume_group {
id = "ksjdlfksjldskjlsk"
status = ["ACTIVE"]
extent_size = 8192 # 4 Megabytes
max_lv = 99
max_pv = 255
physical_volumes {
pv1 {
id = "lksjdflksdlsk"
device = "/dev/hda1" # Hint only
status = ["ALLOCATABLE"]
pe_start = 8192
pe_count = 2048 # 8 Gigabytes
}
pv2 {
id = "lksjdflksdlsk"
device = "/dev/hda2" # Hint only
status = ["ALLOCATABLE"]
pe_start = 8192
pe_count = 1024 # 4 Gigabytes
}
}
logical_volumes {
music {
status = ["ACTIVE"]
read_ahead = 1024
segment_count = 2
segment1 {
start_extent = 0
extent_count = 1024 # 4 Gigabytes
stripes = 1
areas = [
"pv1", 0
]
}
segment2 {
start_extent = 1024
extent_count = 2048 # 8 Gigabytes
stripes = 2
stripe_size = 32 # 16 Kilobytes
areas = [
"pv1", 1024,
"pv2", 0
]
}
}
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "format-text.h"
#include "layout.h"
#include "label.h"
#include "xlate.h"
#include <sys/stat.h>
#include <fcntl.h>
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
{
struct label_header *lh = (struct label_header *) buf;
if (!strncmp(lh->type, LVM2_LABEL, sizeof(lh->type)))
return 1;
return 0;
}
static int _write(struct label *label, char *buf)
{
struct label_header *lh = (struct label_header *) 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;
/* FIXME Move to where label is created */
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
strncpy(lh->type, label->type, sizeof(label->type));
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
info = (struct lvmcache_info *) label->info;
pvhdr->device_size_xl = xlate64(info->device_size);
memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
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);
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
pvh_dlocn_xl++;
}
/* NULL-termination */
pvh_dlocn_xl->offset = xlate64(0);
pvh_dlocn_xl->size = xlate64(0);
pvh_dlocn_xl++;
/* List of metadata area header locations */
list_iterate(mdash, &info->mdas) {
mda = list_item(mdash, struct metadata_area);
mdac = (struct mda_context *) mda->metadata_locn;
if (mdac->area.dev != info->dev)
continue;
pvh_dlocn_xl->offset = xlate64(mdac->area.start);
pvh_dlocn_xl->size = xlate64(mdac->area.size);
pvh_dlocn_xl++;
}
/* NULL-termination */
pvh_dlocn_xl->offset = xlate64(0);
pvh_dlocn_xl->size = xlate64(0);
return 1;
}
int add_da(const struct format_type *fmt, struct pool *mem, struct list *das,
uint64_t start, uint64_t size)
{
struct data_area_list *dal;
if (!mem) {
if (!(dal = dbg_malloc(sizeof(*dal)))) {
log_error("struct data_area_list allocation failed");
return 0;
}
} else {
if (!(dal = pool_alloc(mem, sizeof(*dal)))) {
log_error("struct data_area_list allocation failed");
return 0;
}
}
dal->disk_locn.offset = start;
dal->disk_locn.size = size;
list_add(das, &dal->list);
return 1;
}
void del_das(struct list *das)
{
struct list *dah, *tmp;
struct data_area_list *da;
list_iterate_safe(dah, tmp, das) {
da = list_item(dah, struct data_area_list);
list_del(&da->list);
dbg_free(da);
}
}
int add_mda(const struct format_type *fmt, struct pool *mem, struct list *mdas,
struct device *dev, uint64_t start, uint64_t size)
{
/* FIXME List size restricted by pv_header SECTOR_SIZE */
struct metadata_area *mdal;
struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
struct mda_context *mdac;
if (!mem) {
if (!(mdal = dbg_malloc(sizeof(struct metadata_area)))) {
log_error("struct mda_list allocation failed");
return 0;
}
if (!(mdac = dbg_malloc(sizeof(struct mda_context)))) {
log_error("struct mda_context allocation failed");
dbg_free(mdal);
return 0;
}
} else {
if (!(mdal = pool_alloc(mem, sizeof(struct metadata_area)))) {
log_error("struct mda_list allocation failed");
return 0;
}
if (!(mdac = pool_alloc(mem, sizeof(struct mda_context)))) {
log_error("struct mda_context allocation failed");
return 0;
}
}
mdal->ops = mda_lists->raw_ops;
mdal->metadata_locn = mdac;
mdac->area.dev = dev;
mdac->area.start = start;
mdac->area.size = size;
memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
list_add(mdas, &mdal->list);
return 1;
}
void del_mdas(struct list *mdas)
{
struct list *mdah, *tmp;
struct metadata_area *mda;
list_iterate_safe(mdah, tmp, mdas) {
mda = list_item(mdah, struct metadata_area);
dbg_free(mda->metadata_locn);
list_del(&mda->list);
dbg_free(mda);
}
}
static int _initialise_label(struct labeller *l, struct label *label)
{
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
return 1;
}
static int _read(struct labeller *l, struct device *dev, char *buf,
struct label **label)
{
struct label_header *lh = (struct label_header *) buf;
struct pv_header *pvhdr;
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;
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
return 0;
*label = info->label;
info->device_size = xlate64(pvhdr->device_size_xl);
if (info->das.n)
del_das(&info->das);
list_init(&info->das);
if (info->mdas.n)
del_mdas(&info->mdas);
list_init(&info->mdas);
/* Data areas holding the PEs */
dlocn_xl = pvhdr->disk_areas_xl;
while ((offset = xlate64(dlocn_xl->offset))) {
add_da(info->fmt, NULL, &info->das, offset,
xlate64(dlocn_xl->size));
dlocn_xl++;
}
/* Metadata area headers */
dlocn_xl++;
while ((offset = xlate64(dlocn_xl->offset))) {
add_mda(info->fmt, NULL, &info->mdas, dev, offset,
xlate64(dlocn_xl->size));
dlocn_xl++;
}
list_iterate(mdah, &info->mdas) {
mda = list_item(mdah, struct metadata_area);
mdac = (struct mda_context *) mda->metadata_locn;
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
sizeof(vgnamebuf))) {
lvmcache_update_vgname(info, vgnamebuf);
}
}
info->status &= ~CACHE_INVALID;
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
if (info->mdas.n)
del_mdas(&info->mdas);
if (info->das.n)
del_das(&info->das);
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _text_ops = {
can_handle:_can_handle,
write:_write,
read:_read,
verify:_can_handle,
initialise_label:_initialise_label,
destroy_label:_destroy_label,
destroy:_destroy
};
struct labeller *text_labeller_create(const struct format_type *fmt)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_text_ops;
l->private = (const void *) fmt;
return l;
}

View File

@@ -4,10 +4,18 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "label.h" #include "label.h"
#include "list.h" #include "list.h"
#include "dbg_malloc.h" #include "crc.h"
#include "log.h" #include "xlate.h"
#include "lvmcache.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* FIXME Allow for larger labels? Restricted to single sector currently */
/* /*
* Internal labeller struct. * Internal labeller struct.
@@ -58,6 +66,7 @@ void label_exit(void)
for (c = _labellers.n; c != &_labellers; c = n) { for (c = _labellers.n; c != &_labellers; c = n) {
n = c->n; n = c->n;
li = list_item(c, struct labeller_i); li = list_item(c, struct labeller_i);
li->l->ops->destroy(li->l);
_free_li(li); _free_li(li);
} }
} }
@@ -89,64 +98,257 @@ struct labeller *label_get_handler(const char *name)
return NULL; return NULL;
} }
static struct labeller *_find_labeller(struct device *dev) static struct labeller *_find_labeller(struct device *dev, char *buf,
uint64_t *label_sector)
{ {
struct list *lih; struct list *lih;
struct labeller_i *li; struct labeller_i *li;
struct labeller *r = NULL;
struct label_header *lh;
uint64_t sector;
int found = 0;
char readbuf[LABEL_SCAN_SIZE];
list_iterate(lih, &_labellers) { if (!dev_open(dev)) {
li = list_item(lih, struct labeller_i); stack;
if (li->l->ops->can_handle(li->l, dev)) return NULL;
return li->l;
} }
log_debug("No label on device '%s'.", dev_name(dev)); if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
return NULL; log_debug("%s: Failed to read label area", dev_name(dev));
goto out;
}
/* Scan first few sectors for a valid label */
for (sector = 0; sector < LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
lh = (struct label_header *) (readbuf +
(sector << SECTOR_SHIFT));
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
if (found) {
log_error("Ignoring additional label on %s at "
"sector %" PRIu64, dev_name(dev),
sector);
}
if (xlate64(lh->sector_xl) != sector) {
log_info("%s: Label for sector %" PRIu64
" found at sector %" PRIu64
" - ignoring", dev_name(dev),
xlate64(lh->sector_xl), sector);
continue;
}
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
((void *) &lh->offset_xl - (void *) lh)) !=
xlate32(lh->crc_xl)) {
log_info("Label checksum incorrect on %s - "
"ignoring", dev_name(dev));
continue;
}
if (found)
continue;
}
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
log_very_verbose("%s: %s label detected",
dev_name(dev), li->name);
if (found) {
log_error("Ignoring additional label "
"on %s at sector %" PRIu64,
dev_name(dev), sector);
continue;
}
r = li->l;
memcpy(buf, lh, LABEL_SIZE);
if (label_sector)
*label_sector = sector;
found = 1;
break;
}
}
}
if (!found)
log_very_verbose("%s: No label detected", dev_name(dev));
out:
if (!dev_close(dev))
stack;
return r;
} }
/* FIXME Also wipe associated metadata area headers? */
int label_remove(struct device *dev) int label_remove(struct device *dev)
{ {
struct labeller *l; char buf[LABEL_SIZE];
char readbuf[LABEL_SCAN_SIZE];
int r = 1;
uint64_t sector;
int wipe;
struct list *lih;
struct labeller_i *li;
struct label_header *lh;
if (!(l = _find_labeller(dev))) { memset(buf, 0, LABEL_SIZE);
log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
if (!dev_open(dev)) {
stack; stack;
return 0; return 0;
} }
return l->ops->remove(l, dev); /*
} * We flush the device just in case someone is stupid
* enough to be trying to import an open pv into lvm.
*/
dev_flush(dev);
int label_read(struct device *dev, struct label **result) if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
{ log_debug("%s: Failed to read label area", dev_name(dev));
int r; goto out;
struct list *lih; }
struct labeller_i *li;
list_iterate(lih, &_labellers) { /* Scan first few sectors for anything looking like a label */
li = list_item(lih, struct labeller_i); for (sector = 0; sector < LABEL_SCAN_SECTORS;
if ((r = li->l->ops->read(li->l, dev, result))) { sector += LABEL_SIZE >> SECTOR_SHIFT) {
(*result)->labeller = li->l; lh = (struct label_header *) (readbuf +
return r; (sector << SECTOR_SHIFT));
wipe = 0;
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
if (xlate64(lh->sector_xl) == sector)
wipe = 1;
} else {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, (char *) lh,
sector)) {
wipe = 1;
break;
}
}
}
if (wipe) {
log_info("%s: Wiping label at sector %" PRIu64,
dev_name(dev), sector);
if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
buf)) {
log_error("Failed to remove label from %s at "
"sector %" PRIu64, dev_name(dev),
sector);
r = 0;
}
} }
} }
log_debug("No label on device '%s'.", dev_name(dev)); out:
return 0; if (!dev_close(dev))
stack;
return r;
}
/* FIXME Avoid repeated re-reading if cache lock held */
int label_read(struct device *dev, struct label **result)
{
char buf[LABEL_SIZE];
struct labeller *l;
uint64_t sector;
int r;
if (!(l = _find_labeller(dev, buf, &sector))) {
stack;
return 0;
}
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
(*result)->sector = sector;
return r;
}
/* Caller may need to use label_get_handler to create label struct! */
int label_write(struct device *dev, struct label *label)
{
char buf[LABEL_SIZE];
struct label_header *lh = (struct label_header *) buf;
int r = 1;
if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
log_error("Label sector %" PRIu64 " beyond range (%ld)",
label->sector, LABEL_SCAN_SECTORS);
return 0;
}
memset(buf, 0, LABEL_SIZE);
strncpy(lh->id, LABEL_ID, sizeof(lh->id));
lh->sector_xl = xlate64(label->sector);
lh->offset_xl = xlate32(sizeof(*lh));
if (!label->labeller->ops->write(label, buf))
return 0;
lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
((void *) &lh->offset_xl - (void *) lh)));
if (!dev_open(dev)) {
stack;
return 0;
}
log_info("%s: Writing label to sector %" PRIu64, dev_name(dev),
label->sector);
if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
log_debug("Failed to write label to %s", dev_name(dev));
r = 0;
}
if (!dev_close(dev))
stack;
return r;
} }
int label_verify(struct device *dev) int label_verify(struct device *dev)
{ {
struct labeller *l; struct labeller *l;
char buf[LABEL_SIZE];
uint64_t sector;
if (!(l = _find_labeller(dev))) { if (!(l = _find_labeller(dev, buf, &sector))) {
stack; stack;
return 0; return 0;
} }
return l->ops->verify(l, dev); return l->ops->verify(l, buf, sector);
} }
void label_destroy(struct label *lab) void label_destroy(struct label *label)
{ {
lab->labeller->ops->destroy_label(lab->labeller, lab); label->labeller->ops->destroy_label(label->labeller, label);
dbg_free(label);
}
struct label *label_create(struct labeller *labeller)
{
struct label *label;
if (!(label = dbg_malloc(sizeof(*label)))) {
log_error("label allocaction failed");
return NULL;
}
memset(label, 0, sizeof(*label));
label->labeller = labeller;
labeller->ops->initialise_label(labeller, label);
return label;
} }

View File

@@ -7,18 +7,30 @@
#ifndef _LVM_LABEL_H #ifndef _LVM_LABEL_H
#define _LVM_LABEL_H #define _LVM_LABEL_H
#include "lvmcache.h"
#include "uuid.h" #include "uuid.h"
#include "device.h" #include "device.h"
#define LABEL_ID "LABELONE"
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
#define LABEL_SCAN_SECTORS 4L
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
/* On disk - 32 bytes */
struct label_header {
uint8_t id[8]; /* LABELONE */
uint64_t sector_xl; /* Sector number of this label */
uint32_t crc_xl; /* From next field to end of sector */
uint32_t offset_xl; /* Offset from start of struct to contents */
uint8_t type[8]; /* LVM2 001 */
} __attribute__ ((packed));
/* In core */
struct label { struct label {
struct id id; char type[8];
uint64_t sector;
char volume_type[32];
uint32_t version[3];
void *extra_info;
struct labeller *labeller; struct labeller *labeller;
void *info;
}; };
struct labeller; struct labeller;
@@ -27,47 +39,45 @@ struct label_ops {
/* /*
* Is the device labelled with this format ? * Is the device labelled with this format ?
*/ */
int (*can_handle)(struct labeller *l, struct device *dev); int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
/* /*
* Write a label to a volume. * Write a label to a volume.
*/ */
int (*write)(struct labeller *l, int (*write) (struct label * label, char *buf);
struct device *dev, struct label *label);
/*
* Remove a label from a device.
*/
int (*remove)(struct labeller *l, struct device *dev);
/* /*
* Read a label from a volume. * Read a label from a volume.
*/ */
int (*read)(struct labeller *l, int (*read) (struct labeller * l, struct device * dev,
struct device *dev, struct label **label); char *buf, struct label ** label);
/* /*
* Additional consistency checks for the paranoid. * Additional consistency checks for the paranoid.
*/ */
int (*verify)(struct labeller *l, struct device *dev); int (*verify) (struct labeller * l, char *buf, uint64_t sector);
/*
* Populate label_type etc.
*/
int (*initialise_label) (struct labeller * l, struct label * label);
/* /*
* Destroy a previously read label. * Destroy a previously read label.
*/ */
void (*destroy_label)(struct labeller *l, struct label *label); void (*destroy_label) (struct labeller * l, struct label * label);
/* /*
* Destructor. * Destructor.
*/ */
void (*destroy)(struct labeller *l); void (*destroy) (struct labeller * l);
}; };
struct labeller { struct labeller {
struct label_ops *ops; struct label_ops *ops;
void *private; const void *private;
}; };
int label_init(void); int label_init(void);
void label_exit(void); void label_exit(void);
@@ -77,14 +87,9 @@ struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev); int label_remove(struct device *dev);
int label_read(struct device *dev, struct label **result); int label_read(struct device *dev, struct label **result);
int label_write(struct device *dev, struct label *label);
int label_verify(struct device *dev); int label_verify(struct device *dev);
void label_destroy(struct label *lab); struct label *label_create(struct labeller *labeller);
void label_destroy(struct label *label);
/*
* We'll support two label types: the 'pretend the
* LVM1 pv structure at the begining of the disk
* is a label' hack, and pjc's 1 sector labels at
* the front and back of the device.
*/
#endif #endif

View File

@@ -1,569 +0,0 @@
/*
* Copyright (C) 2001-2002 Sistina Software
*
* This file is released under the LGPL.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "device.h"
#include "dev-cache.h"
#include "log.h"
#include "pool.h"
#include "dbg_malloc.h"
#include "filter.h"
#include "label.h"
#include "lvm2_label.h"
#include "xlate.h"
/* Label Magic is "LnXl" - error: imagination failure */
#define LABEL_MAGIC 0x6c586e4c
/* Size of blocks that dev_get_size() returns the number of */
#define BLOCK_SIZE 512
/* This is just the "struct lvm2_label" with the data pointer removed */
struct label_ondisk {
uint32_t magic;
uint32_t crc;
uint64_t label1_loc;
uint64_t label2_loc;
uint16_t datalen;
uint16_t pad;
uint32_t version[3];
char disk_type[32];
};
struct filter_private {
void *mem;
char disk_type[32];
uint32_t version[3];
int version_match;
};
/* Calculate CRC32 of a buffer */
static uint32_t crc32(uint32_t initial, const unsigned char *databuf,
size_t datalen)
{
static const u_int crctab[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t idx, crc = initial;
for (idx = 0; idx < datalen; idx++) {
crc ^= *databuf++;
crc = (crc >> 4) ^ crctab[crc & 0xf];
crc = (crc >> 4) ^ crctab[crc & 0xf];
}
return crc;
}
/* Calculate crc */
static uint32_t calc_crc(struct label_ondisk *label, char *data)
{
uint32_t crcval = 0xffffffff;
crcval = crc32(crcval, (char *) &label->magic, sizeof(label->magic));
crcval =
crc32(crcval, (char *) &label->label1_loc,
sizeof(label->label1_loc));
crcval =
crc32(crcval, (char *) &label->label2_loc,
sizeof(label->label2_loc));
crcval =
crc32(crcval, (char *) &label->datalen, sizeof(label->datalen));
crcval =
crc32(crcval, (char *) &label->version, sizeof(label->version));
crcval =
crc32(crcval, (char *) label->disk_type, strlen(label->disk_type));
crcval = crc32(crcval, (char *) data, label->datalen);
return crcval;
}
/* Calculate the locations we should find the labels in */
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
long *first, long *second)
{
*first = sectsize;
*second = size * BLOCK_SIZE - sectsize;
}
/* Read a label off disk */
static int lvm2_label_read(struct labeller *l, struct device *dev,
struct label **label)
{
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status;
int iter;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDONLY))
return 0;
block = dbg_malloc(sectsize);
if (!block) {
stack;
return 0;
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* If the first label is bad then use the second */
for (iter = 0; iter <= 1; iter++) {
status = dev_read(dev, offset[iter], sectsize, block);
if (status) {
struct label *incore;
int i;
int found_nul;
/* If the MAGIC doesn't match there's no point in
carrying on */
if (xlate32(ondisk->magic) != LABEL_MAGIC)
continue;
/* Look for a NUL in the disk_type string so we don't
SEGV is something has gone horribly wrong */
found_nul = 0;
for (i = 0; i < sizeof(ondisk->disk_type); i++)
if (ondisk->disk_type[i] == '\0')
found_nul = 1;
if (!found_nul)
continue;
incore = dbg_malloc(sizeof(struct label));
if (incore == NULL) {
return 0;
}
/* Copy and convert endianness */
strncpy(incore->volume_type, ondisk->disk_type,
sizeof(incore->volume_type));
incore->version[0] = xlate32(ondisk->version[0]);
incore->version[1] = xlate32(ondisk->version[1]);
incore->version[2] = xlate32(ondisk->version[2]);
incore->extra_len = xlate16(ondisk->datalen);
incore->extra_info =
block + sizeof(struct label_ondisk);
/* Make sure datalen is a sensible size too */
if (incore->extra_len > sectsize)
continue;
/* Check Crc */
if (xlate32(ondisk->crc) !=
calc_crc(ondisk, incore->extra_info)) {
log_error
("Crc %d on device %s does not match. got %x, expected %x",
iter, dev_name(dev), xlate32(ondisk->crc),
calc_crc(ondisk, incore->extra_info));
continue;
}
/* Check label locations match our view of the device */
if (xlate64(ondisk->label1_loc) != offset[0])
log_error
("Label 1 location is wrong in label %d - check block size of the device\n",
iter);
if (xlate64(ondisk->label2_loc) != offset[1])
log_error
("Label 2 location is wrong in label %d - the size of the device must have changed\n",
iter);
/* Copy to user's data area */
*label = incore;
incore->extra_info = dbg_malloc(incore->extra_len);
if (!incore->extra_info) {
stack;
return 0;
}
memcpy(incore->extra_info,
block + sizeof(struct label_ondisk),
incore->extra_len);
dbg_free(block);
dev_close(dev);
return 1;
}
}
dbg_free(block);
dev_close(dev);
return 0;
}
/* Write a label to a device */
static int lvm2_label_write(struct labeller *l, struct device *dev,
struct label *label)
{
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status1, status2;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Can the metata fit in the remaining space ? */
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
return 0;
block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
if (!block) {
stack;
return 0;
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Make into ondisk format */
ondisk->magic = xlate32(LABEL_MAGIC);
ondisk->version[0] = xlate32(label->version[0]);
ondisk->version[1] = xlate32(label->version[1]);
ondisk->version[2] = xlate32(label->version[2]);
ondisk->label1_loc = xlate64(offset[0]);
ondisk->label2_loc = xlate64(offset[1]);
ondisk->datalen = xlate16(label->extra_len);
strncpy(ondisk->disk_type, label->volume_type,
sizeof(ondisk->disk_type));
memcpy(block + sizeof(struct label_ondisk), label->extra_info,
label->extra_len);
ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
/* Write metadata to disk */
if (!dev_open(dev, O_RDWR)) {
dbg_free(block);
return 0;
}
status1 =
dev_write(dev, offset[0],
sizeof(struct label_ondisk) + label->extra_len, block);
if (!status1)
log_error("Error writing label 1\n");
/* Write another at the end of the device */
status2 =
dev_write(dev, offset[1],
sizeof(struct label_ondisk) + label->extra_len, block);
if (!status2) {
char zerobuf[sizeof(struct label_ondisk)];
log_error("Error writing label 2\n");
/* Wipe the first label so it doesn't get confusing */
memset(zerobuf, 0, sizeof(struct label_ondisk));
if (!dev_write
(dev, offset[0], sizeof(struct label_ondisk),
zerobuf)) log_error("Error erasing label 1\n");
}
dbg_free(block);
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
}
/* Return 1 for Yes, 0 for No */
static int lvm2_is_labelled(struct labeller *l, struct device *dev)
{
struct label *label;
int status;
status = lvm2_label_read(l, dev, &label);
if (status)
label_free(label);
return status;
}
/* Check the device is labelled and has the right format_type */
static int _accept_format(struct dev_filter *f, struct device *dev)
{
struct label *l;
int status;
struct filter_private *fp = (struct filter_private *) f->private;
status = lvm2_label_read(NULL, dev, &l);
if (status) {
if (strcmp(l->volume_type, fp->disk_type) == 0) {
switch (fp->version_match) {
case VERSION_MATCH_EQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] == fp->version[1] &&
l->version[2] == fp->version[2])
return 1;
break;
case VERSION_MATCH_LESSTHAN:
if (l->version[0] == fp->version[0] &&
l->version[1] < fp->version[1])
return 1;
break;
case VERSION_MATCH_LESSEQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] <= fp->version[1])
return 1;
break;
case VERSION_MATCH_ANY:
return 1;
}
}
label_free(l);
}
return 0;
}
/* We just want to know if it's labelled or not */
static int _accept_label(struct dev_filter *f, struct device *dev)
{
return lvm2_is_labelled(NULL, dev);
}
static void _destroy(struct dev_filter *f)
{
struct filter_private *fp = (struct filter_private *) f->private;
}
/* A filter to find devices with a particular label type on them */
struct dev_filter *lvm2_label_format_filter_create(char *disk_type,
uint32_t version[3],
int match_type)
{
struct pool *mem;
struct filter_private *fp;
struct dev_filter *f;
/* Validate the match type */
if (match_type != VERSION_MATCH_EQUAL &&
match_type != VERSION_MATCH_LESSTHAN &&
match_type != VERSION_MATCH_LESSEQUAL &&
match_type != VERSION_MATCH_ANY)
return 0;
mem = pool_create(10 * 1024);
if (!mem) {
stack;
return NULL;
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
}
fp->mem = mem;
strcpy(fp->disk_type, disk_type);
fp->version[0] = version[0];
fp->version[1] = version[1];
fp->version[2] = version[2];
fp->version_match = match_type;
f->passes_filter = _accept_format;
f->destroy = _destroy;
f->private = fp;
return f;
bad:
pool_destroy(mem);
return NULL;
}
/* A filter to find devices with any label on them */
struct dev_filter *lvm2_label_filter_create()
{
struct pool *mem = pool_create(10 * 1024);
struct filter_private *fp;
struct dev_filter *f;
if (!mem) {
stack;
return NULL;
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
}
fp->mem = mem;
f->passes_filter = _accept_label;
f->destroy = _destroy;
f->private = fp;
return f;
bad:
pool_destroy(mem);
return NULL;
}
/* Return 1 if both labels are identical, 0 if not or there was an error */
static int lvm2_labels_match(struct labeller *l, struct device *dev)
{
uint64_t size;
uint32_t sectsize;
char *block1;
char *block2;
struct label_ondisk *ondisk1;
struct label_ondisk *ondisk2;
int status = 0;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Allocate some space for the blocks we are going to read in */
block1 = dbg_malloc(sectsize);
if (!block1) {
stack;
return 0;
}
block2 = dbg_malloc(sectsize);
if (!block2) {
stack;
dbg_free(block1);
return 0;
}
ondisk1 = (struct label_ondisk *) block1;
ondisk2 = (struct label_ondisk *) block2;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Fetch em */
if (!dev_open(dev, O_RDONLY))
goto finish;
if (!dev_read(dev, offset[0], sectsize, block1))
goto finish;
if (!dev_read(dev, offset[1], sectsize, block2))
goto finish;
dev_close(dev);
/* Is it labelled? */
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
goto finish;
/* Compare the whole structs */
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
goto finish;
/* OK, check the data area */
if (memcmp(block1 + sizeof(struct label_ondisk),
block2 + sizeof(struct label_ondisk),
xlate16(ondisk1->datalen)) != 0)
goto finish;
/* They match !! */
status = 1;
finish:
dbg_free(block2);
dbg_free(block1);
return status;
}
static int lvm2_label_remove(struct labeller *l, struct device *dev)
{
uint64_t size;
uint32_t sectsize;
char block[BLOCK_SIZE];
int status1, status2;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDWR)) {
dbg_free(block);
return 0;
}
get_label_locations(size, sectsize, &offset[0], &offset[1]);
memset(block, 0, BLOCK_SIZE);
/* Blank out the first label */
status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
if (!status1)
log_error("Error erasing label 1\n");
/* ...and the other at the end of the device */
status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
if (!status2)
log_error("Error erasing label 2\n");
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
}
static void lvm2_label_destroy(struct labeller *l)
{
}
static struct label_ops handler_ops = {
can_handle: lvm2_is_labelled,
write: lvm2_label_write,
remove: lvm2_label_remove,
read: lvm2_label_read,
verify: lvm2_labels_match,
destroy: lvm2_label_destroy,
};
static struct labeller this_labeller = {
private: NULL,
ops: &handler_ops,
};
/* Don't know how this gets called... */
void lvm2_label_init()
{
label_register_handler("LVM2", &this_labeller);
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
struct lvm2_label
{
uint32_t magic;
uint32_t crc;
uint64_t label1_loc;
uint64_t label2_loc;
uint16_t datalen;
char disk_type[32];
uint32_t version[3];
char *data;
};
#define VERSION_MATCH_EQUAL 1
#define VERSION_MATCH_LESSTHAN 2
#define VERSION_MATCH_LESSEQUAL 3
#define VERSION_MATCH_ANY 4
extern struct dev_filter *lvm2_label_filter_create();
extern struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);

View File

@@ -1,99 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_UUID_MAP_H
#define _LVM_UUID_MAP_H
#include "uuid-map.h"
#include "dev-cache.h"
#include "dbg_malloc.h"
#include "log.h"
#include "label.h"
#include "pool.h"
struct uuid_map {
struct dev_filter *filter;
};
struct uuid_map *uuid_map_create(struct dev_filter *devices)
{
struct uuid_map *um;
if (!(um = dbg_malloc(sizeof(*um)))) {
log_err("Couldn't allocate uuid_map object.");
return NULL;
}
um->filter = devices;
return um;
}
void uuid_map_destroy(struct uuid_map *um)
{
dbg_free(um);
}
/*
* Simple, non-caching implementation to start with.
*/
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
{
struct dev_iter *iter;
struct device *dev;
struct label *lab;
if (!(iter = dev_iter_create(um->filter))) {
stack;
return NULL;
}
while ((dev = dev_iter_get(iter))) {
if (!label_read(dev, &lab))
continue;
if (id_equal(id, &lab->id)) {
label_destroy(lab);
break;
}
label_destroy(lab);
}
dev_iter_destroy(iter);
return dev;
}
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
const char *name)
{
struct device *dev;
struct label *lab;
struct id *id;
if (!(dev = dev_cache_get(name, um->filter))) {
stack;
return NULL;
}
if (!label_read(dev, &lab)) {
stack;
return NULL;
}
if (!(id = pool_alloc(mem, sizeof(*id)))) {
stack;
label_destroy(lab);
return NULL;
}
memcpy(id, &lab->id, sizeof(*id));
label_destroy(lab);
return id;
}
#endif

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_UUID_MAP_H
#define _LVM_UUID_MAP_H
#include "uuid.h"
#include "dev-cache.h"
#include "pool.h"
/*
* Holds a mapping from uuid -> device.
*/
struct uuid_map;
struct uuid_map *uuid_map_create(struct dev_filter *devices);
void uuid_map_destroy(struct uuid_map *um);
/*
* Find the device with a particular uuid.
*/
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id);
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
const char *name);
#endif

View File

@@ -5,111 +5,70 @@
* *
*/ */
#include "log.h" #include "lib.h"
#include "locking.h"
#include "locking_types.h" #include "locking_types.h"
#include "activate.h"
#include "config.h"
#include "defaults.h" #include "defaults.h"
#include "lvm-file.h" #include "sharedlib.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <limits.h> static void *_locking_lib = NULL;
#include <unistd.h> static void (*_end_fn) (void) = NULL;
#include <sys/types.h> static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
#include <sys/stat.h> int flags) = NULL;
#include <sys/file.h> static int (*_init_fn) (int type, struct config_tree * cf) = NULL;
#include <fcntl.h>
#include <dlfcn.h>
#include <signal.h>
static void *locking_module = NULL; static int _lock_resource(struct cmd_context *cmd, const char *resource,
static void (*end_fn) (void) = NULL; int flags)
static int (*lock_fn) (struct cmd_context * cmd, const char *resource,
int flags) = NULL;
static int (*init_fn) (int type, struct config_file * cf) = NULL;
static int lock_resource(struct cmd_context *cmd, const char *resource,
int flags)
{ {
if (lock_fn) if (_lock_fn)
return lock_fn(cmd, resource, flags); return _lock_fn(cmd, resource, flags);
else else
return 0; return 0;
} }
static void fin_external_locking(void) static void _fin_external_locking(void)
{ {
if (end_fn) if (_end_fn)
end_fn(); _end_fn();
dlclose(locking_module); dlclose(_locking_lib);
locking_module = NULL; _locking_lib = NULL;
end_fn = NULL; _init_fn = NULL;
lock_fn = NULL; _end_fn = NULL;
_lock_fn = NULL;
} }
int init_external_locking(struct locking_type *locking, struct config_file *cf) int init_external_locking(struct locking_type *locking, struct config_tree *cf)
{ {
char _lock_lib[PATH_MAX]; const char *libname;
if (locking_module) { if (_locking_lib) {
log_error("External locking already initialised"); log_error("External locking already initialised");
return 1; return 1;
} }
locking->lock_resource = lock_resource;
locking->fin_locking = fin_external_locking;
/* Get locking module name from config file */ locking->lock_resource = _lock_resource;
strncpy(_lock_lib, find_config_str(cf->root, "global/locking_library", locking->fin_locking = _fin_external_locking;
'/', "lvm2_locking.so"),
sizeof(_lock_lib));
/* If there is a module_dir in the config file then libname = find_config_str(cf->root, "global/locking_library", '/',
look for the locking module in there first and then DEFAULT_LOCKING_LIB);
using the normal dlopen(3) mechanism of looking
down LD_LIBRARY_PATH and /lib, /usr/lib.
If course, if the library name starts with a slash then
just use the name... */
if (_lock_lib[0] != '/') {
struct stat st;
char _lock_lib1[PATH_MAX];
lvm_snprintf(_lock_lib1, sizeof(_lock_lib1), if (!(_locking_lib = load_shared_library(cf, libname, "locking"))) {
"%s/%s", stack;
find_config_str(cf->root, "global/module_dir",
'/', "RUBBISH"), _lock_lib);
/* Does it exist ? */
if (stat(_lock_lib1, &st) == 0) {
strcpy(_lock_lib, _lock_lib1);
}
}
log_very_verbose("Opening locking library %s", _lock_lib);
locking_module = dlopen(_lock_lib, RTLD_LAZY);
if (!locking_module) {
log_error("Unable to open external locking module %s",
_lock_lib);
return 0; return 0;
} }
/* Get the functions we need */ /* Get the functions we need */
init_fn = dlsym(locking_module, "init_locking"); if (!(_init_fn = dlsym(_locking_lib, "init_locking")) ||
lock_fn = dlsym(locking_module, "lock_resource"); !(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
end_fn = dlsym(locking_module, "end_locking"); !(_end_fn = dlsym(_locking_lib, "end_locking"))) {
log_error("Shared library %s does not contain locking "
/* Are they all there ? */ "functions", libname);
if (!end_fn || !init_fn || !lock_fn) { dlclose(_locking_lib);
log_error ("Shared library %s does not contain locking " _locking_lib = NULL;
"functions", _lock_lib);
dlclose(locking_module);
return 0; return 0;
} }
log_verbose("Opened external locking module %s", _lock_lib); log_verbose("Loaded external locking library %s", libname);
return init_fn(2, cf); return _init_fn(2, cf);
} }

View File

@@ -5,7 +5,7 @@
* *
*/ */
#include "log.h" #include "lib.h"
#include "locking.h" #include "locking.h"
#include "locking_types.h" #include "locking_types.h"
#include "activate.h" #include "activate.h"
@@ -13,11 +13,10 @@
#include "defaults.h" #include "defaults.h"
#include "lvm-file.h" #include "lvm-file.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "dbg_malloc.h" #include "lvmcache.h"
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/file.h> #include <sys/file.h>
#include <fcntl.h> #include <fcntl.h>
@@ -36,7 +35,7 @@ static sig_t _oldhandler;
static sigset_t _fullsigset, _intsigset; static sigset_t _fullsigset, _intsigset;
static int _handler_installed; static int _handler_installed;
static int _release_lock(const char *file) static int _release_lock(const char *file, int unlock)
{ {
struct lock_list *ll; struct lock_list *ll;
struct list *llh, *llt; struct list *llh, *llt;
@@ -48,10 +47,11 @@ static int _release_lock(const char *file)
if (!file || !strcmp(ll->res, file)) { if (!file || !strcmp(ll->res, file)) {
list_del(llh); list_del(llh);
log_very_verbose("Unlocking %s", ll->res); if (unlock) {
log_very_verbose("Unlocking %s", ll->res);
if (flock(ll->lf, LOCK_NB | LOCK_UN)) if (flock(ll->lf, LOCK_NB | LOCK_UN))
log_sys_error("flock", ll->res); log_sys_error("flock", ll->res);
}
if (!flock(ll->lf, LOCK_NB | LOCK_EX) && if (!flock(ll->lf, LOCK_NB | LOCK_EX) &&
!stat(ll->res, &buf1) && !stat(ll->res, &buf1) &&
@@ -74,9 +74,14 @@ static int _release_lock(const char *file)
return 0; return 0;
} }
void fin_file_locking(void) static void _fin_file_locking(void)
{ {
_release_lock(NULL); _release_lock(NULL, 1);
}
static void _reset_file_locking(void)
{
_release_lock(NULL, 0);
} }
static void _remove_ctrl_c_handler() static void _remove_ctrl_c_handler()
@@ -92,7 +97,7 @@ static void _remove_ctrl_c_handler()
_handler_installed = 0; _handler_installed = 0;
} }
void _trap_ctrl_c(int signal) static void _trap_ctrl_c(int sig)
{ {
_remove_ctrl_c_handler(); _remove_ctrl_c_handler();
log_error("CTRL-c detected: giving up waiting for lock"); log_error("CTRL-c detected: giving up waiting for lock");
@@ -117,16 +122,19 @@ static int _lock_file(const char *file, int flags)
struct lock_list *ll; struct lock_list *ll;
struct stat buf1, buf2; struct stat buf1, buf2;
char state;
switch (flags & LCK_TYPE_MASK) { switch (flags & LCK_TYPE_MASK) {
case LCK_READ: case LCK_READ:
operation = LOCK_SH; operation = LOCK_SH;
state = 'R';
break; break;
case LCK_WRITE: case LCK_WRITE:
operation = LOCK_EX; operation = LOCK_EX;
state = 'W';
break; break;
case LCK_UNLOCK: case LCK_UNLOCK:
return _release_lock(file); return _release_lock(file, 1);
default: default:
log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK); log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
return 0; return 0;
@@ -142,7 +150,8 @@ static int _lock_file(const char *file, int flags)
ll->lf = -1; ll->lf = -1;
log_very_verbose("Locking %s", ll->res); log_very_verbose("Locking %s %c%c", ll->res, state,
flags & LCK_NONBLOCK ? ' ' : 'B');
do { do {
if (ll->lf > -1) if (ll->lf > -1)
close(ll->lf); close(ll->lf);
@@ -181,7 +190,8 @@ static int _lock_file(const char *file, int flags)
return 0; return 0;
} }
int lock_resource(struct cmd_context *cmd, const char *resource, int flags) static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
int flags)
{ {
char lockfile[PATH_MAX]; char lockfile[PATH_MAX];
@@ -193,28 +203,39 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
else else
lvm_snprintf(lockfile, sizeof(lockfile), lvm_snprintf(lockfile, sizeof(lockfile),
"%s/V_%s", _lock_dir, resource); "%s/V_%s", _lock_dir, resource);
if (!_lock_file(lockfile, flags)) if (!_lock_file(lockfile, flags))
return 0; return 0;
break;
case LCK_LV:
/* Skip if driver isn't loaded */
/* FIXME Use /proc/misc instead? */
if (!driver_version(NULL, 0))
return 1;
switch (flags & LCK_TYPE_MASK) { switch (flags & LCK_TYPE_MASK) {
case LCK_UNLOCK: case LCK_UNLOCK:
lvmcache_unlock_vgname(resource);
break;
default:
lvmcache_lock_vgname(resource,
(flags & LCK_TYPE_MASK) ==
LCK_READ);
}
break;
case LCK_LV:
switch (flags & LCK_TYPE_MASK) {
case LCK_UNLOCK:
log_debug("Unlocking LV %s", resource);
if (!lv_resume_if_active(cmd, resource)) if (!lv_resume_if_active(cmd, resource))
return 0; return 0;
break; break;
case LCK_READ: case LCK_READ:
log_debug("Locking LV %s (R)", resource);
if (!lv_activate(cmd, resource)) if (!lv_activate(cmd, resource))
return 0; return 0;
break; break;
case LCK_WRITE: case LCK_WRITE:
log_debug("Locking LV %s (W)", resource);
if (!lv_suspend_if_active(cmd, resource)) if (!lv_suspend_if_active(cmd, resource))
return 0; return 0;
break; break;
case LCK_EXCL: case LCK_EXCL:
log_debug("Locking LV %s (EX)", resource);
if (!lv_deactivate(cmd, resource)) if (!lv_deactivate(cmd, resource))
return 0; return 0;
break; break;
@@ -231,10 +252,11 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
return 1; return 1;
} }
int init_file_locking(struct locking_type *locking, struct config_file *cf) int init_file_locking(struct locking_type *locking, struct config_tree *cf)
{ {
locking->lock_resource = lock_resource; locking->lock_resource = _file_lock_resource;
locking->fin_locking = fin_file_locking; locking->reset_locking = _reset_file_locking;
locking->fin_locking = _fin_file_locking;
/* Get lockfile directory from config file */ /* Get lockfile directory from config file */
strncpy(_lock_dir, find_config_str(cf->root, "global/locking_dir", strncpy(_lock_dir, find_config_str(cf->root, "global/locking_dir",
@@ -244,6 +266,10 @@ int init_file_locking(struct locking_type *locking, struct config_file *cf)
if (!create_dir(_lock_dir)) if (!create_dir(_lock_dir))
return 0; return 0;
/* Trap a read-only file system */
if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS))
return 0;
list_init(&_lock_list); list_init(&_lock_list);
if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) { if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {

View File

@@ -5,13 +5,17 @@
* *
*/ */
#include "log.h" #include "lib.h"
#include "locking.h" #include "locking.h"
#include "locking_types.h" #include "locking_types.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "activate.h" #include "activate.h"
#include "toolcontext.h"
#include <signal.h> #include <signal.h>
#include <sys/stat.h>
#include <limits.h>
#include <unistd.h>
static struct locking_type _locking; static struct locking_type _locking;
static sigset_t _oldset; static sigset_t _oldset;
@@ -19,7 +23,7 @@ static sigset_t _oldset;
static int _lock_count = 0; /* Number of locks held */ static int _lock_count = 0; /* Number of locks held */
static int _signals_blocked = 0; static int _signals_blocked = 0;
static void _block_signals(void) static void _block_signals(int flags)
{ {
sigset_t set; sigset_t set;
@@ -57,6 +61,18 @@ static void _unblock_signals(void)
return; return;
} }
void reset_locking(void)
{
int was_locked = _lock_count;
_lock_count = 0;
_locking.reset_locking();
if (was_locked)
_unblock_signals();
}
static inline void _update_lock_count(int flags) static inline void _update_lock_count(int flags)
{ {
if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK) if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
@@ -68,31 +84,42 @@ static inline void _update_lock_count(int flags)
/* /*
* Select a locking type * Select a locking type
*/ */
int init_locking(int type, struct config_file *cf) int init_locking(int type, struct config_tree *cf)
{ {
switch (type) { switch (type) {
case 0: case 0:
init_no_locking(&_locking, cf); init_no_locking(&_locking, cf);
log_print("WARNING: Locking disabled. Be careful! " log_print("WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata."); "This could corrupt your metadata.");
break; return 1;
case 1: case 1:
if (!init_file_locking(&_locking, cf)) if (!init_file_locking(&_locking, cf))
return 0; break;
log_very_verbose("File-based locking enabled."); log_very_verbose("File-based locking enabled.");
break; return 1;
#ifdef HAVE_LIBDL
case 2: case 2:
if (!init_external_locking(&_locking, cf)) if (!init_external_locking(&_locking, cf))
return 0; break;
log_very_verbose("External locking enabled."); log_very_verbose("External locking enabled.");
break; return 1;
#endif
default: default:
log_error("Unknown locking type requested."); log_error("Unknown locking type requested.");
return 0; return 0;
} }
if (!ignorelockingfailure())
return 0;
/* FIXME Ensure only read ops are permitted */
log_verbose("Locking disabled - only read operations permitted.");
init_no_locking(&_locking, cf);
return 1; return 1;
} }
@@ -101,13 +128,43 @@ void fin_locking(void)
_locking.fin_locking(); _locking.fin_locking();
} }
/*
* Does the LVM1 driver know of this VG name?
*/
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
{
struct stat info;
char path[PATH_MAX];
/* We'll allow operations on orphans */
if (!*vgname)
return 1;
if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
vgname) < 0) {
log_error("LVM1 proc VG pathname too long for %s", vgname);
return 0;
}
if (stat(path, &info) == 0) {
log_error("%s exists: Is the original LVM driver using "
"this volume group?", path);
return 0;
} else if (errno != ENOENT && errno != ENOTDIR) {
log_sys_error("stat", path);
return 0;
}
return 1;
}
/* /*
* VG locking is by VG name. * VG locking is by VG name.
* FIXME This should become VG uuid. * FIXME This should become VG uuid.
*/ */
int _lock_vol(struct cmd_context *cmd, const char *resource, int flags) static int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
{ {
_block_signals(); _block_signals(flags);
if (!(_locking.lock_resource(cmd, resource, flags))) { if (!(_locking.lock_resource(cmd, resource, flags))) {
_unblock_signals(); _unblock_signals();
@@ -125,9 +182,14 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
char resource[258]; char resource[258];
switch (flags & LCK_SCOPE_MASK) { switch (flags & LCK_SCOPE_MASK) {
case LCK_VG: /* Lock VG to change on-disk metadata. */ case LCK_VG:
case LCK_LV: /* Suspends LV if it's active. */ /* Lock VG to change on-disk metadata. */
strncpy(resource, (char *) vol, sizeof(resource)); /* If LVM1 driver knows about the VG, it can't be accessed. */
if (!check_lvm1_vg_inactive(cmd, vol))
return 0;
case LCK_LV:
/* Suspend LV if it's active. */
strncpy(resource, vol, sizeof(resource));
break; break;
default: default:
log_error("Unrecognised lock scope: %d", log_error("Unrecognised lock scope: %d",

View File

@@ -9,8 +9,9 @@
#include "uuid.h" #include "uuid.h"
#include "config.h" #include "config.h"
int init_locking(int type, struct config_file *cf); int init_locking(int type, struct config_tree *cf);
void fin_locking(void); void fin_locking(void);
void reset_locking(void);
/* /*
* LCK_VG: * LCK_VG:
@@ -24,18 +25,23 @@ void fin_locking(void);
*/ */
int lock_vol(struct cmd_context *cmd, const char *vol, int flags); int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
/*
* Does the LVM1 driver have this VG active?
*/
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
/* /*
* Lock type - these numbers are the same as VMS and the IBM DLM * Lock type - these numbers are the same as VMS and the IBM DLM
*/ */
#define LCK_TYPE_MASK 0x000000FF #define LCK_TYPE_MASK 0x000000FF
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */ #define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */ #define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */ /* LCK$_CWMODE */
/* LCK$_PRMODE */ /* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */ #define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */ #define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000010 /* This is ours */ #define LCK_UNLOCK 0x00000010 /* This is ours */
/* /*
* Lock scope * Lock scope
@@ -64,4 +70,3 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK) #define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK) #define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)

View File

@@ -8,25 +8,24 @@
#include "metadata.h" #include "metadata.h"
#include "config.h" #include "config.h"
typedef int (*lock_resource_fn)(struct cmd_context *cmd, const char *resource, typedef int (*lock_resource_fn) (struct cmd_context * cmd, const char *resource,
int flags); int flags);
typedef void (*fin_lock_fn)(void);
typedef void (*fin_lock_fn) (void);
typedef void (*reset_lock_fn) (void);
struct locking_type { struct locking_type {
lock_resource_fn lock_resource; lock_resource_fn lock_resource;
reset_lock_fn reset_locking;
fin_lock_fn fin_locking; fin_lock_fn fin_locking;
}; };
/* /*
* Locking types * Locking types
*/ */
int init_no_locking(struct locking_type *locking, struct config_file *cf); int init_no_locking(struct locking_type *locking, struct config_tree *cf);
int init_file_locking(struct locking_type *locking, struct config_file *cf); int init_file_locking(struct locking_type *locking, struct config_tree *cf);
int init_external_locking(struct locking_type *locking, struct config_file *cf);
int init_external_locking(struct locking_type *locking, struct config_tree *cf);

View File

@@ -5,11 +5,12 @@
* *
*/ */
#include "log.h" #include "lib.h"
#include "locking.h" #include "locking.h"
#include "locking_types.h" #include "locking_types.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "activate.h" #include "activate.h"
#include "lvmcache.h"
#include <signal.h> #include <signal.h>
@@ -22,11 +23,25 @@ static void _no_fin_locking(void)
return; return;
} }
static void _no_reset_locking(void)
{
return;
}
static int _no_lock_resource(struct cmd_context *cmd, const char *resource, static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
int flags) int flags)
{ {
switch (flags & LCK_SCOPE_MASK) { switch (flags & LCK_SCOPE_MASK) {
case LCK_VG: case LCK_VG:
switch (flags & LCK_TYPE_MASK) {
case LCK_UNLOCK:
lvmcache_unlock_vgname(resource);
break;
default:
lvmcache_lock_vgname(resource,
(flags & LCK_TYPE_MASK) ==
LCK_READ);
}
break; break;
case LCK_LV: case LCK_LV:
switch (flags & LCK_TYPE_MASK) { switch (flags & LCK_TYPE_MASK) {
@@ -51,9 +66,10 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
return 1; return 1;
} }
int init_no_locking(struct locking_type *locking, struct config_file *cf) int init_no_locking(struct locking_type *locking, struct config_tree *cf)
{ {
locking->lock_resource = _no_lock_resource; locking->lock_resource = _no_lock_resource;
locking->reset_locking = _no_reset_locking;
locking->fin_locking = _no_fin_locking; locking->fin_locking = _no_fin_locking;
return 1; return 1;

View File

@@ -4,26 +4,63 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "log.h" #include "lib.h"
#include "device.h"
#include "memlock.h"
#include "lvm-string.h"
#include <stdarg.h> #include <stdarg.h>
#include <syslog.h> #include <syslog.h>
static FILE *_log = 0; static FILE *_log_file;
static struct device _log_dev;
static struct str_list _log_dev_alias;
static int _verbose_level = 0; static int _verbose_level = 0;
static int _test = 0; static int _test = 0;
static int _partial = 0; static int _partial = 0;
static int _pvmove = 0;
static int _debug_level = 0; static int _debug_level = 0;
static int _syslog = 0; static int _syslog = 0;
static int _log_to_file = 0;
static int _log_direct = 0;
static int _log_while_suspended = 0;
static int _indent = 1; static int _indent = 1;
static int _log_cmd_name = 0; static int _log_cmd_name = 0;
static int _log_suppress = 0; static int _log_suppress = 0;
static int _ignorelockingfailure = 0;
static char _cmd_name[30] = ""; static char _cmd_name[30] = "";
static char _msg_prefix[30] = " "; static char _msg_prefix[30] = " ";
static int _already_logging = 0;
void init_log(FILE * fp) void init_log_file(const char *log_file, int append)
{ {
_log = fp; const char *open_mode = append ? "a" : "w";
if (!(_log_file = fopen(log_file, open_mode))) {
log_sys_error("fopen", log_file);
return;
}
_log_to_file = 1;
}
void init_log_direct(const char *log_file, int append)
{
const char *filename;
int open_flags = append ? 0 : O_TRUNC;
filename = dbg_strdup(log_file);
dev_create_file(filename, &_log_dev, &_log_dev_alias);
if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0))
return;
_log_direct = 1;
}
void init_log_while_suspended(int log_while_suspended)
{
_log_while_suspended = log_while_suspended;
} }
void init_syslog(int facility) void init_syslog(int facility)
@@ -37,9 +74,23 @@ void log_suppress(int suppress)
_log_suppress = suppress; _log_suppress = suppress;
} }
void fin_log() void release_log_memory(void)
{ {
_log = 0; dbg_free((char *) _log_dev_alias.str);
_log_dev_alias.str = "activate_log file";
}
void fin_log(void)
{
if (_log_direct) {
dev_close(&_log_dev);
_log_direct = 0;
}
if (_log_to_file) {
fclose(_log_file);
_log_to_file = 0;
}
} }
void fin_syslog() void fin_syslog()
@@ -56,9 +107,9 @@ void init_verbose(int level)
void init_test(int level) void init_test(int level)
{ {
if (!_test && level)
log_print("Test mode: Metadata will NOT be updated.");
_test = level; _test = level;
if (_test)
log_print("Test mode. Metadata will NOT be updated.");
} }
void init_partial(int level) void init_partial(int level)
@@ -66,6 +117,16 @@ void init_partial(int level)
_partial = level; _partial = level;
} }
void init_pvmove(int level)
{
_pvmove = level;
}
void init_ignorelockingfailure(int level)
{
_ignorelockingfailure = level;
}
void init_cmd_name(int status) void init_cmd_name(int status)
{ {
_log_cmd_name = status; _log_cmd_name = status;
@@ -100,6 +161,16 @@ int partial_mode()
return _partial; return _partial;
} }
int pvmove_mode()
{
return _pvmove;
}
int ignorelockingfailure()
{
return _ignorelockingfailure;
}
void init_debug(int level) void init_debug(int level)
{ {
_debug_level = level; _debug_level = level;
@@ -113,6 +184,8 @@ int debug_level()
void print_log(int level, const char *file, int line, const char *format, ...) void print_log(int level, const char *file, int line, const char *format, ...)
{ {
va_list ap; va_list ap;
char buf[1024];
int bufused, n;
if (!_log_suppress) { if (!_log_suppress) {
va_start(ap, format); va_start(ap, format);
@@ -171,20 +244,48 @@ void print_log(int level, const char *file, int line, const char *format, ...)
if (level > _debug_level) if (level > _debug_level)
return; return;
if (_log) { if (_log_to_file && (_log_while_suspended || !memlock())) {
fprintf(_log, "%s:%d %s%s", file, line, _cmd_name, _msg_prefix); fprintf(_log_file, "%s:%d %s%s", file, line, _cmd_name,
_msg_prefix);
va_start(ap, format); va_start(ap, format);
vfprintf(_log, format, ap); vfprintf(_log_file, format, ap);
va_end(ap); va_end(ap);
fprintf(_log, "\n"); fprintf(_log_file, "\n");
fflush(_log); fflush(_log_file);
} }
if (_syslog) { if (_syslog && (_log_while_suspended || !memlock())) {
va_start(ap, format); va_start(ap, format);
vsyslog(level, format, ap); vsyslog(level, format, ap);
va_end(ap); va_end(ap);
} }
/* FIXME This code is unfinished - pre-extend & condense. */
if (!_already_logging && _log_direct && memlock()) {
_already_logging = 1;
memset(&buf, ' ', sizeof(buf));
bufused = 0;
if ((n = lvm_snprintf(buf, sizeof(buf) - bufused - 1,
"%s:%d %s%s", file, line, _cmd_name,
_msg_prefix)) == -1)
goto done;
bufused += n;
va_start(ap, format);
n = vsnprintf(buf + bufused - 1, sizeof(buf) - bufused - 1,
format, ap);
va_end(ap);
bufused += n;
done:
buf[bufused - 1] = '\n';
buf[bufused] = '\n';
buf[sizeof(buf) - 1] = '\n';
/* FIXME real size bufused */
dev_append(&_log_dev, sizeof(buf), buf);
_already_logging = 0;
}
} }

View File

@@ -28,8 +28,8 @@
* *
*/ */
#include <stdio.h> #include <stdio.h> /* FILE */
#include <string.h> #include <string.h> /* strerror() */
#include <errno.h> #include <errno.h>
#define _LOG_DEBUG 7 #define _LOG_DEBUG 7
@@ -39,8 +39,11 @@
#define _LOG_ERR 3 #define _LOG_ERR 3
#define _LOG_FATAL 2 #define _LOG_FATAL 2
void init_log(FILE *fp); void init_log_file(const char *log_file, int append);
void init_log_direct(const char *log_file, int append);
void init_log_while_suspended(int log_while_suspended);
void fin_log(void); void fin_log(void);
void release_log_memory(void);
void init_syslog(int facility); void init_syslog(int facility);
void fin_syslog(void); void fin_syslog(void);
@@ -48,22 +51,29 @@ void fin_syslog(void);
void init_verbose(int level); void init_verbose(int level);
void init_test(int level); void init_test(int level);
void init_partial(int level); void init_partial(int level);
void init_pvmove(int level);
void init_debug(int level); void init_debug(int level);
void init_cmd_name(int status); void init_cmd_name(int status);
void init_msg_prefix(const char *prefix); void init_msg_prefix(const char *prefix);
void init_indent(int indent); void init_indent(int indent);
void init_ignorelockingfailure(int level);
void set_cmd_name(const char *cmd_name); void set_cmd_name(const char *cmd_name);
int test_mode(void); int test_mode(void);
int partial_mode(void); int partial_mode(void);
int pvmove_mode(void);
int debug_level(void); int debug_level(void);
int ignorelockingfailure(void);
/* Suppress messages to stdout/stderr */ /* Suppress messages to stdout/stderr */
void log_suppress(int suppress); void log_suppress(int suppress);
/* Suppress messages to syslog */
void syslog_suppress(int suppress);
void print_log(int level, const char *file, int line, const char *format, ...) void print_log(int level, const char *file, int line, const char *format, ...)
__attribute__ (( format (printf, 4, 5) )); __attribute__ ((format(printf, 4, 5)));
#define plog(l, x...) print_log(l, __FILE__, __LINE__ , ## x) #define plog(l, x...) print_log(l, __FILE__, __LINE__ , ## x)
@@ -76,21 +86,17 @@ void print_log(int level, const char *file, int line, const char *format, ...)
#define stack log_debug("<backtrace>") /* Backtrace on error */ #define stack log_debug("<backtrace>") /* Backtrace on error */
#define log_error(fmt, args...) log_err(fmt , ## args) #define log_error(args...) log_err(args)
#define log_print(fmt, args...) log_warn(fmt , ## args) #define log_print(args...) log_warn(args)
#define log_verbose(fmt, args...) log_notice(fmt , ## args) #define log_verbose(args...) log_notice(args)
#define log_very_verbose(fmt, args...) log_info(fmt , ## args) #define log_very_verbose(args...) log_info(args)
/* Two System call equivalents */ /* Two System call equivalents */
#define log_sys_error(x, y) \ #define log_sys_error(x, y) \
log_err("%s: %s failed: %s", y, x, strerror(errno)) log_err("%s: %s failed: %s", y, x, strerror(errno))
#define log_sys_very_verbose(x, y) \ #define log_sys_very_verbose(x, y) \
log_info("%s: %s failed: %s", y, x, strerror(errno)) log_info("%s: %s failed: %s", y, x, strerror(errno))
#define log_sys_debug(x, y) \
log_debug("%s: %s failed: %s", y, x, strerror(errno))
#endif #endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@@ -4,48 +4,54 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "lib.h"
#include "metadata.h" #include "metadata.h"
#include "locking.h"
#include "pv_map.h" #include "pv_map.h"
#include "log.h"
#include "dbg_malloc.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "toolcontext.h" #include "toolcontext.h"
#include <assert.h>
/* /*
* These functions adjust the pe counts in pv's * These functions adjust the pe counts in pv's
* after we've added or removed segments. * after we've added or removed segments.
*/ */
static void _get_extents(struct stripe_segment *seg) static void _get_extents(struct lv_segment *seg)
{ {
int s, count; unsigned int s, count;
struct physical_volume *pv; struct physical_volume *pv;
for (s = 0; s < seg->stripes; s++) { for (s = 0; s < seg->area_count; s++) {
pv = seg->area[s].pv; if (seg->area[s].type != AREA_PV)
count = seg->len / seg->stripes; continue;
pv = seg->area[s].u.pv.pv;
count = seg->area_len;
pv->pe_alloc_count += count; pv->pe_alloc_count += count;
} }
} }
static void _put_extents(struct stripe_segment *seg) static void _put_extents(struct lv_segment *seg)
{ {
int s, count; unsigned int s, count;
struct physical_volume *pv; struct physical_volume *pv;
for (s = 0; s < seg->stripes; s++) { for (s = 0; s < seg->area_count; s++) {
pv = seg->area[s].pv; if (seg->area[s].type != AREA_PV)
count = seg->len / seg->stripes; continue;
assert(pv->pe_alloc_count >= count); pv = seg->area[s].u.pv.pv;
pv->pe_alloc_count -= count;
if (pv) {
count = seg->area_len;
assert(pv->pe_alloc_count >= count);
pv->pe_alloc_count -= count;
}
} }
} }
static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes) static struct lv_segment *_alloc_segment(struct pool *mem, uint32_t stripes)
{ {
struct stripe_segment *seg; struct lv_segment *seg;
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0])); uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) { if (!(seg = pool_zalloc(mem, len))) {
@@ -58,16 +64,16 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
uint32_t stripe_size, uint32_t stripe_size,
struct pv_area **areas, uint32_t * index) struct pv_area **areas, uint32_t *ix)
{ {
uint32_t count = lv->le_count - *index; uint32_t count = lv->le_count - *ix;
uint32_t per_area = count / stripes; uint32_t area_len = count / stripes;
uint32_t smallest = areas[stripes - 1]->count; uint32_t smallest = areas[stripes - 1]->count;
uint32_t s; uint32_t s;
struct stripe_segment *seg; struct lv_segment *seg;
if (smallest < per_area) if (smallest < area_len)
per_area = smallest; area_len = smallest;
if (!(seg = _alloc_segment(lv->vg->cmd->mem, stripes))) { if (!(seg = _alloc_segment(lv->vg->cmd->mem, stripes))) {
log_err("Couldn't allocate new stripe segment."); log_err("Couldn't allocate new stripe segment.");
@@ -75,27 +81,30 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
} }
seg->lv = lv; seg->lv = lv;
seg->le = *index; seg->type = SEG_STRIPED;
seg->len = per_area * stripes; seg->le = *ix;
seg->stripes = stripes; seg->len = area_len * stripes;
seg->area_len = area_len;
seg->area_count = stripes;
seg->stripe_size = stripe_size; seg->stripe_size = stripe_size;
for (s = 0; s < stripes; s++) { for (s = 0; s < stripes; s++) {
struct pv_area *pva = areas[s]; struct pv_area *pva = areas[s];
seg->area[s].pv = pva->map->pv; seg->area[s].type = AREA_PV;
seg->area[s].pe = pva->start; seg->area[s].u.pv.pv = pva->map->pvl->pv;
consume_pv_area(pva, per_area); seg->area[s].u.pv.pe = pva->start;
consume_pv_area(pva, area_len);
} }
list_add(&lv->segments, &seg->list); list_add(&lv->segments, &seg->list);
*index += seg->len; *ix += seg->len;
return 1; return 1;
} }
static int _comp_area(const void *l, const void *r) static int _comp_area(const void *l, const void *r)
{ {
struct pv_area *lhs = *((struct pv_area **) l); const struct pv_area *lhs = *((const struct pv_area **) l);
struct pv_area *rhs = *((struct pv_area **) r); const struct pv_area *rhs = *((const struct pv_area **) r);
if (lhs->count < rhs->count) if (lhs->count < rhs->count)
return 1; return 1;
@@ -113,7 +122,7 @@ static int _alloc_striped(struct logical_volume *lv,
int r = 0; int r = 0;
struct list *pvmh; struct list *pvmh;
struct pv_area **areas; struct pv_area **areas;
int pv_count = 0, index; unsigned int pv_count = 0, ix;
struct pv_map *pvm; struct pv_map *pvm;
size_t len; size_t len;
@@ -129,18 +138,17 @@ static int _alloc_striped(struct logical_volume *lv,
while (allocated != lv->le_count) { while (allocated != lv->le_count) {
index = 0; ix = 0;
list_iterate(pvmh, pvms) { list_iterate(pvmh, pvms) {
pvm = list_item(pvmh, struct pv_map); pvm = list_item(pvmh, struct pv_map);
if (list_empty(&pvm->areas)) if (list_empty(&pvm->areas))
continue; continue;
areas[index++] = list_item(pvm->areas.n, areas[ix++] = list_item(pvm->areas.n, struct pv_area);
struct pv_area);
} }
if (index < stripes) { if (ix < stripes) {
log_error("Insufficient allocatable extents suitable " log_error("Insufficient allocatable extents suitable "
"for striping for logical volume " "for striping for logical volume "
"%s: %u required", lv->name, lv->le_count); "%s: %u required", lv->name, lv->le_count);
@@ -148,7 +156,7 @@ static int _alloc_striped(struct logical_volume *lv,
} }
/* sort the areas so we allocate from the biggest */ /* sort the areas so we allocate from the biggest */
qsort(areas, index, sizeof(*areas), _comp_area); qsort(areas, ix, sizeof(*areas), _comp_area);
if (!_alloc_stripe_area(lv, stripes, stripe_size, areas, if (!_alloc_stripe_area(lv, stripes, stripe_size, areas,
&allocated)) { &allocated)) {
@@ -169,14 +177,14 @@ static int _alloc_striped(struct logical_volume *lv,
* the complete area then the area is split, otherwise the area * the complete area then the area is split, otherwise the area
* is unlinked from the pv_map. * is unlinked from the pv_map.
*/ */
static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index, static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
struct pv_map *map, struct pv_area *pva) struct pv_map *map, struct pv_area *pva)
{ {
uint32_t count, remaining; uint32_t count, remaining;
struct stripe_segment *seg; struct lv_segment *seg;
count = pva->count; count = pva->count;
remaining = lv->le_count - *index; remaining = lv->le_count - *ix;
if (count > remaining) if (count > remaining)
count = remaining; count = remaining;
@@ -186,17 +194,61 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
} }
seg->lv = lv; seg->lv = lv;
seg->le = *index; seg->type = SEG_STRIPED;
seg->le = *ix;
seg->len = count; seg->len = count;
seg->area_len = count;
seg->stripe_size = 0; seg->stripe_size = 0;
seg->stripes = 1; seg->area_count = 1;
seg->area[0].pv = map->pv; seg->area[0].type = AREA_PV;
seg->area[0].pe = pva->start; seg->area[0].u.pv.pv = map->pvl->pv;
seg->area[0].u.pv.pe = pva->start;
list_add(&lv->segments, &seg->list); list_add(&lv->segments, &seg->list);
consume_pv_area(pva, count); consume_pv_area(pva, count);
*index += count; *ix += count;
return 1;
}
static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
struct pv_map *map, struct pv_area *pva,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
uint32_t count, remaining;
struct lv_segment *seg;
count = pva->count;
remaining = lv->le_count - *ix;
if (count > remaining)
count = remaining;
if (!(seg = _alloc_segment(lv->vg->cmd->mem, 2))) {
log_err("Couldn't allocate new mirrored segment.");
return 0;
}
seg->lv = lv;
seg->type = SEG_MIRRORED;
seg->status = 0u;
seg->le = *ix;
seg->len = count;
seg->area_len = count;
seg->stripe_size = 0;
seg->area_count = 2;
seg->extents_moved = 0u;
/* FIXME Remove AREA_PV restriction here? */
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = mirrored_pv;
seg->area[0].u.pv.pe = mirrored_pe;
seg->area[1].type = AREA_PV;
seg->area[1].u.pv.pv = map->pvl->pv;
seg->area[1].u.pv.pe = pva->start;
list_add(&lv->segments, &seg->list);
consume_pv_area(pva, count);
*ix += count;
return 1; return 1;
} }
@@ -224,14 +276,15 @@ static int _alloc_contiguous(struct logical_volume *lv,
/* first item in the list is the biggest */ /* first item in the list is the biggest */
pva = list_item(pvm->areas.n, struct pv_area); pva = list_item(pvm->areas.n, struct pv_area);
if (pva->count < lv->le_count)
continue;
if (!_alloc_linear_area(lv, &allocated, pvm, pva)) { if (!_alloc_linear_area(lv, &allocated, pvm, pva)) {
stack; stack;
return 0; return 0;
} }
if (allocated == lv->le_count) break;
break;
} }
if (allocated != lv->le_count) { if (allocated != lv->le_count) {
@@ -244,12 +297,56 @@ static int _alloc_contiguous(struct logical_volume *lv,
return 1; return 1;
} }
/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
static int _alloc_mirrored(struct logical_volume *lv,
struct list *pvms, uint32_t allocated,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
struct list *tmp1;
struct pv_map *pvm;
struct pv_area *pva;
uint32_t max_found = 0;
/* Try each PV in turn */
list_iterate(tmp1, pvms) {
pvm = list_item(tmp1, struct pv_map);
if (list_empty(&pvm->areas))
continue;
/* first item in the list is the biggest */
pva = list_item(pvm->areas.n, struct pv_area);
if (pva->count < lv->le_count - allocated) {
max_found = pva->count;
continue;
}
if (!_alloc_mirrored_area(lv, &allocated, pvm, pva,
mirrored_pv, mirrored_pe)) {
stack;
return 0;
}
break;
}
if (allocated != lv->le_count) {
log_error("Insufficient contiguous allocatable extents (%u) "
"for logical volume %s: %u required",
allocated + max_found, lv->name, lv->le_count);
return 0;
}
return 1;
}
/* /*
* Areas just get allocated in order until the lv * Areas just get allocated in order until the lv
* is full. * is full.
*/ */
static int _alloc_simple(struct logical_volume *lv, static int _alloc_next_free(struct logical_volume *lv,
struct list *pvms, uint32_t allocated) struct list *pvms, uint32_t allocated)
{ {
struct list *tmp1, *tmp2; struct list *tmp1, *tmp2;
struct pv_map *pvm; struct pv_map *pvm;
@@ -281,12 +378,15 @@ static int _alloc_simple(struct logical_volume *lv,
* Chooses a correct allocation policy. * Chooses a correct allocation policy.
*/ */
static int _allocate(struct volume_group *vg, struct logical_volume *lv, static int _allocate(struct volume_group *vg, struct logical_volume *lv,
struct list *acceptable_pvs, uint32_t allocated, struct list *allocatable_pvs, uint32_t allocated,
uint32_t stripes, uint32_t stripe_size) uint32_t stripes, uint32_t stripe_size,
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
uint32_t status)
{ {
int r = 0; int r = 0;
struct pool *scratch; struct pool *scratch;
struct list *pvms, *old_tail = lv->segments.p, *segh; struct list *pvms, *old_tail = lv->segments.p, *segh;
struct lv_segment *seg;
if (!(scratch = pool_create(1024))) { if (!(scratch = pool_create(1024))) {
stack; stack;
@@ -296,17 +396,20 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
/* /*
* Build the sets of available areas on the pv's. * Build the sets of available areas on the pv's.
*/ */
if (!(pvms = create_pv_maps(scratch, vg, acceptable_pvs))) if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs)))
goto out; goto out;
if (stripes > 1) if (stripes > 1)
r = _alloc_striped(lv, pvms, allocated, stripes, stripe_size); r = _alloc_striped(lv, pvms, allocated, stripes, stripe_size);
else if (lv->status & ALLOC_CONTIGUOUS) else if (mirrored_pv)
r = _alloc_mirrored(lv, pvms, allocated, mirrored_pv,
mirrored_pe);
else if (lv->alloc == ALLOC_CONTIGUOUS)
r = _alloc_contiguous(lv, pvms, allocated); r = _alloc_contiguous(lv, pvms, allocated);
else if (lv->status & ALLOC_SIMPLE) else if (lv->alloc == ALLOC_NEXT_FREE || lv->alloc == ALLOC_DEFAULT)
r = _alloc_simple(lv, pvms, allocated); r = _alloc_next_free(lv, pvms, allocated);
else { else {
log_error("Unknown allocation policy: " log_error("Unknown allocation policy: "
@@ -321,8 +424,11 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
* Iterate through the new segments, updating pe * Iterate through the new segments, updating pe
* counts in pv's. * counts in pv's.
*/ */
for (segh = lv->segments.p; segh != old_tail; segh = segh->p) for (segh = lv->segments.p; segh != old_tail; segh = segh->p) {
_get_extents(list_item(segh, struct stripe_segment)); seg = list_item(segh, struct lv_segment);
_get_extents(seg);
seg->status = status;
}
} else { } else {
/* /*
* Put the segment list back how we found it. * Put the segment list back how we found it.
@@ -336,7 +442,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
return r; return r;
} }
static char *_generate_lv_name(struct volume_group *vg, static char *_generate_lv_name(struct volume_group *vg, const char *format,
char *buffer, size_t len) char *buffer, size_t len)
{ {
struct list *lvh; struct list *lvh;
@@ -346,33 +452,98 @@ static char *_generate_lv_name(struct volume_group *vg,
list_iterate(lvh, &vg->lvs) { list_iterate(lvh, &vg->lvs) {
lv = (list_item(lvh, struct lv_list)->lv); lv = (list_item(lvh, struct lv_list)->lv);
if (sscanf(lv->name, "lvol%d", &i) != 1) if (sscanf(lv->name, format, &i) != 1)
continue; continue;
if (i > high) if (i > high)
high = i; high = i;
} }
if (lvm_snprintf(buffer, len, "lvol%d", high + 1) < 0) if (lvm_snprintf(buffer, len, format, high + 1) < 0)
return NULL; return NULL;
return buffer; return buffer;
} }
struct logical_volume *lv_create(struct format_instance *fi, struct logical_volume *lv_create_empty(struct format_instance *fi,
const char *name, const char *name,
uint32_t status, const char *name_format,
uint32_t stripes, uint32_t status,
uint32_t stripe_size, alloc_policy_t alloc,
uint32_t extents, struct volume_group *vg)
struct volume_group *vg,
struct list *acceptable_pvs)
{ {
struct cmd_context *cmd = vg->cmd; struct cmd_context *cmd = vg->cmd;
struct lv_list *ll = NULL; struct lv_list *ll = NULL;
struct logical_volume *lv; struct logical_volume *lv;
char dname[32]; char dname[32];
if (vg->max_lv == vg->lv_count) {
log_error("Maximum number of logical volumes (%u) reached "
"in volume group %s", vg->max_lv, vg->name);
return NULL;
}
if (!name && !(name = _generate_lv_name(vg, name_format, dname,
sizeof(dname)))) {
log_error("Failed to generate unique name for the new "
"logical volume");
return NULL;
}
log_verbose("Creating logical volume %s", name);
if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
!(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) {
log_error("lv_list allocation failed");
if (ll)
pool_free(cmd->mem, ll);
return NULL;
}
lv = ll->lv;
lv->vg = vg;
if (!(lv->name = pool_strdup(cmd->mem, name))) {
log_error("lv name strdup failed");
if (ll)
pool_free(cmd->mem, ll);
return NULL;
}
lv->status = status;
lv->alloc = alloc;
lv->read_ahead = 0;
lv->major = -1;
lv->minor = -1;
lv->size = UINT64_C(0);
lv->le_count = 0;
list_init(&lv->segments);
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
if (ll)
pool_free(cmd->mem, ll);
return NULL;
}
vg->lv_count++;
list_add(&vg->lvs, &ll->list);
return lv;
}
struct logical_volume *lv_create(struct format_instance *fi,
const char *name,
uint32_t status,
alloc_policy_t alloc,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents,
struct volume_group *vg,
struct list *allocatable_pvs)
{
struct logical_volume *lv;
if (!extents) { if (!extents) {
log_error("Unable to create logical volume %s with no extents", log_error("Unable to create logical volume %s with no extents",
name); name);
@@ -385,81 +556,45 @@ struct logical_volume *lv_create(struct format_instance *fi,
return NULL; return NULL;
} }
if (vg->max_lv == vg->lv_count) { if (stripes > list_size(allocatable_pvs)) {
log_error("Maximum number of logical volumes (%u) reached "
"in volume group %s", vg->max_lv, vg->name);
return NULL;
}
if (stripes > list_size(acceptable_pvs)) {
log_error("Number of stripes (%u) must not exceed " log_error("Number of stripes (%u) must not exceed "
"number of physical volumes (%d)", stripes, "number of physical volumes (%d)", stripes,
list_size(acceptable_pvs)); list_size(allocatable_pvs));
return NULL; return NULL;
} }
if (!name && !(name = _generate_lv_name(vg, dname, sizeof(dname)))) { if (!(lv = lv_create_empty(fi, name, "lvol%d", status, alloc, vg))) {
log_error("Failed to generate unique name for the new "
"logical volume");
return NULL;
}
log_verbose("Creating logical volume %s", name);
if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
!(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) {
stack; stack;
return NULL; return NULL;
} }
lv = ll->lv;
lv->vg = vg;
if (!(lv->name = pool_strdup(cmd->mem, name))) {
stack;
goto bad;
}
lv->status = status;
lv->read_ahead = 0;
lv->minor = -1;
lv->size = (uint64_t) extents *vg->extent_size; lv->size = (uint64_t) extents *vg->extent_size;
lv->le_count = extents; lv->le_count = extents;
list_init(&lv->segments);
if (!_allocate(vg, lv, acceptable_pvs, 0u, stripes, stripe_size)) { if (!_allocate(vg, lv, allocatable_pvs, 0u, stripes, stripe_size,
NULL, 0u, 0u)) {
stack; stack;
goto bad; return NULL;
} }
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack; stack;
goto bad; return NULL;
} }
vg->lv_count++;
list_add(&vg->lvs, &ll->list);
return lv; return lv;
bad:
if (ll)
pool_free(cmd->mem, ll);
return NULL;
} }
int lv_reduce(struct format_instance *fi, int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents) struct logical_volume *lv, uint32_t extents)
{ {
struct list *segh; struct list *segh;
struct stripe_segment *seg; struct lv_segment *seg;
uint32_t count = extents; uint32_t count = extents;
for (segh = lv->segments.p; for (segh = lv->segments.p;
(segh != &lv->segments) && count; segh = segh->p) { (segh != &lv->segments) && count; segh = segh->p) {
seg = list_item(segh, struct stripe_segment); seg = list_item(segh, struct lv_segment);
if (seg->len <= count) { if (seg->len <= count) {
/* remove this segment completely */ /* remove this segment completely */
@@ -490,7 +625,7 @@ int lv_reduce(struct format_instance *fi,
int lv_extend(struct format_instance *fi, int lv_extend(struct format_instance *fi,
struct logical_volume *lv, struct logical_volume *lv,
uint32_t stripes, uint32_t stripe_size, uint32_t stripes, uint32_t stripe_size,
uint32_t extents, struct list *acceptable_pvs) uint32_t extents, struct list *allocatable_pvs)
{ {
uint32_t old_le_count = lv->le_count; uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size; uint64_t old_size = lv->size;
@@ -498,10 +633,11 @@ int lv_extend(struct format_instance *fi,
lv->le_count += extents; lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size; lv->size += (uint64_t) extents *lv->vg->extent_size;
if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count, if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count,
stripes, stripe_size)) { stripes, stripe_size, NULL, 0u, 0u)) {
lv->le_count = old_le_count; lv->le_count = old_le_count;
lv->size = old_size; lv->size = old_size;
stack;
return 0; return 0;
} }
@@ -519,6 +655,35 @@ int lv_extend(struct format_instance *fi,
return 1; return 1;
} }
int lv_extend_mirror(struct format_instance *fid,
struct logical_volume *lv,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe,
uint32_t extents, struct list *allocatable_pvs,
uint32_t status)
{
uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size;
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count,
1, extents, mirrored_pv, mirrored_pe, status)) {
lv->le_count = old_le_count;
lv->size = old_size;
stack;
return 0;
}
if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
stack;
return 0;
}
return 1;
}
int lv_remove(struct volume_group *vg, struct logical_volume *lv) int lv_remove(struct volume_group *vg, struct logical_volume *lv)
{ {
struct list *segh; struct list *segh;
@@ -532,7 +697,7 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
/* iterate through the lv's segments freeing off the pe's */ /* iterate through the lv's segments freeing off the pe's */
list_iterate(segh, &lv->segments) list_iterate(segh, &lv->segments)
_put_extents(list_item(segh, struct stripe_segment)); _put_extents(list_item(segh, struct lv_segment));
vg->lv_count--; vg->lv_count--;
vg->free_count += lv->le_count; vg->free_count += lv->le_count;
@@ -541,3 +706,36 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
return 1; return 1;
} }
/* Unlock list of LVs */
int unlock_lvs(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
unlock_lv(cmd, lv->lvid.s);
}
return 1;
}
/* Lock a list of LVs */
int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags)
{
struct list *lvh;
struct logical_volume *lv;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!lock_vol(cmd, lv->lvid.s, flags)) {
log_error("Failed to lock %s", lv->name);
/* FIXME Only unlock the locked ones */
unlock_lvs(cmd, lvs);
return 0;
}
}
return 1;
}

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "log.h" #include "lib.h"
#include "metadata.h" #include "metadata.h"
/* /*
@@ -12,26 +12,34 @@
* successfully merged. If the do merge, 'first' * successfully merged. If the do merge, 'first'
* will be adjusted to contain both areas. * will be adjusted to contain both areas.
*/ */
static int _merge(struct stripe_segment *first, struct stripe_segment *second) static int _merge(struct lv_segment *first, struct lv_segment *second)
{ {
int s; unsigned int s;
uint32_t width; uint32_t width;
if (!first || if (!first ||
(first->stripes != second->stripes) || (first->type != SEG_STRIPED) ||
(first->type != second->type) ||
(first->area_count != second->area_count) ||
(first->stripe_size != second->stripe_size)) (first->stripe_size != second->stripe_size))
return 0; return 0;
for (s = 0; s < first->stripes; s++) { for (s = 0; s < first->area_count; s++) {
width = first->len / first->stripes; width = first->area_len;
if ((first->area[s].pv != second->area[s].pv) || /* FIXME Relax this to first type != second type ? */
(first->area[s].pe + width != second->area[s].pe)) if (first->area[s].type != AREA_PV ||
second->area[s].type != AREA_PV)
return 0;
if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
(first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
return 0; return 0;
} }
/* we should merge */ /* we should merge */
first->len += second->len; first->len += second->len;
first->area_len += second->area_len;
return 1; return 1;
} }
@@ -39,10 +47,10 @@ static int _merge(struct stripe_segment *first, struct stripe_segment *second)
int lv_merge_segments(struct logical_volume *lv) int lv_merge_segments(struct logical_volume *lv)
{ {
struct list *segh; struct list *segh;
struct stripe_segment *current, *prev = NULL; struct lv_segment *current, *prev = NULL;
list_iterate(segh, &lv->segments) { list_iterate(segh, &lv->segments) {
current = list_item(segh, struct stripe_segment); current = list_item(segh, struct lv_segment);
if (_merge(prev, current)) if (_merge(prev, current))
list_del(&current->list); list_del(&current->list);

View File

@@ -1,38 +1,37 @@
/* /*
* Copyright (C) 2001 Sistina Software (UK) Limited. * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
* *
* This file is released under the LGPL. * This file is released under the LGPL.
*/ */
#include "log.h" #include "lib.h"
#include "pool.h" #include "pool.h"
#include "device.h" #include "device.h"
#include "dev-cache.h"
#include "metadata.h" #include "metadata.h"
#include "toolcontext.h" #include "toolcontext.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "uuid.h" #include "lvmcache.h"
#include "vgcache.h" #include "memlock.h"
#include <string.h> static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
const char *pv_name)
int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
const char *pv_name)
{ {
struct pv_list *pvl; struct pv_list *pvl;
struct physical_volume *pv; struct physical_volume *pv;
struct pool *mem = fi->fmt->cmd->mem; struct pool *mem = fid->fmt->cmd->mem;
struct list mdas;
log_verbose("Adding physical volume '%s' to volume group '%s'", log_verbose("Adding physical volume '%s' to volume group '%s'",
pv_name, vg->name); pv_name, vg->name);
if (!(pvl = pool_alloc(mem, sizeof(*pvl)))) { if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
log_error("pv_list allocation for '%s' failed", pv_name); log_error("pv_list allocation for '%s' failed", pv_name);
return 0; return 0;
} }
if (!(pv = pv_read(fi->fmt->cmd, pv_name))) { list_init(&mdas);
log_error("Failed to read existing physical volume '%s'", if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL))) {
log_error("%s not identified as an existing physical volume",
pv_name); pv_name);
return 0; return 0;
} }
@@ -43,6 +42,12 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
return 0; return 0;
} }
if (pv->fmt != fid->fmt) {
log_error("Physical volume %s is of different format type (%s)",
pv_name, pv->fmt->name);
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) { if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
log_error("vg->name allocation failed for '%s'", pv_name); log_error("vg->name allocation failed for '%s'", pv_name);
return 0; return 0;
@@ -58,13 +63,15 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
/* /*
* The next two fields should be corrected * The next two fields should be corrected
* by fi->pv_setup. * by fid->pv_setup.
*/ */
pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size; pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
pv->pe_alloc_count = 0; pv->pe_alloc_count = 0;
if (!fi->fmt->ops->pv_setup(fi, pv, vg)) { if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
vg->extent_size, 0, UINT64_C(0),
&fid->metadata_areas, pv, vg)) {
log_error("Format-specific setup of physical volume '%s' " log_error("Format-specific setup of physical volume '%s' "
"failed.", pv_name); "failed.", pv_name);
return 0; return 0;
@@ -93,25 +100,51 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
return 1; return 1;
} }
int vg_extend(struct format_instance *fi, int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
const char *new_name)
{
struct pool *mem = cmd->mem;
struct physical_volume *pv;
struct list *pvh;
if (!(vg->name = pool_strdup(mem, new_name))) {
log_error("vg->name allocation failed for '%s'", new_name);
return 0;
}
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
if (!(pv->vg_name = pool_strdup(mem, new_name))) {
log_error("pv->vg_name allocation failed for '%s'",
dev_name(pv->dev));
return 0;
}
}
return 1;
}
int vg_extend(struct format_instance *fid,
struct volume_group *vg, int pv_count, char **pv_names) struct volume_group *vg, int pv_count, char **pv_names)
{ {
int i; int i;
/* attach each pv */ /* attach each pv */
for (i = 0; i < pv_count; i++) for (i = 0; i < pv_count; i++)
if (!_add_pv_to_vg(fi, vg, pv_names[i])) { if (!_add_pv_to_vg(fid, vg, pv_names[i])) {
log_error("Unable to add physical volume '%s' to " log_error("Unable to add physical volume '%s' to "
"volume group '%s'.", pv_names[i], vg->name); "volume group '%s'.", pv_names[i], vg->name);
return 0; return 0;
} }
/* FIXME Decide whether to initialise and add new mdahs to format instance */
return 1; return 1;
} }
const char *strip_dir(const char *vg_name, const char *dev_dir) const char *strip_dir(const char *vg_name, const char *dev_dir)
{ {
int len = strlen(dev_dir); size_t len = strlen(dev_dir);
if (!strncmp(vg_name, dev_dir, len)) if (!strncmp(vg_name, dev_dir, len))
vg_name += len; vg_name += len;
@@ -119,11 +152,13 @@ const char *strip_dir(const char *vg_name, const char *dev_dir)
} }
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
uint32_t extent_size, int max_pv, int max_lv, uint32_t extent_size, uint32_t max_pv,
int pv_count, char **pv_names) uint32_t max_lv, int pv_count, char **pv_names)
{ {
struct volume_group *vg; struct volume_group *vg;
struct pool *mem = cmd->mem; struct pool *mem = cmd->mem;
int consistent = 0;
int old_partial;
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) { if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack; stack;
@@ -131,12 +166,13 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
} }
/* is this vg name already in use ? */ /* is this vg name already in use ? */
old_partial = partial_mode();
init_partial(1); init_partial(1);
if (vg_read(cmd, vg_name)) { if (vg_read(cmd, vg_name, &consistent)) {
log_err("A volume group called '%s' already exists.", vg_name); log_err("A volume group called '%s' already exists.", vg_name);
goto bad; goto bad;
} }
init_partial(0); init_partial(old_partial);
if (!id_create(&vg->id)) { if (!id_create(&vg->id)) {
log_err("Couldn't create uuid for volume group '%s'.", vg_name); log_err("Couldn't create uuid for volume group '%s'.", vg_name);
@@ -198,11 +234,17 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
return NULL; return NULL;
} }
struct physical_volume *pv_create(struct format_instance *fid, /* Sizes in sectors */
const char *name, struct physical_volume *pv_create(const struct format_type *fmt,
struct id *id, uint64_t size) struct device *dev,
struct id *id, uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas)
{ {
struct pool *mem = fid->fmt->cmd->mem; struct pool *mem = fmt->cmd->mem;
struct physical_volume *pv = pool_alloc(mem, sizeof(*pv)); struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
if (!pv) { if (!pv) {
@@ -215,36 +257,32 @@ struct physical_volume *pv_create(struct format_instance *fid,
else else
memcpy(&pv->id, id, sizeof(*id)); memcpy(&pv->id, id, sizeof(*id));
if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) { pv->dev = dev;
log_error("%s: Couldn't find device.", name);
goto bad;
}
if (!(pv->vg_name = pool_alloc(mem, NAME_LEN))) { if (!(pv->vg_name = pool_zalloc(mem, NAME_LEN))) {
stack; stack;
goto bad; goto bad;
} }
*pv->vg_name = 0;
pv->status = ALLOCATABLE_PV; pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) { if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", name); log_error("%s: Couldn't get size.", dev_name(pv->dev));
goto bad; goto bad;
} }
if (size) { if (size) {
if (size > pv->size) if (size > pv->size)
log_print("WARNING: %s: Overriding real size. " log_print("WARNING: %s: Overriding real size. "
"You could lose data.", name); "You could lose data.", dev_name(pv->dev));
log_verbose("%s: Pretending size is %" PRIu64 " sectors.", log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
name, size); dev_name(pv->dev), size);
pv->size = size; pv->size = size;
} }
if (pv->size < PV_MIN_SIZE) { if (pv->size < PV_MIN_SIZE) {
log_error("%s: Size must exceed minimum of %lu sectors.", log_error("%s: Size must exceed minimum of %ld sectors.",
name, PV_MIN_SIZE); dev_name(pv->dev), PV_MIN_SIZE);
goto bad; goto bad;
} }
@@ -252,11 +290,14 @@ struct physical_volume *pv_create(struct format_instance *fid,
pv->pe_start = 0; pv->pe_start = 0;
pv->pe_count = 0; pv->pe_count = 0;
pv->pe_alloc_count = 0; pv->pe_alloc_count = 0;
pv->fid = fid; pv->fmt = fmt;
if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) { if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
existing_extent_size,
pvmetadatacopies, pvmetadatasize, mdas,
pv, NULL)) {
log_error("%s: Format-specific setup of physical volume " log_error("%s: Format-specific setup of physical volume "
"failed.", name); "failed.", dev_name(pv->dev));
goto bad; goto bad;
} }
return pv; return pv;
@@ -278,7 +319,33 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
} }
return NULL; return NULL;
}
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
{
struct list *pvh;
list_iterate(pvh, &vg->pvs) {
if (pv == list_item(pvh, struct pv_list)->pv)
return 1;
}
return 0;
}
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id)
{
struct list *pvh;
struct pv_list *pvl;
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, id))
return pvl->pv;
}
return NULL;
} }
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name) struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
@@ -302,7 +369,8 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
return NULL; return NULL;
} }
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg, union lvid *lvid) struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
const union lvid *lvid)
{ {
struct list *lvh; struct list *lvh;
struct lv_list *lvl; struct lv_list *lvl;
@@ -336,19 +404,32 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
return NULL; return NULL;
} }
/* Find segment at a given logical extent in an LV */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
{
struct list *segh;
struct lv_segment *seg;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (le >= seg->le && le < seg->le + seg->len)
return seg;
}
return NULL;
}
int vg_remove(struct volume_group *vg) int vg_remove(struct volume_group *vg)
{ {
struct list *mdah; struct list *mdah;
void *mdl; struct metadata_area *mda;
if (!vg->fid->fmt->ops->vg_remove)
return 1;
/* FIXME Improve recovery situation? */ /* FIXME Improve recovery situation? */
/* Remove each copy of the metadata */ /* Remove each copy of the metadata */
list_iterate(mdah, &vg->fid->metadata_areas) { list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn; mda = list_item(mdah, struct metadata_area);
if (!vg->fid->fmt->ops->vg_remove(vg->fid, vg, mdl)) { if (mda->ops->vg_remove &&
!mda->ops->vg_remove(vg->fid, vg, mda)) {
stack; stack;
return 0; return 0;
} }
@@ -357,10 +438,14 @@ int vg_remove(struct volume_group *vg)
return 1; return 1;
} }
/*
* After vg_write() returns success,
* caller MUST call either vg_commit() or vg_revert()
*/
int vg_write(struct volume_group *vg) int vg_write(struct volume_group *vg)
{ {
struct list *mdah; struct list *mdah, *mdah2;
void *mdl; struct metadata_area *mda;
if (vg->status & PARTIAL_VG) { if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s", log_error("Cannot change metadata for partial volume group %s",
@@ -368,25 +453,26 @@ int vg_write(struct volume_group *vg)
return 0; return 0;
} }
if (list_empty(&vg->fid->metadata_areas)) {
log_error("Aborting vg_write: No metadata areas to write to!");
return 0;
}
vg->seqno++; vg->seqno++;
/* Write to each copy of the metadata area */ /* Write to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) { list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn; mda = list_item(mdah, struct metadata_area);
if (!vg->fid->fmt->ops->vg_write(vg->fid, vg, mdl)) { if (!mda->ops->vg_write(vg->fid, vg, mda)) {
stack;
return 0;
}
}
if (!vg->fid->fmt->ops->vg_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_commit(vg->fid, vg, mdl)) {
stack; stack;
/* Revert */
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
mda = list_item(mdah2, struct metadata_area);
if (mda->ops->vg_revert &&
!mda->ops->vg_revert(vg->fid, vg, mda)) {
stack;
}
}
return 0; return 0;
} }
} }
@@ -394,46 +480,154 @@ int vg_write(struct volume_group *vg)
return 1; return 1;
} }
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name) /* Commit pending changes */
int vg_commit(struct volume_group *vg)
{ {
struct format_instance *fid; struct list *mdah;
struct format_type *fmt; struct metadata_area *mda;
struct volume_group *vg, *correct_vg; int cache_updated = 0;
struct list *mdah, *names; int failed = 0;
void *mdl;
int inconsistent = 0, first_time = 1;
/* create format instance with appropriate metadata area */ /* Commit to each copy of the metadata area */
if (!(fmt = vgcache_find_format(vg_name))) { list_iterate(mdah, &vg->fid->metadata_areas) {
/* Do full scan */ mda = list_item(mdah, struct metadata_area);
if (!(names = get_vgs(cmd))) { failed = 0;
if (mda->ops->vg_commit &&
!mda->ops->vg_commit(vg->fid, vg, mda)) {
stack; stack;
return NULL; failed = 1;
} }
pool_free(cmd->mem, names); /* Update cache first time we succeed */
if (!(fmt = vgcache_find_format(vg_name))) { if (!failed && !cache_updated) {
lvmcache_update_vg(vg);
cache_updated = 1;
}
}
/* If at least one mda commit succeeded, it was committed */
return cache_updated;
}
/* Don't commit any pending changes */
int vg_revert(struct volume_group *vg)
{
struct list *mdah;
struct metadata_area *mda;
list_iterate(mdah, &vg->fid->metadata_areas) {
mda = list_item(mdah, struct metadata_area);
if (mda->ops->vg_revert &&
!mda->ops->vg_revert(vg->fid, vg, mda)) {
stack; stack;
return NULL;
} }
} }
if (!(fid = fmt->ops->create_instance(fmt, vg_name, NULL))) { return 1;
}
/* Make orphan PVs look like a VG */
static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
{
struct lvmcache_vginfo *vginfo;
struct list *ih;
struct device *dev;
struct pv_list *pvl;
struct volume_group *vg;
struct physical_volume *pv;
if (!(vginfo = vginfo_from_vgname(ORPHAN))) {
stack;
return NULL;
}
if (!(vg = pool_zalloc(cmd->mem, sizeof(*vg)))) {
log_error("vg allocation failed");
return NULL;
}
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
vg->cmd = cmd;
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
log_error("vg name allocation failed");
return NULL;
}
list_iterate(ih, &vginfo->infos) {
dev = list_item(ih, struct lvmcache_info)->dev;
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL))) {
continue;
}
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
log_error("pv_list allocation failed");
return NULL;
}
pvl->pv = pv;
list_add(&vg->pvs, &pvl->list);
vg->pv_count++;
}
return vg;
}
/* Caller sets consistent to 1 if it's safe for vg_read to correct
* inconsistent metadata on disk (i.e. the VG write lock is held).
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
* If consistent is 0, caller must check whether consistent == 1 on return
* and take appropriate action if it isn't (e.g. abort; get write lock
* and call vg_read again).
*/
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
int *consistent)
{
struct format_instance *fid;
const struct format_type *fmt;
struct volume_group *vg, *correct_vg = NULL;
struct list *mdah;
struct metadata_area *mda;
int inconsistent = 0;
if (!*vgname) {
*consistent = 1;
return _vg_read_orphans(cmd);
}
/* Find the vgname in the cache */
/* If it's not there we must do full scan to be completely sure */
if (!(fmt = fmt_from_vgname(vgname))) {
lvmcache_label_scan(cmd, 0);
if (!(fmt = fmt_from_vgname(vgname))) {
if (memlock()) {
stack;
return NULL;
}
lvmcache_label_scan(cmd, 1);
if (!(fmt = fmt_from_vgname(vgname))) {
stack;
return NULL;
}
}
}
/* create format instance with appropriate metadata area */
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
log_error("Failed to create format instance"); log_error("Failed to create format instance");
return NULL; return NULL;
} }
/* Ensure contents of all metadata areas match - else do recovery */ /* Ensure contents of all metadata areas match - else do recovery */
list_iterate(mdah, &fid->metadata_areas) { list_iterate(mdah, &fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn; mda = list_item(mdah, struct metadata_area);
if (!(vg = fid->fmt->ops->vg_read(fid, vg_name, mdl))) { if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
inconsistent = 1; inconsistent = 1;
continue;
}
if (first_time) {
correct_vg = vg;
first_time = 0;
continue; continue;
} }
if (!correct_vg) {
correct_vg = vg;
continue;
}
/* FIXME Also ensure contents same - checksum compare? */
if (correct_vg->seqno != vg->seqno) { if (correct_vg->seqno != vg->seqno) {
inconsistent = 1; inconsistent = 1;
if (vg->seqno > correct_vg->seqno) if (vg->seqno > correct_vg->seqno)
@@ -442,12 +636,26 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
} }
/* Failed to find VG */ /* Failed to find VG */
if (first_time) { if (!correct_vg) {
stack; stack;
return NULL; return NULL;
} }
lvmcache_update_vg(correct_vg);
if (inconsistent) { if (inconsistent) {
if (!*consistent)
return correct_vg;
/* Don't touch partial volume group metadata */
/* Should be fixed manually with vgcfgbackup/restore etc. */
if ((correct_vg->status & PARTIAL_VG)) {
log_error("Inconsistent metadata copies found for "
"partial volume group %s", vgname);
*consistent = 0;
return correct_vg;
}
log_print("Inconsistent metadata copies found - updating " log_print("Inconsistent metadata copies found - updating "
"to use version %u", correct_vg->seqno); "to use version %u", correct_vg->seqno);
if (!vg_write(correct_vg)) { if (!vg_write(correct_vg)) {
@@ -456,51 +664,135 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
} }
} }
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt); if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
log_error("WARNING: Interrupted pvmove detected in "
"volume group %s", vg->name);
log_error("Please restore the metadata by running "
"vgcfgrestore.");
return NULL;
}
*consistent = 1;
return correct_vg; return correct_vg;
} }
/* This is only called by lv_from_lvid, which is only called from
* activate.c so we know the appropriate VG lock is already held and
* the vg_read is therefore safe.
*/
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid) struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
{ {
char *vgname; // const char *vgname;
struct list *vgs, *vgh; // struct list *vgnames, *slh;
struct volume_group *vg; struct volume_group *vg;
struct lvmcache_vginfo *vginfo;
int consistent = 0;
if (!(vgs = get_vgs(cmd))) { /* Is corresponding vgname already cached? */
if ((vginfo = vginfo_from_vgid(vgid)) &&
vginfo->vgname && *vginfo->vgname) {
if ((vg = vg_read(cmd, vginfo->vgname, &consistent)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
if (!consistent) {
log_error("Volume group %s metadata is "
"inconsistent", vginfo->vgname);
return NULL;
}
return vg;
}
}
return NULL;
/* FIXME Need a genuine read by ID here - don't vg_read by name! */
/* FIXME Disabled vgrenames while active for now because we aren't
* allowed to do a full scan here any more. */
/*** FIXME Cope with vgrename here
// The slow way - full scan required to cope with vgrename
if (!(vgnames = get_vgs(cmd, 1))) {
log_error("vg_read_by_vgid: get_vgs failed"); log_error("vg_read_by_vgid: get_vgs failed");
return NULL; return NULL;
} }
list_iterate(vgh, vgs) { list_iterate(slh, vgnames) {
vgname = list_item(vgh, struct name_list)->name; vgname = list_item(slh, struct str_list)->str;
if ((vg = vg_read(cmd, vgname)) && if (!vgname || !*vgname)
!strncmp(vg->id.uuid, vgid, ID_LEN)) return vg; continue; // FIXME Unnecessary?
consistent = 0;
if ((vg = vg_read(cmd, vgname, &consistent)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
if (!consistent) {
log_error("Volume group %s metadata is "
"inconsistent", vgname);
return NULL;
}
return vg;
}
} }
pool_free(cmd->mem, vgs);
return NULL; return NULL;
***/
} }
/* FIXME Use label functions instead of PV functions? */ /* Only called by activate.c */
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name) struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s)
{
struct lv_list *lvl;
struct volume_group *vg;
const union lvid *lvid;
lvid = (const union lvid *) lvid_s;
log_very_verbose("Finding volume group for uuid %s", lvid_s);
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
log_error("Volume group for uuid not found: %s", lvid_s);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
log_very_verbose("Can't find logical volume id %s", lvid_s);
return NULL;
}
return lvl->lv;
}
/* FIXME Use label functions instead of PV functions */
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector)
{ {
struct physical_volume *pv; struct physical_volume *pv;
struct label *label;
struct lvmcache_info *info;
struct device *dev;
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
stack;
return 0;
}
if (!(label_read(dev, &label))) {
log_error("No physical volume label read from %s", pv_name);
return 0;
}
info = (struct lvmcache_info *) label->info;
if (label_sector && *label_sector)
*label_sector = label->sector;
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) { if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
log_error("pv_list allocation for '%s' failed", pv_name); log_error("pv allocation for '%s' failed", pv_name);
return 0; return 0;
} }
/* Member of a format1 VG? */ /* FIXME Move more common code up here */
if (!(cmd->fmt1->ops->pv_read(cmd->fmt1, pv_name, pv))) { if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
}
/* Member of a format_text VG? */
if (!(cmd->fmtt->ops->pv_read(cmd->fmtt, pv_name, pv))) {
log_error("Failed to read existing physical volume '%s'", log_error("Failed to read existing physical volume '%s'",
pv_name); pv_name);
return 0; return 0;
@@ -512,30 +804,24 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
return pv; return pv;
} }
struct list *get_vgs(struct cmd_context *cmd) /* May return empty list */
struct list *get_vgs(struct cmd_context *cmd, int full_scan)
{ {
struct list *names; return lvmcache_get_vgnames(cmd, full_scan);
if (!(names = pool_alloc(cmd->mem, sizeof(*names)))) {
log_error("VG name list allocation failed");
return NULL;
}
list_init(names);
if (!cmd->fmt1->ops->get_vgs(cmd->fmt1, names) ||
!cmd->fmtt->ops->get_vgs(cmd->fmtt, names) ||
list_empty(names)) {
pool_free(cmd->mem, names);
return NULL;
}
return names;
} }
struct list *get_pvs(struct cmd_context *cmd) struct list *get_pvs(struct cmd_context *cmd)
{ {
struct list *results; struct list *results;
const char *vgname;
struct list *pvh, *tmp;
struct list *vgnames, *slh;
struct volume_group *vg;
int consistent = 0;
int old_partial;
int old_pvmove;
lvmcache_label_scan(cmd, 0);
if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) { if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) {
log_error("PV list allocation failed"); log_error("PV list allocation failed");
@@ -544,40 +830,54 @@ struct list *get_pvs(struct cmd_context *cmd)
list_init(results); list_init(results);
/* fmtt modifies fmt1 output */ /* Get list of VGs */
if (!cmd->fmt1->ops->get_pvs(cmd->fmt1, results) || if (!(vgnames = get_vgs(cmd, 0))) {
!cmd->fmtt->ops->get_pvs(cmd->fmtt, results)) { log_error("get_pvs: get_vgs failed");
pool_free(cmd->mem, results);
return NULL; return NULL;
} }
/* Read every VG to ensure cache consistency */
/* Orphan VG is last on list */
old_partial = partial_mode();
old_pvmove = pvmove_mode();
init_partial(1);
init_pvmove(1);
list_iterate(slh, vgnames) {
vgname = list_item(slh, struct str_list)->str;
if (!vgname)
continue; /* FIXME Unnecessary? */
consistent = 0;
if (!(vg = vg_read(cmd, vgname, &consistent))) {
stack;
continue;
}
if (!consistent)
log_print("Warning: Volume Group %s is not consistent",
vgname);
/* Move PVs onto results list */
list_iterate_safe(pvh, tmp, &vg->pvs) {
list_add(results, pvh);
}
}
init_pvmove(old_pvmove);
init_partial(old_partial);
return results; return results;
} }
int pv_write(struct cmd_context *cmd, struct physical_volume *pv) int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
struct list *mdas, int64_t label_sector)
{ {
struct list *mdah; if (*pv->vg_name || pv->pe_alloc_count) {
void *mdl; log_error("Assertion failed: can't _pv_write non-orphan PV "
"(in VG %s)", pv->vg_name);
/* Write to each copy of the metadata area */ return 0;
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_write(pv->fid, pv, mdl)) {
stack;
return 0;
}
} }
if (!pv->fid->fmt->ops->pv_commit) if (!pv->fmt->ops->pv_write(pv->fmt, pv, mdas, label_sector)) {
return 1; stack;
return 0;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_commit(pv->fid, pv, mdl)) {
stack;
return 0;
}
} }
return 1; return 1;

View File

@@ -10,113 +10,163 @@
#ifndef _LVM_METADATA_H #ifndef _LVM_METADATA_H
#define _LVM_METADATA_H #define _LVM_METADATA_H
#include <sys/types.h> #include "ctype.h"
#include <asm/page.h>
#include "dev-cache.h" #include "dev-cache.h"
#include "list.h"
#include "uuid.h" #include "uuid.h"
#define NAME_LEN 128 #define NAME_LEN 128
#define MAX_STRIPES 128 #define MAX_STRIPES 128
#define SECTOR_SIZE 512 #define SECTOR_SHIFT 9L
#define STRIPE_SIZE_DEFAULT 16 /* 16KB */ #define SECTOR_SIZE ( 1L << SECTOR_SHIFT )
#define STRIPE_SIZE_MIN ( PAGE_SIZE/SECTOR_SIZE) /* PAGESIZE in sectors */ #define STRIPE_SIZE_MIN ( getpagesize() >> SECTOR_SHIFT) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MAX ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */ #define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
#define PV_MIN_SIZE ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */ #define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
#define PE_ALIGN (65536UL / SECTOR_SIZE) /* PE alignment */ #define PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */
/* Various flags */ /* Various flags */
/* Note that the bits no longer necessarily correspond to LVM1 disk format */ /* Note that the bits no longer necessarily correspond to LVM1 disk format */
#define EXPORTED_VG 0x00000002 /* VG PV */ #define PARTIAL_VG 0x00000001 /* VG */
#define RESIZEABLE_VG 0x00000004 /* VG */ #define EXPORTED_VG 0x00000002 /* VG PV */
#define PARTIAL_VG 0x00000040 /* VG */ #define RESIZEABLE_VG 0x00000004 /* VG */
/* May any free extents on this PV be used or must they be left free? */ /* May any free extents on this PV be used or must they be left free? */
#define ALLOCATABLE_PV 0x00000008 /* PV */ #define ALLOCATABLE_PV 0x00000008 /* PV */
#define SPINDOWN_LV 0x00000010 /* LV */ #define SPINDOWN_LV 0x00000010 /* LV */
#define BADBLOCK_ON 0x00000020 /* LV */ #define BADBLOCK_ON 0x00000020 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */ #define VISIBLE_LV 0x00000040 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */
/* FIXME Remove when metadata restructuring is completed */
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
#define PVMOVE 0x00002000 /* VG LV SEG */
#define LOCKED 0x00004000 /* LV */
/* FIXME: do we really set read/write for a whole vg ? */ #define LVM_READ 0x00000100 /* LV VG */
#define LVM_READ 0x00000100 /* LV VG */ #define LVM_WRITE 0x00000200 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */ #define CLUSTERED 0x00000400 /* VG */
#define CLUSTERED 0x00000400 /* VG */ #define SHARED 0x00000800 /* VG */
#define SHARED 0x00000800 /* VG */
/* FIXME: This should be an enum rather than a bitset, /* Format features flags */
remove from status - EJT */ #define FMT_SEGMENTS 0x00000001 /* Arbitrary segment params? */
#define ALLOC_SIMPLE 0x00001000 /* LV */ #define FMT_MDAS 0x00000002 /* Proper metadata areas? */
#define ALLOC_STRICT 0x00002000 /* LV */
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */ typedef enum {
ALLOC_DEFAULT,
ALLOC_NEXT_FREE,
ALLOC_CONTIGUOUS
} alloc_policy_t;
#define FMT_TEXT_NAME "text" typedef enum {
#define FMT_LVM1_NAME "lvm1" SEG_STRIPED,
SEG_SNAPSHOT,
SEG_MIRRORED
} segment_type_t;
struct physical_volume { typedef enum {
struct id id; AREA_PV,
struct device *dev; AREA_LV
struct format_instance *fid; } area_type_t;
char *vg_name;
uint32_t status;
uint64_t size;
/* physical extents */
uint64_t pe_size;
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_alloc_count;
};
struct cmd_context; struct cmd_context;
struct format_handler;
struct labeller;
struct format_type { struct format_type {
struct list list;
struct cmd_context *cmd; struct cmd_context *cmd;
struct format_handler *ops; struct format_handler *ops;
struct labeller *labeller;
const char *name; const char *name;
const char *alias;
uint32_t features; uint32_t features;
void *library;
void *private; void *private;
}; };
struct physical_volume {
struct id id;
struct device *dev;
const struct format_type *fmt;
const char *vg_name;
uint32_t status;
uint64_t size;
/* physical extents */
uint32_t pe_size;
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_alloc_count;
};
struct metadata_area;
struct format_instance;
/* Per-format per-metadata area operations */
struct metadata_area_ops {
struct volume_group *(*vg_read) (struct format_instance * fi,
const char *vg_name,
struct metadata_area * mda);
/*
* Write out complete VG metadata. You must ensure internal
* consistency before calling. eg. PEs can't refer to PVs not
* part of the VG.
*
* It is also the responsibility of the caller to ensure external
* consistency, eg by calling pv_write() if removing PVs from
* a VG or calling vg_write() a second time if splitting a VG
* into two.
*
* vg_write() should not read or write from any PVs not included
* in the volume_group structure it is handed.
* (format1 currently breaks this rule.)
*/
int (*vg_write) (struct format_instance * fid, struct volume_group * vg,
struct metadata_area * mda);
int (*vg_commit) (struct format_instance * fid,
struct volume_group * vg, struct metadata_area * mda);
int (*vg_revert) (struct format_instance * fid,
struct volume_group * vg, struct metadata_area * mda);
int (*vg_remove) (struct format_instance * fi, struct volume_group * vg,
struct metadata_area * mda);
};
struct metadata_area { struct metadata_area {
struct list list; struct list list;
struct metadata_area_ops *ops;
void *metadata_locn; void *metadata_locn;
}; };
struct format_instance { struct format_instance {
struct format_type *fmt; const struct format_type *fmt;
struct list metadata_areas; /* e.g. metadata locations */ struct list metadata_areas; /* e.g. metadata locations */
}; };
struct volume_group { struct volume_group {
struct cmd_context *cmd; struct cmd_context *cmd;
struct format_instance *fid; struct format_instance *fid;
uint32_t seqno; /* Metadata sequence number */ uint32_t seqno; /* Metadata sequence number */
struct id id; struct id id;
char *name; char *name;
char *system_id; char *system_id;
uint32_t status; uint32_t status;
uint32_t extent_size; uint32_t extent_size;
uint32_t extent_count; uint32_t extent_count;
uint32_t free_count; uint32_t free_count;
uint32_t max_lv; uint32_t max_lv;
uint32_t max_pv; uint32_t max_pv;
/* physical volumes */ /* physical volumes */
uint32_t pv_count; uint32_t pv_count;
struct list pvs; struct list pvs;
/* logical volumes */ /* logical volumes */
uint32_t lv_count; uint32_t lv_count;
struct list lvs; struct list lvs;
/* snapshots */ /* snapshots */
@@ -124,39 +174,62 @@ struct volume_group {
struct list snapshots; struct list snapshots;
}; };
struct stripe_segment { struct lv_segment {
struct list list; struct list list;
struct logical_volume *lv; struct logical_volume *lv;
segment_type_t type;
uint32_t le; uint32_t le;
uint32_t len; uint32_t len;
uint32_t status;
/* FIXME Fields depend on segment type */
uint32_t stripe_size; uint32_t stripe_size;
uint32_t stripes; uint32_t area_count;
uint32_t area_len;
struct logical_volume *origin;
struct logical_volume *cow;
uint32_t chunk_size;
uint32_t extents_moved;
/* There will be one area for each stripe */ /* There will be one area for each stripe */
struct { struct {
struct physical_volume *pv; area_type_t type;
uint32_t pe; union {
struct {
struct physical_volume *pv;
uint32_t pe;
} pv;
struct {
struct logical_volume *lv;
uint32_t le;
} lv;
} u;
} area[0]; } area[0];
}; };
struct logical_volume { struct logical_volume {
union lvid lvid; union lvid lvid;
char *name; char *name;
struct volume_group *vg; struct volume_group *vg;
uint32_t status; uint32_t status;
alloc_policy_t alloc;
uint32_t read_ahead; uint32_t read_ahead;
int32_t major;
int32_t minor; int32_t minor;
uint64_t size; uint64_t size;
uint32_t le_count; uint32_t le_count;
struct list segments; struct list segments;
}; };
struct snapshot { struct snapshot {
struct id id;
int persistent; /* boolean */ int persistent; /* boolean */
uint32_t chunk_size; /* in 512 byte sectors */ uint32_t chunk_size; /* in 512 byte sectors */
@@ -169,9 +242,17 @@ struct name_list {
char *name; char *name;
}; };
struct alloc_area {
struct list list;
uint32_t start; /* PEs */
uint32_t count; /* PEs */
};
struct pv_list { struct pv_list {
struct list list; struct list list;
struct physical_volume *pv; struct physical_volume *pv;
struct list *mdas; /* Metadata areas */
struct list *alloc_areas; /* Areas we may allocate from */
}; };
struct lv_list { struct lv_list {
@@ -185,133 +266,115 @@ struct snapshot_list {
struct snapshot *snapshot; struct snapshot *snapshot;
}; };
struct mda_list {
struct list list;
struct device_area mda;
};
/* /*
* Ownership of objects passes to caller. * Ownership of objects passes to caller.
*/ */
struct format_handler { struct format_handler {
/* /*
* Returns a name_list of vg's. * Scan any metadata areas that aren't referenced in PV labels
*/ */
struct list *(*get_vgs)(struct format_type *fmt, struct list *names); int (*scan) (const struct format_type * fmt);
/*
* Returns pv_list of fully-populated pv structures.
*/
struct list *(*get_pvs)(struct format_type *fmt, struct list *results);
/* /*
* Return PV with given path. * Return PV with given path.
*/ */
int (*pv_read)(struct format_type *fmt, int (*pv_read) (const struct format_type * fmt, const char *pv_name,
const char *pv_name, struct physical_volume * pv, struct list * mdas);
struct physical_volume *pv);
/* /*
* Tweak an already filled out a pv ready for importing into a * Tweak an already filled out a pv ready for importing into a
* vg. eg. pe_count is format specific. * vg. eg. pe_count is format specific.
*/ */
int (*pv_setup)(struct format_instance *fi, struct physical_volume *pv, int (*pv_setup) (const struct format_type * fmt,
struct volume_group *vg); uint64_t pe_start, uint32_t extent_count,
uint32_t extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list * mdas,
struct physical_volume * pv, struct volume_group * vg);
/* /*
* Write a PV structure to disk. Fails if the PV is in a VG ie * Write a PV structure to disk. Fails if the PV is in a VG ie
* pv->vg_name must be null. * pv->vg_name must be null.
*/ */
int (*pv_write)(struct format_instance *fi, struct physical_volume *pv, int (*pv_write) (const struct format_type * fmt,
void *mdl); struct physical_volume * pv, struct list * mdas,
int (*pv_commit)(struct format_instance *fid, int64_t label_sector);
struct physical_volume *pv, void *mdl);
/* /*
* Tweak an already filled out a lv eg, check there * Tweak an already filled out a lv eg, check there
* aren't too many extents. * aren't too many extents.
*/ */
int (*lv_setup)(struct format_instance *fi, struct logical_volume *lv); int (*lv_setup) (struct format_instance * fi,
struct logical_volume * lv);
/* /*
* Tweak an already filled out vg. eg, max_pv is format * Tweak an already filled out vg. eg, max_pv is format
* specific. * specific.
*/ */
int (*vg_setup)(struct format_instance *fi, struct volume_group *vg); int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
int (*vg_remove)(struct format_instance *fi, struct volume_group *vg,
void *mdl);
/*
* The name may be prefixed with the dev_dir from the
* job_context.
* mdl is the metadata location to use
*/
struct volume_group *(*vg_read)(struct format_instance *fi,
const char *vg_name, void *mdl);
/*
* Write out complete VG metadata. You must ensure internal
* consistency before calling. eg. PEs can't refer to PVs not
* part of the VG.
*
* It is also the responsibility of the caller to ensure external
* consistency, eg by calling pv_write() if removing PVs from
* a VG or calling vg_write() a second time if splitting a VG
* into two.
*
* vg_write() must not read or write from any PVs not included
* in the volume_group structure it is handed. Note: format1
* does read all pv's currently.
*/
int (*vg_write)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
int (*vg_commit)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
/* /*
* Create format instance with a particular metadata area * Create format instance with a particular metadata area
*/ */
struct format_instance *(*create_instance)(struct format_type *fmt, struct format_instance *(*create_instance) (const struct format_type *
const char *vgname, fmt, const char *vgname,
void *context); void *context);
/* /*
* Destructor for format instance * Destructor for format instance
*/ */
void (*destroy_instance)(struct format_instance *fid); void (*destroy_instance) (struct format_instance * fid);
/* /*
* Destructor for format type * Destructor for format type
*/ */
void (*destroy)(struct format_type *fmt); void (*destroy) (const struct format_type * fmt);
}; };
/* /*
* Utility functions * Utility functions
*/ */
int vg_write(struct volume_group *vg); int vg_write(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name); int vg_commit(struct volume_group *vg);
int vg_revert(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
int *consistent);
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid); struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name); struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector);
struct list *get_pvs(struct cmd_context *cmd); struct list *get_pvs(struct cmd_context *cmd);
struct list *get_vgs(struct cmd_context *cmd);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv);
/* Set full_scan to 1 to re-read every (filtered) device label */
struct list *get_vgs(struct cmd_context *cmd, int full_scan);
struct physical_volume *pv_create(struct format_instance *fi, int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
const char *name, struct list *mdas, int64_t label_sector);
/* pe_start and pe_end relate to any existing data so that new metadata
* areas can avoid overlap */
struct physical_volume *pv_create(const struct format_type *fmt,
struct device *dev,
struct id *id, struct id *id,
uint64_t size); uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas);
struct volume_group *vg_create(struct cmd_context *cmd, const char *name, struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, int max_pv, int max_lv, uint32_t extent_size, uint32_t max_pv,
int pv_count, char **pv_names); uint32_t max_lv, int pv_count, char **pv_names);
int vg_remove(struct volume_group *vg); int vg_remove(struct volume_group *vg);
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
/* const char *new_name);
* This needs the format instance to check the int vg_extend(struct format_instance *fi, struct volume_group *vg,
* pv's are orphaned. int pv_count, char **pv_names);
*/
int vg_extend(struct format_instance *fi,
struct volume_group *vg, int pv_count, char **pv_names);
/* /*
* Create a new LV within a given volume group. * Create a new LV within a given volume group.
@@ -320,12 +383,21 @@ int vg_extend(struct format_instance *fi,
struct logical_volume *lv_create(struct format_instance *fi, struct logical_volume *lv_create(struct format_instance *fi,
const char *name, const char *name,
uint32_t status, uint32_t status,
alloc_policy_t alloc,
uint32_t stripes, uint32_t stripes,
uint32_t stripe_size, uint32_t stripe_size,
uint32_t extents, uint32_t extents,
struct volume_group *vg, struct volume_group *vg,
struct list *acceptable_pvs); struct list *allocatable_pvs);
struct logical_volume *lv_create_empty(struct format_instance *fi,
const char *name,
const char *name_format,
uint32_t status,
alloc_policy_t alloc,
struct volume_group *vg);
/* Manipulate LVs */
int lv_reduce(struct format_instance *fi, int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents); struct logical_volume *lv, uint32_t extents);
@@ -333,40 +405,52 @@ int lv_extend(struct format_instance *fi,
struct logical_volume *lv, struct logical_volume *lv,
uint32_t stripes, uint32_t stripes,
uint32_t stripe_size, uint32_t stripe_size,
uint32_t extents, uint32_t extents, struct list *allocatable_pvs);
struct list *allocatable_pvs);
int lv_extend_mirror(struct format_instance *fid,
struct logical_volume *lv,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe,
uint32_t extents, struct list *allocatable_pvs,
uint32_t status);
/* Lock list of LVs */
int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags);
int unlock_lvs(struct cmd_context *cmd, struct list *lvs);
/* lv must be part of vg->lvs */ /* lv must be part of vg->lvs */
int lv_remove(struct volume_group *vg, struct logical_volume *lv); int lv_remove(struct volume_group *vg, struct logical_volume *lv);
/* FIXME: Move to other files */
int id_eq(struct id *op1, struct id *op2);
/* Manipulate PV structures */ /* Manipulate PV structures */
int pv_add(struct volume_group *vg, struct physical_volume *pv); int pv_add(struct volume_group *vg, struct physical_volume *pv);
int pv_remove(struct volume_group *vg, struct physical_volume *pv); int pv_remove(struct volume_group *vg, struct physical_volume *pv);
struct physical_volume *pv_find(struct volume_group *vg, struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
const char *pv_name);
/* Find a PV within a given VG */ /* Find a PV within a given VG */
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name); struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id);
/* Find an LV within a given VG */ /* Find an LV within a given VG */
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name); struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg, struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
union lvid *lvid); const union lvid *lvid);
/* Return the VG that contains a given LV (based on path given in lv_name) */ /* Return the VG that contains a given LV (based on path given in lv_name) */
/* or environment var */ /* or environment var */
struct volume_group *find_vg_with_lv(const char *lv_name); struct volume_group *find_vg_with_lv(const char *lv_name);
/* Find LV with given lvid (used during activation) */
struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
const char *lvid_s);
/* FIXME Merge these functions with ones above */ /* FIXME Merge these functions with ones above */
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev); struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name); struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name);
/* Find LV segment containing given LE */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
/* /*
* Remove a dev_dir if present. * Remove a dev_dir if present.
*/ */
@@ -377,7 +461,6 @@ const char *strip_dir(const char *vg_name, const char *dir);
*/ */
int lv_check_segments(struct logical_volume *lv); int lv_check_segments(struct logical_volume *lv);
/* /*
* Sometimes (eg, after an lvextend), it is possible to merge two * Sometimes (eg, after an lvextend), it is possible to merge two
* adjacent segments into a single segment. This function trys * adjacent segments into a single segment. This function trys
@@ -385,23 +468,64 @@ int lv_check_segments(struct logical_volume *lv);
*/ */
int lv_merge_segments(struct logical_volume *lv); int lv_merge_segments(struct logical_volume *lv);
/* /*
* Useful functions for managing snapshots. * Useful functions for managing snapshots.
*/ */
int lv_is_origin(struct logical_volume *lv); int lv_is_origin(const struct logical_volume *lv);
int lv_is_cow(struct logical_volume *lv); int lv_is_cow(const struct logical_volume *lv);
struct snapshot *find_cow(struct logical_volume *lv); int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
struct snapshot *find_origin(struct logical_volume *lv);
struct list *find_snapshots(struct logical_volume *lv); struct snapshot *find_cow(const struct logical_volume *lv);
struct snapshot *find_origin(const struct logical_volume *lv);
struct list *find_snapshots(const struct logical_volume *lv);
int vg_add_snapshot(struct logical_volume *origin, int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow, struct logical_volume *cow,
int persistent, int persistent, struct id *id, uint32_t chunk_size);
uint32_t chunk_size);
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow); int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
/*
* Mirroring functions
*/
int insert_pvmove_mirrors(struct cmd_context *cmd,
struct logical_volume *lv_mirr,
struct physical_volume *pv,
struct logical_volume *lv,
struct list *allocatable_pvs,
struct list *lvs_changed);
int remove_pvmove_mirrors(struct volume_group *vg,
struct logical_volume *lv_mirr);
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
struct device *dev);
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv);
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
*lv_mirr);
float pvmove_percent(struct logical_volume *lv_mirr);
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv);
static inline int validate_name(const char *n)
{
register char c;
register int len = 0;
if (!n || !*n)
return 0;
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
if (*n == '-')
return 0;
while ((len++, c = *n++))
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
return 0;
if (len > NAME_LEN)
return 0;
return 1;
}
#endif #endif

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