1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-04 05:44:18 +03:00

Compare commits

...

651 Commits

Author SHA1 Message Date
Alasdair Kergon
239f422039 update 2003-07-13 11:07:50 +00:00
Alasdair Kergon
67af3c37be Fix detection of exported LVM1 volume groups. 2003-07-13 11:07:25 +00:00
Alasdair Kergon
a9442385c4 vsn 2.00.02 (rc3) 2003-07-12 12:02:12 +00:00
Alasdair Kergon
8c9cd10b8b Restrict active lvchange -My with -f 2003-07-11 17:10:19 +00:00
Alasdair Kergon
72542059dd Fix inactive snapshot display. 2003-07-11 17:09:21 +00:00
Alasdair Kergon
a843fc6d40 update 2003-07-05 23:27:17 +00:00
Alasdair Kergon
4beed60c08 Driver version 1 compatibility fix for snapshots. 2003-07-05 23:24:10 +00:00
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
Alasdair Kergon
990af7548a Increment version. 2002-05-31 19:33:30 +00:00
Alasdair Kergon
a38aefdfc8 Add vgsplit. 2002-05-31 19:30:51 +00:00
Alasdair Kergon
3bcb12e7d1 Tidy/fix segment rounding. 2002-05-31 19:29:43 +00:00
Alasdair Kergon
7904ecb462 Tidy 2002-05-31 19:28:37 +00:00
Alasdair Kergon
9ba4d45109 Remember to update VG free_count when reducing size of an LV. 2002-05-30 16:08:19 +00:00
Alasdair Kergon
56b8afe19d Fix vgcfgrestore segfault (wrong variable used). 2002-05-30 16:03:26 +00:00
Alasdair Kergon
f7aed9a94c update 2002-05-27 13:00:18 +00:00
AJ Lewis
e12a7e881d o fix changed function names 2002-05-23 14:13:21 +00:00
Alasdair Kergon
5afb65325d Fix LVM1 backwards compatibility issue when LV with a low LV number is deleted. 2002-05-23 11:37:51 +00:00
Joe Thornber
135f520f32 o Remove ext3 incompatibility bug
o	Mention 2.4.18 VM problem
2002-05-23 08:20:44 +00:00
Andres Salomon
bc251f4ff6 update for .08 2002-05-23 07:49:25 +00:00
Alasdair Kergon
b8769751f6 Rename; add some FIXMEs. 2002-05-22 14:03:45 +00:00
Alasdair Kergon
eff96d839e Revert to standard linux macros (for correct behaviour on rare architectures). 2002-05-21 12:37:07 +00:00
Alasdair Kergon
aa34c23807 Update version. 2002-05-21 12:14:05 +00:00
Andres Salomon
195acdac8c ack, missing include 2002-05-19 04:11:34 +00:00
Andres Salomon
903e03c56c update create_dir() comment 2002-05-19 03:52:38 +00:00
Andres Salomon
0892767b8a support recursive mkdir in create_dir() 2002-05-19 03:46:34 +00:00
Andres Salomon
83ebfa772c synch w/ -3 "oh shit" release 2002-05-14 03:56:40 +00:00
Joe Thornber
1583641322 Drop the default chunk size for snapshots down to 8k 2002-05-13 15:14:21 +00:00
Alasdair Kergon
9510e2c256 Rewrite missing/corrupt metadata in more cases. 2002-05-13 12:38:54 +00:00
AJ Lewis
a9dbabe07e o the _status fxns now take more arguments - this way i don't get the
preparsed status info, shove it all into a string, and then parse it
   again to get the info back out (which is what i was doing before)
 o basically that's it...i like this *much* better than the previous
   method and i think it makes the _status fxn more flexible if we need
   to use it to get other info out.
2002-05-10 16:06:06 +00:00
Alasdair Kergon
12884008fa Import snapshot status & persistence + indent etc. 2002-05-10 15:25:38 +00:00
AJ Lewis
02543bad1c o Actually read snapshot percentage from the kernel - what a pain! :)
o Not sure if the code in dev_manager is really optimal, but it works..
   will look at adjusting it a bit now.
 o I *think* it works right when one snapshot if full but others aren't,
   but I haven't really been able to test it because the full snapshot
   somehow resets itself and weird things start happening to the system...
2002-05-09 21:17:57 +00:00
Alasdair Kergon
a8c56a5251 Remove a no-op. 2002-05-09 12:03:55 +00:00
AJ Lewis
4e5a855f3f o header should only be printed once... 2002-05-08 17:58:52 +00:00
AJ Lewis
7e497a951e o Added function find_snapshots to snapshot_manip.c that returns a list
of snapshots whose origin is the lv passed in.
 o Used this new function to make lvdisplay properly display all snapshots
   attached to a origin.
2002-05-08 16:57:46 +00:00
Joe Thornber
cd08eabbfa i) Put back chunksize_ARG for lvcreate. 2002-05-08 14:36:10 +00:00
Alasdair Kergon
f7e62d9f81 Always call init_log() to initialise logging defaults. 2002-05-08 12:26:45 +00:00
Andres Salomon
9a3761e86e implement our own swabbing functions, instead of relying on the kernel's. 2002-05-07 15:28:59 +00:00
Alasdair Kergon
3619a68693 log/{prefix,command_names} use defaults.h & reset between shell cmds 2002-05-07 13:00:01 +00:00
Alasdair Kergon
efaf3c3bf9 Default values for some display output settings 2002-05-07 12:50:01 +00:00
Alasdair Kergon
0e4e6a6f67 Tweaks 2002-05-07 12:47:11 +00:00
Andres Salomon
42458e6278 updated. 2002-05-07 06:13:03 +00:00
Andres Salomon
41ec995377 Make lvm2 compile on big endian archs; use the kernel/glibc's endian
conversion stuff, instead of implementing our own.  Tested on a little
endian system (x86); I'll let the debian handle big endian testing.  :)
2002-05-07 05:54:14 +00:00
AJ Lewis
4f37599326 o Will now correctly remove expired achive files from the system when
archive_vg is called.
 o Added a #define to the top of the file - not sure if this is the
   appropriate place for it though
2002-05-03 19:28:07 +00:00
Patrick Caulfield
4144520e5c Add features to get table/status & wait for next event. 2002-05-03 11:55:58 +00:00
Andres Salomon
6c4800546c forgot to add Conflicts against lvm1 packages 2002-05-03 04:57:49 +00:00
Andres Salomon
733733c8a7 updated for 0.95.05-2. 2002-05-03 04:43:46 +00:00
Andres Salomon
2aa67cc946 ditto 2002-05-03 04:43:24 +00:00
Andres Salomon
9385981a9d dh_installinit makes a perfectly find postrm script.. 2002-05-03 04:13:02 +00:00
Alasdair Kergon
fff780035d Update. 2002-04-30 17:13:43 +00:00
Alasdair Kergon
46127e673d Some partial VG support with format_text. 2002-04-30 17:12:37 +00:00
Alasdair Kergon
70df59b224 get_vgs must check for text format VGs when no lvm1 format VGs present 2002-04-30 12:27:13 +00:00
AJ Lewis
0fdbaa803f o Updated *display output for LVM1 compatibility
o There is still a bit missing
   + all are missing the {PV,VG,LV} # - that is not applicable in LVM2
   + pvdisplay doesn't show how many LVs are contained on it
   + much of the snapshot information isn't available for lvdisplay
 o Look at the code for other potiential FIXMEs  :)
2002-04-29 21:43:14 +00:00
Heinz Mauelshagen
6af1830eff Changed DEFAULT_PV and DEFAULT_LV to 256 (has been fixed in LVM1 before) 2002-04-25 10:53:58 +00:00
Andres Salomon
6f860e2bd5 Updated for new release 2002-04-25 06:12:07 +00:00
Alasdair Kergon
20a492f7ee Update example config 2002-04-24 18:41:02 +00:00
Alasdair Kergon
63875e7591 Merge with text format branch.
Lots of changes/very little testing so far => there'll be bugs!

Use 'vgcreate -M text' to create a volume group with its metadata stored
in text files.  Text format metadata changes should be reasonably atomic,
with a (basic) automatic recovery mechanism if the system crashes while a
change is in progress.

Add a metadata section to lvm.conf to specify multiple directories if
you want (recommended) to keep multiple copies of the metadata (eg on
different filesystems).

e.g. metadata {
        dirs = ["/etc/lvm/metadata1","/usr/local/lvm/metadata2"]
}

Plenty of refinements still in the pipeline.
2002-04-24 18:20:51 +00:00
Patrick Caulfield
0ad98cabde add setlocale() call so that localisation of things like number entry
and display will work correctly.
2002-04-24 10:42:09 +00:00
Joe Thornber
668879d2e1 o Stop printing errors if flushing fails (could be an unconfigured device). 2002-04-24 08:37:34 +00:00
Alasdair Kergon
2e09783302 Prepare for another beta release. 2002-04-23 22:13:04 +00:00
Alasdair Kergon
49734114b3 Commit snapshot-related changes preparing for the next beta release. 2002-04-23 21:47:50 +00:00
Alasdair Kergon
950d9d6ee7 Missing seg->lv gives segfault when activating from text format. 2002-04-16 19:41:54 +00:00
Alasdair Kergon
f7974aee2e Allow deactivation of final snapshot. 2002-04-16 14:42:20 +00:00
Joe Thornber
c870a82621 o Added support for chunk_size to lvcreate. 2002-04-15 18:49:20 +00:00
Alasdair Kergon
984929a001 Missing VG lock when iterating through all LVs. 2002-04-15 16:27:39 +00:00
Patrick Caulfield
7f9e2c1db8 More memory leak plugging. 2002-04-15 13:24:14 +00:00
Joe Thornber
324e8389dc o Drop the default chunk size for snapshots down to 16k. 2002-04-15 08:41:00 +00:00
Alasdair Kergon
6f448c5a38 Implement a no_locking module that *does* attempt activation. 2002-04-11 14:10:32 +00:00
Patrick Caulfield
ec43efbb20 Rename device node during a DM_RENAME command. 2002-04-11 12:45:18 +00:00
Patrick Caulfield
3ed065de37 Return status from _lv_activate and friends.
Alasdair, I think this is right (and I need it) but you may like to check.
2002-04-11 09:14:04 +00:00
Patrick Caulfield
8152f0d72c Remove \n from log messages. 2002-04-10 15:49:47 +00:00
Joe Thornber
f8047f4736 o Perform a BLKFLSBUF ioctl whenever a block device is closed.
Patrick, can you see if this fixes your cluster syncing problem please ?
If so I'll make it so it only syncs if you have actually written to the
device.
2002-04-08 18:59:50 +00:00
Patrick Caulfield
b93c66dc2d Implement an external locking interface. 2002-04-08 16:04:50 +00:00
Patrick Caulfield
ac877b3065 Fix prototype. 2002-04-08 13:35:09 +00:00
Alasdair Kergon
dee8abfdde Fix lv_setup() not to generate a new lvid each time if asked to setup the
same LV more than once - subsequent times validate only.
2002-04-05 14:32:22 +00:00
Patrick Caulfield
cef3841d73 Make lock type numbers match the DLM numbers in use, and move UNLOCK out
of the way.
2002-04-04 13:31:21 +00:00
Alasdair Kergon
3cd5e8a041 Rename LCK_NONE to LCK_UNLOCK 2002-04-04 11:18:45 +00:00
Alasdair Kergon
515b5f866e Tidying. 2002-04-03 12:17:55 +00:00
Alasdair Kergon
321f62bf92 Cope with creation of additional snapshots while active.
(More work on suspension dependencies still needed.)
2002-03-27 18:17:43 +00:00
Alasdair Kergon
f94fa47b52 Snapshots are now attached to their origin device for locking purposes
so lock the origin instead of the snapshot itself when creating one.
2002-03-26 15:01:57 +00:00
Alasdair Kergon
c502f8a722 New-style persistent minor support. 2002-03-26 13:41:37 +00:00
Alasdair Kergon
59b4868ac3 o read-only device support
o name/uuid disambiguation
2002-03-25 18:54:59 +00:00
Alasdair Kergon
3634e12cce Fix typo. 2002-03-25 18:50:37 +00:00
Andres Salomon
6d45445391 all people to actually uninstall lvm2 (*grin*) 2002-03-23 08:23:15 +00:00
Alasdair Kergon
4f47e268cc Improve log messages. 2002-03-20 14:34:15 +00:00
Alasdair Kergon
0035b31cdb Better support for LVs with hyphens in names. 2002-03-19 16:41:44 +00:00
Alasdair Kergon
f2565aee03 Support device queries by uuid as well as by name. (Used by lvrename.) 2002-03-18 23:39:42 +00:00
Alasdair Kergon
5bd85668dd lvrename works on snapshots now 2002-03-18 23:25:50 +00:00
Alasdair Kergon
20f990b6ce Tie all snapshot (de)activation requests to (de)activation of origin device. 2002-03-18 13:09:27 +00:00
Alasdair Kergon
6821379586 s/Removing/Unloading/ in messages to reduce confusion 2002-03-15 23:01:59 +00:00
Alasdair Kergon
73b040eb49 Cut the number of device-mapper calls. 2002-03-15 22:59:12 +00:00
Alasdair Kergon
49aa4b2e1e New function to enable suppression of messages to stdout/stderr. 2002-03-15 22:54:04 +00:00
Alasdair Kergon
972241c74c Review locking: block signals instead of ignoring them and restore state
afterwards; avoid race condition with unlink; add LCK_HOLD to process_each_vg.
2002-03-15 16:07:38 +00:00
Alasdair Kergon
680750e3c2 Reduce the number of dm info calls. 2002-03-14 21:17:30 +00:00
Alasdair Kergon
5e7d4d9d15 distclean also to remove libdm-common.h 2002-03-14 16:56:02 +00:00
Alasdair Kergon
1e57e60613 Integrate suspend. 2002-03-14 15:36:07 +00:00
Alasdair Kergon
3ac7ce605a Suppress verbose/debug messages from libdevmapper. 2002-03-14 13:39:33 +00:00
Joe Thornber
b720dea9f0 o dev_manager_suspend, untested. 2002-03-14 10:56:09 +00:00
Alasdair Kergon
c80722aefe A missing free() found by Valgrind. ( http://developer.kde.org/~sewardj/ ) 2002-03-13 23:19:20 +00:00
Alasdair Kergon
a84fa69f28 dmsetup display uuid 2002-03-13 16:19:17 +00:00
Alasdair Kergon
e33781e59f Set LV uuid. 2002-03-13 15:11:29 +00:00
Joe Thornber
8824bc7ece o Mention that vgscan needs to be run after changing the filter var. 2002-03-13 14:25:53 +00:00
Patrick Caulfield
c2e3b0e448 Fix _align so it works on 64-bit machines. 2002-03-12 15:27:51 +00:00
Alasdair Kergon
f61a38e85a Let dmsetup store the uuid on device creation. 2002-03-11 22:44:36 +00:00
Alasdair Kergon
d23e948216 Move is_empty_dir to lvm-file 2002-03-11 22:23:24 +00:00
Joe Thornber
58bdaa31f0 o Actually check that the vg directory is empty rather than speculatively
rmdiring it.  Work around for devfs bug.
2002-03-11 20:43:58 +00:00
Joe Thornber
b6491d88a6 o This should complete the dev_manager alg. Please could people now
report any activation oddities they see.
2002-03-11 20:36:04 +00:00
Alasdair Kergon
f6061ba62e lv_info replaces lv_active etc. 2002-03-11 19:02:28 +00:00
Alasdair Kergon
427899ddce o activate/reactivate merge
o unlocking macro
2002-03-11 15:08:39 +00:00
Joe Thornber
c4ab7d2dbd o dm->active_list now filled in, ATM this is based on the layer name rather
than the uuid.
2002-03-11 11:27:48 +00:00
Joe Thornber
0fd2ba033f o Comment out some new code that was preventing pjc activating
snapshots.  This will go back in when the active_list is working.
2002-03-11 10:38:16 +00:00
Joe Thornber
ed38939a93 o knock out the offset for origin targets. 2002-03-08 10:45:01 +00:00
Joe Thornber
c7ee26ce5a o Add active_list to dev_manager
o  Origin layer is only added to snapshots if a snapshot is in the
   active_list.
2002-03-08 10:41:48 +00:00
Andres Salomon
909b8cb303 heh, whoops. s/device-mapper/LVM2/g. 2002-03-08 02:39:08 +00:00
Alasdair Kergon
b0277370cf o dm_destroy_all() called on exit - but doesn't touch suspended devices yet.
o 'dmsetup remove_all' calls dm_destroy_all() to provide a quick way to
  prepare for unloading the module
o Ran through indent again.
2002-03-07 20:56:10 +00:00
Joe Thornber
2ec8656bea o First cut at dev scanning.
o  Split up _expand_lv
2002-03-07 17:37:38 +00:00
Joe Thornber
b2ef256910 o Add comment describing what we're aiming for with dev_manager.
o  Remove dev_manager_reactivate, since it'll be the same as activate.

o  Merge the mark, visible and dirty fields into the same flags field.
2002-03-07 16:48:46 +00:00
Joe Thornber
63d6ce95db o Top level device is now just called <vg>-<lv> (there's no 'top'
layer appended).

o  Got rid of the unused layer->type field and enum.
2002-03-07 15:29:31 +00:00
Alasdair Kergon
a9532b189c Kernel functionality that returns device dependencies (ejt). 2002-03-06 19:42:23 +00:00
Joe Thornber
844545411f o Rename dmsetup dependencies -> dmsetup deps 2002-03-06 14:47:13 +00:00
Joe Thornber
4e23a2b9b8 o Add support for getting dependencies for a device.
o  dmsetup dependencies <dev>
2002-03-06 14:38:25 +00:00
Andres Salomon
5deba027eb convert from debian native package 2002-03-06 05:43:54 +00:00
Alasdair Kergon
fc8b7efc6f o Use new LCK_HOLD flag to indicate whether lock should be held on return
from lock_vol() - otherwise it now attempts to acquire the lock and then
  immediately releases it.
o Extend the id field in struct logical_volume to hold VG uuid + LV uuid
  for format1. This unique lvid can be used directly when calling lock_vol().
o Add the VG uuid to vgcache to make VG uuid lookups possible.  (Another
  step towards using them instead of VG names internally.)
2002-03-05 20:03:09 +00:00
Alasdair Kergon
a1c2d9c0f3 Fix activation for VG with more than one LV. 2002-03-04 18:50:34 +00:00
Alasdair Kergon
4ca49a0501 snapshot/zero logic 2002-03-04 15:25:52 +00:00
Joe Thornber
493c53d090 o Add a line to lvdisplay to say if the volume is a snapshot. 2002-03-04 15:12:30 +00:00
Joe Thornber
b27e956d35 o Bad dependency, meant the origin was always getting activated. 2002-03-04 15:10:30 +00:00
Alasdair Kergon
35ebed75c6 Remove unused fns. 2002-03-04 14:27:25 +00:00
Joe Thornber
7bfdb5f77f o I was tearing down device bottom-up instead of top down. Which
is why lvremove of snapshots wasn't working.
2002-03-04 14:26:43 +00:00
Joe Thornber
8d8c02317f o Break creating a snapshot down into:
i)   create cow
   ii)  activate cow
   iii) zero cow
   iv)  deactivate
   v)   add snapshot info
   vi)  reactivate
2002-03-04 13:46:37 +00:00
Andres Salomon
a34482feab proper /etc/lvm/lvm.conf now 2002-03-04 11:13:47 +00:00
Andres Salomon
cbdc8fd4a6 fix various issues 2002-03-04 11:12:57 +00:00
Alasdair Kergon
8d3afaa53c More use of LV locking. 2002-03-01 19:08:11 +00:00
Joe Thornber
7ced9ef3df o point snapshots at origin:real rather than origin:top, and *ping*
snapshots work.
2002-03-01 09:07:00 +00:00
Alasdair Kergon
e8a9ae7e80 Fix unlock parameter. 2002-02-27 14:48:42 +00:00
Alasdair Kergon
73a88ab3d3 o Lock mechanism for LV activation
o #defines for common lock flag combinations
o Try out hyphens instead of colons in device-mapper names - does this
  make messages containing filenames easier to read?
2002-02-27 12:26:41 +00:00
Alasdair Kergon
aaed82738a Running out of filehandles? Close /dev/device-mapper/control then. 2002-02-26 18:30:02 +00:00
Joe Thornber
de7f7b96db o Format1 wasn't recording the snapshot chunk size properly
o  Activation of snapshots now works - though the resulting device
   doesn't (pjc ?)

o  text format wasn't setting vg->cmd.
2002-02-26 16:48:52 +00:00
Alasdair Kergon
1a669b3e68 Clearer link pathname display. 2002-02-26 16:08:22 +00:00
Joe Thornber
333af9b13a o _build_name was allocating 1 byte too few, which meant the
terminating zero was falling off at some later point.

o Don't try and iterate from a deleted node in _prune_unmarked.
2002-02-26 14:44:13 +00:00
Joe Thornber
a5bca5e240 o Removed old files
o  rewrote activate.c to use dev-manager, I'm sure these two will merge
   at some point.

o  Rename is broken ATM

o  dev-manager puts the calls through to fs.c for layers that have the
   'visible' flag set.
2002-02-26 11:49:17 +00:00
Joe Thornber
c885633e02 o More dev_manager fns. 2002-02-25 16:53:12 +00:00
Heinz Mauelshagen
ca7e20b7ca pvresize command 2002-02-25 15:32:58 +00:00
Joe Thornber
545e11a3d7 o In go the populate functions. 2002-02-25 15:19:53 +00:00
Joe Thornber
44f5287664 o More dev_manager work. 2002-02-25 14:46:57 +00:00
Alasdair Kergon
cf510897f1 Begin conversion so LV id is passed to activation unit instead of
struct logical_volume.
2002-02-25 12:56:16 +00:00
Joe Thornber
1d171345f8 o Sync with cvs, dev_manager still needs to be wired into activate.c 2002-02-25 12:02:33 +00:00
Joe Thornber
4fa7e1cd49 o Remove the vg argument from find_cow 2002-02-25 11:55:39 +00:00
Joe Thornber
acd008298e o hash_iterate -> hash_iter 2002-02-25 11:54:15 +00:00
Joe Thornber
83a8021515 o Added a macro called hash_iterate, that is similar to list_iterate
o Renamed hash_iterate function, hash_iter.
2002-02-25 11:52:58 +00:00
Alasdair Kergon
cf88dfb1db indent 2002-02-24 22:31:55 +00:00
Heinz Mauelshagen
8937c4b481 lvmdiskscan 2002-02-22 13:17:46 +00:00
Patrick Caulfield
cc6af10a4d Fill in format_text functions.
Sort of seems to work.
2002-02-22 11:44:56 +00:00
Alasdair Kergon
6d94578955 o Convert lv->id back to lv_number when writing back to disk
o Use first unused lv_number when creating new LV
o Use lv_number for refs to snapshots
o Update persistent minor logic after the lvcreate restructure
o Reset all parameters before use in lvcreate.
2002-02-21 19:04:37 +00:00
Heinz Mauelshagen
08442ab71e Avoid ambigous volume_group argument in vg_add_snapshot() 2002-02-21 18:31:48 +00:00
Alasdair Kergon
10d91d213f Generate LV uuid from lv_number when reading in LVs. 2002-02-21 15:26:44 +00:00
Heinz Mauelshagen
b7a3b06994 Removed wrong 'lv->vg' argument from lv_is_cow() call. Is used in lv_is_cow internally. 2002-02-21 14:00:45 +00:00
Joe Thornber
5f12c37f23 o typo 2002-02-21 10:17:01 +00:00
Joe Thornber
585edebccd o add find_cow function. 2002-02-21 10:16:33 +00:00
Joe Thornber
9921c62234 o misc little fixes. 2002-02-21 10:15:54 +00:00
Andres Salomon
1ac76d2e16 ah, it was that "set -e" that was the culprit.. 2002-02-21 08:52:36 +00:00
Andres Salomon
6e983bf400 stop init script from returning w/ non-zero if not really an error 2002-02-21 08:30:14 +00:00
Alasdair Kergon
6a8fd4fa6e Try out using LV locking for reactivation. 2002-02-20 21:30:27 +00:00
Alasdair Kergon
3698eaa2d2 Remove lv_update_write_access: use lv_reactivate directly now instead. 2002-02-20 21:28:22 +00:00
Alasdair Kergon
8d97ca433c Suppress meaningless <backtrace> msg on screen (no prog/line number given) 2002-02-20 21:26:40 +00:00
Alasdair Kergon
23cc65e537 lvd->lv_access & LV_SNAPSHOT not lvd->lv_status 2002-02-20 21:24:45 +00:00
Alasdair Kergon
2f5a3c2bbe Remove VG arg from lv_is_cow() and lv_is_origin() - use lv->vg instead. 2002-02-20 19:04:55 +00:00
Alasdair Kergon
f6485616cd o Use 'pvcreate --setphysicalvolumesize' with no short form (instead of -s)
and add severe warning if it's used to make a device seem bigger than
  it really is.  This is not an option people should be using as it
  breaks metadata integrity.
o Use uint64_t throughout (rather than unsigned long long)
o Convert a few messages that contain pathnames into the more common form:
  pathname: message
2002-02-20 18:29:30 +00:00
Andres Salomon
6544fb43d9 initial lvm2 debian packages; still missing some manpages, but otherwise lintian passes
E: lvm2: binary-without-manpage e2fsadm
E: lvm2: binary-without-manpage lvmdiskscan
E: lvm2: binary-without-manpage lvmsadc
E: lvm2: binary-without-manpage lvmsar
E: lvm2: binary-without-manpage lvresize
E: lvm2: binary-without-manpage pvdata
E: lvm2: binary-without-manpage pvmove
E: lvm2: binary-without-manpage version
E: lvm2: binary-without-manpage vgcfgrestore
E: lvm2: binary-without-manpage vgexport
E: lvm2: binary-without-manpage vgimport
E: lvm2: binary-without-manpage vgmknodes
E: lvm2: binary-without-manpage vgsplit
2002-02-20 10:28:49 +00:00
Andres Salomon
a954b32dcc install all the manpages (another make-lintian-happy exercise) 2002-02-20 10:22:02 +00:00
Joe Thornber
426dc7836c o Removed the -z (suspend) option from the tools
o  New function: int lv_setup_cow_store(struct logical_volume *lv)
   This zeroes the start of the cow device.

o  Made lvcreate call above fn.
2002-02-18 15:52:48 +00:00
Joe Thornber
ff941ffc16 o small bug in the format1 export code for snapshots.
o  tidied newlines in the snapshot section of format text.
2002-02-18 11:25:43 +00:00
Joe Thornber
a063c201df o Add support for the -s and -c flags to lvcreate. 2002-02-18 10:59:51 +00:00
Heinz Mauelshagen
e2be3fa0aa Second path on "pvcreate -s" 2002-02-15 14:33:59 +00:00
Joe Thornber
609da6fb50 o split lvcreate into seperate functions for parsing the command line,
and creating the lv.  A lot of changes in here so be on the lookout
   for bugs.
2002-02-15 11:53:22 +00:00
Heinz Mauelshagen
fc9f3ccec3 Forgot to remove test printf :-) 2002-02-15 09:37:23 +00:00
Heinz Mauelshagen
f7baa67a0a First cut on "pvcreate -s" 2002-02-15 01:26:16 +00:00
Joe Thornber
e8d78c2cdb o Initialise the snapshot list properly in vgcreate. 2002-02-14 15:06:24 +00:00
Joe Thornber
9d33366092 o Define _read_uint32 2002-02-14 14:52:21 +00:00
Heinz Mauelshagen
f5d61515c2 test printf removed 2002-02-13 21:30:51 +00:00
Heinz Mauelshagen
711a04a972 LV maximum size limit of 2TB ensured in _lv_setup() 2002-02-13 21:28:56 +00:00
Heinz Mauelshagen
e5b470a3f1 spaces 2002-02-13 21:28:15 +00:00
Heinz Mauelshagen
31820e1e22 > 2TB numbers in vgdisplay_full 2002-02-13 20:21:13 +00:00
Joe Thornber
4849e8cd6d o snapshot support for the text format.
The logical_volumes, and snapshots sections of the text format are now
optional.
2002-02-13 13:29:16 +00:00
Joe Thornber
77e3b460aa o First pass at format1 snapshot support. 2002-02-13 11:43:29 +00:00
Joe Thornber
b5321001f8 o First changes to add snapshot support.
I'm taking a different route from LVM1 here in that snapshots are a
seperate entity from the logical volumes, I think of them as an
application of an LV (or two lvs rather).  As such there is a list of
snapshots held against the vg, and there is *not* a SNAPSHOT, or
SHAPSHOT_ORG flag in lv->status.
2002-02-12 16:31:31 +00:00
Patrick Caulfield
38eba9f5ea use portable <inttypes.h> macros for printing. 2002-02-12 14:12:13 +00:00
Joe Thornber
ea6f399454 o Turn the device_create_* functions into device_populate_*, they only
fill in an already created dm_task.  This allows common code, such
  as minor number selection, and read_only to be lifted.
2002-02-12 11:15:45 +00:00
Alasdair Kergon
f8bf2d7b7d Run through indent - no (intentional) changes to any code. 2002-02-11 21:00:35 +00:00
Alasdair Kergon
c4856caebb Preparation for an LVM2 liblvm - pass cmd_context into each tool and
link some globals that the tools need into that structure.
2002-02-11 20:50:53 +00:00
Alasdair Kergon
fc1030bb22 Now that most of the usage of 'stack' only occurs when there's an error,
don't suppress it from the screen output any longer.
2002-02-11 18:25:18 +00:00
Alasdair Kergon
9eb6cad8dc dbg_free(tc->desc) 2002-02-11 18:21:54 +00:00
Alasdair Kergon
0fa2a78dce Document return codes. 2002-02-11 17:42:02 +00:00
Joe Thornber
a56fa1558b o Split activate.c into a high level (remaining in activate.c) and low level (ll-activate.[hc]) API.
o  Creation of a device from an lv now lives in activate-lv.c
2002-02-11 15:48:34 +00:00
Alasdair Kergon
261c73a997 o Support locking with local lock files
o Disable control-c during updates (except if blocked waiting for a lock)
2002-02-11 15:42:34 +00:00
Joe Thornber
929c1333ca o Little recipe for testing LVM2 with loopback devices. 2002-02-11 12:01:59 +00:00
Joe Thornber
286a79d94d o Added functions to display what's in the archive.
o  For now vgcfgrestore -l <vg> displays this list.

A bit hacky, but it'll get better.
2002-02-11 11:43:17 +00:00
Alasdair Kergon
8b951f99da Locking prototypes. 2002-02-08 14:30:37 +00:00
Alasdair Kergon
abb449bca0 move defaults.h 2002-02-08 14:28:52 +00:00
Alasdair Kergon
bd084028d1 Move defaults.h 2002-02-08 14:28:14 +00:00
Joe Thornber
138a27570b o I decided that the archive_format shouldn't really be a format at
all since it only supports vg_write.  It has been replaced with:

int archive_vg(struct volume_group *vg,
	       const char *dir,
	       const char *desc,
	       uint32_t retain_days,
	       uint32_t min_archive);

which is now called directly by tools/archive.c
2002-02-08 11:58:18 +00:00
Joe Thornber
c2ed40a74f o Add cmd_line field to struct cmd_context
o  Text format now has a description and time field at the top level.

o  archiving and backup set the description appropriately. eg,

   for an archive:

     description = "Created *before* executing 'lvextend test_vg/lvol0 -l +1'."
     creation_time = 1013166332

   for a backup:

     description = "Created *after* executing 'lvextend test_vg/lvol0 -l +1'."
     creation_time = 1013166332

This is preparing the way for a simple vgcfgundo command.
2002-02-08 11:13:47 +00:00
Heinz Mauelshagen
a7e7a00cab Poor mans lvmdiskscan 2002-02-05 14:31:57 +00:00
Alasdair Kergon
64a31ab3cd Another release (includes some fixes from last week; persistent minors,
partial activation etc.)
2002-02-04 13:30:21 +00:00
Alasdair Kergon
71958bc0f1 lv->minor >= 0 (ejt) 2002-02-04 13:08:31 +00:00
Alasdair Kergon
366ec35612 Basic support for persistent minor numbers;
slightly different from the current LVM1 method.

  lvcreate --persistent y  --minor 10   (to specify when created)
  lvchange --persistent n  (to turn off)
  lvchange --persistent y  --minor 11   (to change)

--persistent uses a new LV status flag stored on disk
minor number is stored on disk the same way as LVM1 does
(but major number stored is 0; any LVM1 major/minor setting gets lost)

  lvchange -ay --minor 12 (to activate using minor 12, regardless of the
                           on-disk setting, which doesn't get changed)

--minor == -m
--persistent == -M
2002-02-01 17:54:39 +00:00
Alasdair Kergon
3738f6e8ae Failure signalled by -1 not 0; MAX_DEVICES 256 (was 64); change a '>' to '>='. 2002-02-01 17:39:20 +00:00
Alasdair Kergon
051a8e2af1 Display error when running unimplemented functions. 2002-01-31 20:37:26 +00:00
Alasdair Kergon
2f43f28d5e Remove gcc -D to support as different gcc versions handle it differently. 2002-01-31 20:15:26 +00:00
Alasdair Kergon
b64769754b "exit" means "quit" (lamer) 2002-01-31 20:08:52 +00:00
Joe Thornber
a97daa18d1 o Remove redundant dbg_free. 2002-01-31 15:28:30 +00:00
Alasdair Kergon
b6556dce8b Remove stray comma. 2002-01-30 17:25:51 +00:00
Alasdair Kergon
aa8d8bc8b5 Propagate volume group read-only setting down to its logical volumes.
(Might sometimes be safe to relax this restriction.)
2002-01-30 17:12:14 +00:00
Alasdair Kergon
0800dcfdc4 Basic support for (read-only) partial activation if any PVs are
missing from a VG.  (Linear targets use the device-mapper 'error' target
which returns ioerror; striped targets use '/dev/ioerror' for now - which must
already exist e.g. as a sufficiently large block device version of /dev/zero).
2002-01-30 15:33:12 +00:00
Heinz Mauelshagen
12b0101e94 quotes around names in output 2002-01-30 15:04:48 +00:00
Alasdair Kergon
021b391a02 Allocate fixed space for vg->system_id when vg is created, instead of
dynamically.
2002-01-30 12:47:29 +00:00
Alasdair Kergon
d11e2b6057 Correct statement order for case when 'stripes' parameter is not supplied. 2002-01-30 12:17:40 +00:00
Alasdair Kergon
264d90e7e5 add vgimport 2002-01-29 19:23:46 +00:00
Alasdair Kergon
f9f3da9e78 o A vgimport implementation
o Require -a or <list of vgs> parameters with vgexport/vgimport
o Allow pvcreate -ff to destroy exported/partial VGs
2002-01-29 19:19:37 +00:00
Alasdair Kergon
6435b49153 o Basic support for exporting (but importing not completed yet).
o When volume group does not have write flag set, prevent changes to it.
o Preparation for partial activation (not completed yet).
2002-01-29 17:23:33 +00:00
Alasdair Kergon
f9aa2941cf Display 'exported' status. 2002-01-29 16:30:18 +00:00
Alasdair Kergon
5a933d4bee Add list_iterate that's safe with deletions. 2002-01-29 16:28:52 +00:00
Heinz Mauelshagen
5536aea0df Date changed 2002-01-29 15:54:49 +00:00
Heinz Mauelshagen
976666d216 Zero gap after PV structure on write to disk in order to make non LVM tools happier (AED's idea and patch for LVM1) 2002-01-29 15:52:11 +00:00
Heinz Mauelshagen
9a5bcd4392 fixed div bug in calculation of end in calculate_extent_count 2002-01-29 15:43:04 +00:00
Heinz Mauelshagen
812060a118 Check that vgname doesn't already exits in dev_dir 2002-01-28 16:30:42 +00:00
Joe Thornber
089b5052e6 o There were some alignment problems with pool-debug which I've resolved
by allocating the data block with an additional dbg_malloc.

o  Added an assertion to check that no one is requesting alternate
   alignment for memory allocated from pool.  I can't see us needing this
   for LVM2.
2002-01-28 09:16:09 +00:00
Alasdair Kergon
874e5d72f4 *** empty log message *** 2002-01-27 21:48:05 +00:00
Alasdair Kergon
6b11de1329 Tweak some error message levels. 2002-01-27 21:30:47 +00:00
Alasdair Kergon
2245a7ad8d If lv isn't active, skip reactivation. 2002-01-25 22:58:01 +00:00
Alasdair Kergon
ee5ec1b870 Prevent lvextend from adding segments with different stripe characteristics
at the moment because the old LVM format doesn't support this.
2002-01-25 21:14:43 +00:00
Alasdair Kergon
74ccfe851b The latest attempt at making extended striped LVs work portably with LVM1. 2002-01-25 20:24:14 +00:00
Alasdair Kergon
e1c24bd5a2 Set pv->pe_size when reading in text-file backup.
Otherwise LVM1 decides the PV structure is corrupt.
But do we need to keep both pv->pe_size and vg->extent_size
in internal metadata or can we generate pvd->pe_size when writing out
a PV that belongs to a VG?
2002-01-25 20:21:13 +00:00
Alasdair Kergon
1349b79728 Only remove symbolic links when deactivating.
(if this code didn't create it, don't delete it)
2002-01-25 20:17:44 +00:00
Joe Thornber
d294d7604c o Tidy 2002-01-25 13:41:13 +00:00
Alasdair Kergon
01df2cf464 Have a pe_total check using theoretically big number instead of the
unnecessarily small limit LVM1 imposes in vgcreate (but not vgextend)
2002-01-24 23:35:56 +00:00
Alasdair Kergon
45b7322488 Don't bother to write out an empty cache. 2002-01-24 23:17:16 +00:00
Alasdair Kergon
b3055e992f Fix the device cache to cope reasonably safely with device name changes.
This should be a rare occurrence so the aim is to recover if it's
straightforward to do so, otherwise just to abort the operation.
If people *knowingly* change device names, they should always run vgscan
afterwards.

A few bytes of memory gets leaked inside a pool each time an alias
has to be discarded - it's not worth restructuring the code to reuse it.

More of LVM2 needs updating to pass device objects (or uuids) about
instead of pathnames so that resolution of pathname->object only happens
once per operation.

dev_cache_get() should now always return the *current* device at the path given

dev_name_confirmed() replaces dev_name() whenever it's important to
know that name for the device is still current (ie when opening it).
If the cache doesn't know a current name, the function fails.

dev_open() guarantees that the file descriptor returned is for the dev_t
of the device structure it was passed.
2002-01-24 23:16:19 +00:00
Alasdair Kergon
3da548565c Clear a FIXME about checking for identical devices by comparing dev_t
instead of name.
2002-01-24 22:37:24 +00:00
Heinz Mauelshagen
a975e85548 removed ~64limit for PEs per PV agk introduced 2002-01-24 19:20:35 +00:00
Joe Thornber
c4b5ade752 o Limit for number of extents should be 65534. 2002-01-24 17:32:56 +00:00
Alasdair Kergon
a4b61b0794 Improve allocation error messages when PVs in a VG have the allocatable
flag unset.
2002-01-24 17:26:00 +00:00
Alasdair Kergon
f6011184b8 Impose max PE limit for each PV. 2002-01-24 17:24:32 +00:00
Joe Thornber
74de118c6e o Add check for > 65k extents in a single lv. 2002-01-24 17:16:36 +00:00
Joe Thornber
9c25e77c17 o Add extra parameter to lv_manip fns 2002-01-24 17:15:49 +00:00
Joe Thornber
440113e67e o extra fid parameter to lv_manip fns 2002-01-24 17:15:24 +00:00
Joe Thornber
a11b60c445 o Remove pointless calculation. 2002-01-24 14:15:42 +00:00
Alasdair Kergon
a6052681ad Ignore all except one PV found with the same UUID. Use one which
has the md major number if there is such.
2002-01-24 13:36:33 +00:00
Alasdair Kergon
482d50536a Fix dev_close arg. 2002-01-24 13:31:18 +00:00
Alasdair Kergon
25c79a4fcd Remove any core files on distclean. 2002-01-24 13:30:40 +00:00
Joe Thornber
02946144ac o typo 2002-01-24 09:54:09 +00:00
Joe Thornber
71a360e9a3 o Cut and paste description of how pvmove works that I was mailing someone. 2002-01-24 09:26:13 +00:00
Alasdair Kergon
f7912d88b1 o Remove redundant symlink-handling code.
o When opening device, return error if its cached name is incorrect (eg if
  it's changed since the cache was generated).  This prevents use until
  the cache is rebuilt (eg with vgscan).  Doesn't catch every case.
2002-01-23 18:55:01 +00:00
Alasdair Kergon
975101d7d2 Avoid using VG metadata on PVs that are not in VGs. 2002-01-23 15:50:34 +00:00
Alasdair Kergon
ef58c5ff55 *** empty log message *** 2002-01-23 12:25:30 +00:00
Alasdair Kergon
e10221804a Silently remove any existing symlink before creating a new one. 2002-01-22 19:58:37 +00:00
Alasdair Kergon
284ed9ee0e Update with info on how to configure command output to look like LVM1 2002-01-22 19:20:46 +00:00
Alasdair Kergon
5d7b961997 Reviewed interaction with lib/activate now that the interface has settled down. 2002-01-22 19:11:12 +00:00
Alasdair Kergon
c699a5c4b4 New config options to customise message output. 2002-01-22 15:33:57 +00:00
Alasdair Kergon
1f4ceb89cf Customisable message output prefix / indentation. 2002-01-22 15:33:40 +00:00
Joe Thornber
0934ca0040 o added BUGS file. 2002-01-22 14:40:38 +00:00
Joe Thornber
4738f892c2 o Fix inverted logic in list_empty test. 2002-01-22 14:16:27 +00:00
Alasdair Kergon
33004fcf33 old file 2002-01-22 13:29:34 +00:00
Alasdair Kergon
34d214c166 Update. Ready to release? 2002-01-22 13:11:01 +00:00
Alasdair Kergon
a56cd92a1e No need for file output to default to stderr now that log file can be
specified in config file.
2002-01-21 19:05:00 +00:00
Alasdair Kergon
7251348507 Insert a missing hash_remove. 2002-01-21 19:04:13 +00:00
Joe Thornber
01cd5c84d6 o Allow fractional parts for size args. eg, lvcreate -L 34.4M
o  Fix a couple of bugs related to the earlier lv_list change
2002-01-21 17:43:10 +00:00
Joe Thornber
e210599fa6 o Similar changes for lv_list. 2002-01-21 16:49:32 +00:00
Joe Thornber
dbe7cee7e9 o fail if create_pv_list would produce an empty list. 2002-01-21 16:15:25 +00:00
Joe Thornber
7370d88ceb o Typo in comment 2002-01-21 16:10:36 +00:00
Joe Thornber
34458e0c57 o Changed
struct pv_list {
	struct list list;
	struct physical_volume pv;
   };

   to

   struct pv_list {
	struct list list;
	struct physical_volume *pv;
   };


o  New function in toollib 'create_pv_list', which creates a list of pv's
   from a given command line array of pv's.

o  Changed lvcreate/extend to use this (fixes lvextend [pv list] bug).
2002-01-21 16:05:23 +00:00
Alasdair Kergon
05c8c3abf2 Is this sufficient to fix make -j? 2002-01-21 16:02:55 +00:00
Patrick Caulfield
e9d464b4d3 Fixx OB1 error in max LV and max PV numbers 2002-01-21 14:53:47 +00:00
Joe Thornber
6968c3ab9b o Changed find_pv_in_vg, and find_lv_in_vg to return a struct pv_list * and
struct lv_list * respectively.
2002-01-21 14:28:12 +00:00
Joe Thornber
131a8a9650 o names.[hc] 2002-01-21 13:11:03 +00:00
Joe Thornber
379ecbf9a9 o lvdisplay now gives a segment map for the -m option. 2002-01-21 12:05:39 +00:00
Joe Thornber
7b9dfa9a28 o removed display_uuid
o use id_write_format from lib/uuid/uuid.h instead
2002-01-21 11:29:06 +00:00
Joe Thornber
fbd0f5eed2 o move the path building functions to lib/activate/names.c
o  Update activate.c and fs.c to use them

o  device names are now of the form <vg>:<lv>
2002-01-21 11:06:32 +00:00
Alasdair Kergon
5970f904ae Allow syslog facility to be set, or turned off, from the config file. 2002-01-18 21:26:37 +00:00
Alasdair Kergon
8cbcb2868d Display something in the "hypothetical" unknown log level case. 2002-01-18 19:38:19 +00:00
Alasdair Kergon
8ff2a4b026 Use same log levels as LVM2. 2002-01-18 19:37:26 +00:00
Alasdair Kergon
ae14d205a5 Allow compilation against a device-mapper that was installed into $DESTDIR
Always check for negative (error) return code from lv_active()
2002-01-18 16:43:19 +00:00
Alasdair Kergon
ec5d560ec5 More updates. 2002-01-18 13:45:12 +00:00
Heinz Mauelshagen
fb543b53c0 added before 2.1 item 2002-01-18 11:07:26 +00:00
Alasdair Kergon
39c16422e2 beta1-pre1 tagged, but there's still some documentation to update/write. 2002-01-17 18:48:08 +00:00
Alasdair Kergon
4d5b273ebe Support --version argument and 'version' shell command. 2002-01-17 16:39:24 +00:00
Alasdair Kergon
ed6a860fad Add function that returns the library version. 2002-01-17 14:13:25 +00:00
Alasdair Kergon
423e579292 Add another level of symlink to library name (like LVM1) so people who find
themselves running multiple incompatible kernel versions will just need
to swap symlinks at boot.
2002-01-17 13:37:09 +00:00
Alasdair Kergon
ee11aa9e75 Use additional version numbers.
Kernel driver has a version number (stored in kernel/VERSION).
  The first two components of this (0.94) give the version number of the
  ioctl interface.  This number must be changed whenever a change is
  made to the ioctl interface that breaks backwards compatibility.

  The library has a version number (stored in VERSION) which is
  used for linking.
  The first and/or second component of this must be changed whenever
  a change is made to the library API that breaks backwards
  compatibility.
2002-01-17 13:19:55 +00:00
Alasdair Kergon
c46d20fa92 o pvcreate --uuid to specify the uuid (required before using vgcfgrestore
onto a new device).  uuid specified must not already exist on the system.
o More message tidying.
o When checking for label, only read PV metadata.
o Add ataraid.  [Needs moving into config/defaults files.]
2002-01-16 18:10:08 +00:00
Joe Thornber
dc8d17574c o save before committing 2002-01-16 15:53:42 +00:00
Joe Thornber
5c17cd04c8 o lvm.conf file that contains the same settings that would be assumed if it
wasn't there.  A good starting point for tweaking.
2002-01-16 15:52:53 +00:00
Alasdair Kergon
67ada02076 Move test flag from log to global section of config file. 2002-01-16 15:20:51 +00:00
Alasdair Kergon
32d94c2eaf o Don't update vgcache when (not really) writing in test mode.
o Don't continue iterating through a possibly-deleted list.
2002-01-16 14:43:27 +00:00
Alasdair Kergon
687b39a12a Remove a duplicate disk read (can_handle). 2002-01-16 13:09:26 +00:00
Patrick Caulfield
705af407bf #include <string.h> 2002-01-16 12:02:06 +00:00
Joe Thornber
080052da2e o Set the segment counter back to 1, for a new LV. 2002-01-16 11:34:29 +00:00
Joe Thornber
ef735fd92a o Add pvmove to the stub file. 2002-01-16 11:27:19 +00:00
Joe Thornber
17c16dcafc o Knock out the "'%s' is not a block device" debug message. 2002-01-16 09:23:28 +00:00
Alasdair Kergon
a89b3018fb Reduce 'no label found' message severity to debug level. 2002-01-16 00:01:36 +00:00
Alasdair Kergon
851e2ebd32 Fix function typecasts. 2002-01-15 23:47:56 +00:00
Alasdair Kergon
1225ce7fe8 o More comprehensive config parameter debugging messages.
o Make /proc configurable.
 o Review hard-coded "/dev"s - made 2 more of them configurable.
2002-01-15 23:34:13 +00:00
Alasdair Kergon
7e77a31b96 o missing labeller free
o updated vgcfgrestore args
o change _check_for_open_devices only to check devices present in the hash
  table instead of using dev_iter which triggers a full scan even when only
  displaying command line help
2002-01-15 21:28:04 +00:00
Joe Thornber
d146b9002f o Actually check in vgcfgrestore. 2002-01-15 18:17:57 +00:00
Joe Thornber
1f9d567b23 o vgcfgrestore works ! (with the couple of examples I tried). 2002-01-15 17:37:23 +00:00
Alasdair Kergon
ed1b3a023c Another ioctl interface update:
Supply offset to start of variable data area (so struct size can change
without breaking backward compatibility)
  Add command that just returns the driver version
2002-01-15 15:21:57 +00:00
Joe Thornber
1ca18f501a o split the uuid -> device map out from vgcache
o  roll vgcache back to agk's implementation, we'll revisit this as part
   of the cluster integration.

o  change the extra_info field in a label to be a void *
2002-01-15 10:24:48 +00:00
Alasdair Kergon
49588ccd98 Some ioctl interface changes. (Do we want these?)
- use status bits (so we can add flags without changing the struct size)
  - use dev_t
2002-01-14 23:07:32 +00:00
Joe Thornber
098dedc092 o Non-caching implementation of new vgcache interface. 2002-01-14 11:43:52 +00:00
Joe Thornber
b06f6b9545 o LVM1 labeller. 2002-01-14 10:00:56 +00:00
Joe Thornber
ba3cb94999 o Reformat comment and correct typo. 2002-01-14 09:59:12 +00:00
Alasdair Kergon
74c67fbf4b o Add rename support to dmsetup.
o Add support to use specified minor number to library and dmsetup.
2002-01-11 12:12:46 +00:00
Patrick Caulfield
32b46e4910 Couple of typos fixed. 2002-01-11 11:34:53 +00:00
Joe Thornber
ecf5539ed2 o Put in the pv_hash which stores the pv section name -> pv struct mapping. 2002-01-11 11:09:12 +00:00
Joe Thornber
ac9db4e4d5 o label.c now compiles. 2002-01-11 10:43:32 +00:00
Patrick Caulfield
0eb96094b0 Change lvm2_label to use Joe's new label switch system. 2002-01-11 10:39:56 +00:00
Alasdair Kergon
30b3ac7dc5 Support the renaming of active mapped devices (ioctl interface only). 2002-01-10 23:29:16 +00:00
Alasdair Kergon
0092790c7d o ACTIVE is no longer a status flag - lv_active() used to check if an LV
is active in the device-mapper.
o Many operations can be carried out regardless of whether the VG is
  active or not.
o vgscan does not activate anything - use vgchange.
o Change lvrename to support renaming of active LVs.
o Remove '//' appearing in some pathnames.
o Dummy lv_check_segments() for compilation.
2002-01-10 23:21:07 +00:00
Joe Thornber
28909d8a51 o _read_id function for import.c 2002-01-10 18:12:26 +00:00
Alasdair Kergon
b20cfbb7b6 More steps towards successful compilation. 2002-01-10 16:48:28 +00:00
Alasdair Kergon
97639bd0a8 Add 'get' functions. 2002-01-10 16:47:58 +00:00
Alasdair Kergon
161ec73c96 More detail in error msgs. 2002-01-10 16:47:25 +00:00
Alasdair Kergon
957d6bea15 Separate constant fields from variable ones. 2002-01-10 16:47:04 +00:00
Alasdair Kergon
f8b6e5b414 Clarify terminology:
VG is resizeable  - PVs can be added or removed
  PV is allocatable - free extents on it may be allocated to LVs
2002-01-10 15:09:51 +00:00
Joe Thornber
1ab450870e o Moved the current label.[hc] sideways to lvm2_label.[hc]
o  First pass at low level labelling switch.  This allows us to
   register different label types (eg, lvm1, lvm2).
2002-01-10 15:01:58 +00:00
Alasdair Kergon
de45f4884c Allow for multiple spellings / backwards compatibility of renamed
command line options.
      vgchange --resizeable y
      pvchange --allocatable y
But --allocation is still allowed for both (as LVM1) and --resizable is OK.
2002-01-10 14:46:50 +00:00
Joe Thornber
5da1f3e7c8 o vgcfgrestore. 2002-01-10 14:27:47 +00:00
Alasdair Kergon
983014952b Temporary file creation & renaming. 2002-01-10 12:22:17 +00:00
Joe Thornber
55298019a3 o First pass at import.c. Still waiting for label code for the uuid->pv
mapping.
2002-01-10 11:18:08 +00:00
Joe Thornber
a1ffc3f271 o Put in the 'out of memory' log_err for pool. 2002-01-10 09:35:55 +00:00
Alasdair Kergon
2fb60aa997 Renamed to archive.c 2002-01-09 19:17:11 +00:00
Alasdair Kergon
f5ec76537a o Rename many occurrences of 'backup' to 'archive' to reduce confusion.
o Extract file creation/renaming code into a library and change backup code
  to use it too.
o Support umask.
o Bring lvm.conf man page up-to-date.
2002-01-09 19:16:48 +00:00
Alasdair Kergon
728491fd2b Accept octal values for numbers (such as umask). 2002-01-09 18:53:07 +00:00
Joe Thornber
d9d3f2b9e4 o Let the comment wars begin. 2002-01-09 14:14:07 +00:00
Joe Thornber
3fe4864f65 o new function backup_remove(const char *vg_name), to be called from vgremove. 2002-01-09 14:07:49 +00:00
Joe Thornber
0b156f22a4 o Reformat comments. 2002-01-09 13:56:11 +00:00
Alasdair Kergon
35b1d93813 Add archiving. 2002-01-09 13:17:14 +00:00
Alasdair Kergon
d770851ac0 o Try to improve NFS-safety for temporary file creation (unique name; O_APPEND
+ fcntl lock) and rename (using hard link), avoiding any "real" archive
  files ever being zero length.
o Fix filename parsing & ordered list handling.
2002-01-09 13:16:19 +00:00
Alasdair Kergon
989e7b1033 Explicitly close (=>flush) files. 2002-01-09 13:07:03 +00:00
Alasdair Kergon
c4e0eb7b49 Allow pool_begin_object in empty pool. 2002-01-09 13:06:02 +00:00
Alasdair Kergon
71f5d0dac7 Another attempt to support both readline versions. 2002-01-08 19:17:08 +00:00
Alasdair Kergon
561b0c4381 call archive_exit() & backup_exit() on exit 2002-01-08 18:14:04 +00:00
Joe Thornber
995fbc7330 o Remove anomalous punctuation. 2002-01-08 10:51:13 +00:00
Joe Thornber
10ab8949c4 o Introduction to pool for those without psychic powers. 2002-01-08 10:47:17 +00:00
Alasdair Kergon
c441202fea fixes for compilation 2002-01-07 23:28:25 +00:00
Alasdair Kergon
ca261b0bee Sync. 2002-01-07 23:04:48 +00:00
Alasdair Kergon
52f3709f67 Sync tidy. 2002-01-07 22:49:04 +00:00
Alasdair Kergon
c2ca6187fe If a device somehow became suspended, lvchange -ay now reactivates it. 2002-01-07 22:36:12 +00:00
Alasdair Kergon
671a13d295 Support for read-only. 2002-01-07 22:28:36 +00:00
Alasdair Kergon
14c3e2eccf Missing close() in error case. 2002-01-07 22:25:57 +00:00
Alasdair Kergon
08e5b852c2 tidying 2002-01-07 22:01:50 +00:00
Joe Thornber
1c9606c824 o vgcreate wasn't setting vg->cmd 2002-01-07 15:27:55 +00:00
Joe Thornber
3cd47b5c9b o New function 'merge_segments'
o  Call said function at end of lv_extend
2002-01-07 15:08:28 +00:00
Joe Thornber
aedc729087 o tidy up renaming of archive files. 2002-01-07 14:21:33 +00:00
Joe Thornber
5f7cfa3fa9 o sync tool changes for backup stuff. 2002-01-07 11:12:11 +00:00
Joe Thornber
0083f30af5 o Added find_config_bool 2002-01-07 10:23:52 +00:00
Joe Thornber
4a06f05ef5 o Get format-text.c compiling. 2002-01-07 09:16:20 +00:00
Joe Thornber
8f37cadce8 o sync laptop to test machine. 2002-01-07 09:05:31 +00:00
Alasdair Kergon
a11603ca6c Imported man pages from LVM1 with some quick LVM2 updates. 2002-01-04 20:35:19 +00:00
Alasdair Kergon
86274842e9 The start of an lvm man page. 2002-01-04 18:56:56 +00:00
Alasdair Kergon
cf9c955a44 Document remaining configuration file parameters. 2002-01-04 17:49:38 +00:00
Joe Thornber
55d828c35f o Revert to the 6-4-4-4-4-4-6 format for uuid's
o  When reading a uuid all -'s are stripped, wherever they are.
2002-01-04 16:55:14 +00:00
Alasdair Kergon
cdff28aca6 Put device name in quotes. 2002-01-03 17:47:48 +00:00
Joe Thornber
b9da39274f o High level archiving and backup functions.
I've split the old autobackup function into two seperate areas:

'archiving' is performed *before* a vg configuration is changed.  This
produces a numbered backup in /etc/lvm/archive.

A 'backup' is performed *after* a vg change.  So the directory /etc/lvm/backup
will hold the  a copy of the current configuration.
2002-01-03 15:46:48 +00:00
Alasdair Kergon
c379aa5782 stub for read-only functions with fs interface 2002-01-03 15:12:02 +00:00
Alasdair Kergon
9dcabac9dd Fix final comma in arrays. 2002-01-03 12:43:01 +00:00
Alasdair Kergon
794f3a2b9f *** empty log message *** 2002-01-03 12:39:04 +00:00
Joe Thornber
2066121b7c o Added -r, --read-only switch to dmsetup for use with create and reload. 2002-01-03 10:39:21 +00:00
Alasdair Kergon
0c4067f143 o Allow the definition of read-only devices (ioctl interface only) (Joe)
o Add version number to ioctl structure with error on kernel/library mismatch
2002-01-02 19:01:09 +00:00
Joe Thornber
8aa69243b7 o Added section on the syntax of the config file, with an informal grammar. 2002-01-02 17:54:57 +00:00
Alasdair Kergon
8697263bde Fix $DESTDIR support 2002-01-02 14:23:10 +00:00
Alasdair Kergon
ea25c4f65c Tidy makefiles - $DESTDIR & shared library version (like LVM1) 2002-01-02 13:40:49 +00:00
Alasdair Kergon
82ac3ebd7e Add test mode parm. 2001-12-31 22:12:03 +00:00
Alasdair Kergon
13cb94909c o Add autobackup support to tools (follows most vg_write calls).
o Skip autobackup when in test mode.
o Set test mode from config file.
o Create system/backup dirs if not present (unless LVM_SYSTEM_DIR holds "").
2001-12-31 21:27:39 +00:00
Alasdair Kergon
b57ca2a763 vgcache.h inclusion (avoid compiler warning) 2001-12-31 19:18:44 +00:00
Alasdair Kergon
83c49e9745 o Use lvm_snprintf wherever return value is used
o Add parameters to set retention limits for backups
2001-12-31 19:09:51 +00:00
Alasdair Kergon
e15771d78d Remove some old files. 2001-12-31 17:34:51 +00:00
Alasdair Kergon
6edc4920ba Redundant. 2001-12-31 17:26:42 +00:00
Alasdair Kergon
302bb1bd93 Document lvm.conf fields 2001-12-31 17:20:22 +00:00
Alasdair Kergon
529b1bceee Outline docs 2001-12-31 16:12:40 +00:00
Alasdair Kergon
42cd47d32e o Allow more default values to be overridden from config file.
o Cope with both the readline versions used around here.
2001-12-31 15:20:18 +00:00
Alasdair Kergon
711d884c2e Fix C99 error case handling (snprintf ret value >= buffer size). 2001-12-31 15:17:34 +00:00
Alasdair Kergon
183d1c4674 Fixes for compilation. 2001-12-31 15:14:44 +00:00
Alasdair Kergon
faed63a0bb Remove unused --with_kernel_dir
Current version of LVM2 instead relies on /usr/include/libdevmapper.h
which gets installed by the device mapper package.
(Should this location now be configurable?)
2001-12-31 15:13:42 +00:00
Alasdair Kergon
53bff262f8 Revised ioctl/dmfs merge with fixes for bugs found in tests. 2001-12-20 20:32:14 +00:00
Joe Thornber
3251a708e4 o Added a quick vgcfgbackup, needs parameters as yet. 2001-12-20 16:05:14 +00:00
Joe Thornber
b5dbdbf7b2 o Debug version of the pool_grow stuff. 2001-12-20 12:27:41 +00:00
Joe Thornber
a9649e92c9 o sync backup changes 2001-12-20 11:52:54 +00:00
Patrick Caulfield
b561f1fa8b Wipe the first label if writing the second one failed. 2001-12-18 14:39:32 +00:00
Joe Thornber
cecd7491b5 o sync the backup stuff 2001-12-17 19:46:10 +00:00
Joe Thornber
55a66322b5 o history is now saved in ~/.lvm_history 2001-12-17 17:59:58 +00:00
Joe Thornber
155c31a2d7 o Shuffled completion functions around so we dont have to declare them
at the top of the file.

o Changed completion_matches -> rl_completion_matches, and added some consts.

This will probably break things on pre readline 4.2 systems.
2001-12-17 17:18:47 +00:00
Joe Thornber
a89ce91089 o Changed the macro name in args.h from 'xx' to 'arg'
o  There is now a _default_debug, and _default_verbose level, when
   using lvm interactively -vv and -dd switches just effect the current
   command.

o  Added a --quiet switch which sets both verbose and debug to zero.
2001-12-17 16:58:17 +00:00
Joe Thornber
b897fe6700 o Use lvm_snprintf 2001-12-17 14:05:43 +00:00
Joe Thornber
548a351b06 o Add symlink for lvm-string.h 2001-12-17 14:04:33 +00:00
Joe Thornber
4b1da57ca1 o lvm_snprintf
Could everyone please use this from now on.
2001-12-17 14:04:10 +00:00
Joe Thornber
529aec7f25 o Remove LVM_CONFIG_FILE environment variable.
o  Introduced the LVM_SYSTEM_DIR variable.

This makes more sense because the persistent cache, and backup directories
are config specific.

eg, I use /etc/lvm for running my real LV's

    but I have another directory /dev/lvm_loops that contains a config
    that allows only loopback devices, I use this for testing.
2001-12-17 12:01:09 +00:00
Heinz Mauelshagen
1661e545cb Typos in error messages 2001-12-17 11:07:33 +00:00
Joe Thornber
ec71d08878 I had another look at the argument processing code:
o You must list long args with no short option (eg. --version) at the
  front of the args.h file.

o If an argument has no short option, set the short option in args.h to '\0'

o The index into the 'the_args' var is now stored as the option value
  for getopt, iff there is no short opt.
2001-12-17 10:08:27 +00:00
Alasdair Kergon
ac258b7dd7 o Include dmsetup man page in build
o Allow pathname in dmsetup device arg
o Generated patches for 0.90.02
2001-12-14 13:30:04 +00:00
Patrick Caulfield
0f57876233 Write the location of both labels in the labels so we can check them. I don't do
much with this ATM (apart from check that they all match up).
Use a different CRC routine.
2001-12-14 13:15:15 +00:00
Joe Thornber
1d25a3693d o I figure if I can't remember how to use my code, then I should add
a comment.  It's quite cool, wish I remember writing it.
2001-12-13 16:09:06 +00:00
Alasdair Kergon
45fa428bf1 Handle orphan PVs too, so hints remain valid after vgreduce. 2001-12-13 15:08:58 +00:00
Joe Thornber
177fa80f1a o Man page for dmsetup 2001-12-13 13:46:21 +00:00
Patrick Caulfield
3261261bfe made the hard-coded 512 into BLOCK_SIZE just for neatness sake.
log_error() if writing the label fails so someone knows which was in error.
2001-12-13 08:40:47 +00:00
Alasdair Kergon
d4de7934f8 Add internal cache holding a 'hint' list of the PVs belonging to each VG.
A substantial speed-up - particularly in readline mode.
If the hints turn out to be wrong, the relevant parts get thrown away.
vgscan destroys it totally.  In both cases it then rebuilds itself as
required.
2001-12-13 00:07:29 +00:00
Alasdair Kergon
c3475af809 fix for clean compilation 2001-12-12 16:25:53 +00:00
Joe Thornber
b12f707812 o silly bugs 2001-12-12 16:22:38 +00:00
Joe Thornber
22c0c34d60 o pool-debug version of end_object wasn't returning the object. 2001-12-12 16:05:52 +00:00
Joe Thornber
a60b66f230 o Add error checking in _new_chunk 2001-12-12 14:54:24 +00:00
Joe Thornber
83f6e93628 o pool-debug versions of begin_object, grow_object etc. 2001-12-12 14:25:20 +00:00
Patrick Caulfield
222b5f0229 Build label code into the library 2001-12-12 09:09:04 +00:00
Patrick Caulfield
30aa383e26 Use a proper CRC calculation. 2001-12-12 09:05:44 +00:00
Patrick Caulfield
676b401294 - Change label format to include a string disk_type and a version number.
- The iterator can find labels by string and also appropriate version number (==,
  <= or any) if you want.
- Add labels_match() call that compares the two labels and returns an error if
  they do not match.
- Write labels in sector 1 & last rather than 2 & last as per Joe.
2001-12-11 16:49:40 +00:00
Alasdair Kergon
ebf57159de Apply make distclean to test subdirs too. 2001-12-11 16:26:34 +00:00
Patrick Caulfield
199d2aafec Fix label filter. 2001-12-11 14:17:10 +00:00
Joe Thornber
81952f56fd o Add output_date 2001-12-11 12:29:25 +00:00
Joe Thornber
c5bac82b43 o flags.c reads and writes a status bitset 2001-12-11 12:18:56 +00:00
Joe Thornber
081b86109c o Split import-export.c into two files. 2001-12-11 12:16:58 +00:00
Joe Thornber
8ac2028a75 o Update sample to a format that supports multiple vg's per file. 2001-12-11 12:15:08 +00:00
Patrick Caulfield
264fed1c9f Label reading/writing code.
Not tested the filter yet.
2001-12-11 11:42:30 +00:00
Joe Thornber
dd59f7b2c7 o Pretty print and read for uuid's 2001-12-11 11:40:34 +00:00
Patrick Caulfield
9245a760db Add a dev_get_sectsize call. 2001-12-11 10:18:49 +00:00
Alasdair Kergon
b61b32bbc3 Fixes for allocation of striped volumes. 2001-12-07 21:17:12 +00:00
Alasdair Kergon
09b3914f5d Fixes for library compilation. 2001-12-07 21:15:33 +00:00
Alasdair Kergon
fe644e4c9e Moved across to device-mapper repository. 2001-12-06 14:20:38 +00:00
steve
7b09bf2156 o Updated projects.txt to remove the earlier error which turned out to be
a build error.
2001-12-05 18:04:55 +00:00
Alasdair Kergon
987d0aae66 Various fixes & restructure to extract common code. 2001-12-05 16:41:52 +00:00
steve
9cbcbc1c22 o Removed unused MOD_INC/DEC_USE_COUNT 2001-12-05 12:00:01 +00:00
steve
cfc4e2bc60 o Added a few more projects 2001-12-05 11:58:43 +00:00
steve
a03405fa81 o Initial merge attempt
There are still a few odd things going on, so more debugging remains to be
done.
2001-12-05 11:28:41 +00:00
Alasdair Kergon
d5c9ccbe6e Correct activation message. 2001-12-05 00:04:18 +00:00
Alasdair Kergon
e52772d65f Added more log messages. 2001-12-04 23:20:27 +00:00
Joe Thornber
1e3259e728 o sync 2001-12-04 14:14:07 +00:00
Alasdair Kergon
e905a20a60 Tweaks for make install. -m args replaces verbose to display maps. 2001-12-03 20:23:53 +00:00
Alasdair Kergon
88e2be7a33 More striping support & fixes. 2001-12-03 16:27:16 +00:00
Joe Thornber
8939131600 o Comparison function was sorting things in ascending rather than
descending order.

o free off the sort array when finished with it.
2001-11-30 09:19:46 +00:00
Joe Thornber
ba37ebff8b o Striped allocator
o  Changed pv_map.c to maintain the list of free areas in size order, which
   is more helpful to the allocators.  If you want to allocate a bit of an
   area call consume_area(area, size), this will adjust the area if there's
   some space left and shuffle it to the correct place in the list.


Not tested.
2001-11-29 18:45:35 +00:00
Joe Thornber
28f4cb7e07 o I was reading striped volumes incorrectly. 2001-11-29 14:13:43 +00:00
steve
db1e7102cd o Confusingly, dmfs-tdir isn't gone, its now called dmfs-lv.c and its the
old dmfs-lv.c thats gone.
 o Dropped out support for multiple tables in line with ioctl interface
 o Some reordering to better support the userland library
 o Updated to 2.4.16

I'm fairly happy with the way that this is working now, so the next job is
to start the integration with the ioctl interface so there is a single
common dm.[ch] and selectable interfaces (fs or ioctl).

Further improvements can be made even now, but I hope to wait until we've
got this going and integrated and the libdm parts working as well before
investigating other avenues.
2001-11-29 14:00:04 +00:00
steve
07eb7a5830 New patches for 2.4.16 2001-11-29 13:44:46 +00:00
Alasdair Kergon
b7c6c685fa configure --with-interface=ioctl (default) or =fs to choose kernel interface 2001-11-28 21:03:50 +00:00
Alasdair Kergon
212134df70 Add autoconf & makefile structure like LVM2. 2001-11-28 20:08:11 +00:00
Alasdair Kergon
6eeb5528f5 Add -t or --test arg to all tools that update metadata to avoid
committing metadata changes or (de)activating.
2001-11-28 18:03:11 +00:00
Joe Thornber
54fad845c9 o Output the correct format for the stripe target 2001-11-28 17:52:27 +00:00
Alasdair Kergon
d6c0de6fc7 Fix single stripe resizing. 2001-11-28 16:16:44 +00:00
Alasdair Kergon
649c8649f7 Make source files depend on makefiles. 2001-11-28 15:00:49 +00:00
Joe Thornber
da2f53d1b1 o pool_free was leaving one block hanging around. 2001-11-28 14:58:33 +00:00
Alasdair Kergon
405139e3b8 o Tool support for segments.
o vgmerge working.
2001-11-28 13:45:50 +00:00
Alasdair Kergon
4f8d347171 Use CFLAGS during make rule generation. 2001-11-28 12:28:03 +00:00
Joe Thornber
bf0db4876c o pool-debug.c contains an alternative implementation of pool that gets
a seperate chunk of memory from dbg_malloc for each pool_alloc.  This
   will allow the bounds checking code in dbg_malloc to do it's stuff.

o  The normal implementation moved to pool-fast.c

o  pool.c now just contains a #ifdef and includes the appropriate .c file.

Alasdair, could you make sure that gcc -MM get's passed all the
CFLAGS please, otherwise the dependencies get calculated incorrectly.
2001-11-28 09:13:00 +00:00
Joe Thornber
47a14884d6 o Turn on pool debugging by default (-DDEBUG_POOL) 2001-11-28 09:07:53 +00:00
Alasdair Kergon
3a7bbc8b08 Fix a memory smash. 2001-11-27 23:12:06 +00:00
Joe Thornber
1b1d65372c o extra error checking 2001-11-27 20:03:45 +00:00
Joe Thornber
fd2faaa16e o These now compile. 2001-11-27 17:39:15 +00:00
Joe Thornber
0609cdb9ea o Get format1 building. 2001-11-27 17:29:56 +00:00
Alasdair Kergon
d3bb140f89 vgmerge first cut 2001-11-27 17:02:24 +00:00
Joe Thornber
b31dc66628 o Sync up todays work on converting to the segmented representation of
logical volumes.  It includes:

   format1 changes.

   metadata.h changes.

   lv_manip.c changed (striped allocation still not done though).

   activate.c changes.

Nothing has been near a compiler as yet.

Alasdair can you look at changing display.c to use to output the mappings
in a more segment oriented format please ?

I haven't put the span list into struct physical_volume to represent allocated
extents.  I think the burden of maintaining it for things like lv_extend may
out weigh it's uses.
2001-11-27 16:37:33 +00:00
Alasdair Kergon
09476171a6 Tool support for multiple (striped) segments (incomplete). 2001-11-27 13:42:37 +00:00
Joe Thornber
33dee813b5 o change chunk_size to stripe_size 2001-11-26 16:30:43 +00:00
Joe Thornber
bb4e73c40b o More metadata changes. 2001-11-26 16:18:48 +00:00
Alasdair Kergon
b1f23ffa94 LV create/extend prototype changes for striping 2001-11-26 15:31:46 +00:00
Joe Thornber
b0e8cec1e7 o make it obvious that stripe_segment is variable sized. 2001-11-26 13:15:22 +00:00
Joe Thornber
5077ae19bc o segments will have to be held as an array of pointers since they're now
variable sized.
2001-11-26 13:03:36 +00:00
Joe Thornber
0d8447bf59 o sync the new in core rep. for Alasdair.
This will break everything !  Hopefully things will be working again by
   this evening.
2001-11-26 12:49:29 +00:00
Alasdair Kergon
c6cf08a274 additional patch required 2001-11-23 12:35:31 +00:00
steve
dc49ae519e o Revised seq_file usage after discussions on linux-fsdevel 2001-11-22 15:14:20 +00:00
Joe Thornber
904539476a o Make sure that every switch has a short option, even if it's
non-displayable so we can remove the pointer mangling that was
   breaking 64bit arch.s
2001-11-22 14:37:07 +00:00
Alasdair Kergon
3fbf02dc82 o activation & active status tests
o lvdisplay fields from kernel
o update lv->size on resize
2001-11-21 19:32:35 +00:00
Alasdair Kergon
c9392a840d dmdir path 2001-11-21 19:20:41 +00:00
Joe Thornber
d164e8ab72 o Remove an old debug statement 2001-11-21 18:24:22 +00:00
Joe Thornber
6dc62c9fb6 o Display major number 2001-11-21 18:12:41 +00:00
Joe Thornber
87a9684d66 o use the major number returned from dm_ioctl. 2001-11-21 17:57:57 +00:00
Joe Thornber
94525e2f44 o There's no need to prefix dm_dir() with /dev/ anymore 2001-11-21 17:20:49 +00:00
Joe Thornber
b408b1b3b9 o You can now specify the dev directory for libdm
o  dm_dir() returns the full path to the device-mapper dir (eg, /dev/device-mapper).

o  put stat in on _rm_node
2001-11-21 17:08:37 +00:00
Joe Thornber
27c2f09e32 o Removed _check_devfs
o  We now do a stat to see if the device node is there
2001-11-21 16:47:10 +00:00
Joe Thornber
19bc4d3349 o Remove hard coded path to /dev/device-mapper/control 2001-11-21 15:49:45 +00:00
Alasdair Kergon
f2b6c424d6 Tidy makefiles 2001-11-21 15:41:14 +00:00
Joe Thornber
a49d4453e9 o Change name of libdm.h 2001-11-21 15:15:37 +00:00
Joe Thornber
65e50087b9 o Use MKDEV to build the dev_t for mknod 2001-11-21 15:14:35 +00:00
Joe Thornber
2d90f759d9 o Don't use dmt->dmi until it has been initialised. 2001-11-21 14:52:16 +00:00
Joe Thornber
4230ac7674 o Migration of device-mapper from LVM_WORK to it's own (public) repository.
Please use this one from now on.
2001-11-21 12:47:42 +00:00
Joe Thornber
d96e9182e9 o Oops, I thought this was checked in ages ago. 2001-11-21 09:21:31 +00:00
Joe Thornber
68c87b9616 o Sync. only 2001-11-21 09:20:05 +00:00
Joe Thornber
7f8e9a0b6d o _emit_target wasn't spotting contiguous targets properly. 2001-11-19 15:44:06 +00:00
Joe Thornber
81a229f2a5 o Use new info interface to dm. 2001-11-19 15:38:39 +00:00
Alasdair Kergon
8be7ae2733 vgdisplay 2001-11-19 15:20:50 +00:00
Patrick Caulfield
846bca4cb1 file cmgr.h was initially added on branch CLUSTER_TAG. 2001-11-19 14:40:32 +00:00
Patrick Caulfield
f36f353789 file cmgr.c was initially added on branch CLUSTER_TAG. 2001-11-19 14:40:32 +00:00
Patrick Caulfield
939a2731ed file clvm.h was initially added on branch CLUSTER_TAG. 2001-11-19 14:40:32 +00:00
267 changed files with 33862 additions and 10540 deletions

2
BUGS Normal file
View File

@@ -0,0 +1,2 @@
Snapshots under 2.4.18 can deadlock due to a bug in the VM system.
2.4.19-pre8 is fine.

340
COPYING Normal file
View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

483
COPYING.LIB Normal file
View File

@@ -0,0 +1,483 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

45
INSTALL Normal file
View File

@@ -0,0 +1,45 @@
LVM2 installation
=================
1) Install device-mapper
Ensure the device-mapper has been installed on the machine.
The device-mapper should be in the kernel (look for 'device-mapper'
messages in the kernel logs) and /usr/include/libdevmapper.h
and libdevmapper.so should be present.
The device-mapper is available from:
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
2) Generate custom makefiles.
Run the 'configure' script from the top directory.
If you wish to use the built-in LVM2 shell and have GNU readline
installed (http://www.gnu.org/directory/readline.html) use:
./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.
Run 'make install' from the top directory.
4) Create a configuration file
The tools will work fine without a configuration file being
present, but you ought to review the example file in doc/example.conf.
For example, specifying the devices that LVM2 is to use can
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.

View File

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

27
README
View File

@@ -1,2 +1,25 @@
This is pretty much empty so far...if you can't see subdirectories,
try 'cvs -f update'
This directory contains a beta release of LVM2, the new version of
the userland LVM tools designed for the new device-mapper for
the Linux kernel.
The device-mapper needs to be installed before compiling these LVM2 tools.
For more information about LVM2 read the WHATS_NEW file.
Installation instructions are in INSTALL.
This is beta-quality software, released for testing purposes only.
There is no warranty - see COPYING and COPYING.LIB.
Tarballs are available from:
ftp://ftp.sistina.com/pub/LVM2/tools/
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
To access the CVS tree use:
cvs -d :pserver:cvs@tech.sistina.com:/data/cvs login
CVS password: cvs1
cvs -d :pserver:cvs@tech.sistina.com:/data/cvs checkout LVM2
Mailing list for discussion/bug reports etc.
lvm-devel@sistina.com
Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel

35
TODO
View File

@@ -1,35 +0,0 @@
before alpha
------------
FIXME review
extra validation in format1 (must be done before alpha)
status flag review (confirm all use of ->status is consistent)
file system handling (being done)
error message review
correct handling of *existing* snapshots
review statics
review consistency checks for full compatibility with LVM1
iospace split/rename
before beta1
-----------
autobackup/text format
export/import
striping
64bit review
LVM1 compatible tool exit codes
before 2.0
----------
partial activation
atomic transactions
bidirectional format1/format2 migration tool
persistent minors
stats
snapshots
pvmove

1
VERSION Normal file
View File

@@ -0,0 +1 @@
2.00.03-cvs (2003-07-13)

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
# Configuration validation subroutine script, version 1.1.
# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
# Configuration validation subroutine script.
# 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.
# 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.
@@ -25,6 +29,8 @@
# configuration script generated by Autoconf, you may include it under
# 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.
# Supply the specified configuration type as an argument.
# 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
# It is wrong to echo any other type of specification.
if [ x$1 = x ]
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
me=`echo "$0" | sed -e 's,.*/,,'`
# First pass through any local machine types.
case $1 in
*local*)
echo $1
exit 0
;;
*)
;;
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
$0 [OPTION] ALIAS
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
# 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.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
linux-gnu*)
nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -94,7 +143,7 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple)
-apple | -axis)
os=
basic_machine=$1
;;
@@ -105,9 +154,17 @@ case $os in
-scout)
;;
-wrs)
os=vxworks
os=-vxworks
basic_machine=$1
;;
-chorusos*)
os=-chorusos
basic_machine=$1
;;
-chorusrdb)
os=-chorusrdb
basic_machine=$1
;;
-hiux*)
os=-hiuxwe2
;;
@@ -156,33 +213,60 @@ case $os in
-psos*)
os=-psos
;;
-mint | -mint[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
esac
# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
# Recognize the basic CPU types without company name.
# Some are omitted here because they have special meanings below.
tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
| 580 | i960 | h8300 \
| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
| mips64orion | mips64orionel | mipstx39 | mipstx39el \
| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
| mips64vr5000 | miprs64vr5000el | mcore \
| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
| thumb | d10v)
1750a | 580 \
| a29k \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
| c4x | clipper \
| d10v | d30v | dsp16xx \
| fr30 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| m32r | m68000 | m68k | m88k | mcore \
| mips16 | mips64 | mips64el | mips64orion | mips64orionel \
| 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
;;
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'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
i[34567]86)
i*86 | x86_64)
basic_machine=$basic_machine-pc
;;
# Object if more than one company name word.
@@ -191,24 +275,43 @@ case $basic_machine in
exit 1
;;
# Recognize the basic CPU types with company name.
# FIXME: clean up the formatting here.
vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
| m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
| power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
| xmp-* | ymp-* \
| hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
| alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
| we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
| clipper-* | orion-* \
| sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
| sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
| mips64el-* | mips64orion-* | mips64orionel-* \
| mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
| mipstx39-* | mipstx39el-* | mcore-* \
| f301-* | armv*-* | t3e-* \
| m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
| thumb-* | v850-* | d30v-* | tic30-* | c30-* )
580-* \
| a29k-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alphapca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armv*-* \
| bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c54x-* \
| clipper-* | cray2-* | cydra-* \
| d10v-* | d30v-* \
| elxsi-* \
| f30[01]-* | f700-* | fr30-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| m32r-* \
| m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | mcore-* \
| 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
# for a CPU type and a company and sometimes even an OS.
@@ -245,14 +348,14 @@ case $basic_machine in
os=-sysv
;;
amiga | amiga-*)
basic_machine=m68k-cbm
basic_machine=m68k-unknown
;;
amigaos | amigados)
basic_machine=m68k-cbm
basic_machine=m68k-unknown
os=-amigaos
;;
amigaunix | amix)
basic_machine=m68k-cbm
basic_machine=m68k-unknown
os=-sysv4
;;
apollo68)
@@ -299,13 +402,16 @@ case $basic_machine in
basic_machine=cray2-cray
os=-unicos
;;
[ctj]90-cray)
basic_machine=c90-cray
[cjt]90)
basic_machine=${basic_machine}-cray
os=-unicos
;;
crds | unos)
basic_machine=m68k-crds
;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
da30 | da30-*)
basic_machine=m68k-da30
;;
@@ -353,6 +459,10 @@ case $basic_machine in
basic_machine=tron-gmicro
os=-sysv
;;
go32)
basic_machine=i386-pc
os=-go32
;;
h3050r* | hiux*)
basic_machine=hppa1.1-hitachi
os=-hiuxwe2
@@ -426,22 +536,21 @@ case $basic_machine in
;;
i370-ibm* | ibm*)
basic_machine=i370-ibm
os=-mvs
;;
# 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/'`
os=-sysv32
;;
i[34567]86v4*)
i*86v4*)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4
;;
i[34567]86v)
i*86v)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv
;;
i[34567]86sol2)
i*86sol2)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2
;;
@@ -453,14 +562,6 @@ case $basic_machine in
basic_machine=i386-unknown
os=-vsta
;;
i386-go32 | go32)
basic_machine=i386-unknown
os=-go32
;;
i386-mingw32 | mingw32)
basic_machine=i386-unknown
os=-mingw32
;;
iris | iris4d)
basic_machine=mips-sgi
case $os in
@@ -486,10 +587,14 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
mingw32)
basic_machine=i386-pc
os=-mingw32
;;
miniframe)
basic_machine=m68000-convergent
;;
*mint | *MiNT)
*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
@@ -507,14 +612,22 @@ case $basic_machine in
mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;;
mmix*)
basic_machine=mmix-knuth
os=-mmixware
;;
monitor)
basic_machine=m68k-rom68k
os=-coff
;;
msdos)
basic_machine=i386-unknown
basic_machine=i386-pc
os=-msdos
;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
@@ -524,7 +637,7 @@ case $basic_machine in
os=-netbsd
;;
netwinder)
basic_machine=armv4l-corel
basic_machine=armv4l-rebel
os=-linux
;;
news | news700 | news800 | news900)
@@ -572,9 +685,16 @@ case $basic_machine in
basic_machine=i960-intel
os=-mon960
;;
nonstopux)
basic_machine=mips-compaq
os=-nonstopux
;;
np1)
basic_machine=np1-gould
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
@@ -604,28 +724,28 @@ case $basic_machine in
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
pentium | p5 | k5 | k6 | nexen)
pentium | p5 | k5 | k6 | nexgen)
basic_machine=i586-pc
;;
pentiumpro | p6 | 6x86)
pentiumpro | p6 | 6x86 | athlon)
basic_machine=i686-pc
;;
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/^[^-]*-//'`
;;
pentiumpro-* | p6-* | 6x86-*)
pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumii-* | pentium2-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn)
basic_machine=pn-gould
;;
power) basic_machine=rs6000-ibm
power) basic_machine=power-ibm
;;
ppc) basic_machine=powerpc-unknown
;;
@@ -637,9 +757,23 @@ case $basic_machine in
ppcle-* | powerpclittle-*)
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)
basic_machine=i386-ibm
;;
pw32)
basic_machine=i586-unknown
os=-pw32
;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
@@ -719,6 +853,10 @@ case $basic_machine in
sun386 | sun386i | roadrunner)
basic_machine=i386-sun
;;
sv1)
basic_machine=sv1-cray
os=-unicos
;;
symmetry)
basic_machine=i386-sequent
os=-dynix
@@ -727,6 +865,10 @@ case $basic_machine in
basic_machine=t3e-cray
os=-unicos
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tx39)
basic_machine=mipstx39-unknown
;;
@@ -779,6 +921,10 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
windows32)
basic_machine=i386-pc
os=-windows32-msvcrt
;;
xmp)
basic_machine=xmp-cray
os=-unicos
@@ -822,13 +968,20 @@ case $basic_machine in
vax)
basic_machine=vax-dec
;;
pdp10)
# there are many clones, so DEC is not a safe bet
basic_machine=pdp10-unknown
;;
pdp11)
basic_machine=pdp11-dec
;;
we32k)
basic_machine=we32k-att
;;
sparc | sparcv9)
sh3 | sh4 | sh3eb | sh4eb)
basic_machine=sh-unknown
;;
sparc | sparcv9 | sparcv9b)
basic_machine=sparc-sun
;;
cydra)
@@ -850,6 +1003,9 @@ case $basic_machine in
basic_machine=c4x-none
os=-coff
;;
*-unknown)
# Make sure to match an already-canonicalized machine name.
;;
*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
@@ -906,14 +1062,30 @@ case $os in
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -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.
;;
-qnx*)
case $basic_machine in
x86-* | i*86-*)
;;
*)
os=-nto$os
;;
esac
;;
-nto*)
os=-nto-qnx
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
| -macos* | -mpw* | -magic* | -mon960* | -lnews*)
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;;
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
@@ -927,6 +1099,12 @@ case $os in
-sunos6*)
os=`echo $os | sed -e 's|sunos6|solaris3|'`
;;
-opened*)
os=-openedition
;;
-wince*)
os=-wince
;;
-osfrose*)
os=-osfrose
;;
@@ -951,6 +1129,9 @@ case $os in
-ns2 )
os=-nextstep2
;;
-nsk*)
os=-nsk
;;
# Preserve the version number of sinix5.
-sinix5.*)
os=`echo $os | sed -e 's|sinix|sysv|'`
@@ -985,7 +1166,7 @@ case $os in
-xenix)
os=-xenix
;;
-*mint | -*MiNT)
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint
;;
-none)
@@ -1013,12 +1194,15 @@ case $basic_machine in
*-acorn)
os=-riscix1.2
;;
arm*-corel)
arm*-rebel)
os=-linux
;;
arm*-semi)
os=-aout
;;
pdp10-*)
os=-tops20
;;
pdp11-*)
os=-none
;;
@@ -1127,7 +1311,7 @@ case $basic_machine in
*-masscomp)
os=-rtu
;;
f301-fujitsu)
f30[01]-fujitsu | f700-fujitsu)
os=-uxpv
;;
*-rom68k)
@@ -1187,7 +1371,7 @@ case $basic_machine in
-genix*)
vendor=ns
;;
-mvs*)
-mvs* | -opened*)
vendor=ibm
;;
-ptx*)
@@ -1205,12 +1389,23 @@ case $basic_machine in
-mpw* | -macos*)
vendor=apple
;;
-*mint | -*MiNT)
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
vendor=atari
;;
-vos*)
vendor=stratus
;;
esac
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;;
esac
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:

498
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,14 @@ AC_TYPE_SIZE_T
AC_STRUCT_ST_RDEV
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
AC_PREFIX_DEFAULT(/usr)
@@ -61,21 +69,49 @@ AC_ARG_WITH(group,
[ GROUP="$withval" ],
[ GROUP="root" ])
dnl -- Where the linux src tree is
AC_ARG_WITH(kernel_dir,
[ --with-kernel_dir=DIR linux kernel source in DIR [/usr/src/linux]],
[ kernel_dir="$withval" ],
[ kernel_dir=/usr/src/linux ])
dnl -- format1 inclusion type
AC_ARG_WITH(lvm1,
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] ],
[ LVM1="$withval" ],
[ LVM1="internal" ])
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
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
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)
dnl Disable readline
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
READLINE=$enableval, READLINE=yes)
dnl Enable readline
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
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
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -105,6 +141,17 @@ Note: (n)curses also seems to work as a substitute for termcap. This was
)
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)
if test x$READLINE = xyes; then
AC_CHECK_LIB(readline, readline, ,
@@ -118,15 +165,27 @@ package as well (which may be called readline-devel or something similar).
)
exit
)
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
fi
if test "-f VERSION"; then
LVM_VERSION="\"`cat VERSION`\""
else
LVM_VERSION="Unknown"
fi
AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK)
AC_SUBST(READLINE)
AC_SUBST(kernel_dir)
AC_SUBST(LVM1)
AC_SUBST(OWNER)
AC_SUBST(GROUP)
AC_SUBST(CFLAGS)
AC_SUBST(LIBS)
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 keep utility scripts running properly
AC_OUTPUT( \
@@ -134,8 +193,10 @@ Makefile \
make.tmpl \
include/Makefile \
lib/Makefile \
lib/format1/Makefile \
man/Makefile \
tools/Makefile \
tools/version.h \
test/mm/Makefile \
test/device/Makefile \
test/format1/Makefile \

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.

82
debian/changelog vendored Normal file
View File

@@ -0,0 +1,82 @@
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.
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 16 Feb 2002 04:21:26 -0400
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
* Get rid of awk dependency in init script. (Closes: #146257)
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 12 May 2002 04:39:06 -0500
lvm2 (0.95.05-2) unstable; urgency=low
* Use ${shlibs:Depends} in Depends.
* Get rid of postinst/postrm scripts, use debhelper's init script instead.
* Add Conflicts against lvm10, lvm-common.
* Fix endian issues on big-endian machines.
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 2 May 2002 23:53:53 -0500
lvm2 (0.95.05-1) unstable; urgency=low
* New release (Beta2).
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 25 Apr 2002 00:37:41 -0500
lvm2 (0.95.04cvs20020306-1) unstable; urgency=low
* CVS updated.
* Convert from debian native package.
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 6 Mar 2002 00:43:21 -0500
lvm2 (0.95.04cvs20020304) unstable; urgency=low
* CVS updated.
* Enhance init script; create devmapper control device, etc.
* Add dmsetup as a suggestion.
* Add /etc/lvm/lvm.conf conffile.
* Add undocumented(7) for the commands missing manpages.
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 4 Mar 2002 04:51:26 -0500
lvm2 (0.95.02cvs20020220) unstable; urgency=low
* Initial Release.
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 20 Feb 2002 03:17:25 -0500

24
debian/control vendored Normal file
View File

@@ -0,0 +1,24 @@
Source: lvm2
Section: admin
Priority: optional
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
Standards-Version: 3.5.8.0
Package: lvm2
Architecture: any
Depends: ${shlibs:Depends}
Conflicts: lvm10, lvm-common
Replaces: lvm10, lvm-common
Provides: lvm-binaries
Suggests: dmsetup, kernel-patch-device-mapper
Description: The Linux Logical Volume Manager
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
supports enterprise level volume management of disk and disk subsystems
by grouping arbitrary disks into volume groups. The total capacity of
volume groups can be allocated to logical volumes, which are accessed as
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.

25
debian/copyright vendored Normal file
View File

@@ -0,0 +1,25 @@
This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on
Wed, 20 Feb 2002 03:17:25 -0500.
It was downloaded from http://www.sistina.com/products_lvm.htm
Upstream Author: LVM Development Team
Copyright (c) 2001-2002 LVM Development Team
LVM2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
LVM2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
On Debian systems, the full text of the GPL can be found in
/usr/share/common-licenses/GPL

4
debian/dirs vendored Normal file
View File

@@ -0,0 +1,4 @@
etc/lvm
usr/share/man/man5
usr/share/man/man8
sbin

5
debian/docs vendored Normal file
View File

@@ -0,0 +1,5 @@
BUGS
README
VERSION
WHATS_NEW
doc/*

64
debian/init.d vendored Normal file
View File

@@ -0,0 +1,64 @@
#! /bin/sh
#
# lvm2 This script handles LVM2 initialization/shutdown.
#
# Written by Andres Salomon <dilinger@mp3revolution.net>.
#
PATH=/sbin:/bin:/usr/sbin:/usr/bin
NAME=lvm2
DESC=LVM
test -x /sbin/vgchange || exit 0
modprobe dm-mod >/dev/null 2>&1
# Create necessary files in /dev for device-mapper
create_devfiles() {
DIR="/dev/mapper"
FILE="$DIR/control"
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
if test ! -d $DIR; then
mkdir --mode=755 $DIR >/dev/null 2>&1
fi
if test ! -c $FILE -a ! -z "$minor"; then
mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1
fi
}
case "$1" in
start)
echo -n "Initializing $DESC: "
create_devfiles
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."
;;
stop)
echo -n "Shutting down $DESC: "
# We don't really try all that hard to shut it down; far too many
# things that can keep it from successfully shutting down.
vgchange -a n
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
vgchange -a n
sleep 1
vgchange -a y
echo "$NAME."
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

26
debian/manpages vendored Normal file
View File

@@ -0,0 +1,26 @@
debian/lvm2/usr/share/man/man5/lvm.conf.5
debian/lvm2/usr/share/man/man8/lvchange.8
debian/lvm2/usr/share/man/man8/lvcreate.8
debian/lvm2/usr/share/man/man8/lvdisplay.8
debian/lvm2/usr/share/man/man8/lvextend.8
debian/lvm2/usr/share/man/man8/lvm.8
debian/lvm2/usr/share/man/man8/lvmchange.8
debian/lvm2/usr/share/man/man8/lvreduce.8
debian/lvm2/usr/share/man/man8/lvremove.8
debian/lvm2/usr/share/man/man8/lvrename.8
debian/lvm2/usr/share/man/man8/lvscan.8
debian/lvm2/usr/share/man/man8/pvchange.8
debian/lvm2/usr/share/man/man8/pvcreate.8
debian/lvm2/usr/share/man/man8/pvdisplay.8
debian/lvm2/usr/share/man/man8/pvscan.8
debian/lvm2/usr/share/man/man8/vgcfgbackup.8
debian/lvm2/usr/share/man/man8/vgchange.8
debian/lvm2/usr/share/man/man8/vgck.8
debian/lvm2/usr/share/man/man8/vgcreate.8
debian/lvm2/usr/share/man/man8/vgdisplay.8
debian/lvm2/usr/share/man/man8/vgextend.8
debian/lvm2/usr/share/man/man8/vgmerge.8
debian/lvm2/usr/share/man/man8/vgreduce.8
debian/lvm2/usr/share/man/man8/vgremove.8
debian/lvm2/usr/share/man/man8/vgrename.8
debian/lvm2/usr/share/man/man8/vgscan.8

119
debian/rules vendored Executable file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/make -f
# Sample debian/rules that uses debhelper.
# GNU copyright 1997 by Joey Hess.
#
# This version is for a hypothetical package that builds an
# architecture-dependant package, as well as an architecture-independent
# package.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This is the debhelper compatibility version to use.
export DH_COMPAT=3
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
CFLAGS += -g
endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
INSTALL_PROGRAM += -s
endif
configure: configure-stamp
configure-stamp:
dh_testdir
# Add here commands to configure the package.
./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info
touch configure-stamp
build-arch: configure-stamp build-arch-stamp
build-arch-stamp:
dh_testdir
# Add here command to compile/build the package.
$(MAKE)
touch build-arch-stamp
build-indep: configure-stamp build-indep-stamp
build-indep-stamp:
dh_testdir
# Add here command to compile/build the arch indep package.
# It's ok not to do anything here, if you don't need to build
# anything for this package.
#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1
touch build-indep-stamp
build: build-arch build-indep
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
# Add here commands to clean up after the build process.
-$(MAKE) distclean
-test -r /usr/share/misc/config.sub && \
cp -f /usr/share/misc/config.sub config.sub
-test -r /usr/share/misc/config.guess && \
cp -f /usr/share/misc/config.guess config.guess
dh_clean
install: DH_OPTIONS=
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/lvm2.
$(MAKE) install prefix=$(CURDIR)/debian/lvm2
install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf
# Build architecture-independent files here.
# Pass -i to all debhelper commands in this target to reduce clutter.
binary-indep: build install
# nada.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
# dh_installdebconf
dh_installdocs
dh_installexamples
# dh_installlogrotate -a
# dh_installemacsen -a
# dh_installpam -a
# dh_installmime -a
dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
dh_installcron
dh_installman
dh_installinfo
dh_installchangelogs
dh_strip
dh_link
dh_compress
dh_fixperms
dh_makeshlibs
dh_installdeb
# dh_perl -a
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

View File

@@ -1 +0,0 @@
Wow! This is really incredible documentation!

257
doc/example.conf Normal file
View File

@@ -0,0 +1,257 @@
# This is an example configuration file for the LVM2 system.
# It contains the default settings that would be used if there was no
# /etc/lvm/lvm.conf file.
#
# 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 you to configure which block devices should
# be used by the LVM system.
devices {
# Where do you want your volume groups to appear ?
dir = "/dev"
# An array of directories that contain the device nodes you wish
# to use with LVM2.
scan = [ "/dev" ]
# A filter that tells LVM2 to only use a restricted set of devices.
# The filter consists of an array of regular expressions. These
# expressions can be delimited by a character of your choice, and
# prefixed with either an 'a' (for accept) or 'r' (for reject).
# 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.
# 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:
filter = [ "a/.*/" ]
# Exclude the cdrom drive
# filter = [ "r|/dev/cdrom|" ]
# When testing I like to work with just loopback devices:
# filter = [ "a/loop/", "r/.*/" ]
# Or maybe all loops and ide drives except hdc:
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
# 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
# default this cache file is hidden in the /etc/lvm directory.
# It is safe to delete this file: the tools regenerate it.
cache = "/etc/lvm/.cache"
# You can turn off writing this cache file by setting this to 0.
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 ]
}
# This section that allows you to configure the nature of the
# information that LVM2 reports.
log {
# Controls the messages sent to stdout or stderr.
# There are three levels of verbosity, 3 being the most verbose.
verbose = 0
# Should we send log messages through syslog?
# 1 is yes; 0 is no.
syslog = 1
# 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
indent = 1
# Whether or not (1 or 0) to display the command name on each line output
command_names = 0
# A prefix to use before the message text (but after the command name,
# if selected). Default is two spaces, so you can see/grep the severity
# of each message.
prefix = " "
# To make the messages look similar to the original LVM tools use:
# indent = 0
# command_names = 1
# 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
# talk about a 'backup' we mean making a copy of the metadata for the
# *current* system. The 'archive' contains old metadata configurations.
# Backups are stored in a human readeable text format.
backup {
# Should we maintain a backup of the current metadata configuration ?
# Use 1 for Yes; 0 for No.
# Think very hard before turning this off!
backup = 1
# Where shall we keep it ?
# Remember to back up this directory regularly!
backup_dir = "/etc/lvm/backup"
# Should we maintain an archive of old metadata configurations.
# Use 1 for Yes; 0 for No.
# On by default. Think very hard before turning this off.
archive = 1
# Where should archived files go ?
# Remember to back up this directory regularly!
archive_dir = "/etc/lvm/archive"
# What is the minimum number of archive files you wish to keep ?
retain_min = 10
# What is the minimum time you wish to keep an archive file for ?
retain_days = 30
}
# Settings for the running LVM2 in shell (readline) mode.
shell {
# Number of lines of history to store in ~/.lvm_history
history_size = 100
}
# Miscellaneous global LVM2 settings
global {
# The file creation mask for any files and directories created.
# Interpreted as octal if the first digit is zero.
umask = 077
# Allow other users to read the files
#umask = 022
# Enabling test mode means that no changes to the on disk metadata
# will be made. Equivalent to having the -t option on every
# command. Defaults to off.
test = 0
# Whether or not to communicate with the kernel device-mapper.
# Set to 0 if you want to use the tools to manipulate LVM metadata
# without activating any logical volumes.
# 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
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" ]
#}

52
doc/pvmove_outline.txt Normal file
View File

@@ -0,0 +1,52 @@
Let's say we have an LV, made up of three segments of different PV's,
I've also added in the device major:minor as this will be useful
later:
+-----------------------------+
| PV1 | PV2 | PV3 | 254:3
+----------+---------+--------+
Now our hero decides to PV move PV2 to PV4:
1. Suspend our LV (254:3), this starts queueing all io, and flushes
all pending io. Once the suspend has completed we are free to change
the mapping table.
2. Set up *another* (254:4) device with the mapping table of our LV.
3. Load a new mapping table into (254:3) that has identity targets for
parts that aren't moving, and a mirror target for parts that are.
4. Unsuspend (254:3)
So now we have:
destination of copy
+--------------------->--------------+
| |
+-----------------------------+ + -----------+
| Identity | mirror | Ident. | 254:3 | PV4 |
+----------+---------+--------+ +------------+
| | |
\/ \/ \/
+-----------------------------+
| PV1 | PV2 | PV3 | 254:4
+----------+---------+--------+
Any writes to segment2 of the LV get intercepted by the mirror target
who checks that that chunk has been copied to the new destination, if
it hasn't it queues the initial copy and defers the current io until
it has finished. Then the current io is written to *both* PV2 and the
PV4.
5. When the copying has completed 254:3 is suspended/pending flushed.
6. 254:4 is taken down
7. metadata is updated on disk
8. 254:3 has new mapping table loaded:
+-----------------------------+
| PV1 | PV4 | PV3 | 254:3
+----------+---------+--------+

46
doc/testing.txt Normal file
View File

@@ -0,0 +1,46 @@
Here's how I test new LVM2 builds without interfering with the stable
LVM2 that is running the LV's on my development box.
1) Create a set of loopback devices.
2) Create a new directory to contain the LVM2 configuration files for
this setup. (I use /etc/lvm_loops)
3) Write a suitable lvm.conf file, this goes in the directory you just
created. eg, my /etc/lvm_loops/lvm.conf looks like:
log {
file="/tmp/lvm2_loop.log"
level=9
verbose=0
overwrite=1
}
devices {
scan = "/dev"
filter = ["a/loop/", "r/.*/"]
}
The important this to note is the devices section which makes sure that
only the loopback devices are considered for LVM2 operations.
4) When you want to use this test setup just set the environment
variable LVM_SYSTEM_DIR to point to your config directory
(/etc/lvm_loops in my case).
5) It's a good idea to do a vgscan to initialise the filters:
export LVM_SYSTEM_DIR=/etc/lvm_loops
./lvm vgscan
where ./lvm is the new build of LVM2 that I'm trying out.
7) Test away. Make sure that you are explicit about which lvm
executable you want to execute (eg, ./lvm if you are in
LVM2/tools).

View File

@@ -1 +0,0 @@
The driver directory

View File

@@ -1,104 +0,0 @@
The main goal of this driver is to support volume management in
general, not just for LVM. The kernel should provide general
services, not support specific applications. eg, The driver has no
concept of volume groups.
The driver does this by mapping sector ranges for the logical device
onto 'targets'.
When the logical device is accessed, the make_request function looks
up the correct target for the given sector, and then asks this target
to do the remapping.
A btree structure is used to hold the sector range -> target mapping.
Since we know all the entries in the btree in advance we can make a
very compact tree, omitting pointers to child nodes, (child nodes
locations can be calculated). Typical users would find they only have
a handful of targets for each logical volume LV.
Benchmarking with bonnie++ suggests that this is certainly no slower
than current LVM.
Target types are not hard coded, instead the register_mapping_type
function should be called. A target type is specified using three
functions (see the header):
dm_ctr_fn - takes a string and contructs a target specific piece of
context data.
dm_dtr_fn - destroy contexts.
dm_map_fn - function that takes a buffer_head and some previously
constructed context and performs the remapping.
Currently there are two two trivial mappers, which are automatically
registered: 'linear', and 'io_error'. Linear alone is enough to
implement most of LVM.
I do not like ioctl interfaces so this driver is currently controlled
through a /proc interface. /proc/device-mapper/control allows you to
create and remove devices by 'cat'ing a line of the following format:
create <device name> [minor no]
remove <device name>
If you're not using devfs you'll have to do the mknod'ing yourself,
otherwise the device will appear in /dev/device-mapper automatically.
/proc/device-mapper/<device name> accepts the mapping table:
begin
<sector start> <length> <target name> <target args>...
...
end
where <target args> are specific to the target type, eg. for a linear
mapping:
<sector start> <length> linear <major> <minor> <start>
and the io-err mapping:
<sector start> <length> io-err
The begin/end lines around the table are nasty, they should be handled
by open/close of the file.
The interface is far from complete, currently loading a table either
succeeds or fails, you have no way of knowing which line of the
mapping table was erroneous. Also there is no way to get status
information out, though this should be easy to add, either as another
/proc file, or just by reading the same /proc/device-mapper/<device>
file. I will be seperating the loading and validation of a table from
the binding of a valid table to a device.
It has been suggested that I should implement a little custom
filesystem rather than labouring with /proc. For example doing a
mkdir foo in /wherever/device-mapper would create a new device. People
waiting for a status change (eg, a mirror operation to complete) could
poll a file. Does the community find this an acceptable way to go ?
At the moment the table assumes 32 bit keys (sectors), the move to 64
bits will involve no interface changes, since the tables will be read
in as ascii data. A different table implementation can therefor be
provided at another time. Either just by changing offset_t to 64
bits, or maybe implementing a structure which looks up the keys in
stages (ie, 32 bits at a time).
More interesting targets:
striped mapping; given a stripe size and a number of device regions
this would stripe data across the regions. Especially useful, since
we could limit each striped region to a 32 bit area and then avoid
nasty 64 bit %'s.
mirror mapping; would set off a kernel thread slowly copying data from
one region to another, ensuring that any new writes got copied to both
destinations correctly. Enabling us to implement a live pvmove
correctly.

View File

@@ -1,84 +0,0 @@
/*
* device-mapper.h
*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
/*
* Changelog
*
* 14/08/2001 - First version [Joe Thornber]
*/
#ifndef DEVICE_MAPPER_H
#define DEVICE_MAPPER_H
#include <linux/major.h>
/* FIXME: Use value from local range for now, for co-existence with LVM 1 */
#define DM_BLK_MAJOR 124
struct dm_table;
struct dm_dev;
typedef unsigned int offset_t;
typedef void (*dm_error_fn)(const char *message, void *private);
/*
* constructor, destructor and map fn types
*/
typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l,
char *args, void **context);
typedef void (*dm_dtr_fn)(struct dm_table *t, void *c);
typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context);
typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context);
typedef char *(*dm_print_fn)(void *context);
/*
* Contructors should call this to make sure any
* destination devices are handled correctly
* (ie. opened/closed).
*/
int dm_table_get_device(struct dm_table *t, const char *path,
struct dm_dev **result);
void dm_table_put_device(struct dm_table *table, struct dm_dev *d);
/*
* information about a target type
*/
struct target_type {
const char *name;
struct module *module;
dm_ctr_fn ctr;
dm_dtr_fn dtr;
dm_map_fn map;
dm_err_fn err;
dm_print_fn print;
};
int dm_register_target(struct target_type *t);
int dm_unregister_target(struct target_type *t);
static inline char *next_token(char **p)
{
static const char *delim = " \t";
char *r;
do {
r = strsep(p, delim);
} while(r && *r == 0);
return r;
}
#endif /* DEVICE_MAPPER_H */
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@@ -1,134 +0,0 @@
/*
* dm-linear.c
*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/device-mapper.h>
#include "dm.h"
/*
* linear: maps a linear range of a device.
*/
struct linear_c {
long delta; /* FIXME: we need a signed offset type */
struct dm_dev *dev;
};
/*
* construct a linear mapping.
* <dev_path> <offset>
*/
static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
char *args, void **context)
{
struct linear_c *lc;
unsigned int start;
int r = -EINVAL;
char *tok;
char *path;
char *p = args;
*context = "No device path given";
path = next_token(&p);
if (!path)
goto bad;
*context = "No initial offset given";
tok = next_token(&p);
if (!tok)
goto bad;
start = simple_strtoul(tok, NULL, 10);
*context = "Cannot allocate linear context private structure";
lc = kmalloc(sizeof(lc), GFP_KERNEL);
if (lc == NULL)
goto bad;
*context = "Cannot get target device";
r = dm_table_get_device(t, path, &lc->dev);
if (r)
goto bad_free;
lc->delta = (int) start - (int) b;
*context = lc;
return 0;
bad_free:
kfree(lc);
bad:
return r;
}
static void linear_dtr(struct dm_table *t, void *c)
{
struct linear_c *lc = (struct linear_c *) c;
dm_table_put_device(t, lc->dev);
kfree(c);
}
static int linear_map(struct buffer_head *bh, int rw, void *context)
{
struct linear_c *lc = (struct linear_c *) context;
bh->b_rdev = lc->dev->dev;
bh->b_rsector = bh->b_rsector + lc->delta;
return 1;
}
/*
* Debugging use only.
*/
static char *linear_print(void *context)
{
struct linear_c *lc = (struct linear_c *)context;
static char buf[256];
sprintf(buf, " %lu", lc->delta);
return buf;
}
static struct target_type linear_target = {
name: "linear",
module: THIS_MODULE,
ctr: linear_ctr,
dtr: linear_dtr,
map: linear_map,
print: linear_print,
};
static int __init linear_init(void)
{
int r = dm_register_target(&linear_target);
if (r < 0)
printk(KERN_ERR
"Device mapper: Linear: register failed %d\n", r);
return r;
}
static void __exit linear_exit(void)
{
int r = dm_unregister_target(&linear_target);
if (r < 0)
printk(KERN_ERR
"Device mapper: Linear: unregister failed %d\n", r);
}
module_init(linear_init);
module_exit(linear_exit);
MODULE_AUTHOR("Joe Thornber <thornber@uk.sistina.com>");
MODULE_DESCRIPTION("Device Mapper: Linear mapping");
MODULE_LICENSE("GPL");

View File

@@ -1,340 +0,0 @@
/*
* dm-table.c
*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
/*
* Changelog
*
* 16/08/2001 - First version [Joe Thornber]
*/
#include "dm.h"
/* ceiling(n / size) * size */
static inline ulong round_up(ulong n, ulong size)
{
ulong r = n % size;
return n + (r ? (size - r) : 0);
}
/* ceiling(n / size) */
static inline ulong div_up(ulong n, ulong size)
{
return round_up(n, size) / size;
}
/* similar to ceiling(log_size(n)) */
static uint int_log(ulong n, ulong base)
{
int result = 0;
while (n > 1) {
n = div_up(n, base);
result++;
}
return result;
}
/*
* return the highest key that you could lookup
* from the n'th node on level l of the btree.
*/
static offset_t high(struct dm_table *t, int l, int n)
{
for (; l < t->depth - 1; l++)
n = get_child(n, CHILDREN_PER_NODE - 1);
if (n >= t->counts[l])
return (offset_t) -1;
return get_node(t, l, n)[KEYS_PER_NODE - 1];
}
/*
* fills in a level of the btree based on the
* highs of the level below it.
*/
static int setup_btree_index(int l, struct dm_table *t)
{
int n, k;
offset_t *node;
for (n = 0; n < t->counts[l]; n++) {
node = get_node(t, l, n);
for (k = 0; k < KEYS_PER_NODE; k++)
node[k] = high(t, l + 1, get_child(n, k));
}
return 0;
}
/*
* highs, and targets are managed as dynamic
* arrays during a table load.
*/
static int alloc_targets(struct dm_table *t, int num)
{
offset_t *n_highs;
struct target *n_targets;
int n = t->num_targets;
int size = (sizeof(struct target) + sizeof(offset_t)) * num;
n_highs = vmalloc(size);
if (!n_highs)
return -ENOMEM;
n_targets = (struct target *) (n_highs + num);
if (n) {
memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
memcpy(n_targets, t->targets, sizeof(*n_targets) * n);
}
vfree(t->highs);
t->num_allocated = num;
t->highs = n_highs;
t->targets = n_targets;
return 0;
}
struct dm_table *dm_table_create(void)
{
struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO);
if (!t)
return 0;
memset(t, 0, sizeof(*t));
INIT_LIST_HEAD(&t->devices);
/* allocate a single nodes worth of targets to
begin with */
if (alloc_targets(t, KEYS_PER_NODE)) {
kfree(t);
t = 0;
}
return t;
}
static void free_devices(struct list_head *devices)
{
struct list_head *tmp, *next;
for (tmp = devices->next; tmp != devices; tmp = next) {
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
next = tmp->next;
kfree(dd);
}
}
void dm_table_destroy(struct dm_table *t)
{
int i;
/* free the indexes (see dm_table_complete) */
if (t->depth >= 2)
vfree(t->index[t->depth - 2]);
/* free the targets */
for (i = 0; i < t->num_targets; i++) {
struct target *tgt = &t->targets[i];
if (tgt->type->dtr)
tgt->type->dtr(t, tgt->private);
}
vfree(t->highs);
/* free the device list */
if (t->devices.next != &t->devices) {
WARN("there are still devices present, someone isn't "
"calling dm_table_remove_device");
free_devices(&t->devices);
}
kfree(t);
}
/*
* Checks to see if we need to extend
* highs or targets.
*/
static inline int check_space(struct dm_table *t)
{
if (t->num_targets >= t->num_allocated)
return alloc_targets(t, t->num_allocated * 2);
return 0;
}
/*
* convert a device path to a kdev_t.
*/
int lookup_device(const char *path, kdev_t *dev)
{
int r;
struct nameidata nd;
struct inode *inode;
if (!path_init(path, LOOKUP_FOLLOW, &nd))
return 0;
if ((r = path_walk(path, &nd)))
goto bad;
inode = nd.dentry->d_inode;
if (!inode) {
r = -ENOENT;
goto bad;
}
if (!S_ISBLK(inode->i_mode)) {
r = -EINVAL;
goto bad;
}
*dev = inode->i_rdev;
bad:
path_release(&nd);
return r;
}
/*
* see if we've already got a device in the list.
*/
static struct dm_dev *find_device(struct list_head *l, kdev_t dev)
{
struct list_head *tmp;
for (tmp = l->next; tmp != l; tmp = tmp->next) {
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
if (dd->dev == dev)
return dd;
}
return 0;
}
/*
* add a device to the list, or just increment the
* usage count if it's already present.
*/
int dm_table_get_device(struct dm_table *t, const char *path,
struct dm_dev **result)
{
int r;
kdev_t dev;
struct dm_dev *dd;
/* convert the path to a device */
if ((r = lookup_device(path, &dev)))
return r;
dd = find_device(&t->devices, dev);
if (!dd) {
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
if (!dd)
return -ENOMEM;
dd->dev = dev;
dd->bd = 0;
atomic_set(&dd->count, 0);
list_add(&dd->list, &t->devices);
}
atomic_inc(&dd->count);
*result = dd;
return 0;
}
/*
* decrement a devices use count and remove it if
* neccessary.
*/
void dm_table_put_device(struct dm_table *t, struct dm_dev *dd)
{
if (atomic_dec_and_test(&dd->count)) {
list_del(&dd->list);
kfree(dd);
}
}
/*
* adds a target to the map
*/
int dm_table_add_target(struct dm_table *t, offset_t high,
struct target_type *type, void *private)
{
int r, n;
if ((r = check_space(t)))
return r;
n = t->num_targets++;
t->highs[n] = high;
t->targets[n].type = type;
t->targets[n].private = private;
return 0;
}
static int setup_indexes(struct dm_table *t)
{
int i, total = 0;
offset_t *indexes;
/* allocate the space for *all* the indexes */
for (i = t->depth - 2; i >= 0; i--) {
t->counts[i] = div_up(t->counts[i + 1], CHILDREN_PER_NODE);
total += t->counts[i];
}
if (!(indexes = vmalloc(NODE_SIZE * total)))
return -ENOMEM;
/* set up internal nodes, bottom-up */
for (i = t->depth - 2, total = 0; i >= 0; i--) {
t->index[i] = indexes + (KEYS_PER_NODE * t->counts[i]);
setup_btree_index(i, t);
}
return 0;
}
/*
* builds the btree to index the map
*/
int dm_table_complete(struct dm_table *t)
{
int leaf_nodes, r = 0;
/* how many indexes will the btree have ? */
leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE);
t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
/* leaf layer has already been set up */
t->counts[t->depth - 1] = leaf_nodes;
t->index[t->depth - 1] = t->highs;
if (t->depth >= 2)
r = setup_indexes(t);
return r;
}
EXPORT_SYMBOL(dm_table_get_device);
EXPORT_SYMBOL(dm_table_put_device);

View File

@@ -1,180 +0,0 @@
/*
* dm-target.c
*
* Copyright (C) 2001 Sistina Software (UK) Limited
*
* This file is released under the GPL.
*/
/*
* 16/08/2001 - First Version [Joe Thornber]
*/
#include "dm.h"
#include <linux/kmod.h>
struct tt_internal {
struct target_type tt;
struct list_head list;
long use;
};
static LIST_HEAD(_targets);
static rwlock_t _lock = RW_LOCK_UNLOCKED;
#define DM_MOD_NAME_SIZE 32
static inline struct tt_internal *__find_target_type(const char *name)
{
struct list_head *tmp;
struct tt_internal *ti;
for(tmp = _targets.next; tmp != &_targets; tmp = tmp->next) {
ti = list_entry(tmp, struct tt_internal, list);
if (!strcmp(name, ti->tt.name))
return ti;
}
return 0;
}
static struct tt_internal *get_target_type(const char *name)
{
struct tt_internal *ti;
read_lock(&_lock);
ti = __find_target_type(name);
if (ti) {
if (ti->use == 0 && ti->tt.module)
__MOD_INC_USE_COUNT(ti->tt.module);
ti->use++;
}
read_unlock(&_lock);
return ti;
}
static void load_module(const char *name)
{
char module_name[DM_MOD_NAME_SIZE] = "dm-";
/* Length check for strcat() below */
if (strlen(name) > (DM_MOD_NAME_SIZE - 4))
return;
strcat(module_name, name);
request_module(module_name);
}
struct target_type *dm_get_target_type(const char *name)
{
struct tt_internal *ti = get_target_type(name);
if (!ti) {
load_module(name);
ti = get_target_type(name);
}
return ti ? &ti->tt : 0;
}
void dm_put_target_type(struct target_type *t)
{
struct tt_internal *ti = (struct tt_internal *) t;
read_lock(&_lock);
if (--ti->use == 0 && ti->tt.module)
__MOD_DEC_USE_COUNT(ti->tt.module);
if (ti->use < 0)
BUG();
read_unlock(&_lock);
}
static struct tt_internal *alloc_target(struct target_type *t)
{
struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
if (ti) {
memset(ti, 0, sizeof(*ti));
ti->tt = *t;
}
return ti;
}
int dm_register_target(struct target_type *t)
{
int rv = 0;
struct tt_internal *ti = alloc_target(t);
if (!ti)
return -ENOMEM;
write_lock(&_lock);
if (__find_target_type(t->name))
rv = -EEXIST;
else
list_add(&ti->list, &_targets);
write_unlock(&_lock);
return rv;
}
int dm_unregister_target(struct target_type *t)
{
struct tt_internal *ti = (struct tt_internal *) t;
int rv = -ETXTBSY;
write_lock(&_lock);
if (ti->use == 0) {
list_del(&ti->list);
kfree(ti);
rv = 0;
}
write_unlock(&_lock);
return rv;
}
/*
* io-err: always fails an io, useful for bringing
* up LV's that have holes in them.
*/
static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
char *args, void **context)
{
*context = 0;
return 0;
}
static void io_err_dtr(struct dm_table *t, void *c)
{
/* empty */
}
static int io_err_map(struct buffer_head *bh, int rw, void *context)
{
buffer_IO_error(bh);
return 0;
}
static struct target_type error_target = {
name: "error",
ctr: io_err_ctr,
dtr: io_err_dtr,
map: io_err_map
};
int dm_target_init(void)
{
return dm_register_target(&error_target);
}
EXPORT_SYMBOL(dm_register_target);
EXPORT_SYMBOL(dm_unregister_target);

View File

@@ -1,963 +0,0 @@
/*
* device-mapper.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Changelog
*
* 14/08/2001 - First Version [Joe Thornber]
*/
#include "dm.h"
#include "dmfs.h"
#include <linux/blkpg.h>
#include <linux/blkdev.h>
#include <linux/kmod.h>
/* we only need this for the lv_bmap struct definition, not happy */
#include <linux/lvm.h>
#define MAX_DEVICES 64
#define DEFAULT_READ_AHEAD 64
static int major = 0;
const char *_name = "device-mapper";
int _version[3] = {0, 1, 0};
struct io_hook {
struct mapped_device *md;
struct target *target;
int rw;
void (*end_io)(struct buffer_head * bh, int uptodate);
void *context;
};
kmem_cache_t *_io_hook_cache;
#define rl down_read(&_dev_lock)
#define ru up_read(&_dev_lock)
#define wl down_write(&_dev_lock)
#define wu up_write(&_dev_lock)
struct rw_semaphore _dev_lock;
static struct mapped_device *_devs[MAX_DEVICES];
/* block device arrays */
static int _block_size[MAX_DEVICES];
static int _blksize_size[MAX_DEVICES];
static int _hardsect_size[MAX_DEVICES];
const char *_fs_dir = "device-mapper";
static devfs_handle_t _dev_dir;
static int request(request_queue_t *q, int rw, struct buffer_head *bh);
static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb);
/*
* setup and teardown the driver
*/
static int __init dm_init(void)
{
int ret = -ENOMEM;
init_rwsem(&_dev_lock);
_io_hook_cache = kmem_cache_create("dm io hooks",
sizeof(struct io_hook),
0, 0, NULL, NULL);
if (!_io_hook_cache)
goto err;
ret = dmfs_init();
if (ret < 0)
goto err_kmem_cache_destroy;
ret = dm_target_init();
if (ret)
goto err_kmem_cache_destroy;
ret = devfs_register_blkdev(major, _name, &dm_blk_dops);
if (ret < 0)
goto err_blkdev;
if (major == 0)
major = ret;
/* set up the arrays */
read_ahead[major] = DEFAULT_READ_AHEAD;
blk_size[major] = _block_size;
blksize_size[major] = _blksize_size;
hardsect_size[major] = _hardsect_size;
ret = -EIO;
blk_queue_make_request(BLK_DEFAULT_QUEUE(major), request);
_dev_dir = devfs_mk_dir(0, _fs_dir, NULL);
printk(KERN_INFO "%s %d.%d.%d initialised\n", _name,
_version[0], _version[1], _version[2]);
return 0;
err_blkdev:
printk(KERN_ERR "%s -- register_blkdev failed\n", _name);
err_kmem_cache_destroy:
kmem_cache_destroy(_io_hook_cache);
err:
return ret;
}
static void __exit dm_exit(void)
{
dmfs_exit();
if (kmem_cache_destroy(_io_hook_cache))
WARN("it looks like there are still some io_hooks allocated");
if (devfs_unregister_blkdev(major, _name) < 0)
printk(KERN_ERR "%s -- unregister_blkdev failed\n", _name);
read_ahead[major] = 0;
blk_size[major] = NULL;
blksize_size[major] = NULL;
hardsect_size[major] = NULL;
printk(KERN_INFO "%s %d.%d.%d cleaned up\n", _name,
_version[0], _version[1], _version[2]);
}
#ifdef CONFIG_HOTPLUG
static void dm_sbin_hotplug(struct mapped_device *md, char *action, int minor)
{
int i;
char *argv[3];
char *envp[7];
char name[DM_NAME_LEN + 16];
char dev_major[16], dev_minor[16];
if (!hotplug_path[0])
return;
if (!current->fs->root)
return;
sprintf(name, "DMNAME=%s\n", md->name);
sprintf(dev_major, "MAJOR=%d", major);
sprintf(dev_minor, "MINOR=%d", minor);
i = 0;
argv[i++] = hotplug_path;
argv[i++] = "devmap";
argv[i] = 0;
i = 0;
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[i++] = name;
envp[i++] = action;
envp[i++] = dev_minor;
envp[i++] = dev_major;
envp[i] = 0;
call_usermodehelper(argv[0], argv, envp);
}
#else
#define dm_sbin_hotplug(md, action, minor) do { } while(0)
#endif /* CONFIG_HOTPLUG */
/*
* block device functions
*/
static int dm_blk_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
struct mapped_device *md;
if (minor >= MAX_DEVICES)
return -ENXIO;
wl;
md = _devs[minor];
if (!md || !is_active(md)) {
wu;
return -ENXIO;
}
md->use_count++;
wu;
return 0;
}
static int dm_blk_close(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
struct mapped_device *md;
if (minor >= MAX_DEVICES)
return -ENXIO;
wl;
md = _devs[minor];
if (!md || md->use_count < 1) {
WARN("reference count in mapped_device incorrect");
wu;
return -ENXIO;
}
md->use_count--;
wu;
return 0;
}
/* In 512-byte units */
#define VOLUME_SIZE(minor) (_block_size[(minor)] >> 1)
static int dm_blk_ioctl(struct inode *inode, struct file *file,
uint command, ulong a)
{
int minor = MINOR(inode->i_rdev);
long size;
if (minor >= MAX_DEVICES)
return -ENXIO;
switch (command) {
case BLKSSZGET:
case BLKBSZGET:
case BLKROGET:
case BLKROSET:
case BLKRASET:
case BLKRAGET:
case BLKFLSBUF:
#if 0
case BLKELVSET:
case BLKELVGET:
#endif
return blk_ioctl(inode->i_rdev, command, a);
break;
case BLKGETSIZE:
size = VOLUME_SIZE(minor);
if (copy_to_user((void *) a, &size, sizeof (long)))
return -EFAULT;
break;
case BLKGETSIZE64:
size = VOLUME_SIZE(minor);
if (put_user((u64)size, (u64 *)a))
return -EFAULT;
break;
case BLKRRPART:
return -EINVAL;
case LV_BMAP:
return dm_user_bmap(inode, (struct lv_bmap *) a);
default:
WARN("unknown block ioctl %d", command);
return -EINVAL;
}
return 0;
}
static inline struct io_hook *alloc_io_hook(void)
{
return kmem_cache_alloc(_io_hook_cache, GFP_NOIO);
}
static inline void free_io_hook(struct io_hook *ih)
{
kmem_cache_free(_io_hook_cache, ih);
}
/*
* FIXME: need to decide if deferred_io's need
* their own slab, I say no for now since they are
* only used when the device is suspended.
*/
static inline struct deferred_io *alloc_deferred(void)
{
return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
}
static inline void free_deferred(struct deferred_io *di)
{
kfree(di);
}
/*
* call a targets optional error function if
* an io failed.
*/
static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh)
{
dm_err_fn err = ih->target->type->err;
if (err)
return err(bh, ih->rw, ih->target->private);
return 0;
}
/*
* bh->b_end_io routine that decrements the
* pending count and then calls the original
* bh->b_end_io fn.
*/
static void dec_pending(struct buffer_head *bh, int uptodate)
{
struct io_hook *ih = bh->b_private;
if (!uptodate && call_err_fn(ih, bh))
return;
if (atomic_dec_and_test(&ih->md->pending))
/* nudge anyone waiting on suspend queue */
wake_up(&ih->md->wait);
bh->b_end_io = ih->end_io;
bh->b_private = ih->context;
free_io_hook(ih);
bh->b_end_io(bh, uptodate);
}
/*
* add the bh to the list of deferred io.
*/
static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
{
struct deferred_io *di = alloc_deferred();
if (!di)
return -ENOMEM;
wl;
if (test_bit(DM_ACTIVE, &md->state)) {
wu;
return 0;
}
di->bh = bh;
di->rw = rw;
di->next = md->deferred;
md->deferred = di;
wu;
return 1;
}
/*
* do the bh mapping for a given leaf
*/
static inline int __map_buffer(struct mapped_device *md,
struct buffer_head *bh, int rw, int leaf)
{
int r;
dm_map_fn fn;
void *context;
struct io_hook *ih = NULL;
struct target *ti = md->map->targets + leaf;
fn = ti->type->map;
context = ti->private;
ih = alloc_io_hook();
if (!ih)
return 0;
ih->md = md;
ih->rw = rw;
ih->target = ti;
ih->end_io = bh->b_end_io;
ih->context = bh->b_private;
r = fn(bh, rw, context);
if (r > 0) {
/* hook the end io request fn */
atomic_inc(&md->pending);
bh->b_end_io = dec_pending;
bh->b_private = ih;
} else if (r == 0)
/* we don't need to hook */
free_io_hook(ih);
else if (r < 0) {
free_io_hook(ih);
return 0;
}
return 1;
}
/*
* search the btree for the correct target.
*/
static inline int __find_node(struct dm_table *t, struct buffer_head *bh)
{
int l, n = 0, k = 0;
offset_t *node;
for (l = 0; l < t->depth; l++) {
n = get_child(n, k);
node = get_node(t, l, n);
for (k = 0; k < KEYS_PER_NODE; k++)
if (node[k] >= bh->b_rsector)
break;
}
return (KEYS_PER_NODE * n) + k;
}
static int request(request_queue_t *q, int rw, struct buffer_head *bh)
{
struct mapped_device *md;
int r, minor = MINOR(bh->b_rdev);
if (minor >= MAX_DEVICES)
goto bad_no_lock;
rl;
md = _devs[minor];
if (!md || !md->map)
goto bad;
/* if we're suspended we have to queue this io for later */
if (!test_bit(DM_ACTIVE, &md->state)) {
ru;
r = queue_io(md, bh, rw);
if (r < 0)
goto bad_no_lock;
else if (r > 0)
return 0; /* deferred successfully */
rl; /* FIXME: there's still a race here */
}
if (!__map_buffer(md, bh, rw, __find_node(md->map, bh)))
goto bad;
ru;
return 1;
bad:
ru;
bad_no_lock:
buffer_IO_error(bh);
return 0;
}
static int check_dev_size(int minor, unsigned long block)
{
/* FIXME: check this */
unsigned long max_sector = (_block_size[minor] << 1) + 1;
unsigned long sector = (block + 1) * (_blksize_size[minor] >> 9);
return (sector > max_sector) ? 0 : 1;
}
/*
* creates a dummy buffer head and maps it (for lilo).
*/
static int do_bmap(kdev_t dev, unsigned long block,
kdev_t *r_dev, unsigned long *r_block)
{
struct mapped_device *md;
struct buffer_head bh;
int minor = MINOR(dev), r;
struct target *t;
rl;
if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) ||
!test_bit(DM_ACTIVE, &md->state)) {
r = -ENXIO;
goto out;
}
if (!check_dev_size(minor, block)) {
r = -EINVAL;
goto out;
}
/* setup dummy bh */
memset(&bh, 0, sizeof(bh));
bh.b_blocknr = block;
bh.b_dev = bh.b_rdev = dev;
bh.b_size = _blksize_size[minor];
bh.b_rsector = block * (bh.b_size >> 9);
/* find target */
t = md->map->targets + __find_node(md->map, &bh);
/* do the mapping */
r = t->type->map(&bh, READ, t->private);
*r_dev = bh.b_rdev;
*r_block = bh.b_rsector / (bh.b_size >> 9);
out:
ru;
return r;
}
/*
* marshals arguments and results between user and
* kernel space.
*/
static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb)
{
unsigned long block, r_block;
kdev_t r_dev;
int r;
if (get_user(block, &lvb->lv_block))
return -EFAULT;
if ((r = do_bmap(inode->i_rdev, block, &r_dev, &r_block)))
return r;
if (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
put_user(r_block, &lvb->lv_block))
return -EFAULT;
return 0;
}
/*
* see if the device with a specific minor # is
* free.
*/
static inline int __specific_dev(int minor)
{
if (minor > MAX_DEVICES) {
WARN("request for a mapped_device > than MAX_DEVICES");
return 0;
}
if (!_devs[minor])
return minor;
return -1;
}
/*
* find the first free device.
*/
static inline int __any_old_dev(void)
{
int i;
for (i = 0; i < MAX_DEVICES; i++)
if (!_devs[i])
return i;
return -1;
}
/*
* allocate and initialise a blank device.
*/
static struct mapped_device *alloc_dev(int minor)
{
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
if (!md)
return 0;
memset(md, 0, sizeof (*md));
wl;
minor = (minor < 0) ? __any_old_dev() : __specific_dev(minor);
if (minor < 0) {
WARN("no free devices available");
wu;
kfree(md);
return 0;
}
md->dev = MKDEV(DM_BLK_MAJOR, minor);
md->name[0] = '\0';
md->state = 0;
init_waitqueue_head(&md->wait);
_devs[minor] = md;
wu;
return md;
}
/*
* open a device so we can use it as a map
* destination.
*/
static int open_dev(struct dm_dev *d)
{
int err;
if (d->bd)
BUG();
if (!(d->bd = bdget(kdev_t_to_nr(d->dev))))
return -ENOMEM;
if ((err = blkdev_get(d->bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE))) {
bdput(d->bd);
return err;
}
return 0;
}
/*
* close a device that we've been using.
*/
static void close_dev(struct dm_dev *d)
{
if (!d->bd)
return;
blkdev_put(d->bd, BDEV_FILE);
bdput(d->bd);
d->bd = 0;
}
/*
* Close a list of devices.
*/
static void close_devices(struct list_head *devices)
{
struct list_head *tmp;
for (tmp = devices->next; tmp != devices; tmp = tmp->next) {
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
close_dev(dd);
}
}
/*
* Open a list of devices.
*/
static int open_devices(struct list_head *devices)
{
int r = 0;
struct list_head *tmp;
for (tmp = devices->next; tmp != devices; tmp = tmp->next) {
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
if ((r = open_dev(dd)))
goto bad;
}
return 0;
bad:
close_devices(devices);
return r;
}
struct mapped_device *dm_find_by_minor(int minor)
{
struct mapped_device *md;
rl;
md = _devs[minor];
ru;
return md;
}
static int register_device(struct mapped_device *md)
{
md->devfs_entry =
devfs_register(_dev_dir, md->name, DEVFS_FL_CURRENT_OWNER,
MAJOR(md->dev), MINOR(md->dev),
S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
&dm_blk_dops, NULL);
return 0;
}
static int unregister_device(struct mapped_device *md)
{
devfs_unregister(md->devfs_entry);
return 0;
}
/*
* constructor for a new device
*/
struct mapped_device *dm_create(const char *name, int minor)
{
int r;
struct mapped_device *md;
if (minor >= MAX_DEVICES)
return ERR_PTR(-ENXIO);
if (!(md = alloc_dev(minor)))
return ERR_PTR(-ENXIO);
wl;
strcpy(md->name, name);
_devs[minor] = md;
if ((r = register_device(md))) {
wu;
return ERR_PTR(r);
}
wu;
dm_sbin_hotplug(md, "ACTION=create", minor);
return md;
}
/*
* destructor for the device. md->map is
* deliberately not destroyed, dm-fs should manage
* table objects.
*/
int dm_remove(struct mapped_device *md)
{
int minor, r;
wl;
if (md->use_count) {
wu;
return -EPERM;
}
if ((r = unregister_device(md))) {
wu;
return r;
}
minor = MINOR(md->dev);
_devs[minor] = 0;
wu;
dm_sbin_hotplug(md, "ACTION=remove", minor);
kfree(md);
return 0;
}
/*
* the hardsect size for a mapped device is the
* smallest hard sect size from the devices it
* maps onto.
*/
static int __find_hardsect_size(struct list_head *devices)
{
int result = INT_MAX, size;
struct list_head *tmp;
for (tmp = devices->next; tmp != devices; tmp = tmp->next) {
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
size = get_hardsect_size(dd->dev);
if (size < result)
result = size;
}
return result;
}
/*
* Bind a table to the device.
*/
void __bind(struct mapped_device *md, struct dm_table *t)
{
int minor = MINOR(md->dev);
md->map = t;
/* in k */
_block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1;
_blksize_size[minor] = BLOCK_SIZE;
_hardsect_size[minor] = __find_hardsect_size(&t->devices);
register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
}
/*
* requeue the deferred buffer_heads by calling
* generic_make_request.
*/
static void __flush_deferred_io(struct mapped_device *md)
{
struct deferred_io *c, *n;
for (c = md->deferred, md->deferred = 0; c; c = n) {
n = c->next;
generic_make_request(c->rw, c->bh);
free_deferred(c);
}
}
/*
* make the device available for use, if was
* previously suspended rather than newly created
* then all queued io is flushed
*/
int dm_activate(struct mapped_device *md, struct dm_table *table)
{
int r;
/* check that the mapping has at least been loaded. */
if (!table->num_targets)
return -EINVAL;
wl;
/* you must be deactivated first */
if (is_active(md)) {
wu;
return -EPERM;
}
__bind(md, table);
if ((r = open_devices(&md->map->devices))) {
wu;
return r;
}
set_bit(DM_ACTIVE, &md->state);
__flush_deferred_io(md);
wu;
return 0;
}
/*
* Deactivate the device, the device must not be
* opened by anyone.
*/
int dm_deactivate(struct mapped_device *md)
{
rl;
if (md->use_count) {
ru;
return -EPERM;
}
fsync_dev(md->dev);
ru;
wl;
if (md->use_count) {
/* drat, somebody got in quick ... */
wu;
return -EPERM;
}
if (md->map)
close_devices(&md->map->devices);
md->map = NULL;
clear_bit(DM_ACTIVE, &md->state);
wu;
return 0;
}
/*
* We need to be able to change a mapping table
* under a mounted filesystem. for example we
* might want to move some data in the background.
* Before the table can be swapped with
* dm_bind_table, dm_suspend must be called to
* flush any in flight buffer_heads and ensure
* that any further io gets deferred.
*/
void dm_suspend(struct mapped_device *md)
{
DECLARE_WAITQUEUE(wait, current);
wl;
if (!is_active(md)) {
wu;
return;
}
clear_bit(DM_ACTIVE, &md->state);
wu;
/* wait for all the pending io to flush */
add_wait_queue(&md->wait, &wait);
current->state = TASK_UNINTERRUPTIBLE;
do {
wl;
if (!atomic_read(&md->pending))
break;
wu;
schedule();
} while (1);
current->state = TASK_RUNNING;
remove_wait_queue(&md->wait, &wait);
close_devices(&md->map->devices);
md->map = 0;
wu;
}
struct block_device_operations dm_blk_dops = {
open: dm_blk_open,
release: dm_blk_close,
ioctl: dm_blk_ioctl,
owner: THIS_MODULE,
};
/*
* module hooks
*/
module_init(dm_init);
module_exit(dm_exit);
MODULE_PARM(major, "i");
MODULE_PARM_DESC(major, "The major device number of the device-mapper");
MODULE_DESCRIPTION("device-mapper driver");
MODULE_AUTHOR("Joe Thornber <thornber@btconnect.com>");
MODULE_LICENSE("GPL");
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@@ -1,256 +0,0 @@
/*
* dm.h
*
* Copyright (C) 2001 Sistina Software
*
* This file is released under the GPL.
*/
/*
* Internal header file for device mapper
*
* Changelog
*
* 16/08/2001 - First version [Joe Thornber]
*/
/*
* This driver attempts to provide a generic way of specifying logical
* devices which are mapped onto other devices.
*
* It does this by mapping sections of the logical device onto 'targets'.
*
* When the logical device is accessed the make_request function looks up
* the correct target for the given sector, and then asks this target
* to do the remapping.
*
* (dm-table.c) A btree like structure is used to hold the sector
* range -> target mapping. Because we know all the entries in the
* btree in advance we can make a very compact tree, omitting pointers
* to child nodes, (child nodes locations can be calculated). Each
* node of the btree is 1 level cache line in size, this gives a small
* performance boost.
*
* A userland test program for the btree gave the following results on a
* 1 Gigahertz Athlon machine:
*
* entries in btree lookups per second
* ---------------- ------------------
* 5 25,000,000
* 1000 7,700,000
* 10,000,000 3,800,000
*
* Of course these results should be taken with a pinch of salt; the
* lookups were sequential and there were no other applications (other
* than X + emacs) running to give any pressure on the level 1 cache.
*
* Typical LVM users would find they have very few targets for each
* LV (probably less than 10).
*
* (dm-target.c) Target types are not hard coded, instead the
* register_mapping_type function should be called. A target type is
* specified using three functions (see the header):
*
* dm_ctr_fn - takes a string and contructs a target specific piece of
* context data.
* dm_dtr_fn - destroy contexts.
* dm_map_fn - function that takes a buffer_head and some previously
* constructed context and performs the remapping.
*
* Currently there are two two trivial mappers, which are
* automatically registered: 'linear', and 'io_error'. Linear alone
* is enough to implement most LVM features (omitting striped volumes
* and snapshots).
*
* (dm-fs.c) The driver is controlled through a /proc interface:
* /proc/device-mapper/control allows you to create and remove devices
* by 'cat'ing a line of the following format:
*
* create <device name> [minor no]
* remove <device name>
*
* /proc/device-mapper/<device name> accepts the mapping table:
*
* begin
* <sector start> <length> <target name> <target args>...
* ...
* end
*
* The begin/end lines are nasty, they should be handled by open/close
* for the file.
*
* At the moment the table assumes 32 bit keys (sectors), the move to
* 64 bits will involve no interface changes, since the tables will be
* read in as ascii data. A different table implementation can
* therefor be provided at another time. Either just by changing offset_t
* to 64 bits, or maybe implementing a structure which looks up the keys in
* stages (ie, 32 bits at a time).
*
* More interesting targets:
*
* striped mapping; given a stripe size and a number of device regions
* this would stripe data across the regions. Especially useful, since
* we could limit each striped region to a 32 bit area and then avoid
* nasty 64 bit %'s.
*
* mirror mapping (reflector ?); would set off a kernel thread slowly
* copying data from one region to another, ensuring that any new
* writes got copied to both destinations correctly. Great for
* implementing pvmove. Not sure how userland would be notified that
* the copying process had completed. Possibly by reading a /proc entry
* for the LV. Could also use poll() for this kind of thing.
*/
#ifndef DM_INTERNAL_H
#define DM_INTERNAL_H
#include <linux/version.h>
#include <linux/major.h>
#include <linux/iobuf.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/compatmac.h>
#include <linux/cache.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/ctype.h>
#include <linux/device-mapper.h>
#include <linux/list.h>
#define MAX_DEPTH 16
#define NODE_SIZE L1_CACHE_BYTES
#define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t))
#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
#define DM_NAME_LEN 128
#define MAX_TARGET_LINE 256
enum {
DM_BOUND = 0, /* device has been bound to a table */
DM_ACTIVE, /* device is running */
};
/*
* list of devices that a metadevice uses
* and hence should open/close.
*/
struct dm_dev {
atomic_t count;
struct list_head list;
kdev_t dev;
struct block_device *bd;
};
/*
* io that had to be deferred while we were
* suspended
*/
struct deferred_io {
int rw;
struct buffer_head *bh;
struct deferred_io *next;
};
/*
* btree leaf, these do the actual mapping
*/
struct target {
struct target_type *type;
void *private;
};
/*
* the btree
*/
struct dm_table {
/* btree table */
int depth;
int counts[MAX_DEPTH]; /* in nodes */
offset_t *index[MAX_DEPTH];
int num_targets;
int num_allocated;
offset_t *highs;
struct target *targets;
/* a list of devices used by this table */
struct list_head devices;
};
/*
* the actual device struct
*/
struct mapped_device {
kdev_t dev;
char name[DM_NAME_LEN];
int use_count;
int state;
/* a list of io's that arrived while we were suspended */
atomic_t pending;
wait_queue_head_t wait;
struct deferred_io *deferred;
struct dm_table *map;
/* used by dm-fs.c */
devfs_handle_t devfs_entry;
};
extern struct block_device_operations dm_blk_dops;
/* dm-target.c */
int dm_target_init(void);
struct target_type *dm_get_target_type(const char *name);
void dm_put_target_type(struct target_type *t);
/* dm.c */
struct mapped_device *dm_find_by_minor(int minor);
struct mapped_device *dm_create(const char *name, int minor);
int dm_remove(struct mapped_device *md);
int dm_activate(struct mapped_device *md, struct dm_table *t);
int dm_deactivate(struct mapped_device *md);
void dm_suspend(struct mapped_device *md);
/* dm-table.c */
struct dm_table *dm_table_create(void);
void dm_table_destroy(struct dm_table *t);
int dm_table_add_target(struct dm_table *t, offset_t high,
struct target_type *type, void *private);
int dm_table_complete(struct dm_table *t);
#define WARN(f, x...) printk(KERN_WARNING "device-mapper: " f "\n" , ## x)
/*
* calculate the index of the child node of the
* n'th node k'th key.
*/
static inline int get_child(int n, int k)
{
return (n * CHILDREN_PER_NODE) + k;
}
/*
* returns the n'th node of level l from table t.
*/
static inline offset_t *get_node(struct dm_table *t, int l, int n)
{
return t->index[l] + (n * KEYS_PER_NODE);
}
static inline int is_active(struct mapped_device *md)
{
return test_bit(DM_ACTIVE, &md->state);
}
#endif

View File

@@ -1,154 +0,0 @@
/*
* dmfs-error.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include "dm.h"
#include "dmfs.h"
struct dmfs_error {
struct list_head list;
unsigned len;
char *msg;
};
static struct dmfs_error oom_error;
static struct list_head oom_list = {
next: &oom_error.list,
prev: &oom_error.list,
};
static struct dmfs_error oom_error = {
list: { next: &oom_list, prev: &oom_list },
len: 39,
msg: "Out of memory during creation of table\n",
};
void dmfs_add_error(struct inode *inode, unsigned num, char *str)
{
struct dmfs_i *dmi = DMFS_I(inode);
int len = strlen(str) + sizeof(struct dmfs_error) + 12;
struct dmfs_error *e = kmalloc(len, GFP_KERNEL);
if (e) {
e->msg = (char *)(e + 1);
e->len = sprintf(e->msg, "%8u: %s\n", num, str);
list_add(&e->list, &dmi->errors);
}
}
void dmfs_zap_errors(struct inode *inode)
{
struct dmfs_i *dmi = DMFS_I(inode);
struct dmfs_error *e;
while(!list_empty(&dmi->errors)) {
e = list_entry(dmi->errors.next, struct dmfs_error, list);
list_del(&e->list);
kfree(e);
}
}
static void *e_start(void *context, loff_t *pos)
{
struct list_head *p;
loff_t n = *pos;
struct dmfs_i *dmi = context;
down(&dmi->sem);
if (dmi->status) {
list_for_each(p, &oom_list)
if (n-- == 0)
return list_entry(p, struct dmfs_error, list);
} else {
list_for_each(p, &dmi->errors)
if (n-- == 0)
return list_entry(p, struct dmfs_error, list);
}
return NULL;
}
static void *e_next(void *context, void *v, loff_t *pos)
{
struct dmfs_i *dmi = context;
struct list_head *p = ((struct dmfs_error *)v)->list.next;
(*pos)++;
return (p == &dmi->errors) || (p == &oom_list) ? NULL
: list_entry(p, struct dmfs_error, list);
}
static void e_stop(void *context, void *v)
{
struct dmfs_i *dmi = context;
up(&dmi->sem);
}
static int show_error(struct seq_file *e, void *v)
{
struct dmfs_error *d = v;
seq_puts(e, d->msg);
return 0;
}
static struct seq_operations error_op = {
start: e_start,
next: e_next,
stop: e_stop,
show: show_error,
};
static int dmfs_error_open(struct inode *inode, struct file *file)
{
return seq_open(file, &error_op, DMFS_I(file->f_dentry->d_parent->d_inode));
}
static int dmfs_error_sync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
static struct file_operations dmfs_error_file_operations = {
open: dmfs_error_open,
read: seq_read,
llseek: seq_lseek,
release: seq_release,
fsync: dmfs_error_sync,
};
static struct inode_operations dmfs_error_inode_operations = {
};
struct inode *dmfs_create_error(struct inode *dir, int mode)
{
struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG);
if (inode) {
inode->i_fop = &dmfs_error_file_operations;
inode->i_op = &dmfs_error_inode_operations;
}
return inode;
}

View File

@@ -1,286 +0,0 @@
/*
* dmfs-lv.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Heavily based upon ramfs */
#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/fs.h>
#include "dm.h"
#include "dmfs.h"
extern struct address_space_operations dmfs_address_space_operations;
extern struct inode *dmfs_create_tdir(struct super_block *sb, int mode);
struct dentry *dmfs_verify_name(struct inode *dir, const char *name)
{
struct nameidata nd;
int err = -ENOENT;
struct file file;
struct dentry *dentry;
memset(&file, 0, sizeof(struct file));
if (!path_init(name, LOOKUP_FOLLOW, &nd))
return ERR_PTR(-EINVAL);
err = path_walk(name, &nd);
if (err)
goto err_out;
err = -EINVAL;
if (nd.mnt->mnt_sb != dir->i_sb)
goto err_out;
if (nd.dentry->d_parent->d_inode != dir)
goto err_out;
err = -ENODATA;
if (DMFS_I(nd.dentry->d_inode) == NULL ||
DMFS_I(nd.dentry->d_inode)->table == NULL)
goto err_out;
if (!list_empty(&(DMFS_I(nd.dentry->d_inode)->errors)))
goto err_out;
dentry = nd.dentry;
file.f_dentry = nd.dentry;
err = deny_write_access(&file);
if (err)
goto err_out;
dget(dentry);
path_release(&nd);
return dentry;
err_out:
path_release(&nd);
return ERR_PTR(err);
}
struct inode *dmfs_create_symlink(struct inode *dir, int mode)
{
struct inode *inode = dmfs_new_private_inode(dir->i_sb, mode | S_IFLNK);
if (inode) {
inode->i_mapping->a_ops = &dmfs_address_space_operations;
inode->i_op = &page_symlink_inode_operations;
}
return inode;
}
static int dmfs_lv_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct file file = { f_dentry: DMFS_I(inode)->dentry };
if (!(inode->i_mode & S_IFLNK))
return -EINVAL;
dm_suspend(DMFS_I(dir)->md);
allow_write_access(&file);
dput(DMFS_I(inode)->dentry);
DMFS_I(inode)->dentry = NULL;
inode->i_nlink--;
dput(dentry);
return 0;
}
static int dmfs_lv_symlink(struct inode *dir, struct dentry *dentry,
const char *symname)
{
struct inode *inode;
struct dentry *de;
int rv;
int l;
if (dentry->d_name.len != 6 ||
memcmp(dentry->d_name.name, "ACTIVE", 6) != 0)
return -EINVAL;
de = dmfs_verify_name(dir, symname);
if (IS_ERR(de))
return PTR_ERR(de);
inode = dmfs_create_symlink(dir, S_IRWXUGO);
if (inode == NULL) {
rv = -ENOSPC;
goto out_allow_write;
}
DMFS_I(inode)->dentry = de;
d_instantiate(dentry, inode);
dget(dentry);
l = strlen(symname) + 1;
rv = block_symlink(inode, symname, l);
if (rv)
goto out_dput;
rv = dm_activate(DMFS_I(dir)->md, DMFS_I(de->d_inode)->table);
if (rv)
goto out_dput;
return rv;
out_dput:
dput(dentry);
DMFS_I(inode)->dentry = NULL;
out_allow_write:
{
struct file file = { f_dentry: de };
allow_write_access(&file);
dput(de);
}
return rv;
}
static int is_identifier(const char *str, int len)
{
while(len--) {
if (!isalnum(*str) && *str != '_')
return 0;
str++;
}
return 1;
}
static int dmfs_lv_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
int rv = -ENOSPC;
if (dentry->d_name.len >= DM_NAME_LEN)
return -EINVAL;
if (!is_identifier(dentry->d_name.name, dentry->d_name.len))
return -EPERM;
if (dentry->d_name.len == 6 &&
memcmp(dentry->d_name.name, "ACTIVE", 6) == 0)
return -EINVAL;
if (dentry->d_name.name[0] == '.')
return -EINVAL;
inode = dmfs_create_tdir(dir->i_sb, mode);
if (inode) {
d_instantiate(dentry, inode);
dget(dentry);
rv = 0;
}
return rv;
}
/*
* if u.generic_ip is not NULL, then it indicates an inode which
* represents a table. If it is NULL then the inode is a virtual
* file and should be deleted along with the directory.
*/
static inline int positive(struct dentry *dentry)
{
return dentry->d_inode && !d_unhashed(dentry);
}
static int empty(struct dentry *dentry)
{
struct list_head *list;
spin_lock(&dcache_lock);
list = dentry->d_subdirs.next;
while(list != &dentry->d_subdirs) {
struct dentry *de = list_entry(list, struct dentry, d_child);
if (positive(de)) {
spin_unlock(&dcache_lock);
return 0;
}
list = list->next;
}
spin_unlock(&dcache_lock);
return 1;
}
static int dmfs_lv_rmdir(struct inode *dir, struct dentry *dentry)
{
int ret = -ENOTEMPTY;
if (empty(dentry)) {
struct inode *inode = dentry->d_inode;
inode->i_nlink--;
dput(dentry);
ret = 0;
}
return ret;
}
static struct dentry *dmfs_lv_lookup(struct inode *dir, struct dentry *dentry)
{
d_add(dentry, NULL);
return NULL;
}
static int dmfs_lv_sync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
static struct file_operations dmfs_lv_file_operations = {
read: generic_read_dir,
readdir: dcache_readdir,
fsync: dmfs_lv_sync,
};
static struct inode_operations dmfs_lv_inode_operations = {
lookup: dmfs_lv_lookup,
unlink: dmfs_lv_unlink,
symlink: dmfs_lv_symlink,
mkdir: dmfs_lv_mkdir,
rmdir: dmfs_lv_rmdir,
};
struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *dentry)
{
struct inode *inode = dmfs_new_private_inode(sb, mode | S_IFDIR);
struct mapped_device *md;
const char *name = dentry->d_name.name;
char tmp_name[DM_NAME_LEN + 1];
if (inode) {
inode->i_fop = &dmfs_lv_file_operations;
inode->i_op = &dmfs_lv_inode_operations;
memcpy(tmp_name, name, dentry->d_name.len);
tmp_name[dentry->d_name.len] = 0;
md = dm_create(tmp_name, -1);
if (IS_ERR(md)) {
iput(inode);
return ERR_PTR(PTR_ERR(md));
}
DMFS_I(inode)->md = md;
}
return inode;
}

View File

@@ -1,158 +0,0 @@
/*
* dmfs-root.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Heavily based upon ramfs */
#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/fs.h>
#include "dm.h"
#include "dmfs.h"
extern struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *dentry);
static int is_identifier(const char *str, int len)
{
while(len--) {
if (!isalnum(*str) && *str != '_')
return 0;
str++;
}
return 1;
}
static int dmfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct inode *inode;
int rv = -ENOSPC;
if (dentry->d_name.len >= DM_NAME_LEN)
return -EINVAL;
if (!is_identifier(dentry->d_name.name, dentry->d_name.len))
return -EPERM;
if (dentry->d_name.name[0] == '.')
return -EINVAL;
inode = dmfs_create_lv(dir->i_sb, mode, dentry);
if (inode) {
d_instantiate(dentry, inode);
dget(dentry);
rv = 0;
}
return rv;
}
/*
* if u.generic_ip is not NULL, then it indicates an inode which
* represents a table. If it is NULL then the inode is a virtual
* file and should be deleted along with the directory.
*/
static inline int positive(struct dentry *dentry)
{
return dentry->d_inode && !d_unhashed(dentry);
}
static int empty(struct dentry *dentry)
{
struct list_head *list;
spin_lock(&dcache_lock);
list = dentry->d_subdirs.next;
while(list != &dentry->d_subdirs) {
struct dentry *de = list_entry(list, struct dentry, d_child);
if (positive(de)) {
spin_unlock(&dcache_lock);
return 0;
}
list = list->next;
}
spin_unlock(&dcache_lock);
return 1;
}
static int dmfs_root_rmdir(struct inode *dir, struct dentry *dentry)
{
int ret = -ENOTEMPTY;
if (empty(dentry)) {
struct inode *inode = dentry->d_inode;
ret = dm_deactivate(DMFS_I(inode)->md);
if (ret == 0) {
inode->i_nlink--;
dput(dentry);
}
}
return ret;
}
static struct dentry *dmfs_root_lookup(struct inode *dir, struct dentry *dentry)
{
d_add(dentry, NULL);
return NULL;
}
static int dmfs_root_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
/* Can only rename - not move between directories! */
if (old_dir != new_dir)
return -EPERM;
return -EINVAL; /* FIXME: a change of LV name here */
}
static int dmfs_root_sync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
static struct file_operations dmfs_root_file_operations = {
read: generic_read_dir,
readdir: dcache_readdir,
fsync: dmfs_root_sync,
};
static struct inode_operations dmfs_root_inode_operations = {
lookup: dmfs_root_lookup,
mkdir: dmfs_root_mkdir,
rmdir: dmfs_root_rmdir,
rename: dmfs_root_rename,
};
struct inode *dmfs_create_root(struct super_block *sb, int mode)
{
struct inode *inode = dmfs_new_inode(sb, mode | S_IFDIR);
if (inode) {
inode->i_fop = &dmfs_root_file_operations;
inode->i_op = &dmfs_root_inode_operations;
}
return inode;
}

View File

@@ -1,57 +0,0 @@
/*
* dmfs-status.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/fs.h>
#include "dm.h"
#include "dmfs.h"
static ssize_t dmfs_status_read(struct file *file, char *buf, size_t size, loff_t *pos)
{
return 0;
}
static int dmfs_status_sync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
static struct file_operations dmfs_status_file_operations = {
read: dmfs_status_read,
fsync: dmfs_status_sync,
};
static struct inode_operations dmfs_status_inode_operations = {
};
struct inode *dmfs_create_status(struct inode *dir, int mode)
{
struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG);
if (inode) {
inode->i_fop = &dmfs_status_file_operations;
inode->i_op = &dmfs_status_inode_operations;
}
return inode;
}

View File

@@ -1,162 +0,0 @@
/*
* dmfs-super.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include "dmfs.h"
#include "dm.h"
#define DMFS_MAGIC 0x444D4653
extern struct inode *dmfs_create_root(struct super_block *sb, int);
static int dmfs_statfs(struct super_block *sb, struct statfs *buf)
{
buf->f_type = sb->s_magic;
buf->f_bsize = sb->s_blocksize;
buf->f_namelen = DM_NAME_LEN - 1;
return 0;
}
static void dmfs_delete_inode(struct inode *inode)
{
struct dmfs_i *dmi = DMFS_I(inode);
if (dmi) {
if (dmi->md)
dm_remove(dmi->md);
if (dmi->table)
dm_table_destroy(dmi->table);
if (dmi->dentry)
dput(dmi->dentry);
if (!list_empty(&dmi->errors))
dmfs_zap_errors(inode);
kfree(dmi);
MOD_DEC_USE_COUNT; /* Don't remove */
}
inode->u.generic_ip = NULL;
clear_inode(inode);
}
static struct super_operations dmfs_super_operations = {
statfs: dmfs_statfs,
put_inode: force_delete,
delete_inode: dmfs_delete_inode,
};
static struct super_block *dmfs_read_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = DMFS_MAGIC;
sb->s_op = &dmfs_super_operations;
sb->s_maxbytes = MAX_NON_LFS;
inode = dmfs_create_root(sb, 0755);
if (IS_ERR(inode))
return NULL;
root = d_alloc_root(inode);
if (!root) {
iput(inode);
return NULL;
}
sb->s_root = root;
return sb;
}
struct inode *dmfs_new_inode(struct super_block *sb, int mode)
{
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_rdev = NODEV;
inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
}
return inode;
}
struct inode *dmfs_new_private_inode(struct super_block *sb, int mode)
{
struct inode *inode = dmfs_new_inode(sb, mode);
struct dmfs_i *dmi;
if (inode) {
dmi = kmalloc(sizeof(struct dmfs_i), GFP_KERNEL);
if (dmi == NULL) {
iput(inode);
return NULL;
}
memset(dmi, 0, sizeof(struct dmfs_i));
init_MUTEX(&dmi->sem);
INIT_LIST_HEAD(&dmi->errors);
inode->u.generic_ip = dmi;
MOD_INC_USE_COUNT; /* Don't remove */
}
return inode;
}
static DECLARE_FSTYPE(dmfs_fstype, "dmfs", dmfs_read_super, FS_SINGLE);
static struct vfsmount *dmfs_mnt;
int __init dmfs_init(void)
{
int ret;
ret = register_filesystem(&dmfs_fstype);
if (ret < 0)
goto out;
dmfs_mnt = kern_mount(&dmfs_fstype);
if (IS_ERR(dmfs_mnt)) {
ret = PTR_ERR(dmfs_mnt);
unregister_filesystem(&dmfs_fstype);
} else {
MOD_DEC_USE_COUNT; /* Yes, this really is correct... */
}
out:
return ret;
}
int __exit dmfs_exit(void)
{
MOD_INC_USE_COUNT; /* So that it lands up being zero */
do_umount(dmfs_mnt, 0);
unregister_filesystem(&dmfs_fstype);
return 0;
}

View File

@@ -1,353 +0,0 @@
/*
* dmfs-table.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include "dm.h"
#include "dmfs.h"
static offset_t start_of_next_range(struct dm_table *t)
{
offset_t n = 0;
if (t->num_targets) {
n = t->highs[t->num_targets - 1] + 1;
}
return n;
}
static char *dmfs_parse_line(struct dm_table *t, char *str)
{
offset_t start, size, high;
void *context;
struct target_type *ttype;
int rv = 0;
char *msg;
int pos = 0;
char target[33];
static char *err_table[] = {
"Missing/Invalid start argument",
"Missing/Invalid size argument",
"Missing target type"
};
printk("dmfs_parse_line: (%s)\n", str);
rv = sscanf(str, "%d %d %32s%n", &start, &size, target, &pos);
if (rv < 3) {
msg = err_table[rv];
goto out;
}
str += pos;
while(*str && isspace(*str))
str++;
msg = "Gap in table";
if (start != start_of_next_range(t))
goto out;
msg = "Target type unknown";
ttype = dm_get_target_type(target);
if (ttype) {
msg = "This message should never appear (constructor error)";
rv = ttype->ctr(t, start, size, str, &context);
msg = context;
if (rv == 0) {
printk("dmfs_parse: %u %u %s %s\n", start, size,
ttype->name,
ttype->print ? ttype->print(context) : "-");
msg = "Error adding target to table";
high = start + (size - 1);
if (dm_table_add_target(t, high, ttype, context) == 0)
return NULL;
ttype->dtr(t, context);
}
dm_put_target_type(ttype);
}
out:
return msg;
}
static int dmfs_copy(char *dst, int dstlen, char *src, int srclen, int *flag)
{
int len = min(dstlen, srclen);
char *start = dst;
while(len) {
*dst = *src++;
if (*dst == '\n')
goto end_of_line;
dst++;
len--;
}
out:
return (dst - start);
end_of_line:
dst++;
*flag = 1;
goto out;
}
static int dmfs_line_is_not_comment(char *str)
{
while(*str) {
if (*str == '#')
break;
if (!isspace(*str))
return 1;
str++;
}
return 0;
}
struct dmfs_desc {
struct dm_table *table;
struct inode *inode;
char *tmp;
loff_t tmpl;
unsigned long lnum;
};
static int dmfs_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size)
{
char *buf, *msg;
unsigned long count = desc->count, len, copied;
struct dmfs_desc *d = (struct dmfs_desc *)desc->buf;
if (size > count)
size = count;
len = size;
buf = kmap(page);
do {
int flag = 0;
copied = dmfs_copy(d->tmp + d->tmpl, PAGE_SIZE - d->tmpl - 1,
buf + offset, len, &flag);
offset += copied;
len -= copied;
if (d->tmpl + copied == PAGE_SIZE - 1)
goto line_too_long;
d->tmpl += copied;
if (flag || (len == 0 && count == size)) {
*(d->tmp + d->tmpl) = 0;
if (dmfs_line_is_not_comment(d->tmp)) {
msg = dmfs_parse_line(d->table, d->tmp);
if (msg) {
dmfs_add_error(d->inode, d->lnum, msg);
}
}
d->lnum++;
d->tmpl = 0;
}
} while(len > 0);
kunmap(page);
desc->count = count - size;
desc->written += size;
return size;
line_too_long:
printk(KERN_INFO "dmfs_read_actor: Line %lu too long\n", d->lnum);
kunmap(page);
return 0;
}
static struct dm_table *dmfs_parse(struct inode *inode, struct file *filp)
{
struct dm_table *t = NULL;
unsigned long page;
struct dmfs_desc d;
loff_t pos = 0;
if (inode->i_size == 0)
return NULL;
page = __get_free_page(GFP_NOFS);
if (page) {
t = dm_table_create();
if (t) {
read_descriptor_t desc;
desc.written = 0;
desc.count = inode->i_size;
desc.buf = (char *)&d;
d.table = t;
d.inode = inode;
d.tmp = (char *)page;
d.tmpl = 0;
d.lnum = 1;
do_generic_file_read(filp, &pos, &desc, dmfs_read_actor);
if (desc.written != inode->i_size) {
dm_table_destroy(t);
t = NULL;
}
}
free_page(page);
}
return t;
}
static int dmfs_table_release(struct inode *inode, struct file *f)
{
struct dentry *dentry = f->f_dentry;
struct inode *parent = dentry->d_parent->d_inode;
struct dmfs_i *dmi = DMFS_I(parent);
struct dm_table *table;
if (f->f_mode & FMODE_WRITE) {
down(&dmi->sem);
dmfs_zap_errors(dentry->d_parent->d_inode);
table = dmfs_parse(dentry->d_parent->d_inode, f);
if (table) {
if (dmi->table)
dm_table_destroy(dmi->table);
dmi->table = table;
}
up(&dmi->sem);
put_write_access(parent);
}
return 0;
}
static int dmfs_readpage(struct file *file, struct page *page)
{
if (!Page_Uptodate(page)) {
memset(kmap(page), 0, PAGE_CACHE_SIZE);
kunmap(page);
flush_dcache_page(page);
SetPageUptodate(page);
}
UnlockPage(page);
return 0;
}
static int dmfs_prepare_write(struct file *file, struct page *page,
unsigned offset, unsigned to)
{
void *addr = kmap(page);
if (!Page_Uptodate(page)) {
memset(addr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
SetPageUptodate(page);
}
SetPageDirty(page);
return 0;
}
static int dmfs_commit_write(struct file *file, struct page *page,
unsigned offset, unsigned to)
{
struct inode *inode = page->mapping->host;
loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to;
kunmap(page);
if (pos > inode->i_size)
inode->i_size = pos;
return 0;
}
/*
* There is a small race here in that two processes might call this at
* the same time and both fail. So its a fail safe race :-) This should
* move into namei.c (and thus use the spinlock and do this properly)
* at some stage if we continue to use this set of functions for ensuring
* exclusive write access to the file
*/
static int get_exclusive_write_access(struct inode *inode)
{
if (get_write_access(inode))
return -1;
if (atomic_read(&inode->i_writecount) != 1) {
put_write_access(inode);
return -1;
}
return 0;
}
static int dmfs_table_open(struct inode *inode, struct file *file)
{
struct dentry *dentry = file->f_dentry;
struct inode *parent = dentry->d_parent->d_inode;
if (file->f_mode & FMODE_WRITE) {
if (get_exclusive_write_access(parent))
return -EPERM;
}
return 0;
}
static int dmfs_table_sync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
static int dmfs_table_revalidate(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct inode *parent = dentry->d_parent->d_inode;
inode->i_size = parent->i_size;
return 0;
}
struct address_space_operations dmfs_address_space_operations = {
readpage: dmfs_readpage,
writepage: fail_writepage,
prepare_write: dmfs_prepare_write,
commit_write: dmfs_commit_write,
};
static struct file_operations dmfs_table_file_operations = {
llseek: generic_file_llseek,
read: generic_file_read,
write: generic_file_write,
open: dmfs_table_open,
release: dmfs_table_release,
fsync: dmfs_table_sync,
};
static struct inode_operations dmfs_table_inode_operations = {
revalidate: dmfs_table_revalidate,
};
struct inode *dmfs_create_table(struct inode *dir, int mode)
{
struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG);
if (inode) {
inode->i_mapping = dir->i_mapping;
inode->i_mapping->a_ops = &dmfs_address_space_operations;
inode->i_fop = &dmfs_table_file_operations;
inode->i_op = &dmfs_table_inode_operations;
}
return inode;
}

View File

@@ -1,138 +0,0 @@
/*
* dmfs-tdir.c
*
* Copyright (C) 2001 Sistina Software
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2, or (at
* your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Heavily based upon ramfs */
#include <linux/config.h>
#include <linux/fs.h>
#include "dm.h"
#include "dmfs.h"
extern struct inode *dmfs_create_error(struct inode *, int);
extern struct inode *dmfs_create_table(struct inode *, int);
extern struct inode *dmfs_create_status(struct inode *, int);
static int dmfs_tdir_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
inode->i_mapping = &inode->i_data;
inode->i_nlink--;
dput(dentry);
return 0;
}
static struct dentry *dmfs_tdir_lookup(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = NULL;
const char *name = dentry->d_name.name;
switch(dentry->d_name.len) {
case 5:
if (memcmp("table", name, 5) == 0) {
inode = dmfs_create_table(dir, 0600);
break;
}
if (memcmp("error", name, 5) == 0)
inode = dmfs_create_error(dir, 0600);
break;
case 6:
if (memcmp("status", name, 6) == 0)
inode = dmfs_create_status(dir, 0600);
break;
}
d_add(dentry, inode);
return NULL;
}
static int dmfs_tdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
int i;
struct dentry *dentry = filp->f_dentry;
i = filp->f_pos;
switch(i) {
case 0:
if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
break;
i++;
filp->f_pos++;
/* fallthrough */
case 1:
if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
break;
i++;
filp->f_pos++;
/* fallthrough */
case 2:
if (filldir(dirent, "table", 5, i, 2, DT_REG) < 0)
break;
i++;
filp->f_pos++;
/* fallthrough */
case 3:
if (filldir(dirent, "error", 5, i, 3, DT_REG) < 0)
break;
i++;
filp->f_pos++;
/* fallthrough */
case 4:
if (filldir(dirent, "status", 6, i, 4, DT_REG) < 0)
break;
i++;
filp->f_pos++;
}
return 0;
}
static int dmfs_tdir_sync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
static struct file_operations dmfs_tdir_file_operations = {
read: generic_read_dir,
readdir: dmfs_tdir_readdir,
fsync: dmfs_tdir_sync,
};
static struct inode_operations dmfs_tdir_inode_operations = {
lookup: dmfs_tdir_lookup,
unlink: dmfs_tdir_unlink,
};
struct inode *dmfs_create_tdir(struct super_block *sb, int mode)
{
struct inode *inode = dmfs_new_private_inode(sb, mode | S_IFDIR);
if (inode) {
inode->i_fop = &dmfs_tdir_file_operations;
inode->i_op = &dmfs_tdir_inode_operations;
}
return inode;
}

View File

@@ -1,27 +0,0 @@
#ifndef LINUX_DMFS_H
#define LINUX_DMFS_H
struct dmfs_i {
struct semaphore sem;
struct dm_table *table;
struct mapped_device *md;
struct dentry *dentry;
struct list_head errors;
int status;
};
#define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip)
extern int dmfs_init(void) __init;
extern int dmfs_exit(void) __exit;
struct inode *dmfs_new_inode(struct super_block *sb, int mode);
struct inode *dmfs_new_private_inode(struct super_block *sb, int mode);
void dmfs_add_error(struct inode *inode, unsigned num, char *str);
void dmfs_zap_errors(struct inode *inode);
#endif /* LINUX_DMFS_H */

View File

@@ -1,10 +0,0 @@
--- linux-2.4.14/drivers/md/Config.in Mon Sep 24 16:29:14 2001
+++ linux/drivers/md/Config.in Tue Nov 6 11:25:35 2001
@@ -14,5 +14,7 @@
dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD
+dep_tristate ' Device mapper support' CONFIG_BLK_DEV_DM $CONFIG_MD
+dep_tristate ' Device mapper linear target' CONFIG_BLK_DEV_DM_LINEAR $CONFIG_BLK_DEV_DM
endmenu

View File

@@ -1,13 +0,0 @@
--- uml_build/arch/um/config.in.orig Tue Jan 2 14:33:42 2001
+++ uml_build/arch/um/config.in Tue Jan 2 14:35:42 2001
@@ -15,6 +15,8 @@
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
+source drivers/md/Config.in
+
mainmenu_option next_comment
comment 'Processor features'
bool 'Symmetric multi-processing support' CONFIG_SMP

View File

@@ -1,10 +0,0 @@
--- linux-2.4.14/kernel/ksyms.c Tue Nov 6 11:18:14 2001
+++ linux/kernel/ksyms.c Wed Nov 7 11:26:45 2001
@@ -521,6 +521,7 @@
/* binfmt_aout */
EXPORT_SYMBOL(get_write_access);
+EXPORT_SYMBOL(deny_write_access);
/* time */
EXPORT_SYMBOL(get_fast_time);

View File

@@ -1,31 +0,0 @@
--- linux-2.4.14/drivers/md/Makefile Mon Sep 24 16:29:14 2001
+++ linux/drivers/md/Makefile Wed Nov 7 10:48:26 2001
@@ -4,9 +4,12 @@
O_TARGET := mddev.o
-export-objs := md.o xor.o
+export-objs := md.o xor.o dm-table.o dm-target.o
list-multi := lvm-mod.o
lvm-mod-objs := lvm.o lvm-snap.o
+dm-mod-objs := dm.o dm-table.o dm-target.o dmfs-super.o dmfs-root.o \
+ dmfs-tdir.o dmfs-table.o dmfs-error.o dmfs-status.o \
+ dmfs-lv.o seq_file.o
# Note: link order is important. All raid personalities
# and xor.o must come before md.o, as they each initialise
@@ -20,8 +23,14 @@
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
obj-$(CONFIG_BLK_DEV_MD) += md.o
obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o
+obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
+obj-$(CONFIG_BLK_DEV_DM_LINEAR) += dm-linear.o
include $(TOPDIR)/Rules.make
lvm-mod.o: $(lvm-mod-objs)
$(LD) -r -o $@ $(lvm-mod-objs)
+
+dm-mod.o: $(dm-mod-objs)
+ $(LD) -r -o $@ $(dm-mod-objs)
+

View File

@@ -1,13 +0,0 @@
00_latest Latest source - I only tend to update this before
making a release. So if you got this from CVS copy
or link the source files in by hand.
00_config Add device-mapper to the MD section
00_config_uml only apply for uml, turns on the md section
00_makefile Add device-mapper to the MD Makefile.
00_bh-async-3 AA's async bh patch so we can hook b_end_io
to keep track of pending io.

View File

@@ -1,6 +0,0 @@
List of projects, ideas and pending bug fixes
===============================================
o Check tables are an integer multiple of the underlying block size at
table load time.

View File

@@ -1,240 +0,0 @@
/*
* linux/fs/seq_file.c
*
* helper functions for making syntetic files from sequences of records.
* initial implementation -- AV, Oct 2001.
*
* Slight modifications to the original. Will be passed on to Al Viro in
* the next few days.
*/
#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
/**
* seq_open - initialize sequential file
* @file: file we initialize
* @op: method table describing the sequence
*
* seq_open() sets @file, associating it with a sequence described
* by @op. @op->start() sets the iterator up and returns the first
* element of sequence. @op->stop() shuts it down. @op->next()
* returns the next element of sequence. @op->show() prints element
* into the buffer. In case of error ->start() and ->next() return
* ERR_PTR(error). In the end of sequence they return %NULL. ->show()
* returns 0 in case of success and negative number in case of error.
*/
int seq_open(struct file *file, struct seq_operations *op, void *context)
{
struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
memset(p, 0, sizeof(*p));
sema_init(&p->sem, 1);
p->op = op;
p->context = context;
file->private_data = p;
return 0;
}
/**
* seq_read - ->read() method for sequential files.
* @file, @buf, @size, @ppos: see file_operations method
*
* Ready-made ->f_op->read()
*/
ssize_t seq_read(struct file *file, char *buf, size_t size, loff_t *ppos)
{
struct seq_file *m = (struct seq_file *)file->private_data;
size_t copied = 0;
loff_t pos;
size_t n;
void *p;
int err = 0;
if (ppos != &file->f_pos)
return -EPIPE;
down(&m->sem);
/* grab buffer if we didn't have one */
if (!m->buf) {
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
if (!m->buf)
goto Enomem;
}
/* if not empty - flush it first */
if (m->count) {
n = min(m->count, size);
err = copy_to_user(buf, m->buf + m->from, n);
if (err)
goto Efault;
m->count -= n;
m->from += n;
size -= n;
buf += n;
copied += n;
if (!m->count)
(*ppos)++;
if (!size)
goto Done;
}
/* we need at least one record in buffer */
while (1) {
pos = *ppos;
p = m->op->start(m->context, &pos);
err = PTR_ERR(p);
if (!p || IS_ERR(p))
break;
err = m->op->show(m, p);
if (err)
break;
if (m->count < m->size)
goto Fill;
m->op->stop(m->context, p);
kfree(m->buf);
m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
if (!m->buf)
goto Enomem;
}
m->op->stop(m->context, p);
goto Done;
Fill:
/* they want more? let's try to get some more */
while (m->count < size) {
size_t offs = m->count;
loff_t next = pos;
p = m->op->next(m->context, p, &next);
if (!p || IS_ERR(p)) {
err = PTR_ERR(p);
break;
}
err = m->op->show(m, p);
if (err || m->count == m->size) {
m->count = offs;
break;
}
pos = next;
}
m->op->stop(m->context, p);
n = min(m->count, size);
err = copy_to_user(buf, m->buf, n);
if (err)
goto Efault;
copied += n;
m->count -= n;
if (m->count)
m->from = n;
else
pos++;
*ppos = pos;
Done:
if (!copied)
copied = err;
up(&m->sem);
return copied;
Enomem:
err = -ENOMEM;
goto Done;
Efault:
err = -EFAULT;
goto Done;
}
/**
* seq_lseek - ->llseek() method for sequential files.
* @file, @offset, @origin: see file_operations method
*
* Ready-made ->f_op->llseek()
*/
loff_t seq_lseek(struct file *file, loff_t offset, int origin)
{
struct seq_file *m = (struct seq_file *)file->private_data;
long long retval = -EINVAL;
down(&m->sem);
switch (origin) {
case 1:
offset += file->f_pos;
case 0:
if (offset < 0)
break;
if (offset != file->f_pos) {
file->f_pos = offset;
m->count = 0;
}
retval = offset;
}
up(&m->sem);
return retval;
}
/**
* seq_release - free the structures associated with sequential file.
* @file: file in question
* @inode: file->f_dentry->d_inode
*
* Frees the structures associated with sequential file; can be used
* as ->f_op->release() if you don't have private data to destroy.
*/
int seq_release(struct inode *inode, struct file *file)
{
struct seq_file *m = (struct seq_file *)file->private_data;
kfree(m->buf);
kfree(m);
return 0;
}
/**
* seq_escape - print string into buffer, escaping some characters
* @m: target buffer
* @s: string
* @esc: set of characters that need escaping
*
* Puts string into buffer, replacing each occurence of character from
* @esc with usual octal escape. Returns 0 in case of success, -1 - in
* case of overflow.
*/
int seq_escape(struct seq_file *m, const char *s, const char *esc)
{
char *end = m->buf + m->size;
char *p;
char c;
for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
if (!strchr(esc, c)) {
*p++ = c;
continue;
}
if (p + 3 < end) {
*p++ = '\\';
*p++ = '0' + ((c & 0300) >> 6);
*p++ = '0' + ((c & 070) >> 3);
*p++ = '0' + (c & 07);
continue;
}
m->count = m->size;
return -1;
}
m->count = p - m->buf;
return 0;
}
int seq_printf(struct seq_file *m, const char *f, ...)
{
va_list args;
int len;
if (m->count < m->size) {
va_start(args, f);
len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
va_end(args);
if (m->count + len < m->size) {
m->count += len;
return 0;
}
}
m->count = m->size;
return -1;
}

View File

@@ -1,60 +0,0 @@
/*
* Original file by Al Viro. This is a slight modification which I'll
* pass on to Al Viro shortly.
*/
#ifndef _LINUX_SEQ_FILE_H
#define _LINUX_SEQ_FILE_H
#ifdef __KERNEL__
struct seq_operations;
struct seq_file {
char *buf;
size_t size;
size_t from;
size_t count;
loff_t index;
struct semaphore sem;
struct seq_operations *op;
void *context;
};
struct seq_operations {
void * (*start) (void *context, loff_t *pos);
void (*stop) (void *context, void *v);
void * (*next) (void *context, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
};
int seq_open(struct file *, struct seq_operations *, void *context);
ssize_t seq_read(struct file *, char *, size_t, loff_t *);
loff_t seq_lseek(struct file *, loff_t, int);
int seq_release(struct inode *, struct file *);
int seq_escape(struct seq_file *, const char *, const char *);
static inline int seq_putc(struct seq_file *m, char c)
{
if (m->count < m->size) {
m->buf[m->count++] = c;
return 0;
}
return -1;
}
static inline int seq_puts(struct seq_file *m, const char *s)
{
int len = strlen(s);
if (m->count + len < m->size) {
memcpy(m->buf + m->count, s, len);
m->count += len;
return 0;
}
m->count = m->size;
return -1;
}
int seq_printf(struct seq_file *, const char *, ...)
__attribute__ ((format (printf,2,3)));
#endif
#endif

View File

@@ -1,30 +0,0 @@
FILES
-----
setup-uml - script to build a user mode linux system, with the lvm driver
symbolically linked back to the LVM dir so I can work from CVS.
uml-lvm.patch - patch to enable lvm in the uml configuration
uml.patch.bz2 - uml patch from
http://sourceforge.net/project/showfiles.php?group_id=429
config-uml - .config which turns on LVM
RUNNING
-------
o checkout an LVM dir for use with uml
make sure you've got a copy of a root filesystem kicking about
o edit the variables at the top of 'setup'
o run setup-uml
o move to your uml dir and run lvm-install as root
o then run the 'up' script to run uml
o if you want to rebuild uml after changing the LVM driver just change into
the linux directory and do a 'make linux ARCH=um'. Don't forget the ARCH=um.

View File

@@ -1,299 +0,0 @@
#
# Automatically generated by make menuconfig: don't edit
#
CONFIG_USERMODE=y
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
# CONFIG_PCI is not set
CONFIG_UID16=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
#
# Multi-device support (RAID and LVM)
#
CONFIG_MD=y
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
# CONFIG_BLK_DEV_LVM is not set
CONFIG_BLK_DEV_DM=y
#
# General Setup
#
CONFIG_STDIO_CONSOLE=y
CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
CONFIG_SSL=y
CONFIG_HOSTFS=m
CONFIG_MCONSOLE=y
CONFIG_MAGIC_SYSRQ=y
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_KMOD is not set
#
# Devices
#
CONFIG_BLK_DEV_UBD=y
# CONFIG_BLK_DEV_UBD_SYNC is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
# CONFIG_MMAPPER is not set
#
# Networking options
#
# CONFIG_PACKET is not set
CONFIG_NETLINK=y
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
#
# Network drivers
#
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=y
CONFIG_ETHERTAP=y
#
# Ethernet (10 or 100Mbit)
#
# CONFIG_NET_ETHERNET is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_ACENIC_OMIT_TIGON_I is not set
# CONFIG_DL2K is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PLIP is not set
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_FILTER is not set
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
# CONFIG_PPPOE is not set
CONFIG_SLIP=y
# CONFIG_SLIP_COMPRESSED is not set
# CONFIG_SLIP_SMART is not set
# CONFIG_SLIP_MODE_SLIP6 is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
# CONFIG_RCPCI is not set
# CONFIG_SHAPER is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# Network device support
#
CONFIG_NETDEVICES=y
CONFIG_UML_NET=y
CONFIG_UML_NET_ETHERTAP=y
CONFIG_UML_NET_SLIP=y
CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_MCAST=y
CONFIG_ETHERTAP=y
CONFIG_TUN=y
#
# File systems
#
CONFIG_QUOTA=y
CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
CONFIG_REISERFS_FS=m
# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_UMSDOS_FS=m
CONFIG_VFAT_FS=m
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_TMPFS is not set
# CONFIG_RAMFS is not set
CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
CONFIG_MINIX_FS=m
# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
CONFIG_DEVFS_FS=y
CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
# CONFIG_NFS_FS is not set
# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
# CONFIG_NFSD is not set
# CONFIG_NFSD_V3 is not set
# CONFIG_SUNRPC is not set
# CONFIG_LOCKD is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set
# CONFIG_NCPFS_STRONG is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_SMB_NLS is not set
CONFIG_NLS=y
#
# Native Language Support
#
CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_CODEPAGE_437 is not set
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
#
# Kernel hacking
#
CONFIG_DEBUGSYM=y
CONFIG_PT_PROXY=y
# CONFIG_GPROF is not set
# CONFIG_GCOV is not set

View File

@@ -1,179 +0,0 @@
#! /usr/bin/perl -w
use Cwd;
##############################
# Start user configurable bit
##############################
# Please use absolute paths too.
# you can't use ~'s in your paths here.
# the directory where you've checked out lvm, keep a seperate copy for uml,
# the uml kernel will have links to these files
$lvm_src="/home/thornber/sistina/LVM2";
# the debian root image, get it from here:
# http://prdownloads.sourceforge.net/user-mode-linux/root_fs_debian2.2_small.bz2
# unzip it once you've downloaded it
$root_fs="/home/thornber/uml/root_fs_debian2.2_small";
# these are 100 Meg files created with dd
# these become our PV's /dev/ubd/[1-4]
# I sometimes use ubd/1 as swap though.
@block_devices = ("/home/thornber/uml/scratch1",
"/home/thornber/uml/scratch2",
"/home/thornber/uml/scratch3",
"/home/thornber/uml/scratch4");
# directory where uml will be built, and the up, lvm-install scripts will
# be placed
$dest_dir="/home/thornber/builds/uml-lvm2";
# It must be 2.4.8, can be .gz or .bz2
$kernel_tarball="/home/thornber/packages/2.4/linux-2.4.9.tar";
###############################
# end of user configurable bit
###############################
$wd = cwd;
$uml_patch = $wd . "/uml.patch.bz2";
$lvm_uml_patch = $wd . "/uml-lvm.patch";
$driver = $lvm_src . "/driver/device-mapper";
# check we've got everything we need
&check_file($root_fs);
&check_dir($lvm_src);
&check_file($kernel_tarball);
&check_dir($dest_dir);
&check_file($uml_patch);
&check_file($lvm_uml_patch);
chdir($dest_dir);
&extract_kernel($dest_dir, $kernel_tarball);
chdir("linux");
&run_command("bzip2 -dc $uml_patch | patch -p1", "patching kernel with uml");
&run_command("patch -p1 < $lvm_uml_patch", "enabling LVM driver");
chdir("$dest_dir/linux");
&run_command("cd include/linux; ln -s $driver/device-mapper.h",
"linking device-mapper.h");
&run_command("cd drivers/md; ln -s $driver/dm.h", "linking dm.h");
&run_command("cd drivers/md; ln -s $driver/dm-fs.c", "linking dm-fs.c");
&run_command("cd drivers/md; ln -s $driver/dm-table.c", "linking dm-table.c");
&run_command("cd drivers/md; ln -s $driver/dm-target.c",
"linking dm-target.c");
&run_command("cd drivers/md; ln -s $driver/dm.c", "linking dm.c");
chdir("$dest_dir/linux");
&run_command("make oldconfig ARCH=um", "making oldconfig ARCH=um");
&run_command("make dep ARCH=um", "making dependencies");
&run_command("make linux ARCH=um", "building linux uml");
chdir($dest_dir);
&run_command("ln -s $dest_dir/linux/linux uml", "creating link for linux");
chdir($dest_dir);
&run_command("ln -s $root_fs ./root_fs", "linking root filesystem");
chdir($dest_dir);
&link_devices();
&write_up();
&run_command("mkdir root_fs_mnt");
&write_lvm_install();
print "Dont forget to run $dest_dir/lvm-install as root\n";
sub write_lvm_install {
open(OUT, "> lvm-install");
print OUT "#! /bin/sh\n\n";
print OUT <<"end";
mount root_fs root_fs_mnt -o loop
cd $lvm_src; make install; cd $dest_dir
umount root_fs_mnt
end
close OUT;
system "chmod +x lvm-install";
}
sub write_up {
open(UP, "> up");
print UP "#! /bin/sh\n\n./uml ";
$count = 1;
for $d (@block_devices) {
print UP "ubd$count=ubd$count ";
$count++;
}
print UP "\n";
close UP;
system("chmod +x up");
}
sub link_devices {
$count = 1;
foreach $d (@block_devices) {
&run_command("ln -s $d ubd$count",
"linking block device ubd$count");
$count++;
}
}
sub extract_kernel {
my($dest, $tb) = @_;
my($cmd);
if($tb =~ m/\.bz2/) {
$cmd = "tar Ixf $tb";
} elsif($tb =~ m/\.gz/) {
$cmd = "tar zxf $tb";
} else {
$cmd = "tar xf $tb";
}
&run_command($cmd, "extracting kernel");
}
sub run_command {
my($cmd) = shift;
my($desc) = shift;
my($r);
print STDERR $desc, " ... ";
$r = system("$cmd > /dev/null");
if(!$r) {
print STDERR "done.\n";
return;
} else {
print STDERR "failed.\n";
exit(1);
}
}
sub check_file {
$f = shift;
if(! -e $f) {
print STDERR "couldn't find $f\n";
exit;
}
}
sub check_dir {
$f = shift;
if(! -e $f || ! -d $f) {
print STDERR "couldn't find a directory called $f\n";
exit;
}
}

View File

@@ -1,30 +0,0 @@
--- uml_build/arch/um/config.in.orig Tue Jan 2 14:33:42 2001
+++ uml_build/arch/um/config.in Tue Jan 2 14:35:42 2001
@@ -15,6 +15,8 @@
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
+source drivers/md/Config.in
+
mainmenu_option next_comment
comment 'Processor features'
bool 'Symmetric multi-processing support' CONFIG_SMP
--- linux/drivers/md/Config.in.orig Tue Aug 21 14:18:30 2001
+++ linux/drivers/md/Config.in Tue Aug 21 14:19:08 2001
@@ -14,4 +14,6 @@
dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD
+dep_tristate ' Device mapper support' CONFIG_BLK_DEV_DM $CONFIG_MD
+
endmenu
--- linux/drivers/md/Makefile.orig Tue Aug 21 14:19:14 2001
+++ linux/drivers/md/Makefile Tue Aug 21 14:20:06 2001
@@ -19,6 +19,7 @@
obj-$(CONFIG_MD_RAID5) += raid5.o xor.o
obj-$(CONFIG_BLK_DEV_MD) += md.o
obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o
+obj-$(CONFIG_BLK_DEV_DM) += dm.o dm-table.o dm-target.o dm-fs.o dm-parse.o
include $(TOPDIR)/Rules.make

Binary file not shown.

View File

@@ -1,5 +1,9 @@
../lib/activate/activate.h
../lib/cache/lvmcache.h
../lib/commands/errors.h
../lib/commands/toolcontext.h
../lib/config/config.h
../lib/config/defaults.h
../lib/datastruct/bitset.h
../lib/datastruct/btree.h
../lib/datastruct/hash.h
@@ -13,10 +17,21 @@
../lib/filters/filter-regex.h
../lib/filters/filter.h
../lib/format1/format1.h
../lib/format1/lvm1-label.h
../lib/format_text/format-text.h
../lib/label/label.h
../lib/locking/locking.h
../lib/log/log.h
../lib/metadata/metadata.h
../lib/mm/dbg_malloc.h
../lib/mm/memlock.h
../lib/mm/pool.h
../lib/mm/xlate.h
../lib/misc/crc.h
../lib/misc/lib.h
../lib/misc/lvm-file.h
../lib/misc/lvm-string.h
../lib/misc/sharedlib.h
../lib/regex/matcher.h
../lib/report/report.h
../lib/uuid/uuid.h

View File

@@ -31,11 +31,13 @@ all: .symlinks_created
for i in `cat .symlinks`; do $(LN_S) $$i ; done
touch $@
clean:
distclean:
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
$(RM) Makefile .include_symlinks .symlinks_created
.PHONY: clean distclean all
clean:
install:
.PHONY: clean distclean all install

View File

@@ -8,9 +8,14 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
ifeq ("@LVM1@", "shared")
SUBDIRS = format1
endif
SOURCES=\
activate/activate.c \
activate/fs.c \
cache/lvmcache.c \
commands/toolcontext.c \
config/config.c \
datastruct/bitset.c \
datastruct/btree.c \
@@ -23,21 +28,62 @@ SOURCES=\
filters/filter-persistent.c \
filters/filter-regex.c \
filters/filter.c \
format1/disk-rep.c \
format1/format1.c \
format1/import-export.c \
format1/layout.c \
format1/vg_number.c \
format_text/archive.c \
format_text/export.c \
format_text/flags.c \
format_text/format-text.c \
format_text/import.c \
format_text/import_vsn1.c \
format_text/text_label.c \
label/label.c \
locking/file_locking.c \
locking/locking.c \
locking/no_locking.c \
log/log.c \
metadata/lv_manip.c \
metadata/merge.c \
metadata/metadata.c \
metadata/mirror.c \
metadata/pv_map.c \
mm/dbg_malloc.c \
metadata/snapshot_manip.c \
misc/crc.c \
misc/lvm-file.c \
misc/lvm-string.c \
mm/memlock.c \
mm/pool.c \
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
uuid/uuid.c
report/report.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

View File

@@ -1 +0,0 @@
Base library directory

View File

@@ -4,273 +4,315 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "activate.h"
#include "memlock.h"
#include "display.h"
#include "log.h"
#include "fs.h"
#include "lvm-string.h"
#include "pool.h"
#include "toolcontext.h"
#include "dev_manager.h"
#include <devmapper/libdevmapper.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
static void _build_lv_name(char *buffer, size_t s, struct logical_volume *lv)
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
#ifndef DEVMAPPER_SUPPORT
void set_activation(int act)
{
snprintf(buffer, s, "%s_%s", lv->vg->name, lv->name);
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)
{
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;
}
static struct dm_task *_setup_task(struct logical_volume *lv, int task)
#else /* DEVMAPPER_SUPPORT */
static int _activation = 1;
void set_activation(int act)
{
char name[128];
struct dm_task *dmt;
if (act == _activation)
return;
if (!(dmt = dm_task_create(task))) {
stack;
return NULL;
}
_build_lv_name(name, sizeof(name), lv);
dm_task_set_name(dmt, name);
return dmt;
_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.");
}
static struct dm_task *_info(struct logical_volume *lv)
int activation(void)
{
return _activation;
}
int library_version(char *version, size_t size)
{
if (!activation())
return 0;
if (!dm_get_library_version(version, size))
return 0;
return 1;
}
int driver_version(char *version, size_t size)
{
int r = 0;
struct dm_task *dmt;
if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) {
if (!activation())
return 0;
log_very_verbose("Getting driver version");
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
stack;
return 0;
}
if (!dm_task_run(dmt)) {
stack;
goto bad;
}
if (!dm_task_run(dmt))
log_error("Failed to get driver version");
return dmt;
bad:
dm_task_destroy(dmt);
return NULL;
}
int lv_active(struct logical_volume *lv)
{
int r = -1;
struct dm_task *dmt;
if (!(dmt = _info(lv))) {
stack;
return r;
}
if (!dm_task_exists(dmt, &r)) {
stack;
if (!dm_task_get_driver_version(dmt, version, size))
goto out;
}
out:
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
int lv_open_count(struct logical_volume *lv)
{
int r = -1;
struct dm_task *dmt;
if (!(dmt = _info(lv))) {
stack;
return r;
}
if (!dm_task_open_count(dmt, &r)) {
stack;
goto out;
}
out:
dm_task_destroy(dmt);
return r;
}
/*
* Creates a target for the next contiguous run of
* extents.
* Returns 1 if info structure populated, else 0 on failure.
*/
static int _emit_target(struct dm_task *dmt, struct logical_volume *lv,
unsigned int *ple)
{
char params[1024];
unsigned int le = *ple;
uint64_t esize = lv->vg->extent_size;
int i, count = 0;
struct pe_specifier *pes, *first = NULL;
for (i = le; i < lv->le_count; i++) {
pes = lv->map + i;
if (!first)
first = pes;
else if (first->pv != pes->pv || first->pe != pes->pe + 1)
break; /* no longer contig. */
count++;
}
snprintf(params, sizeof(params), "%s %" PRIu64,
dev_name(first->pv->dev),
first->pv->pe_start + (esize * first->pe));
if (!dm_task_add_target(dmt, esize * le, esize * count,
"linear", params)) {
stack;
return 0;
}
*ple = i;
return 1;
}
int _load(struct logical_volume *lv, int task)
{
int r = 0;
uint32_t le = 0;
struct dm_task *dmt;
if (!(dmt = _setup_task(lv, task))) {
stack;
return 0;
}
/*
* Merge adjacent extents.
*/
while (le < lv->le_count) {
if (!_emit_target(dmt, lv, &le)) {
log_error("Unable to activate logical volume '%s'",
lv->name);
goto out;
}
}
if (!(r = dm_task_run(dmt)))
stack;
out:
dm_task_destroy(dmt);
return r;
}
/* FIXME: Always display error msg */
int lv_activate(struct logical_volume *lv)
{
return _load(lv, DM_DEVICE_CREATE) && fs_add_lv(lv);
}
int _suspend(struct logical_volume *lv, int sus)
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
{
int r;
struct dm_task *dmt;
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
struct dev_manager *dm;
struct dm_info dminfo;
if (!(dmt = _setup_task(lv, task))) {
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dm_task_run(dmt)))
log_err("Couldn't %s device '%s'", sus ? "suspend" : "resume",
lv->name);
if (!(r = dev_manager_info(dm, lv, &dminfo)))
stack;
dm_task_destroy(dmt);
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);
return r;
}
int lv_reactivate(struct logical_volume *lv)
/*
* Returns 1 if percent set, else 0 on failure.
*/
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
{
int r;
if (!_suspend(lv, 1)) {
struct dev_manager *dm;
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
r = _load(lv, DM_DEVICE_RELOAD);
if (!_suspend(lv, 0)) {
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
stack;
return 0;
}
dev_manager_destroy(dm);
return r;
}
int lv_deactivate(struct logical_volume *lv)
/* FIXME Merge with snapshot_percent */
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
uint32_t *event_nr)
{
int r;
struct dm_task *dmt;
struct dev_manager *dm;
if (!(dmt = _setup_task(lv, DM_DEVICE_REMOVE))) {
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dm_task_run(dmt)))
if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
stack;
dm_task_destroy(dmt);
fs_del_lv(lv);
dev_manager_destroy(dm);
return r;
}
int activate_lvs_in_vg(struct volume_group *vg)
static int _lv_active(struct logical_volume *lv)
{
struct list *lvh;
struct logical_volume *lv;
int count = 0;
struct lvinfo info;
list_iterate(lvh, &vg->lvs) {
lv = &(list_item(lvh, struct lv_list)->lv);
count += (!lv_active(lv) && lv_activate(lv));
if (!lv_info(lv, &info)) {
stack;
return -1;
}
return count;
return info.exists;
}
int lv_update_write_access(struct logical_volume *lv)
static int _lv_open_count(struct logical_volume *lv)
{
return 0;
}
struct lvinfo info;
int deactivate_lvs_in_vg(struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lv;
int count = 0;
list_iterate(lvh, &vg->lvs) {
lv = &(list_item(lvh, struct lv_list)->lv);
count += ((lv_active(lv) == 1) && lv_deactivate(lv));
if (!lv_info(lv, &info)) {
stack;
return -1;
}
return count;
return info.open_count;
}
/* FIXME Need to detect and handle an lv rename */
static int _lv_activate(struct logical_volume *lv)
{
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_activate(dm, lv)))
stack;
dev_manager_destroy(dm);
return r;
}
static int _lv_deactivate(struct logical_volume *lv)
{
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_deactivate(dm, lv)))
stack;
dev_manager_destroy(dm);
return r;
}
static int _lv_suspend(struct logical_volume *lv)
{
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_suspend(dm, lv)))
stack;
dev_manager_destroy(dm);
return r;
}
/*
* These two functions return the number of LVs in the state,
* or -1 on error.
*/
int lvs_in_vg_activated(struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lv;
int count = 0;
list_iterate(lvh, &vg->lvs) {
lv = &(list_item(lvh, struct lv_list)->lv);
if (!activation())
return 0;
count += (lv_active(lv) == 1);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_active(lv) == 1);
}
return count;
@@ -282,12 +324,153 @@ int lvs_in_vg_opened(struct volume_group *vg)
struct logical_volume *lv;
int count = 0;
list_iterate(lvh, &vg->lvs) {
lv = &(list_item(lvh, struct lv_list)->lv);
if (!activation())
return 0;
count += (lv_open_count(lv) == 1);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_open_count(lv) == 1);
}
return count;
}
/* These return success if the device is not active */
int lv_suspend_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("Suspending '%s'.", lv->name);
return 1;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (!info.exists || info.suspended)
return 1;
memlock_inc();
if (!_lv_suspend(lv)) {
memlock_dec();
fs_unlock();
return 0;
}
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

@@ -1,43 +1,57 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
* This file is released under the LGPL.
*/
#ifndef LVM_ACTIVATE_H
#define LVM_ACTIVATE_H
/* FIXME Snapshot handling? */
#include "metadata.h"
int lv_active(struct logical_volume *lv);
int lv_open_count(struct logical_volume *lv);
#ifdef DEVMAPPER_SUPPORT
# include <libdevmapper.h>
#endif
int lv_activate(struct logical_volume *lv);
int lv_reactivate(struct logical_volume *lv);
int lv_deactivate(struct logical_volume *lv);
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 library_version(char *version, size_t size);
void activation_exit(void);
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_activate(struct cmd_context *cmd, const char *lvid_s);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
/*
* Return number of LVs in the VG that are
* active.
* Returns 1 if info structure has been populated, else 0.
*/
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.
*/
int lvs_in_vg_activated(struct volume_group *vg);
int lvs_in_vg_opened(struct volume_group *vg);
/*
* Test for (lv->status & LVM_WRITE)
*/
int lv_update_write_access(struct logical_volume *lv);
/*
* Activate all LVs in the VG. Ignore any that
* are already active. Return number
* activated.
*/
int activate_lvs_in_vg(struct volume_group *vg);
/*
* Deactivate all LVs in the VG
*/
int deactivate_lvs_in_vg(struct volume_group *vg);
int lv_setup_cow_store(struct logical_volume *lv);
#endif

2181
lib/activate/dev_manager.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_DEV_MANAGER_H
#define _LVM_DEV_MANAGER_H
#include "metadata.h"
#include "config.h"
struct dev_manager;
struct dm_info;
/*
* Constructor and destructor.
*/
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_exit(void);
/*
* The device handler is responsible for creating all the layered
* dm devices, and ensuring that all constraints are maintained
* (eg, an origin is created before its snapshot, but is not
* unsuspended until the snapshot is also created.)
*/
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
struct dm_info *info);
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent);
int dev_manager_mirror_percent(struct dev_manager *dm,
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_activate(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
/*
* Put the desired changes into effect.
*/
int dev_manager_execute(struct dev_manager *dm);
#endif

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#ifndef DMFS_INTERFACE_H
#define DMFS_INTERFACE_H
struct dmfs;
struct dmfs *dmfs_create(void);
void dmfs_destroy(struct dmfs *dm);
int dmfs_dev_is_present(struct dmfs *dm, const char *dev);
int dmfs_dev_is_active(struct dmfs *dm, const char *dev);
int dmfs_table_is_present(struct dmfs *dm, const char *dev, const char *table);
int dmfs_table_is_active(struct dmfs *dm, const char *dev, const char *table);
int dmfs_dev_create(struct dmfs *dm, const char *name);
int dmfs_dev_load_table(struct dmfs *dm, const char *dev,
const char *table, const char *file);
int dmfs_dev_drop_table(struct dmfs *dm, const char *dev, const char *table);
int dmfs_dev_activate_table(struct dmfs *dm, const char *dev,
const char *table);
int dmfs_dev_deactivate(struct dmfs *dm, const char *dev);
#endif

View File

@@ -4,109 +4,189 @@
* This file is released under the LGPL.
*/
#include <sys/types.h>
#include "lib.h"
#include "fs.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "lvm-file.h"
#include "memlock.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <libdevmapper.h>
#include "fs.h"
#include "log.h"
#include <devmapper/libdevmapper.h>
/*
* FIXME: copied straight from LVM1.
*
* This should run through /proc/mounts once only,
* storing devfs mount points in a hash table.
*/
static int _check_devfs(const char *dev_dir)
static int _mk_dir(const char *dev_dir, const char *vg_name)
{
int r = 0, len;
char dir[PATH_MAX], line[512];
char type[32];
FILE *mounts = NULL;
char vg_path[PATH_MAX];
if (!(mounts = fopen("/proc/mounts", "r")))
goto out;
/* trim the trailing slash off dev_dir, yuck */
len = strlen(dev_dir) - 1;
while(len && dev_dir[len] == '/')
len--;
while (!feof(mounts)) {
fgets(line, sizeof(line) - 1, mounts);
if (sscanf(line, "%*s %s %s %*s", dir, type) != 2)
continue;
if (!strcmp(type, "devfs") && !strncmp(dir, dev_dir, len)) {
r = 1;
break;
}
}
fclose(mounts);
out:
return r;
}
void _build_lv_path(char *buffer, size_t len, struct logical_volume *lv)
{
snprintf(buffer, len, "%s%s/%s_%s",
lv->vg->cmd->dev_dir, dm_dir(), lv->vg->name, lv->name);
}
void _build_vg_path(char *buffer, size_t len, struct volume_group *vg)
{
snprintf(buffer, len, "%s/%s", vg->cmd->dev_dir, vg->name);
}
void _build_link_path(char *buffer, size_t len, struct logical_volume *lv)
{
snprintf(buffer, len, "%s/%s/%s", lv->vg->cmd->dev_dir,
lv->vg->name, lv->name);
}
static int _mk_node(struct logical_volume *lv)
{
char lv_path[PATH_MAX];
char dm_path[PATH_MAX];
dev_t dev;
const char *dev_dir = lv->vg->cmd->dev_dir;
if (_check_devfs(dev_dir))
return 1;
snprintf(dm_path, PATH_MAX, "%s%s", dev_dir, dm_dir());
if (mkdir(dm_path, 0555) && errno != EEXIST) {
log_sys_error("mkdir", dm_path);
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
return 0;
}
_build_lv_path(lv_path, sizeof(lv_path), lv);
if (dir_exists(vg_path))
return 1;
if (mknod(lv_path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
log_sys_error("mknod", lv_path);
log_very_verbose("Creating directory %s", vg_path);
if (mkdir(vg_path, 0555)) {
log_sys_error("mkdir", vg_path);
return 0;
}
return 1;
}
static int _rm_node(struct logical_volume *lv)
static int _rm_dir(const char *dev_dir, const char *vg_name)
{
char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
return 0;
}
log_very_verbose("Removing directory %s", vg_path);
if (is_empty_dir(vg_path))
rmdir(vg_path);
return 1;
}
static void _rm_blks(const char *dir)
{
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;
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
dev_dir, vg_name) == -1) {
log_error("Couldn't create path for volume group dir %s",
vg_name);
return 0;
}
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
lv_name) == -1) {
log_error("Couldn't create source pathname for "
"logical volume link %s", lv_name);
return 0;
}
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
dm_dir(), dev) == -1) {
log_error("Couldn't create destination pathname for "
"logical volume link for %s", lv_name);
return 0;
}
if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
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 (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) {
log_error("Symbolic link %s not created: file exists",
link_path);
return 0;
}
log_very_verbose("Removing %s", lv_path);
if (unlink(lv_path) < 0) {
log_sys_error("unlink", lv_path);
return 0;
}
}
log_very_verbose("Linking %s -> %s", lv_path, link_path);
if (symlink(link_path, lv_path) < 0) {
log_sys_error("symlink", lv_path);
return 0;
}
return 1;
}
static int _rm_link(const char *dev_dir, const char *vg_name,
const char *lv_name)
{
struct stat buf;
char lv_path[PATH_MAX];
const char *dev_dir = lv->vg->cmd->dev_dir;
if (_check_devfs(dev_dir))
return 1;
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
dev_dir, vg_name, lv_name) == -1) {
log_error("Couldn't determine link pathname.");
return 0;
}
_build_lv_path(lv_path, sizeof(lv_path), lv);
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
log_error("%s not symbolic link - not removing", lv_path);
return 0;
}
log_very_verbose("Removing link %s", lv_path);
if (unlink(lv_path) < 0) {
log_sys_error("unlink", lv_path);
return 0;
@@ -115,95 +195,143 @@ static int _rm_node(struct logical_volume *lv)
return 1;
}
/*
* Lazy programmer: I'm just going to always try
* and create/remove the vg directory, and not say
* anything if it fails.
*/
static int _mk_dir(struct volume_group *vg)
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)
{
char vg_path[PATH_MAX];
switch (type) {
case FS_ADD:
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;
_build_vg_path(vg_path, sizeof(vg_path), vg);
mkdir(vg_path, 0555);
return 1;
}
static int _rm_dir(struct volume_group *vg)
{
char vg_path[PATH_MAX];
_build_vg_path(vg_path, sizeof(vg_path), vg);
rmdir(vg_path);
return 1;
}
static int _mk_link(struct logical_volume *lv)
{
char lv_path[PATH_MAX], link_path[PATH_MAX];
_build_lv_path(lv_path, sizeof(lv_path), lv);
_build_link_path(link_path, sizeof(link_path), lv);
if (symlink(lv_path, link_path) < 0) {
log_sys_error("symlink", link_path);
return 0;
if (!_mk_link(dev_dir, vg_name, lv_name, dev))
stack;
}
return 1;
}
static int _rm_link(struct logical_volume *lv)
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)
{
char link_path[PATH_MAX];
strcpy(*pos, str);
*ptr = *pos;
*pos += strlen(*ptr) + 1;
}
_build_link_path(link_path, sizeof(link_path), lv);
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 (unlink(link_path) < 0) {
log_sys_error("unlink", link_path);
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;
}
int fs_add_lv(struct logical_volume *lv)
static void _pop_fs_ops(void)
{
if (!_mk_node(lv)) {
stack;
return 0;
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;
}
if (!_mk_dir(lv->vg)) {
stack;
return 0;
}
return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name);
}
if (!_mk_link(lv)) {
stack;
return 0;
}
return 1;
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)
{
if (!_rm_link(lv)) {
stack;
return 0;
}
if (!_rm_dir(lv->vg)) {
stack;
return 0;
}
if (!_rm_node(lv)) {
stack;
return 0;
}
return 1;
return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
"", "");
}
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name)
{
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
dev, old_name);
}
void fs_unlock(void)
{
if (!memlock()) {
dm_lib_release();
_pop_fs_ops();
}
}

View File

@@ -9,7 +9,15 @@
#include "metadata.h"
int fs_add_lv(struct logical_volume *lv);
/*
* These calls, private to the activate unit, set
* up the volume group directory in /dev and the
* symbolic links to the dm device.
*/
int fs_add_lv(struct logical_volume *lv, const char *dev);
int fs_del_lv(struct logical_volume *lv);
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name);
void fs_unlock(void);
#endif

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "table-build.c"
static void _print_run(FILE *fp, struct logical_volume *lv)
{
}
int build_table(struct volume_group *vg, struct logical_volume *lv,
const char *file)
{
int i;
uint64_t sector = 0;
uint64_t pe_size = vg->extent_size;
uint64_t dest;
struct pe_specifier *pes;
FILE *fp = fopen(file, "w");
if (!fp) {
log_err("couldn't open '%s' to write table", file);
return 0;
}
for (i = 0; i < lv->le_count; i++) {
pes = lv->map + i;
dest = pes->pv->pe_start + (pe_size * pes->pe);
fprintf(fp, "%ull %ull linear %s %ull\n",
sector, pe_size, pes->pv->dev->name, dest);
sector += pe_size;
}
fclose(fp);
return 1;
}

View File

@@ -1,13 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#ifndef TABLE_BUILD_H
#define TABLE_BUILD_H
int build_table(struct volume_group *vg, struct logical_volume *lv,
const char *file);
#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

15
lib/commands/errors.h Normal file
View File

@@ -0,0 +1,15 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_ERRORS_H
#define _LVM_ERRORS_H
#define EINVALID_CMD_LINE 1
#define ENO_SUCH_CMD 3
#define ECMD_PROCESSED 4
#define ECMD_FAILED 5
#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

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#ifndef _LVM_TOOLCONTEXT_H
#define _LVM_TOOLCONTEXT_H
#include "dev-cache.h"
#include "config.h"
#include "pool.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 */
struct cmd_context {
/* format handler allocates all objects from here */
struct pool *mem;
const struct format_type *fmt; /* Current format to use by default */
struct format_type *fmt_backup; /* Format to use for backups */
struct list formats; /* Available formats */
char *cmd_line;
struct command *command;
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

View File

@@ -4,51 +4,52 @@
* 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/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#include "pool.h"
#include "log.h"
enum {
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_COMMA,
TOK_EOF
};
struct parser {
const char *fb, *fe; /* file limits */
char *fb, *fe; /* file limits */
int t; /* token limits and type */
const char *tb, *te;
int t; /* token limits and type */
char *tb, *te;
int fd; /* descriptor for file being parsed */
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
struct pool *mem;
struct pool *mem;
};
struct cs {
struct config_file cf;
struct pool *mem;
struct config_tree cf;
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 struct config_node *_file(struct parser *p);
static struct config_node *_section(struct parser *p);
@@ -58,7 +59,6 @@ static int _match_aux(struct parser *p, int t);
static struct config_value *_create_value(struct parser *p);
static struct config_node *_create_node(struct parser *p);
static char *_dup_tok(struct parser *p);
static int _tok_match(const char *str, const char *b, const char *e);
#define MAX_INDENT 32
@@ -69,84 +69,249 @@ static int _tok_match(const char *str, const char *b, const char *e);
} \
} while(0);
static int _tok_match(const char *str, const char *b, const char *e)
{
while (*str && (b != e)) {
if (*str++ != *b++)
return 0;
}
return !(*str || (b != e));
}
/*
* public interface
*/
struct config_file *create_config_file(void)
struct config_tree *create_config_tree(void)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
if (!mem) {
stack;
return 0;
}
if (!mem) {
stack;
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
}
c->mem = mem;
c->cf.root = (struct config_node *)NULL;
return &c->cf;
c->mem = mem;
c->cf.root = (struct config_node *) NULL;
c->timestamp = 0;
c->filename = NULL;
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 parser *p;
struct stat info;
int r = 1, fd;
struct parser *p;
int r = 0;
int use_mmap = 1;
off_t mmap_offset = 0;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
p->mem = c->mem;
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
log_sys_error("stat", file);
return 0;
}
/* Only use mmap with regular files */
if (!(dev->flags & DEV_REGULAR) || size2)
use_mmap = 0;
if ((fd = open(file, O_RDONLY)) < 0) {
log_sys_error("open", file);
return 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;
}
}
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == MAP_FAILED) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
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;
}
/* parse */
p->tb = p->te = p->fb;
p->fe = p->fb + size + size2;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
_get_token(p, TOK_SECTION_E);
if (!(cf->root = _file(p))) {
stack;
goto out;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
}
r = 1;
close(fd);
return r;
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);
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("%s is not a regular file", file);
return 0;
}
if (info.st_size == 0) {
log_verbose("%s is empty", file);
return 1;
}
if (!(dev = dev_create_file(file, NULL, NULL))) {
stack;
return 0;
}
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
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;
}
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)
@@ -163,24 +328,32 @@ static void _write_value(FILE *fp, struct config_value *v)
case CFG_INT:
fprintf(fp, "%d", v->v.i);
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)
{
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
int i;
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
int i;
if (!n)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\0';
for (i = 0; i < l; i++)
space[i] = '\t';
space[i] = '\0';
while (n) {
fprintf(fp, "%s%s", space, n->key);
while (n) {
fprintf(fp, "%s%s", space, n->key);
if (!n->v) {
/* it's a sub section */
fprintf(fp, " {\n");
@@ -203,26 +376,26 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
_write_value(fp, v);
}
fprintf(fp, "\n");
n = n->sib;
}
n = n->sib;
}
/* FIXME: add error checking */
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;
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_error("open", file);
return 0;
}
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_error("open", file);
return 0;
}
if (!_write_config(cf->root, fp, 0)) {
if (!_write_config(cf->root, fp, 0)) {
stack;
r = 0;
}
fclose(fp);
fclose(fp);
return r;
}
@@ -249,7 +422,7 @@ static struct config_node *_file(struct parser *p)
static struct config_node *_section(struct parser *p)
{
/* IDENTIFIER '{' VALUE* '}' */
/* IDENTIFIER '{' VALUE* '}' */
struct config_node *root, *n, *l = NULL;
if (!(root = _create_node(p))) {
stack;
@@ -261,7 +434,7 @@ static struct config_node *_section(struct parser *p)
return 0;
}
match (TOK_IDENTIFIER);
match(TOK_IDENTIFIER);
if (p->t == TOK_SECTION_B) {
match(TOK_SECTION_B);
@@ -286,17 +459,17 @@ static struct config_node *_section(struct parser *p)
}
}
return root;
return root;
}
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
if (p->t == TOK_ARRAY_B) {
match (TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
/* '[' TYPE* ']' | TYPE */
struct config_value *h = NULL, *l, *ll = NULL;
if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
stack;
return 0;
}
@@ -310,48 +483,61 @@ static struct config_value *_value(struct parser *p)
if (p->t == TOK_COMMA)
match(TOK_COMMA);
}
match(TOK_ARRAY_E);
} else
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
h = _type(p);
return h;
return h;
}
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);
switch (p->t) {
case TOK_INT:
if (!v)
return NULL;
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 10); /* FIXME: check error */
match(TOK_INT);
break;
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
match(TOK_FLOAT);
break;
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
match(TOK_FLOAT);
break;
case TOK_STRING:
case TOK_STRING:
v->type = CFG_STRING;
p->tb++, p->te--; /* strip "'s */
p->tb++, p->te--; /* strip "'s */
if (!(v->v.str = _dup_tok(p))) {
stack;
return 0;
}
p->te++;
match(TOK_STRING);
break;
match(TOK_STRING);
break;
default:
default:
log_error("Parse error at line %d: expected a value", p->line);
return 0;
}
return v;
return 0;
}
return v;
}
static int _match_aux(struct parser *p, int t)
@@ -359,115 +545,144 @@ static int _match_aux(struct parser *p, int t)
if (p->t != t)
return 0;
_get_token(p);
_get_token(p, t);
return 1;
}
/*
* tokeniser
*/
static void _get_token(struct parser *p)
static void _get_token(struct parser *p, int tok_prev)
{
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
int values_allowed = 0;
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe || !*p->tb) {
p->t = TOK_EOF;
return;
}
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
break;
/* 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;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
p->te++;
p->te++;
}
break;
if (p->te != p->fe)
p->te++;
break;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '.':
p->t = TOK_FLOAT;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
p->te++;
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++;
}
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
}
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
*(p->te + 1))
p->te++;
p->te++;
}
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++;
break;
case '.':
p->t = TOK_FLOAT;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (values_allowed) {
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;
}
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
(*p->te != '}'))
p->te++;
break;
}
}
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
p->te++;
while ((p->tb != p->fe) && (*p->tb)) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
p->te++;
p->line++;
}
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')
p->line++;
p->te++;
p->te++;
}
}
else
return;
else
return;
p->tb = p->te;
}
p->tb = p->te;
}
}
/*
@@ -489,7 +704,7 @@ static struct config_node *_create_node(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);
if (!str) {
stack;
@@ -504,7 +719,7 @@ static char *_dup_tok(struct parser *p)
* utility functions
*/
struct config_node *find_config_node(struct config_node *cn,
const char *path, char sep)
const char *path, const int sep)
{
const char *e;
@@ -514,8 +729,7 @@ struct config_node *find_config_node(struct config_node *cn,
path++;
/* find the end of this segment */
for (e = path; *e && (*e != sep); e++)
;
for (e = path; *e && (*e != sep); e++) ;
/* hunt for the node */
while (cn) {
@@ -536,56 +750,142 @@ struct config_node *find_config_node(struct config_node *cn,
return cn;
}
const char *
find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
const char *find_config_str(struct config_node *cn,
const char *path, const int sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
if (n && n->v->type == CFG_STRING)
if (n && n->v->type == CFG_STRING) {
if (*n->v->v.str)
log_very_verbose("Setting %s to %s", path, n->v->v.str);
return n->v->v.str;
}
if (fail)
log_debug("%s not found in config: defaulting to %s",
path, fail);
log_very_verbose("%s not found in config: defaulting to %s",
path, fail);
return fail;
}
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);
if (n && n->v->type == CFG_INT)
if (n && n->v->type == CFG_INT) {
log_very_verbose("Setting %s to %d", path, n->v->v.i);
return n->v->v.i;
}
log_very_verbose("%s not found in config: defaulting to %d",
path, fail);
return fail;
}
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);
if (n && n->v->type == CFG_FLOAT)
if (n && n->v->type == CFG_FLOAT) {
log_very_verbose("Setting %s to %f", path, n->v->v.r);
return n->v->v.r;
}
log_very_verbose("%s not found in config: defaulting to %f",
path, fail);
return fail;
}
static int _tok_match(const char *str, const char *b, const char *e)
static int _str_in_array(const char *str, const char *values[])
{
while (*str && (b != e)) {
if (*str++ != *b++)
return 0;
}
int i;
return !(*str || (b != e));
for (i = 0; values[i]; i++)
if (!strcasecmp(str, values[i]))
return 1;
return 0;
}
/*
* Local variables:
* c-file-style: "linux"
* End:
*/
static int _str_to_bool(const char *str, int fail)
{
static const char *_true_values[] = { "y", "yes", "on", "true", NULL };
static const char *_false_values[] =
{ "n", "no", "off", "false", NULL };
if (_str_in_array(str, _true_values))
return 1;
if (_str_in_array(str, _false_values))
return 0;
return fail;
}
int find_config_bool(struct config_node *cn, const char *path,
const int sep, int fail)
{
struct config_node *n = find_config_node(cn, path, sep);
struct config_value *v;
if (!n)
return fail;
v = n->v;
switch (v->type) {
case CFG_INT:
return v->v.i ? 1 : 0;
case CFG_STRING:
return _str_to_bool(v->v.str, fail);
}
return fail;
}
int get_config_uint32(struct config_node *cn, const char *path,
const int sep, uint32_t *result)
{
struct config_node *n;
n = find_config_node(cn, path, sep);
if (!n || !n->v || n->v->type != CFG_INT)
return 0;
*result = n->v->v.i;
return 1;
}
int get_config_uint64(struct config_node *cn, const char *path,
const int sep, uint64_t *result)
{
struct config_node *n;
n = find_config_node(cn, path, sep);
if (!n || !n->v || n->v->type != CFG_INT)
return 0;
/* FIXME Support 64-bit value! */
*result = (uint64_t) n->v->v.i;
return 1;
}
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

@@ -1,61 +1,81 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
* This file is released under the LGPL.
*/
#ifndef _LVM_CONFIG_H
#define _LVM_CONFIG_H
#include "device.h"
enum {
CFG_STRING,
CFG_FLOAT,
CFG_INT,
CFG_STRING,
CFG_FLOAT,
CFG_INT,
CFG_EMPTY_ARRAY
};
struct config_value {
int type;
union {
int i;
float r;
char *str;
} v;
struct config_value *next; /* for arrays */
int type;
union {
int i;
float r;
char *str;
} v;
struct config_value *next; /* for arrays */
};
struct config_node {
char *key;
struct config_node *sib, *child;
struct config_value *v;
char *key;
struct config_node *sib, *child;
struct config_value *v;
};
struct config_file {
struct config_node *root;
struct config_tree {
struct config_node *root;
};
struct config_file *create_config_file(void);
void destroy_config_file(struct config_file *cf);
struct config_tree *create_config_tree(void);
void destroy_config_tree(struct config_tree *cf);
int read_config(struct config_file *cf, const char *file);
int write_config(struct config_file *cf, const char *file);
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
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,
const char *path, char seperator);
const char *path, const int separator);
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,
char sep, int fail);
const int sep, int fail);
float find_config_float(struct config_node *cn, const char *path,
char sep, float fail);
#endif
const int sep, float fail);
/*
* Local variables:
* c-file-style: "linux"
* End:
* Understands (0, ~0), (y, n), (yes, no), (on,
* off), (true, false).
*/
int find_config_bool(struct config_node *cn, const char *path,
const int sep, int fail);
int get_config_uint32(struct config_node *cn, const char *path,
const int sep, uint32_t *result);
int get_config_uint64(struct config_node *cn, const char *path,
const int sep, uint64_t *result);
int get_config_str(struct config_node *cn, const char *path,
const int sep, char **result);
#endif

91
lib/config/defaults.h Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#ifndef _LVM_DEFAULTS_H
#define _LVM_DEFAULTS_H
#define DEFAULT_ARCHIVE_ENABLED 1
#define DEFAULT_BACKUP_ENABLED 1
#define DEFAULT_ARCHIVE_SUBDIR "archive"
#define DEFAULT_BACKUP_SUBDIR "backup"
#define DEFAULT_ARCHIVE_DAYS 30
#define DEFAULT_ARCHIVE_NUMBER 10
#define DEFAULT_SYS_DIR "/etc/lvm"
#define DEFAULT_DEV_DIR "/dev"
#define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
#define DEFAULT_UMASK 0077
#ifdef LVM1_SUPPORT
# define DEFAULT_FORMAT "lvm1"
#else
# define DEFAULT_FORMAT "lvm2"
#endif
#define DEFAULT_STRIPESIZE 64 /* KB */
#define DEFAULT_PVMETADATASIZE 255
#define DEFAULT_PVMETADATACOPIES 1
#define DEFAULT_LABELSECTOR UINT64_C(1)
#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.
*/
#include "lib.h"
#include "bitset.h"
#include "dbg_malloc.h"
#include <stdlib.h>
/* FIXME: calculate this. */
#define INT_SHIFT 5
bitset_t bitset_create(struct pool *mem, unsigned num_bits)
{
int n = (num_bits / BITS_PER_INT) + 2;
int size = sizeof(int) * n;
unsigned n = (num_bits / BITS_PER_INT) + 2;
size_t size = sizeof(int) * n;
unsigned *bs = pool_zalloc(mem, size);
if (!bs)
@@ -33,7 +31,7 @@ void bitset_destroy(bitset_t bs)
void bit_union(bitset_t out, bitset_t in1, bitset_t in2)
{
int i;
for(i = (in1[0] / BITS_PER_INT) + 1; i; i--)
for (i = (in1[0] / BITS_PER_INT) + 1; i; i--)
out[i] = in1[i] | in2[i];
}
@@ -58,7 +56,7 @@ int bit_get_next(bitset_t bs, int last_bit)
last_bit++; /* otherwise we'll return the same bit again */
while(last_bit < bs[0]) {
while (last_bit < bs[0]) {
word = last_bit >> INT_SHIFT;
test = bs[word + 1];
bit = last_bit & (BITS_PER_INT - 1);
@@ -66,8 +64,8 @@ int bit_get_next(bitset_t bs, int last_bit)
if ((bit = _test_word(test, bit)) >= 0)
return (word * BITS_PER_INT) + bit;
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
BITS_PER_INT;
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
BITS_PER_INT;
}
return -1;

View File

@@ -7,22 +7,19 @@
#ifndef _LVM_BITSET_H
#define _LVM_BITSET_H
#include "lvm-types.h"
#include "pool.h"
#include <limits.h>
#include <string.h>
typedef uint32_t *bitset_t;
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);
int bit_get_first(bitset_t bs);
int bit_get_next(bitset_t bs, int last_bit);
#define BITS_PER_INT (sizeof(int) * CHAR_BIT)
#define bit(bs, i) \

View File

@@ -4,8 +4,8 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "btree.h"
#include "log.h"
struct node {
uint32_t key;
@@ -40,14 +40,13 @@ static uint32_t _shuffle(uint32_t k)
#if 1
return ((k & 0xff) << 24 |
(k & 0xff00) << 8 |
(k & 0xff0000) >> 8 |
(k & 0xff000000) >> 24);
(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
#else
return k;
#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;
while (*c) {

View File

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

View File

@@ -4,10 +4,8 @@
* This file is released under the LGPL.
*/
#include "dbg_malloc.h"
#include "lib.h"
#include "hash.h"
#include "log.h"
struct hash_node {
struct hash_node *next;
@@ -23,22 +21,30 @@ struct hash_table {
/* Permutation of the Integers 0 through 255 */
static unsigned char _nums[] = {
1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51,
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,
12,181,103, 70, 22, 58, 75, 78,183,167,238,157,124,147,172,144,
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,221,
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,
121, 64, 77, 72,208,245,130,122,143, 55,105,134, 29,164,185,194,
193,239,101,242, 5,171,126, 11, 74, 59,137,228,108,191,232,139,
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, 43,
249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71,
230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,109,
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,209
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
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,
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
144,
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,
221,
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,
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
194,
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
139,
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,
43,
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
71,
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
109,
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,
209
};
static struct hash_node *_create_node(const char *str)
@@ -55,7 +61,7 @@ static struct hash_node *_create_node(const char *str)
static unsigned _hash(const char *str)
{
unsigned long int h = 0, g;
unsigned long h = 0, g;
while (*str) {
h <<= 4;
h += _nums[(int) *str++];
@@ -83,7 +89,7 @@ struct hash_table *hash_create(unsigned size_hint)
/* round size hint up to a power of two */
while (new_size < size_hint)
new_size = new_size << 1;
new_size = new_size << 1;
hc->num_slots = new_size;
len = sizeof(*(hc->slots)) * new_size;
@@ -94,7 +100,7 @@ struct hash_table *hash_create(unsigned size_hint)
memset(hc->slots, 0, len);
return hc;
bad:
bad:
dbg_free(hc->slots);
dbg_free(hc);
return 0;
@@ -124,8 +130,8 @@ static inline struct hash_node **_find(struct hash_table *t, const char *key)
unsigned h = _hash(key) & (t->num_slots - 1);
struct hash_node **c;
for(c = &t->slots[h]; *c; c = &((*c)->next))
if(!strcmp(key, (*c)->key))
for (c = &t->slots[h]; *c; c = &((*c)->next))
if (!strcmp(key, (*c)->key))
break;
return c;
@@ -141,7 +147,7 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
{
struct hash_node **c = _find(t, key);
if(*c)
if (*c)
(*c)->data = data;
else {
struct hash_node *n = _create_node(key);
@@ -175,7 +181,7 @@ unsigned hash_get_num_entries(struct hash_table *t)
return t->num_nodes;
}
void hash_iterate(struct hash_table *t, iterate_fn f)
void hash_iter(struct hash_table *t, iterate_fn f)
{
struct hash_node *c;
int i;
@@ -202,7 +208,7 @@ void *hash_get_data(struct hash_table *t, struct hash_node *n)
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;
int i;
@@ -220,7 +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)
{
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);
}

View File

@@ -10,23 +10,27 @@
struct hash_table;
struct hash_node;
typedef void (*iterate_fn)(void *data);
typedef void (*iterate_fn) (void *data);
struct hash_table *hash_create(unsigned size_hint);
void hash_destroy(struct hash_table *t);
void hash_wipe(struct hash_table *t);
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);
void hash_remove(struct hash_table *t, const char *key);
unsigned hash_get_num_entries(struct hash_table *t);
void hash_iterate(struct hash_table *t, iterate_fn f);
void hash_iter(struct hash_table *t, iterate_fn f);
char *hash_get_key(struct hash_table *t, struct hash_node *n);
void *hash_get_data(struct hash_table *t, struct hash_node *n);
struct hash_node *hash_get_first(struct hash_table *t);
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
#endif
#define hash_iterate(v, h) \
for (v = hash_get_first(h); v; \
v = hash_get_next(h, v))
#endif

View File

@@ -13,11 +13,15 @@ struct list {
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;
}
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);
elem->n = head;
@@ -27,7 +31,8 @@ static inline void list_add(struct list *head, struct list *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);
elem->n = head->n;
@@ -37,23 +42,58 @@ static inline void list_add_h(struct list *head, struct list *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->p->n = elem->n;
}
static inline int list_empty(struct list *head) {
static inline int list_empty(struct list *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) \
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) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
static inline unsigned int list_size(const struct list *head)
{
unsigned int s = 0;
const struct list *v;
list_iterate(v, head)
s++;
return s;
}
#define list_item(v, t) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
/* Given a known element in a known structure, locate the struct list */
#define list_head(v, t, e) \
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->list)
#define list_struct_base(v, t, h) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
/* 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

View File

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

View File

@@ -4,27 +4,19 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "dev-cache.h"
#include "log.h"
#include "pool.h"
#include "hash.h"
#include "list.h"
#include "lvm-types.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 <sys/param.h>
#include <dirent.h>
/*
* FIXME: really need to seperate names from the devices since
* multiple names can point to the same device.
*/
struct dev_iter {
struct btree_iter *current;
struct dev_filter *filter;
@@ -45,42 +37,168 @@ static struct {
} _cache;
#define _alloc(x) pool_alloc(_cache.mem, (x))
#define _free(x) pool_free(_cache.mem, (x))
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;
if (!(dev = _alloc(sizeof(*dev)))) {
stack;
log_error("struct device allocation failed");
return NULL;
}
dev->flags = 0;
list_init(&dev->aliases);
dev->dev = d;
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 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)
{
struct str_list *sl = _alloc(sizeof(*sl));
struct list *ah;
const char *oldpath;
int prefer_old = 1;
if (!sl) {
stack;
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))) {
stack;
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;
}
@@ -93,14 +211,15 @@ static int _insert_dev(const char *path, dev_t d)
struct device *dev;
/* 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 */
if (!(dev = _create_dev(d))) {
if (!(dev = _dev_create(d))) {
stack;
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.");
_free(dev);
return 0;
@@ -108,43 +227,21 @@ static int _insert_dev(const char *path, dev_t d)
}
if (!_add_alias(dev, path)) {
log_err("Couldn't add alias to dir cache.");
log_err("Couldn't add alias to dev cache.");
return 0;
}
if (!hash_insert(_cache.names, path, dev)) {
log_err("Couldn't add name to hash in dir cache.");
log_err("Couldn't add name to hash in dev cache.");
return 0;
}
return 1;
}
/*
* return a new path for the destination of the link.
*/
static char *_follow_link(const char *path, struct stat *info)
{
char buffer[PATH_MAX + 1];
int n;
n = readlink(path, buffer, sizeof(buffer) - 1);
if (n <= 0)
return NULL;
buffer[n] = '\0';
if (stat(buffer, info) < 0) {
log_sys_very_verbose("stat", buffer);
return NULL;
}
return pool_strdup(_cache.mem, buffer);
}
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);
if (r)
snprintf(r, len, "%s/%s", dir, name);
@@ -208,7 +305,6 @@ static int _insert_dir(const char *dir)
static int _insert(const char *path, int rec)
{
struct stat info;
char *actual_path;
int r = 0;
if (stat(path, &info) < 0) {
@@ -216,23 +312,7 @@ static int _insert(const char *path, int rec)
return 0;
}
/* follow symlinks if neccessary. */
if (S_ISLNK(info.st_mode)) {
log_debug("%s: Following symbolic link", path);
if (!(actual_path = _follow_link(path, &info))) {
stack;
return 0;
}
if (stat(actual_path, &info) < 0) {
log_sys_very_verbose("stat", actual_path);
return 0;
}
dbg_free(actual_path);
}
if (S_ISDIR(info.st_mode)) { /* add a directory */
if (S_ISDIR(info.st_mode)) { /* add a directory */
if (rec)
r = _insert_dir(path);
@@ -268,6 +348,21 @@ static void _full_scan(void)
_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)
{
_cache.names = NULL;
@@ -293,30 +388,20 @@ int dev_cache_init(void)
return 1;
bad:
bad:
dev_cache_exit();
return 0;
}
static void _check_closed(struct device *dev)
{
if (dev->fd >= 0)
log_err("Device '%s' has been left open.", dev_name(dev));
}
static inline void _check_for_open_devices(void)
{
#ifndef NDEBUG
struct dev_iter *i = dev_iter_create(NULL);
struct device *dev;
if (!i) {
stack;
return;
}
while ((dev = dev_iter_get(i))) {
if (dev->fd >= 0)
log_err("Device '%s' has been left open.",
dev_name(dev));
}
dev_iter_destroy(i);
#endif
hash_iter(_cache.names, (iterate_fn) _check_closed);
}
void dev_cache_exit(void)
@@ -344,18 +429,76 @@ int dev_cache_add_dir(const char *path)
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;
}
strcpy(dl->dir, path);
list_add(&_cache.dirs, &dl->list);
return 1;
}
/* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
const char *dev_name_confirmed(struct device *dev, int quiet)
{
struct stat buf;
const char *name;
int r;
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
if (r < 0) {
if (quiet)
log_sys_debug("stat", name);
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 */
hash_remove(_cache.names, name);
/* Leave list alone if there isn't an alternative name */
/* so dev_name will always find something to return. */
/* Otherwise add the name to the correct device. */
if (list_size(&dev->aliases) > 1) {
list_del(dev->aliases.n);
if (!r)
_insert(name, 0);
continue;
}
log_error("Aborting - please provide new pathname for what "
"used to be %s", name);
return NULL;
}
return dev_name(dev);
}
struct device *dev_cache_get(const char *name, struct dev_filter *f)
{
struct stat buf;
struct device *d = (struct device *) hash_lookup(_cache.names, name);
/* If the entry's wrong, remove it */
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
hash_remove(_cache.names, name);
d = NULL;
}
if (!d) {
_insert(name, 0);
d = (struct device *) hash_lookup(_cache.names, name);
@@ -368,8 +511,10 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
{
struct dev_iter *di = dbg_malloc(sizeof(*di));
if (!di)
if (!di) {
log_error("dev_iter allocation failed");
return NULL;
}
_full_scan();
di->current = btree_first(_cache.devices);
@@ -401,6 +546,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
return NULL;
}

View File

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

View File

@@ -4,22 +4,206 @@
* This file is released under the LGPL.
*/
#include "device.h"
#include "lib.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 <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#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;
long s;
const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name);
@@ -28,36 +212,140 @@ int dev_get_size(struct device *dev, uint64_t *size)
return 0;
}
/* FIXME: add 64 bit ioctl */
if (ioctl(fd, BLKGETSIZE, &s) < 0) {
log_sys_error("ioctl BLKGETSIZE", name);
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
log_sys_error("ioctl BLKGETSIZE64", name);
close(fd);
return 0;
}
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
close(fd);
return 1;
}
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
int fd;
int s;
const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name);
if ((fd = open(name, O_RDONLY)) < 0) {
log_sys_error("open", name);
return 0;
}
if (ioctl(fd, BLKSSZGET, &s) < 0) {
log_sys_error("ioctl BLKSSZGET", name);
close(fd);
return 0;
}
close(fd);
*size = (uint64_t) s;
*size = (uint32_t) s;
return 1;
}
int dev_open(struct device *dev, int flags)
void dev_flush(struct device *dev)
{
const char *name = dev_name(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;
const char *name;
/* FIXME Check flags (eg is write now reqd?) */
if (dev->fd >= 0) {
log_error("Device '%s' has already been opened", name);
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;
return 0;
}
if ((dev->fd = open(name, flags)) < 0) {
if (!(dev->flags & DEV_REGULAR) &&
((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) {
log_error("%s: stat failed: Has device name changed?", name);
return 0;
}
if (direct)
flags |= O_DIRECT;
if ((dev->fd = open(name, flags, 0777)) < 0) {
log_sys_error("open", name);
return 0;
}
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);
dev_close(dev);
dev->fd = -1;
return 0;
}
#if !O_DIRECT
if (!(dev->flags & DEV_REGULAR))
dev_flush(dev);
#endif
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;
}
int dev_open_quiet(struct device *dev)
{
/* 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)
{
if (dev->fd < 0) {
@@ -65,128 +353,115 @@ int dev_close(struct device *dev)
"which is not open.", dev_name(dev));
return 0;
}
#if !O_DIRECT
if (dev->flags & DEV_ACCESSED_W)
dev_flush(dev);
#endif
if (close(dev->fd))
log_sys_error("close", dev_name(dev));
dev->fd = -1;
/* FIXME lookup device in cache to get vgname and see if it's locked? */
if (--dev->open_count < 1 && !vgs_locked())
_close(dev);
return 1;
}
/*
* FIXME: factor common code out.
void dev_close_all(void)
{
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 tot = 0;
int r;
while (tot < count) {
do
n = read(fd, buf, count - tot);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (!dev->open_count)
return 0;
if (n <= 0)
return tot ? tot : n;
r = dev_write(dev, dev->end, len, buffer);
dev->end += (uint64_t) len;
tot += n;
buf += n;
}
return tot;
#if !O_DIRECT
dev_flush(dev);
#endif
return r;
}
int64_t dev_read(struct device *dev, uint64_t offset,
int64_t len, void *buffer)
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
{
const char *name = dev_name(dev);
int fd = dev->fd;
struct device_area where;
if (fd < 0) {
log_err("Attempt to read an unopened device (%s).", name);
if (!dev->open_count)
return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", name);
return 0;
}
where.dev = dev;
where.start = offset;
where.size = len;
return _read(fd, buffer, len);
dev->flags |= DEV_ACCESSED_W;
return _aligned_io(&where, buffer, 1);
}
int _write(int fd, const void *buf, size_t count)
int dev_zero(struct device *dev, uint64_t offset, size_t len)
{
size_t n = 0;
int tot = 0;
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;
}
return _write(fd, buffer, len);
}
int dev_zero(struct device *dev, uint64_t offset, int64_t len)
{
int64_t r, s;
size_t s;
char buffer[4096];
const char *name = dev_name(dev);
int fd = dev->fd;
if (fd < 0) {
log_error("Attempt to zero part of an unopened device %s",
name);
if (!dev_open(dev)) {
stack;
return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", name);
return 0;
}
if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t,
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));
while (1) {
s = len > sizeof(buffer) ? sizeof(buffer) : len;
r = _write(fd, buffer, s);
if (r <= 0)
if (!dev_write(dev, offset, s, buffer))
break;
len -= r;
if (!len) {
r = 1;
len -= s;
if (!len)
break;
}
}
dev->flags |= DEV_ACCESSED_W;
if (!dev_close(dev))
stack;
/* FIXME: Always display error */
return (len == 0);
}

View File

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

View File

@@ -7,44 +7,87 @@
#ifndef _LVM_DEVICE_H
#define _LVM_DEVICE_H
#include "lvm-types.h"
#include "list.h"
#include "uuid.h"
#include <fcntl.h>
#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.
* pointer comparisons are valid.
*/
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;
/* private */
int fd;
int open_count;
uint32_t flags;
uint64_t end;
struct list open_list;
char pvid[ID_LEN + 1];
};
struct device_list {
struct list list;
struct device *dev;
};
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
uint64_t size; /* Bytes */
};
/*
* All io should use these routines.
*/
int dev_get_size(struct device *dev, uint64_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);
void dev_close_all(void);
int64_t dev_read(struct device *dev,
uint64_t offset, int64_t len, void *buffer);
int64_t dev_write(struct device *dev,
uint64_t offset, int64_t len, void *buffer);
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
static inline const char *dev_name(struct device *dev) {
return list_item(dev->aliases.n, struct str_list)->str;
static inline int dev_fd(struct device *dev)
{
return dev->fd;
}
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 int is_lvm_partition(const char *name) {
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 :
"unknown device";
}
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
/* FIXME Check partition type if appropriate */
#define is_lvm_partition(a) 1
/*
static inline int is_lvm_partition(const char *name)
{
return 1;
}
*/
#endif

View File

@@ -18,417 +18,663 @@
*
*/
#include <sys/types.h>
#include <string.h>
#include "lib.h"
#include "metadata.h"
#include "dbg_malloc.h"
#include "log.h"
#include "display.h"
#include "activate.h"
#include "toolcontext.h"
#define SIZE_BUF 128
char *display_size(unsigned long long 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)
{
int s;
ulong byte = 1024 * 1024 * 1024;
char *size_buf = NULL;
char *size_str[][2] = {
{"Terabyte", "TB"},
{"Gigabyte", "GB"},
{"Megabyte", "MB"},
{"Kilobyte", "KB"},
{"", ""}
};
char *ptr = NULL;
uint64_t v;
if (!(size_buf = dbg_malloc(SIZE_BUF))) {
log_error("no memory for size display buffer");
return NULL;
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 (size == 0LL)
sprintf(size_buf, "0");
else {
s = 0;
while (size_str[s] && size < byte)
s++, byte /= 1024;
snprintf(size_buf, SIZE_BUF - 1,
"%.2f %s", (float) size / byte, size_str[s][sl]);
}
if (*(units + 1))
return 0;
/* Caller to deallocate */
return size_buf;
return v;
}
/*
* FIXME: this function is badly named, it doesn't display the data it
* creates a new uuid string with -'s in it. It would be better if
* the destination was passed in as well. EJT
*/
char *display_uuid(char *uuidstr)
const char *get_alloc_string(alloc_policy_t alloc)
{
int i, j;
char *uuid;
int i;
if ((!uuidstr) || !(uuid = dbg_malloc(NAME_LEN))) {
log_error("no memory for uuid display buffer");
return NULL;
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 suffix = 1;
uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
const char *size_str[][3] = {
{" Terabyte", " TB", "T"},
{" Gigabyte", " GB", "G"},
{" Megabyte", " MB", "M"},
{" Kilobyte", " KB", "K"},
{"", "", ""},
{" Byte ", " B ", "B"},
{" Units ", " Un", "U"},
{" Sectors ", " Se", "S"},
{" ", " ", " "},
};
if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
log_error("no memory for size display buffer");
return "";
}
memset(uuid, 0, NAME_LEN);
suffix = cmd->current_settings.suffix;
i = 6;
memcpy(uuid, uuidstr, i);
uuidstr += i;
for (s = 0; s < 8; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[s][2])
break;
for (j = 0; j < 6; j++) {
uuid[i++] = '-';
memcpy(&uuid[i], uuidstr, 4);
uuidstr += 4;
i += 4;
if (size == UINT64_C(0)) {
sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : "");
return size_buf;
}
memcpy(&uuid[i], uuidstr, 2);
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;
while (size_str[s] && size < byte)
s++, byte /= units;
}
/* Caller must free */
return uuid;
snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
suffix ? size_str[s][sl] : "");
return size_buf;
}
void pvdisplay_colons(struct physical_volume *pv)
{
char *uuid;
char uuid[64];
if (!pv)
return;
uuid = display_uuid(pv->id.uuid);
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
stack;
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,
/* FIXME pv->pv_number, Derive or remove? */
pv->status, /* FIXME Support old or new format here? */
pv->status & ALLOCATED_PV, /* FIXME Remove? */
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
/* FIXME pv->lv_cur, Remove? */
pv->pe_size / 2,
pv->pe_count,
pv->pe_count - pv->pe_allocated,
pv->pe_allocated, *uuid ? uuid : "none");
dbg_free(uuid);
pv->pe_count - pv->pe_alloc_count,
pv->pe_alloc_count, *uuid ? uuid : "none");
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;
char *size, *size1; /*, *size2; */
char uuid[64];
const char *size;
uint64_t pe_free;
uint32_t pe_free;
if (!pv)
return;
uuid = display_uuid(pv->id.uuid);
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
stack;
return;
}
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
log_print("PV Name %s", dev_name(pv->dev));
log_print("VG Name %s", pv->vg_name);
log_print("VG Name %s%s", pv->vg_name,
pv->status & EXPORTED_VG ? " (exported)" : "");
size = display_size(pv->size / 2, SIZE_SHORT);
size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
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
/******** FIXME display LVM on-disk data size
size2 = display_size(pv->size / 2, SIZE_SHORT);
********/
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
size, size1); /* , size2); */
size, display_size(cmd,
(pv->size -
pv->pe_count * pv->pe_size) / 2,
SIZE_SHORT));
dbg_free(size1);
/* dbg_free(size2); */
} else
log_print("PV Size %s", size);
dbg_free(size);
/*********FIXME Anything use this?
log_print("PV# %u", pv->pv_number);
**********/
/* PV number not part of LVM2 design
log_print("PV# %u", pv->pv_number);
*/
log_print("PV Status %savailable",
(pv->status & ACTIVE) ? "" : "NOT ");
pe_free = pv->pe_count - pv->pe_allocated;
if (pv->pe_count && (pv->status & ALLOCATED_PV))
pe_free = pv->pe_count - pv->pe_alloc_count;
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
log_print("Allocatable yes %s",
(!pe_free && pv->pe_count) ? "(but full)" : "");
else
log_print("Allocatable NO");
/*********FIXME
log_print("Cur LV %u", pv->lv_cur);
*********/
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
/* LV count is no longer available when displaying PV
log_print("Cur LV %u", vg->lv_count);
*/
log_print("PE Size (KByte) %" PRIu32, pv->pe_size / 2);
log_print("Total PE %u", pv->pe_count);
log_print("Free PE %" PRIu64, pe_free);
log_print("Allocated PE %u", pv->pe_allocated);
#ifdef LVM_FUTURE
printf("Stale PE %u", pv->pe_stale);
#endif
log_print("Free PE %" PRIu32, pe_free);
log_print("Allocated PE %u", pv->pe_alloc_count);
log_print("PV UUID %s", *uuid ? uuid : "none");
log_print(" ");
dbg_free(uuid);
return;
}
void pv_display_short(struct physical_volume *pv)
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle)
{
char uuid[64];
if (!pv)
return;
return 0;
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
stack;
return 0;
}
log_print("PV Name %s ", dev_name(pv->dev));
/* FIXME pv->pv_number); */
log_print("PV Status %savailable / %sallocatable",
(pv->status & ACTIVE) ? "" : "NOT ",
(pv->status & ALLOCATED_PV) ? "" : "NOT ");
log_print("PV UUID %s", *uuid ? uuid : "none");
log_print("PV Status %sallocatable",
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
log_print("Total PE / Free PE %u / %u",
pv->pe_count, pv->pe_count - pv->pe_allocated);
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
return;
log_print(" ");
return 0;
}
void lvdisplay_colons(struct logical_volume *lv)
{
log_print("%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:-1:-1",
/* FIXME Prefix - attach to struct volume_group? */
int inkernel;
struct lvinfo info;
inkernel = lv_info(lv, &info) && info.exists;
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
lv->vg->cmd->dev_dir,
lv->vg->name,
lv->name,
lv->vg->name,
(lv->status & (LVM_READ | LVM_WRITE)) >> 8,
lv->status & ACTIVE,
(lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
/* FIXME lv->lv_number, */
lvs_in_vg_opened(lv->vg), 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, */
((lv->status & ALLOC_STRICT) +
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead
/* FIXME device num MAJOR(lv->lv_dev), MINOR(lv->lv_dev) */
);
(lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
inkernel ? info.major : -1, inkernel ? info.minor : -1);
return;
}
void lvdisplay_full(struct logical_volume *lv)
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
char *size;
uint32_t alloc;
struct lvinfo info;
int inkernel, snap_active;
char uuid[64];
struct snapshot *snap = NULL;
struct list *slh, *snaplist;
float snap_percent; /* fused, fsize; */
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
stack;
return 0;
}
inkernel = lv_info(lv, &info) && info.exists;
log_print("--- Logical volume ---");
/* FIXME Add dev_dir */
log_print("LV Name %s/%s", lv->vg->name, lv->name);
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
lv->vg->name, lv->name);
log_print("VG Name %s", lv->vg->name);
log_print("LV UUID %s", uuid);
log_print("LV Write Access %s",
(lv->status & LVM_WRITE) ? "read/write" : "read only");
/******* FIXME Snapshot
if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
ret = -LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV;
goto lv_show_end;
}
printf("LV snapshot status ");
if (vg_check_active(vg_name) == TRUE) {
vg_t *vg_core;
if ((ret = vg_status_with_pv_and_lv(vg_name, &vg_core)) == 0) {
lv_t *lv_ptr =
vg_core->
lv[lv_get_index_by_name(vg_core, lv->lv_name)];
if (lv_ptr->lv_access & LV_SNAPSHOT) {
if (lv_ptr->lv_status & LV_ACTIVE)
printf("active ");
else
printf("INACTIVE ");
}
if (lv_ptr->lv_access & LV_SNAPSHOT_ORG) {
printf("source of\n");
while (lv_ptr->lv_snapshot_next != NULL) {
lv_ptr = lv_ptr->lv_snapshot_next;
printf(" %s [%s]\n",
lv_ptr->lv_name,
(lv_ptr->
lv_status & LV_ACTIVE) ? "active" :
"INACTIVE");
}
vg_free(vg_core, TRUE);
} else {
printf("destination for %s\n",
lv_ptr->lv_snapshot_org->lv_name);
}
}
} else {
printf("INACTIVE ");
if (lv->lv_access & LV_SNAPSHOT_ORG)
printf("original\n");
else
printf("snapshot\n");
}
}
***********/
if (lv_is_origin(lv)) {
log_print("LV snapshot status source of");
log_print("LV Status %savailable",
(lv->status & ACTIVE) ? "" : "NOT ");
snaplist = find_snapshots(lv);
list_iterate(slh, snaplist) {
snap = list_item(slh, struct snapshot_list)->snapshot;
snap_active = lv_snapshot_percent(snap->cow,
&snap_percent);
if (!snap_active || snap_percent < 0 ||
snap_percent >= 100)
snap_active = 0;
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
}
snap = NULL;
} else if ((snap = find_cow(lv))) {
snap_active = lv_snapshot_percent(lv, &snap_percent);
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
}
if (inkernel && info.suspended)
log_print("LV Status suspended");
else
log_print("LV Status %savailable",
inkernel ? "" : "NOT ");
/********* FIXME lv_number
log_print("LV # %u", lv->lv_number + 1);
************/
/********* FIXME lv_open
log_print("# open %u\n", lv->lv_open);
**********/
/********
#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 (inkernel)
log_print("# open %u", info.open_count);
size = display_size(lv->size / 2, SIZE_SHORT);
log_print("LV Size %s", size);
dbg_free(size);
log_print("LV Size %s",
display_size(cmd,
snap ? snap->origin->size / 2 : lv->size / 2,
SIZE_SHORT));
log_print("Current LE %u", lv->le_count);
log_print("Current LE %u",
snap ? snap->origin->le_count : lv->le_count);
/********** FIXME allocation
log_print("Allocated LE %u", lv->allocated_le);
**********/
/********** FIXME Snapshot
if (lv->lv_access & LV_SNAPSHOT) {
printf("snapshot chunk size %s\n",
(dummy = lvm_show_size(lv->lv_chunk_size / 2, SHORT)));
dbg_free(dummy);
dummy = NULL;
if (lv->lv_remap_end > 0) {
lv_remap_ptr = lv->lv_remap_ptr;
if (lv_remap_ptr > lv->lv_remap_end)
lv_remap_ptr = lv->lv_remap_end;
dummy = lvm_show_size(lv_remap_ptr *
lv->lv_chunk_size / 2, SHORT);
dummy1 = lvm_show_size(lv->lv_remap_end *
lv->lv_chunk_size / 2, SHORT);
printf("Allocated to snapshot %.2f%% [%s/%s]\n",
(float) lv_remap_ptr * 100 / lv->lv_remap_end,
dummy, dummy1);
dbg_free(dummy);
dbg_free(dummy1);
dummy =
lvm_show_size((vg->
lv[lv_get_index_by_number
(vg,
lv->lv_number)]->lv_size -
lv->lv_remap_end * lv->lv_chunk_size) / 2,
SHORT);
printf("Allocated to COW-table %s\n", dummy);
dbg_free(dummy);
log_print("Segments %u", list_size(&lv->segments));
/********* FIXME Stripes & stripesize for each segment
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
***********/
if (snap) {
if (snap_percent == -1)
snap_percent = 100;
log_print("Snapshot chunk size %s",
display_size(cmd, (uint64_t) snap->chunk_size / 2,
SIZE_SHORT));
/*
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);
}
******************/
if (lv->stripes > 1) {
log_print("Stripes %u", lv->stripes);
/*********** FIXME stripesize
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
***********/
log_print("Allocation %s", get_alloc_string(lv->alloc));
log_print("Read ahead sectors %u", lv->read_ahead);
if (lv->status & FIXED_MINOR) {
if (lv->major >= 0)
log_print("Persistent major %d", lv->major);
log_print("Persistent minor %d", lv->minor);
}
/**************
#ifdef LVM_FUTURE
printf("Bad block ");
if (lv->lv_badblock == LV_BADBLOCK_ON)
printf("on\n");
else
printf("off\n");
#endif
***************/
if (inkernel)
log_print("Block device %d:%d", info.major,
info.minor);
/* FIXME next free == ALLOC_SIMPLE */
alloc = lv->status & (ALLOC_STRICT | ALLOC_CONTIGUOUS);
log_print("Allocation %s%s%s%s",
!(alloc & (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "next free" :
"", (alloc == ALLOC_STRICT) ? "strict" : "",
(alloc == ALLOC_CONTIGUOUS) ? "contiguous" : "",
(alloc ==
(ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "strict/contiguous" :
"");
log_print(" ");
log_print("Read ahead sectors %u\n", lv->read_ahead);
/****************
#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
*************/
/********* FIXME blockdev
printf("Block device %d:%d\n",
MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
*************/
return;
return 0;
}
void lvdisplay_extents(struct logical_volume *lv)
static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
{
int le;
struct list *pvh;
struct physical_volume *pv;
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_verbose("--- Distribution of logical volume on physical "
"volumes ---");
log_verbose("PV Name PE on PV ");
if (seg->area[s].u.pv.pv)
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");
list_iterate(pvh, &lv->vg->pvs) {
int count = 0;
pv = &list_item(pvh, struct pv_list)->pv;
for (le = 0; le < lv->le_count; le++)
if (lv->map[le].pv->dev == pv->dev)
count++;
if (count)
log_verbose("%-25s %d", dev_name(pv->dev), count);
if (seg->area[s].u.lv.lv)
log_print("%sLogical extents\t%d to %d", pre,
seg->area[s].u.lv.le,
seg->area[s].u.lv.le + seg->area_len - 1);
}
}
int lvdisplay_segments(struct logical_volume *lv)
{
uint32_t s;
struct list *segh;
struct lv_segment *seg;
log_print("--- Segments ---");
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
log_print("Logical extent %u to %u:",
seg->le, seg->le + seg->len - 1);
if (seg->type == SEG_STRIPED && seg->area_count == 1)
log_print(" Type\t\tlinear");
else
log_print(" Type\t\t%s",
get_segtype_string(seg->type));
switch (seg->type) {
case SEG_STRIPED:
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->area_count; s++) {
log_print(" Stripe %d:", 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;
}
}
/********* FIXME "reads writes"
log_print(" ");
return 1;
}
printf("\n --- logical volume i/o statistic ---\n"
" %d reads %d writes\n", sum_reads, sum_writes);
void vgdisplay_extents(struct volume_group *vg)
{
return;
}
******* */
void vgdisplay_full(struct volume_group *vg)
{
uint32_t access;
uint32_t active_pvs;
char uuid[64];
log_verbose(" ");
log_verbose("--- Logical extents ---");
log_verbose("LE PV PE");
if (vg->status & PARTIAL_VG)
active_pvs = list_size(&vg->pvs);
else
active_pvs = vg->pv_count;
for (le = 0; le < lv->le_count; le++) {
log_verbose("%05d %-25s %05u ", le,
dev_name(lv->map[le].pv->dev), lv->map[le].pe);
log_print("--- Volume group ---");
log_print("VG Name %s", vg->name);
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);
log_print("VG Access %s%s%s%s",
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
access == LVM_READ ? "read" : "",
access == LVM_WRITE ? "write" : "",
access == 0 ? "error" : "");
log_print("VG Status %s%sresizable",
vg->status & EXPORTED_VG ? "exported/" : "",
vg->status & RESIZEABLE_VG ? "" : "NOT ");
/* vg number not part of LVM2 design
log_print ("VG # %u\n", vg->vg_number);
*/
if (vg->status & CLUSTERED) {
log_print("Clustered yes");
log_print("Shared %s",
vg->status & SHARED ? "yes" : "no");
}
log_print("MAX LV %u", vg->max_lv);
log_print("Cur LV %u", vg->lv_count);
log_print("Open LV %u", lvs_in_vg_opened(vg));
/****** 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("Cur PV %u", vg->pv_count);
log_print("Act PV %u", active_pvs);
log_print("VG Size %s",
display_size(vg->cmd,
(uint64_t) vg->extent_count * (vg->extent_size /
2), SIZE_SHORT));
log_print("PE Size %s",
display_size(vg->cmd, (uint64_t) vg->extent_size / 2,
SIZE_SHORT));
log_print("Total PE %u", vg->extent_count);
log_print("Alloc PE / Size %u / %s",
vg->extent_count - vg->free_count, display_size(vg->cmd,
((uint64_t)
vg->
extent_count
-
vg->
free_count) *
(vg->
extent_size /
2),
SIZE_SHORT));
log_print("Free PE / Size %u / %s", vg->free_count,
display_size(vg->cmd,
(uint64_t) vg->free_count * (vg->extent_size /
2), SIZE_SHORT));
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
stack;
return;
}
log_print("VG UUID %s", uuid);
log_print(" ");
return;
}
void vgdisplay_colons(struct volume_group *vg)
{
return;
}
void vgdisplay_short(struct volume_group *vg)
{
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
display_size(vg->cmd, (uint64_t) vg->extent_count *
vg->extent_size / 2, SIZE_SHORT),
display_size(vg->cmd,
((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;
}

View File

@@ -25,29 +25,40 @@
#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 */
char *display_size(unsigned long long 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);
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,
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_extents(struct logical_volume *lv);
void lvdisplay_full(struct logical_volume *lv);
int lvdisplay_segments(struct logical_volume *lv);
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle);
#if 0
void pv_show_short(pv_t * pv);
void pv_display_pe(pv_t * pv, pe_disk_t * pe);
void pv_display_pe_free(int pe_free, int p);
void pv_display_pe_text(pv_t * pv, pe_disk_t * pe, lv_disk_t * lvs);
void vgdisplay_extents(struct volume_group *vg);
void vgdisplay_full(struct volume_group *vg);
void vgdisplay_colons(struct volume_group *vg);
void vgdisplay_short(struct volume_group *vg);
static inline unsigned long get_pe_offset(ulong p, pv_t *pv)
{
return pv->pe_start + (p * pv->pe_size);
}
/*
* 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.
*/
#include "lib.h"
#include "filter-composite.h"
#include "dbg_malloc.h"
#include "log.h"
#include <stdarg.h>
@@ -20,6 +19,8 @@ static int _and_p(struct dev_filter *f, struct device *dev)
filters++;
}
log_debug("Using %s", dev_name(dev));
return 1;
}
@@ -36,7 +37,6 @@ static void _destroy(struct dev_filter *f)
dbg_free(f);
}
struct dev_filter *composite_filter_create(int n, ...)
{
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));

View File

@@ -4,14 +4,12 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "config.h"
#include "dev-cache.h"
#include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "filter-persistent.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
@@ -34,8 +32,12 @@ static int _init_hash(struct pfilter *pf)
if (pf->devices)
hash_destroy(pf->devices);
pf->devices = hash_create(128);
return pf->devices ? 1 : 0;
if (!(pf->devices = hash_create(128))) {
stack;
return 0;
}
return 1;
}
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;
hash_wipe(pf->devices);
/* Trigger complete device scan */
dev_cache_scan(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)
{
struct config_node *cn;
@@ -54,7 +59,7 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
if (!(cn = find_config_node(cf->root, path, '/'))) {
log_very_verbose("Couldn't find %s array in '%s'",
path, pf->file);
path, pf->file);
return 0;
}
@@ -65,13 +70,15 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_verbose("Devices array contains a value "
"which is not a string ... ignoring");
"which is not a string ... ignoring");
continue;
}
if (!hash_insert(pf->devices, cv->v.str, data))
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;
}
@@ -81,28 +88,35 @@ int persistent_filter_load(struct dev_filter *f)
struct pfilter *pf = (struct pfilter *) f->private;
int r = 0;
struct config_file *cf;
struct config_tree *cf;
if (!(cf = create_config_file())) {
if (!(cf = create_config_tree())) {
stack;
return 0;
}
if (!read_config(cf, pf->file)) {
if (!read_config_file(cf, pf->file)) {
stack;
goto out;
}
_read_array(pf, cf, "persistent_filter_cache/valid_devices",
PF_GOOD_DEVICE);
_read_array(pf, cf, "persistent_filter_cache/invalid_devices",
PF_BAD_DEVICE);
/* We don't gain anything by holding invalid devices */
/* _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;
}
out:
destroy_config_file(cf);
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out:
destroy_config_tree(cf);
return r;
}
@@ -141,12 +155,24 @@ int persistent_filter_dump(struct dev_filter *f)
struct pfilter *pf = (struct pfilter *) f->private;
FILE *fp;
if (!hash_get_num_entries(pf->devices)) {
log_very_verbose("Internal persistent device cache empty "
"- not writing to %s", pf->file);
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);
fp = fopen(pf->file, "w");
if (!fp) {
log_sys_error("fopen", pf->file);
if (errno != EROFS)
log_sys_error("fopen", pf->file);
return 0;
}
@@ -154,7 +180,8 @@ int persistent_filter_dump(struct dev_filter *f)
fprintf(fp, "persistent_filter_cache {\n");
_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");
fclose(fp);
@@ -170,7 +197,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
if (!l) {
l = pf->real->passes_filter(pf->real, dev) ?
PF_GOOD_DEVICE : PF_BAD_DEVICE;
PF_GOOD_DEVICE : PF_BAD_DEVICE;
list_iterate(ah, &dev->aliases) {
sl = list_item(ah, struct str_list);
@@ -178,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)
@@ -227,7 +258,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
return f;
bad:
bad:
dbg_free(pf->file);
if (pf->devices)
hash_destroy(pf->devices);

View File

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

View File

@@ -18,28 +18,34 @@
*
*/
#include "dbg_malloc.h"
#include "log.h"
#include "lib.h"
#include "dev-cache.h"
#include "filter.h"
#include "lvm-string.h"
#include "config.h"
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <linux/kdev_t.h>
#include <limits.h>
#define NUMBER_OF_MAJORS 256
typedef struct {
char *name;
int max_partitions;
const char *name;
const int max_partitions;
} device_info_t;
static device_info_t device_info[] = {
static int _md_major = -1;
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 */
{"sd", 16}, /* SCSI disk */
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
@@ -50,81 +56,75 @@ static device_info_t device_info[] = {
{"ida", 16}, /* Compaq SMART2 */
{"cciss", 16}, /* Compaq CCISS array */
{"ubd", 16}, /* User-mode virtual block device */
{"ataraid", 16}, /* ATA Raid */
{NULL, 0}
};
static int *scan_proc_dev(void);
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;
const char *name = dev_name(dev);
/* Is this a recognised device type? */
if (!(((int *) f->private)[MAJOR(dev->dev)]))
return 0;
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno));
if (!(((int *) f->private)[MAJOR(dev->dev)])) {
log_debug("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev));
return 0;
}
close(fd);
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("%s: Skipping: open failed: %s", name,
strerror(errno));
return 0;
}
close(fd);
return 1;
}
struct dev_filter *lvm_type_filter_create()
{
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()))
return NULL;
return f;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}
static int *scan_proc_dev(void)
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
{
char line[80];
FILE *procdevices = NULL;
int ret = 0;
char proc_devices[PATH_MAX];
FILE *pd = NULL;
int i, j = 0;
int line_maj = 0;
int blocksection = 0;
int dev_len = 0;
size_t dev_len = 0;
struct config_value *cv;
int *max_partitions_by_major;
char *name;
if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
log_error("Filter failed to allocate max_partitions_by_major");
return NULL;
}
if (!(procdevices = fopen("/proc/devices", "r"))) {
log_error("Failed to open /proc/devices: %s", strerror(errno));
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),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return NULL;
}
memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
while (fgets(line, 80, procdevices) != NULL) {
if (!(pd = fopen(proc_devices, "r"))) {
log_sys_error("fopen", proc_devices);
return NULL;
}
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
while (fgets(line, 80, pd) != NULL) {
i = 0;
while (line[i] == ' ' && line[i] != '\0')
i++;
@@ -146,21 +146,85 @@ static int *scan_proc_dev(void)
while (line[i] == ' ' && line[i] != '\0')
i++;
/* Look for md device */
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
_md_major = line_maj;
/* Go through the valid device names and if there is a
match store max number of partitions */
match store max number of partitions */
for (j = 0; device_info[j].name != NULL; j++) {
dev_len = strlen(device_info[j].name);
if (dev_len <= strlen(line + i)
&& !strncmp(device_info[j].name, line + i, dev_len)
&& (line_maj < NUMBER_OF_MAJORS)) {
if (dev_len <= strlen(line + i) &&
!strncmp(device_info[j].name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
max_partitions_by_major[line_maj] =
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;
}
}
}
fclose(procdevices);
fclose(pd);
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,9 +21,23 @@
#ifndef _LVM_FILTER_H
#define _LVM_FILTER_H
struct dev_filter *lvm_type_filter_create();
#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);
#endif
int md_major(void);
#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,13 +4,13 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "pool.h"
#include "xlate.h"
#include "log.h"
#include "filter.h"
#include "lvmcache.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define fail do {stack; return 0;} while(0)
@@ -25,69 +25,74 @@
*/
static void _xlate_pvd(struct pv_disk *disk)
{
xx16(version);
xx16(version);
xx32(pv_on_disk.base); xx32(pv_on_disk.size);
xx32(vg_on_disk.base); xx32(vg_on_disk.size);
xx32(pv_uuidlist_on_disk.base); xx32(pv_uuidlist_on_disk.size);
xx32(lv_on_disk.base); xx32(lv_on_disk.size);
xx32(pe_on_disk.base); xx32(pe_on_disk.size);
xx32(pv_on_disk.base);
xx32(pv_on_disk.size);
xx32(vg_on_disk.base);
xx32(vg_on_disk.size);
xx32(pv_uuidlist_on_disk.base);
xx32(pv_uuidlist_on_disk.size);
xx32(lv_on_disk.base);
xx32(lv_on_disk.size);
xx32(pe_on_disk.base);
xx32(pe_on_disk.size);
xx32(pv_major);
xx32(pv_number);
xx32(pv_status);
xx32(pv_allocatable);
xx32(pv_size);
xx32(lv_cur);
xx32(pe_size);
xx32(pe_total);
xx32(pe_allocated);
xx32(pv_major);
xx32(pv_number);
xx32(pv_status);
xx32(pv_allocatable);
xx32(pv_size);
xx32(lv_cur);
xx32(pe_size);
xx32(pe_total);
xx32(pe_allocated);
xx32(pe_start);
}
static void _xlate_lvd(struct lv_disk *disk)
{
xx32(lv_access);
xx32(lv_status);
xx32(lv_open);
xx32(lv_dev);
xx32(lv_number);
xx32(lv_mirror_copies);
xx32(lv_recovery);
xx32(lv_schedule);
xx32(lv_size);
xx32(lv_snapshot_minor);
xx16(lv_chunk_size);
xx16(dummy);
xx32(lv_allocated_le);
xx32(lv_stripes);
xx32(lv_stripesize);
xx32(lv_badblock);
xx32(lv_allocation);
xx32(lv_io_timeout);
xx32(lv_read_ahead);
xx32(lv_access);
xx32(lv_status);
xx32(lv_open);
xx32(lv_dev);
xx32(lv_number);
xx32(lv_mirror_copies);
xx32(lv_recovery);
xx32(lv_schedule);
xx32(lv_size);
xx32(lv_snapshot_minor);
xx16(lv_chunk_size);
xx16(dummy);
xx32(lv_allocated_le);
xx32(lv_stripes);
xx32(lv_stripesize);
xx32(lv_badblock);
xx32(lv_allocation);
xx32(lv_io_timeout);
xx32(lv_read_ahead);
}
static void _xlate_vgd(struct vg_disk *disk)
{
xx32(vg_number);
xx32(vg_access);
xx32(vg_status);
xx32(lv_max);
xx32(lv_cur);
xx32(lv_open);
xx32(pv_max);
xx32(pv_cur);
xx32(pv_act);
xx32(dummy);
xx32(vgda);
xx32(pe_size);
xx32(pe_total);
xx32(pe_allocated);
xx32(pvg_total);
xx32(vg_number);
xx32(vg_access);
xx32(vg_status);
xx32(lv_max);
xx32(lv_cur);
xx32(lv_open);
xx32(pv_max);
xx32(pv_cur);
xx32(pv_act);
xx32(dummy);
xx32(vgda);
xx32(pe_size);
xx32(pe_total);
xx32(pe_allocated);
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;
@@ -107,12 +112,12 @@ static int _munge_formats(struct pv_disk *pvd)
switch (pvd->version) {
case 1:
pvd->pe_start = ((pvd->pe_on_disk.base +
pvd->pe_on_disk.size) / SECTOR_SIZE);
pvd->pe_on_disk.size) >> SECTOR_SHIFT);
break;
case 2:
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;
break;
@@ -123,19 +128,34 @@ static int _munge_formats(struct pv_disk *pvd)
return 1;
}
static int _read_pvd(struct disk_list *data)
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{
struct pv_disk *pvd = &data->pvd;
if (dev_read(data->dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd))
fail;
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
}
_xlate_pvd(pvd);
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
log_very_verbose("%s does not have a valid LVM1 PV identifier",
dev_name(dev));
return 0;
}
if (!_munge_formats(pvd)) {
log_very_verbose("format1: Unknown metadata version %d "
"found on %s", pvd->version, dev_name(dev));
return 0;
}
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;
_xlate_lvd(disk);
@@ -146,8 +166,8 @@ static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
static int _read_vgd(struct disk_list *data)
{
struct vg_disk *vgd = &data->vgd;
unsigned long pos = data->pvd.vg_on_disk.base;
if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
uint64_t pos = data->pvd.vg_on_disk.base;
if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
fail;
_xlate_vgd(vgd);
@@ -160,19 +180,18 @@ static int _read_uuids(struct disk_list *data)
int num_read = 0;
struct uuid_list *ul;
char buffer[NAME_LEN];
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
while(pos < end && num_read < data->vgd.pv_cur) {
if (dev_read(data->dev, pos, sizeof(buffer), buffer) !=
sizeof(buffer))
while (pos < end && num_read < data->vgd.pv_cur) {
if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
fail;
if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
fail;
memcpy(ul->uuid, buffer, NAME_LEN);
ul->uuid[NAME_LEN] = '\0';
ul->uuid[NAME_LEN - 1] = '\0';
list_add(&data->uuids, &ul->list);
@@ -190,12 +209,12 @@ static inline int _check_lvd(struct lv_disk *lvd)
static int _read_lvs(struct disk_list *data)
{
int i, read = 0;
unsigned long pos;
unsigned int i, read = 0;
uint64_t pos;
struct lvd_list *ll;
struct vg_disk *vgd = &data->vgd;
for(i = 0; (i < vgd->lv_max) && (read < vgd->lv_cur); i++) {
for (i = 0; (i < vgd->lv_max) && (read < vgd->lv_cur); i++) {
pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk));
ll = pool_alloc(data->mem, sizeof(*ll));
@@ -219,12 +238,12 @@ static int _read_extents(struct disk_list *data)
{
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
struct pe_disk *extents = pool_alloc(data->mem, len);
unsigned long pos = data->pvd.pe_on_disk.base;
uint64_t pos = data->pvd.pe_on_disk.base;
if (!extents)
fail;
if (dev_read(data->dev, pos, len, extents) != len)
if (!dev_read(data->dev, pos, len, extents))
fail;
_xlate_extents(extents, data->pvd.pe_total);
@@ -233,93 +252,124 @@ static int _read_extents(struct disk_list *data)
return 1;
}
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
/*
* If exported, remove "PV_EXP" from end of VG name
*/
void munge_exported_vg(struct pv_disk *pvd, struct vg_disk *vgd)
{
int l;
size_t s;
/* Return if PV not in a VG or VG not exported */
if ((!*pvd->vg_name) || (vgd && !(vgd->vg_status & VG_EXPORTED)))
return;
l = strlen(pvd->vg_name);
s = sizeof(EXPORTED_TAG);
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s))
pvd->vg_name[l - s + 1] = '\0';
pvd->pv_status |= VG_EXPORTED;
}
static struct disk_list *__read_disk(const struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name)
{
struct disk_list *data = pool_alloc(mem, sizeof(*data));
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
const char *name = dev_name(dev);
struct lvmcache_info *info;
if (!data) {
if (!dl) {
stack;
return NULL;
}
data->dev = dev;
data->mem = mem;
list_init(&data->uuids);
list_init(&data->lvds);
dl->dev = dev;
dl->mem = mem;
list_init(&dl->uuids);
list_init(&dl->lvds);
if (!_read_pvd(data)) {
log_debug("Failed to read PV data from %s", name);
if (!_read_pvd(dev, &dl->pvd)) {
stack;
goto bad;
}
if (data->pvd.id[0] != 'H' || data->pvd.id[1] != 'M') {
log_very_verbose("%s does not have a valid PV identifier",
name);
goto bad;
}
/* If VG is exported, set VG name back to the real name */
munge_exported_vg(&dl->pvd, &dl->vgd);
if (!_munge_formats(&data->pvd)) {
log_very_verbose("Unknown metadata version %d found on %s",
data->pvd.version, name);
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 ?
*/
if (data->pvd.vg_name == '\0') {
log_very_verbose("%s is not a member of any VG", name);
return data;
if (!*dl->pvd.vg_name) {
log_very_verbose("%s is not a member of any format1 VG", name);
/* Update VG cache */
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
return (vg_name) ? NULL : dl;
}
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
if (!_read_vgd(dl)) {
log_error("Failed to read VG data from PV (%s)", name);
goto bad;
}
/* Update VG cache with what we found */
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s",
name, vg_name);
goto bad;
}
if (!_read_vgd(data)) {
log_error("Failed to read VG data from PV (%s)", name);
goto bad;
}
if (!_read_uuids(data)) {
if (!_read_uuids(dl)) {
log_error("Failed to read PV uuid list from %s", name);
goto bad;
}
if (!_read_lvs(data)) {
if (!_read_lvs(dl)) {
log_error("Failed to read LV's from %s", name);
goto bad;
}
if (!_read_extents(data)) {
if (!_read_extents(dl)) {
log_error("Failed to read extents from %s", name);
goto bad;
}
log_very_verbose("Found %s in VG %s", name, data->pvd.vg_name);
log_very_verbose("Found %s in %sVG %s", name,
(dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
dl->pvd.vg_name);
return data;
return dl;
bad:
pool_free(data->mem, data);
bad:
pool_free(dl->mem, dl);
return NULL;
}
struct disk_list *read_disk(struct device *dev, struct pool *mem,
const char *vg_name)
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name)
{
struct disk_list *r;
if (!dev_open(dev, O_RDONLY)) {
if (!dev_open(dev)) {
stack;
return NULL;
}
r = __read_disk(dev, mem, vg_name);
r = __read_disk(fmt, dev, mem, vg_name);
if (!dev_close(dev))
stack;
@@ -327,23 +377,76 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem,
return r;
}
static void _add_pv_to_list(struct list *head, struct disk_list *data)
{
struct list *pvdh;
struct pv_disk *pvd;
list_iterate(pvdh, head) {
pvd = &list_item(pvdh, struct disk_list)->pvd;
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
sizeof(pvd->pv_uuid))) {
if (MAJOR(data->dev->dev) != md_major()) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s", pvd->pv_uuid,
dev_name(data->dev));
return;
}
log_very_verbose("Duplicate PV %s - using md %s",
pvd->pv_uuid, dev_name(data->dev));
list_del(pvdh);
break;
}
}
list_add(head, &data->list);
}
/*
* Build a list of pv_d's structures, allocated
* from mem. We keep track of the first object
* allocated form the pool so we can free off all
* the memory if something goes wrong.
* Build a list of pv_d's structures, allocated from mem.
* We keep track of the first object allocated form the pool
* so we can free off all the memory if something goes wrong.
*/
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
struct pool *mem, struct list *head)
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_filter *filter, struct pool *mem,
struct list *head)
{
struct dev_iter *iter = dev_iter_create(filter);
struct dev_iter *iter;
struct device *dev;
struct disk_list *data = NULL;
struct list *vgih;
struct lvmcache_vginfo *vginfo;
/* Fast path if we already saw this VG and cached the list of PVs */
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
vginfo->infos.n) {
list_iterate(vgih, &vginfo->infos) {
dev = list_item(vgih, struct lvmcache_info)->dev;
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
break;
_add_pv_to_list(head, data);
}
/* Did we find the whole VG? */
if (!vg_name || !*vg_name ||
(data && *data->pvd.vg_name &&
list_size(head) == data->vgd.pv_cur))
return 1;
/* Failed */
list_init(head);
/* vgcache_del(vg_name); */
}
if (!(iter = dev_iter_create(filter))) {
log_error("read_pvs_in_vg: dev_iter_create failed");
return 0;
}
/* Otherwise do a complete scan */
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
if ((data = read_disk(dev, mem, vg_name)))
list_add(head, &data->list);
if ((data = read_disk(fmt, dev, mem, vg_name))) {
_add_pv_to_list(head, data);
}
}
dev_iter_destroy(iter);
@@ -353,14 +456,13 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
return 1;
}
static int _write_vgd(struct disk_list *data)
{
struct vg_disk *vgd = &data->vgd;
unsigned long pos = data->pvd.vg_on_disk.base;
uint64_t pos = data->pvd.vg_on_disk.base;
_xlate_vgd(vgd);
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
fail;
_xlate_vgd(vgd);
@@ -372,8 +474,8 @@ static int _write_uuids(struct disk_list *data)
{
struct uuid_list *ul;
struct list *uh;
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
list_iterate(uh, &data->uuids) {
if (pos >= end) {
@@ -383,7 +485,7 @@ static int _write_uuids(struct disk_list *data)
}
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;
pos += NAME_LEN;
@@ -392,10 +494,10 @@ static int _write_uuids(struct disk_list *data)
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);
if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
if (!dev_write(dev, pos, sizeof(*disk), disk))
fail;
_xlate_lvd(disk);
@@ -406,23 +508,27 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
static int _write_lvs(struct disk_list *data)
{
struct list *lvh;
unsigned long pos;
uint64_t pos, offset;
pos = data->pvd.lv_on_disk.base;
if (!dev_zero(data->dev, pos, data->pvd.lv_on_disk.size)) {
log_error("Couldn't zero lv area on device '%s'",
dev_name(data->dev));
dev_name(data->dev));
return 0;
}
list_iterate(lvh, &data->lvds) {
struct lvd_list *ll = list_item(lvh, struct lvd_list);
if (!_write_lvd(data->dev, pos, &ll->lvd))
fail;
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
log_error("lv_number %d too large", ll->lvd.lv_number);
return 0;
}
pos += sizeof(struct lv_disk);
if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
fail;
}
return 1;
@@ -432,10 +538,10 @@ static int _write_extents(struct disk_list *data)
{
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
struct pe_disk *extents = data->extents;
unsigned long pos = data->pvd.pe_on_disk.base;
uint64_t pos = data->pvd.pe_on_disk.base;
_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;
_xlate_extents(extents, data->pvd.pe_total);
@@ -445,21 +551,42 @@ static int _write_extents(struct disk_list *data)
static int _write_pvd(struct disk_list *data)
{
struct pv_disk *disk = &data->pvd;
char *buf;
uint64_t pos = data->pvd.pv_on_disk.base;
size_t size = data->pvd.pv_on_disk.size;
_xlate_pvd(disk);
if (dev_write(data->dev, 0, sizeof(*disk), disk) != sizeof(*disk))
if (size < sizeof(struct pv_disk)) {
log_error("Invalid PV structure size.");
return 0;
}
/* Make sure that the gap between the PV structure and
the next one is zeroed in order to make non LVM tools
happy (idea from AED) */
buf = dbg_malloc(size);
if (!buf) {
log_err("Couldn't allocate temporary PV buffer.");
return 0;
}
memset(buf, 0, size);
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
_xlate_pvd((struct pv_disk *) buf);
if (!dev_write(data->dev, pos, size, buf)) {
dbg_free(buf);
fail;
}
_xlate_pvd(disk);
dbg_free(buf);
return 1;
}
/*
* assumes the device has been opened.
*/
static int __write_all_pvd(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);
@@ -468,11 +595,19 @@ static int __write_all_pvd(struct disk_list *data)
return 0;
}
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
/*
* Stop here for orphan pv's.
*/
if (data->pvd.vg_name[0] == '\0')
if (data->pvd.vg_name[0] == '\0') {
/* if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
return 1;
}
/* if (!test_mode())
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
fmt); */
if (!_write_vgd(data)) {
log_error("Failed to write VG data to %s", pv_name);
@@ -500,16 +635,16 @@ static int __write_all_pvd(struct disk_list *data)
/*
* opens the device and hands to the above fn.
*/
static int _write_all_pvd(struct disk_list *data)
static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
{
int r;
if (!dev_open(data->dev, O_WRONLY)) {
if (!dev_open(data->dev)) {
stack;
return 0;
}
r = __write_all_pvd(data);
r = __write_all_pvd(fmt, data);
if (!dev_close(data->dev))
stack;
@@ -517,23 +652,23 @@ static int _write_all_pvd(struct disk_list *data)
return r;
}
/*
* Writes all the given pv's to disk. Does very
* little sanity checking, so make sure correct
* data is passed to here.
*/
int write_disks(struct list *pvs)
int write_disks(const struct format_type *fmt, struct list *pvs)
{
struct list *pvh;
struct disk_list *dl;
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
if (!(_write_all_pvd(dl)))
if (!(_write_all_pvd(fmt, dl)))
fail;
log_debug("Successfully wrote data to %s", dev_name(dl->dev));
log_very_verbose("Successfully wrote data to %s",
dev_name(dl->dev));
}
return 1;

View File

@@ -11,16 +11,16 @@
#include "metadata.h"
#include "pool.h"
#define SECTOR_SIZE 512
#define MAX_PV 256
#define MAX_LV 256
#define MAX_VG 99
#define MIN_PE_SIZE ( 8192L / SECTOR_SIZE) /* 8 KB in sectors */
#define MAX_PE_SIZE ( 16L * 1024L * 1024L / SECTOR_SIZE * 1024)
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
#define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */
#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 MAX_LE_TOTAL 65534 /* 2^16 - 2 */
#define MAX_PE_TOTAL ((uint32_t) -2)
#define UNMAPPED_EXTENT 0
@@ -37,6 +37,7 @@
/* logical volume */
#define LV_ACTIVE 0x01 /* lv_status */
#define LV_SPINDOWN 0x02 /* " */
#define LV_PERSISTENT_MINOR 0x04 /* " */
#define LV_READ 0x01 /* lv_access */
#define LV_WRITE 0x02 /* " */
@@ -52,86 +53,87 @@
#define PV_ACTIVE 0x01 /* pv_status */
#define PV_ALLOCATABLE 0x02 /* pv_allocatable */
#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */
#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */
struct data_area {
uint32_t base;
uint32_t size;
};
} __attribute__ ((packed));
struct pv_disk {
uint8_t id[2];
uint16_t version; /* lvm version */
struct data_area pv_on_disk;
struct data_area vg_on_disk;
struct data_area pv_uuidlist_on_disk;
struct data_area lv_on_disk;
struct data_area pe_on_disk;
uint8_t pv_uuid[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
uint32_t pv_major;
uint32_t pv_number;
uint32_t pv_status;
uint32_t pv_allocatable;
uint32_t pv_size;
uint32_t lv_cur;
uint32_t pe_size;
uint32_t pe_total;
uint32_t pe_allocated;
uint8_t id[2];
uint16_t version; /* lvm version */
struct data_area pv_on_disk;
struct data_area vg_on_disk;
struct data_area pv_uuidlist_on_disk;
struct data_area lv_on_disk;
struct data_area pe_on_disk;
uint8_t pv_uuid[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
uint32_t pv_major;
uint32_t pv_number;
uint32_t pv_status;
uint32_t pv_allocatable;
uint32_t pv_size;
uint32_t lv_cur;
uint32_t pe_size;
uint32_t pe_total;
uint32_t pe_allocated;
/* only present on version == 2 pv's */
uint32_t pe_start;
};
} __attribute__ ((packed));
struct lv_disk {
uint8_t lv_name[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint32_t lv_access;
uint32_t lv_status;
uint32_t lv_open;
uint32_t lv_dev;
uint32_t lv_number;
uint32_t lv_mirror_copies; /* for future use */
uint32_t lv_recovery; /* " */
uint32_t lv_schedule; /* " */
uint32_t lv_size;
uint32_t lv_snapshot_minor; /* minor number of original */
uint16_t lv_chunk_size; /* chunk size of snapshot */
uint16_t dummy;
uint32_t lv_allocated_le;
uint32_t lv_stripes;
uint32_t lv_stripesize;
uint32_t lv_badblock; /* for future use */
uint32_t lv_allocation;
uint32_t lv_io_timeout; /* for future use */
uint32_t lv_read_ahead;
};
uint8_t lv_name[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint32_t lv_access;
uint32_t lv_status;
uint32_t lv_open;
uint32_t lv_dev;
uint32_t lv_number;
uint32_t lv_mirror_copies; /* for future use */
uint32_t lv_recovery; /* " */
uint32_t lv_schedule; /* " */
uint32_t lv_size;
uint32_t lv_snapshot_minor; /* minor number of original */
uint16_t lv_chunk_size; /* chunk size of snapshot */
uint16_t dummy;
uint32_t lv_allocated_le;
uint32_t lv_stripes;
uint32_t lv_stripesize;
uint32_t lv_badblock; /* for future use */
uint32_t lv_allocation;
uint32_t lv_io_timeout; /* for future use */
uint32_t lv_read_ahead;
} __attribute__ ((packed));
struct vg_disk {
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
uint32_t vg_number; /* volume group number */
uint32_t vg_access; /* read/write */
uint32_t vg_status; /* active or not */
uint32_t lv_max; /* maximum logical volumes */
uint32_t lv_cur; /* current logical volumes */
uint32_t lv_open; /* open logical volumes */
uint32_t pv_max; /* maximum physical volumes */
uint32_t pv_cur; /* current physical volumes FU */
uint32_t pv_act; /* active physical volumes */
uint32_t dummy;
uint32_t vgda; /* volume group descriptor arrays FU */
uint32_t pe_size; /* physical extent size in sectors */
uint32_t pe_total; /* total of physical extents */
uint32_t pe_allocated; /* allocated physical extents */
uint32_t pvg_total; /* physical volume groups FU */
};
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
uint32_t vg_number; /* volume group number */
uint32_t vg_access; /* read/write */
uint32_t vg_status; /* active or not */
uint32_t lv_max; /* maximum logical volumes */
uint32_t lv_cur; /* current logical volumes */
uint32_t lv_open; /* open logical volumes */
uint32_t pv_max; /* maximum physical volumes */
uint32_t pv_cur; /* current physical volumes FU */
uint32_t pv_act; /* active physical volumes */
uint32_t dummy;
uint32_t vgda; /* volume group descriptor arrays FU */
uint32_t pe_size; /* physical extent size in sectors */
uint32_t pe_total; /* total of physical extents */
uint32_t pe_allocated; /* allocated physical extents */
uint32_t pvg_total; /* physical volume groups FU */
} __attribute__ ((packed));
struct pe_disk {
uint16_t lv_num;
uint16_t le_num;
};
} __attribute__ ((packed));
struct uuid_list {
struct list list;
@@ -155,80 +157,79 @@ struct disk_list {
struct pe_disk *extents;
};
/*
* Layout constants.
*/
#define METADATA_ALIGN 4096UL
#define PE_ALIGN (65536UL / SECTOR_SIZE)
#define METADATA_BASE 0UL
#define PV_SIZE 1024UL
#define VG_SIZE 4096UL
/*
* Functions to calculate layout info.
*/
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
* disk_lists.
*/
struct disk_list *read_disk(struct device *dev, struct pool *mem,
const char *vg_name);
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, 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 list *results);
int write_disks(struct list *pvds);
int write_disks(const struct format_type *fmt, struct list *pvds);
/*
* Functions to translate to between disk and in
* core structures.
*/
int import_pv(struct pool *mem, struct device *dev,
struct volume_group *vg,
struct physical_volume *pv, struct pv_disk *pvd);
int export_pv(struct pv_disk *pvd, struct physical_volume *pv);
int export_pv(struct pool *mem, struct volume_group *vg,
struct pv_disk *pvd, struct physical_volume *pv);
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 export_vg(struct vg_disk *vgd, struct volume_group *vg);
int import_lv(struct pool *mem, struct logical_volume *lv,
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_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
int import_extents(struct pool *mem, struct volume_group *vg,
int import_extents(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int export_extents(struct disk_list *dl, int lv_num,
struct logical_volume *lv,
struct physical_volume *pv);
int export_extents(struct disk_list *dl, uint32_t lv_num,
struct logical_volume *lv, struct physical_volume *pv);
int import_pvs(struct pool *mem, struct list *pvds,
struct list *results, int *count);
int import_pvs(const struct format_type *fmt, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count);
int import_lvs(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds);
int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct physical_volume *pv, const char *dev_dir);
int import_snapshots(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int export_uuids(struct disk_list *dl, struct volume_group *vg);
void export_numbers(struct list *pvds, struct volume_group *vg);
void export_pv_act(struct list *pvds);
void munge_exported_vg(struct pv_disk *pvd, struct vg_disk *vgd);
/* blech */
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
int *result);
int export_vg_number(struct list *pvds, const char *vg_name,
struct dev_filter *filter);
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
const char *candidate_vg, int *result);
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter);
#endif

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