1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-08 13:44:19 +03:00

Compare commits

...

277 Commits

Author SHA1 Message Date
Alasdair Kergon
e3f8892003 more syncing with lvm2 build process 2004-02-24 19:23:28 +00:00
Alasdair Kergon
9d00ad5f18 Extract log.h and tweak funcs to be like lvm2 ones. 2004-02-24 18:50:09 +00:00
Alasdair Kergon
dae4344850 more makefile syncing 2004-02-24 18:46:20 +00:00
Alasdair Kergon
aa7f3fabe2 File missed from last checkin. 2004-02-18 13:06:21 +00:00
Alasdair Kergon
f93434a8ce Basic internationalisation support. 2004-02-13 22:56:45 +00:00
Alasdair Kergon
25dee56be9 Don't recurse symlinked dirs such as /dev/fd on 2.6. 2004-02-13 18:55:43 +00:00
Alasdair Kergon
ce9a3f3797 Update autoconf files 2004-02-13 16:00:22 +00:00
Alasdair Kergon
11e384920a don't inline pool_zalloc(); lift duplicated pool_str(n)dup to pool.c 2004-02-13 15:38:54 +00:00
Alasdair Kergon
a0a1f1e536 Don't inline hash _find 2004-02-13 15:36:58 +00:00
Alasdair Kergon
3b3d0ea9eb Sysfs block device filtering option for 2.6. 2004-02-13 14:46:04 +00:00
Alasdair Kergon
2f4d78286d split_words() 2004-02-13 14:43:35 +00:00
Alasdair Kergon
677dc6f985 Update CVS info for move to sources.redhat.com. 2004-02-10 15:26:51 +00:00
Alasdair Kergon
d52057e732 Static build too. 2004-01-28 03:40:31 +00:00
Alasdair Kergon
fa2a1cb1fb Define BLKGETSIZE64 on systems with out-of-date header files. 2004-01-27 20:53:57 +00:00
Alasdair Kergon
19a0fb04ad Userspace support for LIST_VERSIONS ioctl. 2004-01-23 14:37:47 +00:00
Alasdair Kergon
947352f2fe Add event number arg to dmsetup wait. 2004-01-23 14:09:33 +00:00
Alasdair Kergon
adcbedb686 Document that sector size is always 512 bytes. [AJ] 2004-01-23 14:08:09 +00:00
Alasdair Kergon
7732f92acd pv/vgchange --uuid to change (non-random) UUIDs to random values 2004-01-13 18:42:05 +00:00
Alasdair Kergon
ad8a001688 If PV/VG uuids are missing, generate them from the pv/vg numbers.
[This situation could occur if the uuids were oritinally created by
LVM1 on a system without /dev/urandom.]
2004-01-09 19:18:20 +00:00
Alasdair Kergon
9121eada08 Log full details when "VG data differs between PVs" error message occurs. 2004-01-02 14:04:44 +00:00
Alasdair Kergon
49bd4d25a2 Option to revert to default logging function after using a custom one. 2003-12-21 16:08:20 +00:00
Alasdair Kergon
d80b4129c6 Change pvscan to show total of usable device size (instead of free data space). 2003-12-09 22:32:47 +00:00
Alasdair Kergon
7edb4172d5 Remove undocumented -m abbreviation. 2003-12-09 22:17:17 +00:00
Alasdair Kergon
c3a4677990 Relax restriction on pe_start location when re-writing LVM1 metadata. 2003-12-09 17:51:39 +00:00
Alasdair Kergon
5cbb893a3b Fix support for PVs on read only devices. [Still must set LVs read only] 2003-11-21 19:54:40 +00:00
Alasdair Kergon
f28a2a432b dumpconfig 2003-11-21 19:53:05 +00:00
Alasdair Kergon
03b75a2d27 Don't remove mirror LV until after other LVs reloaded. 2003-11-20 16:22:04 +00:00
Alasdair Kergon
859fe69083 Update dmsetup man. 2003-11-17 14:24:22 +00:00
Alasdair Kergon
f6f2205ddb Ready for another release. 2003-11-14 23:46:49 +00:00
Alasdair Kergon
0f9a03ef61 lvcreate should close the initialised snapshot device immediately. 2003-11-14 17:55:39 +00:00
Alasdair Kergon
9aa417c084 Add/update some man pages. 2003-11-14 16:17:55 +00:00
Alasdair Kergon
7b70952f5d vgscan --mknodes 2003-11-14 14:03:48 +00:00
Alasdair Kergon
edd3d07b49 Fix dev_zero() offset. 2003-11-13 23:55:03 +00:00
Alasdair Kergon
5293d0a4ec Immediate error on big memory allocations when --enable-debug. 2003-11-13 23:54:02 +00:00
Alasdair Kergon
3c8c7beae1 Missing include. 2003-11-13 18:47:22 +00:00
Alasdair Kergon
9c3ba9fdcd vgmknodes also creates necessary nodes in /dev/mapper 2003-11-13 14:11:41 +00:00
Alasdair Kergon
fb1748fb0f dmsetup mknodes 2003-11-13 13:14:28 +00:00
Alasdair Kergon
0a109fbd03 The LVM2 part of vgmknodes [still to do the non-devfs device-mapper bit]. 2003-11-12 19:16:48 +00:00
Alasdair Kergon
5cf64db74e Accept tables from stdin with dmsetup.
Update autoconf.
2003-11-12 17:30:32 +00:00
Alasdair Kergon
488cc94f36 Exclude v1 compatibility code when configured with --disable-compat
[Use this with 2.6 kernels + device-mapper V4 interface]
CVS ----------------------------------------------------------------------
2003-11-10 21:06:16 +00:00
Alasdair Kergon
e15846bf79 Default to unlimited number of LVs/PVs in lvm2 format. 2003-11-06 20:33:34 +00:00
Alasdair Kergon
752bd00674 Prevent PV allocation bit getting changed for format_text orphans. 2003-11-06 20:15:13 +00:00
Alasdair Kergon
7fadfcbe32 Fix vgremove 'all OK' check 2003-11-06 17:16:22 +00:00
Alasdair Kergon
41141e75bb Configuration-time O_DIRECT setting. 2003-11-06 17:14:06 +00:00
Alasdair Kergon
50f641e627 Add drbd. 2003-11-06 17:10:35 +00:00
Alasdair Kergon
c7883fd093 Fit locking bits into 1 byte. 2003-11-06 17:08:18 +00:00
Alasdair Kergon
4fcb24b2b1 Ban vgcreate -s 0 2003-11-06 17:07:19 +00:00
Alasdair Kergon
5003557935 Fix pvchange segfault with orphans. 2003-11-06 17:06:06 +00:00
Alasdair Kergon
bdf1ba84da Don't trigger error if changing PV allocation to the state it already is. 2003-11-06 17:04:35 +00:00
Alasdair Kergon
b0b4def983 Cope better with LVM1 minor numbers & LV numbers. 2003-11-06 16:58:38 +00:00
Alasdair Kergon
cc184bbe9e Fix exported format1 VG recognition. 2003-10-21 22:21:41 +00:00
Alasdair Kergon
ad30c830aa More consistent error code usage. 2003-10-21 22:06:07 +00:00
Alasdair Kergon
1d791a8af4 Check no fs mounted before deactivating. 2003-10-21 22:00:36 +00:00
Alasdair Kergon
e63c51cd97 Inherit CFLAGS at make time 2003-10-21 21:59:42 +00:00
Alasdair Kergon
f202e32908 Dump active configuration 2003-10-15 20:19:43 +00:00
Alasdair Kergon
26e1a08e82 dumpconfig to dump active configuration 2003-10-15 20:17:19 +00:00
Alasdair Kergon
4d5119d435 relax a scanning restriction 2003-10-15 20:10:11 +00:00
Alasdair Kergon
75e34ea62e Fix >32bit lvcreate size calculation. 2003-10-15 20:07:55 +00:00
Alasdair Kergon
0a183d6274 Prevent creation of MDA bigger than disk. 2003-10-15 20:06:37 +00:00
Alasdair Kergon
21d8060aea Don't forget to set 64-bit arg values too. 2003-10-15 20:05:30 +00:00
Alasdair Kergon
9cbe906f60 more str_list fns 2003-10-15 20:04:29 +00:00
Alasdair Kergon
8ce4137399 macro changes 2003-10-15 20:02:46 +00:00
Alasdair Kergon
5f8a139347 str_list_del 2003-10-15 20:01:12 +00:00
Alasdair Kergon
9bb009a3fe Extract some common functions. 2003-09-17 20:35:57 +00:00
Alasdair Kergon
726d65923f Update to incorporate most of version 4 interface changes. 2003-09-17 13:23:49 +00:00
Alasdair Kergon
8a6be4cb2d Remove incorrect comments. 2003-09-16 16:23:21 +00:00
Alasdair Kergon
10b06beb8e out-of-date 2003-09-16 16:18:50 +00:00
Alasdair Kergon
81318c7968 Update 2003-09-16 16:15:07 +00:00
Alasdair Kergon
47a2c1c6e5 Fix read-only snapshot creation. 2003-09-16 16:08:05 +00:00
Alasdair Kergon
39cee65c6b Make dev_name optional to show details for all devices.
e.g. 'dmsetup info', 'dmsetup status -v', 'dmsetup table'
2003-09-16 14:13:51 +00:00
Alasdair Kergon
8582ec724e Improve segment merge/split code. 2003-09-15 18:22:50 +00:00
Alasdair Kergon
b0139682e8 Don't install the pvdata stub; update built-in mesg. 2003-09-15 15:05:23 +00:00
Alasdair Kergon
d39c475a6d Ensure more args aren't negative. 2003-09-15 15:04:39 +00:00
Alasdair Kergon
48f38354c6 Missing vg_commit() 2003-09-15 15:03:54 +00:00
Alasdair Kergon
cd5a920ed5 vgcfgrestore -l lists backup file too 2003-09-15 15:03:22 +00:00
Alasdair Kergon
71bc1f378d Prevent cmdline flags that take args getting repeated. 2003-09-15 15:02:24 +00:00
Alasdair Kergon
0ee6c31cff Missing ] in pvmove usage display 2003-09-15 15:01:36 +00:00
Alasdair Kergon
af89a9971e Generalise 'invalid chars' error mesg to just say 'invalid' 2003-09-15 15:01:00 +00:00
Alasdair Kergon
c718a8ef72 Correct order of consistency/exists checks. 2003-09-15 15:00:01 +00:00
Alasdair Kergon
8c8ad0faf0 Don't use !# in randomly-generated uuids. 2003-09-15 14:58:43 +00:00
Alasdair Kergon
314d5bbb7f Fix makefile install mesg displayed for man5 2003-09-15 14:57:15 +00:00
Alasdair Kergon
102255757a Additional validation of LV segments read from metadata. [HM] 2003-09-01 19:55:16 +00:00
Alasdair Kergon
914067a0d0 Fix unsafe list iteration in segment merge code. [HM] 2003-08-27 15:30:39 +00:00
Alasdair Kergon
06e3ae2536 Remove unnecessary file. 2003-08-26 21:12:45 +00:00
Alasdair Kergon
7f9b252556 Cope better when format functions are missing. 2003-08-26 21:12:06 +00:00
Alasdair Kergon
3d700e243f Log each command & args. 2003-08-26 21:00:05 +00:00
Alasdair Kergon
bcfc78ce11 Update. 2003-08-20 15:48:46 +00:00
Alasdair Kergon
09241765d5 Some tidyups and minor fixes. 2003-08-20 15:48:27 +00:00
Alasdair Kergon
671c83c265 Remove small hard-coded activation target line parameter limit. 2003-08-20 12:53:57 +00:00
Alasdair Kergon
772d28b766 Also allow pvmove --abort when pvmove mirror not active (e.g. after a reboot). 2003-08-18 17:21:51 +00:00
Alasdair Kergon
c26fcea58d Missing check for inconsistent VG in pvmove. 2003-08-18 13:52:43 +00:00
Alasdair Kergon
1e5e26dbff update 2003-07-18 00:41:04 +00:00
Alasdair Kergon
742fc54864 Accept signed numbers in config file. 2003-07-15 16:32:20 +00:00
Alasdair Kergon
49738f43c0 update 2003-07-15 01:30:18 +00:00
Alasdair Kergon
9f85f61010 Fix vgimport fix to work outside debug mode. 2003-07-15 01:26:24 +00:00
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
250 changed files with 28554 additions and 8903 deletions

1
BUGS
View File

@@ -1 +0,0 @@
LVM2's device-mapper driver and ext3 are incompatible at the moment.

21
INSTALL
View File

@@ -6,8 +6,8 @@ LVM2 installation
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 should
be present.
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/
@@ -17,9 +17,15 @@ LVM2 installation
Run the 'configure' script from the top directory.
If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
installed use
./configure --disable-readline
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.
@@ -31,6 +37,9 @@ LVM2 installation
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 should
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.

18
INTRO
View File

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

View File

@@ -20,15 +20,30 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SUBDIRS = include man lib tools
SUBDIRS = include man
ifeq ("@INTL@", "yes")
SUBDIRS += po
endif
SUBDIRS += lib tools
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += test/mm test/device test/format1 test/regex test/filters
SUBDIRS += lib/format1 \
po \
test/mm test/device test/format1 test/regex test/filters
endif
include make.tmpl
lib: include
tools: include lib
tools: lib
po: lib tools
ifeq ("@INTL@", "yes")
lib.pofile: include.pofile
tools.pofile: lib.pofile
po.pofile: lib.pofile tools.pofile
pofile: po.pofile
endif

18
README
View File

@@ -1,13 +1,11 @@
This directory contains a beta release of LMV2, the new version of
the userland LVM tools designed for the new device-mapper for
the Linux kernel.
This directory contains 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 INTRO file.
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:
@@ -15,11 +13,11 @@ Tarballs are available from:
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
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
CVS password: cvs
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2
Mailing list for discussion/bug reports etc.
lvm-devel@sistina.com
Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel
linux-lvm@redhat.com
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm

28
TODO
View File

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

View File

@@ -1 +1 @@
1.95.08-cvs (2002-05-21)
2.00.08-cvs (2003-11-14)

111
WHATS_NEW Normal file
View File

@@ -0,0 +1,111 @@
Friday 14th November 2003
=========================
Some bug fixes & minor enhancements, including:
Backwards compatibility with LVM1 metadata improved.
Missing man pages written.
Tool error codes made more consistent.
vgmknodes written.
O_DIRECT can be turned off if it doesn't work in your kernel.
dumpconfig to display the active configuration file
You need to update libdevmapper before using 'vgmknodes' or 'vgscan --mknodes'.
If your root filesystem is on an LV, you should run one of those two
commands to fix up the special files in /dev in your real root filesystem
after finishing with your initrd. Also, remember you can use
'vgchange --ignorelockingfailure' on your initrd if the tool fails because
it can't write a lock file to a read-only filesystem.
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
activation=1
}
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!

1082
autoconf/config.guess vendored

File diff suppressed because it is too large Load Diff

560
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, 2002, 2003 Free Software Foundation, Inc.
timestamp='2003-06-17'
# 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,9 @@
# 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>. Submit a context
# diff and a properly formatted ChangeLog entry.
#
# 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 +52,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* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -94,7 +144,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 +155,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 +214,72 @@ 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] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
| fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k \
| m32r | m68000 | m68k | m88k | mcore \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
| mips64vr | mips64vrel \
| mips64orion | mips64orionel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| msp430 \
| ns16k | ns32k \
| openrisc | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
| strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \
| we32k \
| x86 | xscale | xstormy16 | xtensa \
| 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 +288,60 @@ 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]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* \
| bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| clipper-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* \
| m32r-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | mcore-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
| mips64vr-* | mips64vrel-* \
| mips64orion-* | mips64orionel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
| msp430-* \
| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tron-* \
| v850-* | v850e-* | vax-* \
| we32k-* \
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
| xtensa-* \
| ymp-* \
| z8k-*)
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -240,19 +373,22 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
amd64)
basic_machine=x86_64-pc
;;
amdahl)
basic_machine=580-amdahl
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)
@@ -271,6 +407,10 @@ case $basic_machine in
basic_machine=ns32k-sequent
os=-dynix
;;
c90)
basic_machine=c90-cray
os=-unicos
;;
convex-c1)
basic_machine=c1-convex
os=-bsd
@@ -291,27 +431,30 @@ case $basic_machine in
basic_machine=c38-convex
os=-bsd
;;
cray | ymp)
basic_machine=ymp-cray
os=-unicos
;;
cray2)
basic_machine=cray2-cray
os=-unicos
;;
[ctj]90-cray)
basic_machine=c90-cray
cray | j90)
basic_machine=j90-cray
os=-unicos
;;
crds | unos)
basic_machine=m68k-crds
;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
da30 | da30-*)
basic_machine=m68k-da30
;;
decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
basic_machine=mips-dec
;;
decsystem10* | dec10*)
basic_machine=pdp10-dec
os=-tops10
;;
decsystem20* | dec20*)
basic_machine=pdp10-dec
os=-tops20
;;
delta | 3300 | motorola-3300 | motorola-delta \
| 3300-motorola | delta-motorola)
basic_machine=m68k-motorola
@@ -353,6 +496,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 +573,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 +599,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,35 +624,43 @@ 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
;;
mipsel*-linux*)
basic_machine=mipsel-unknown
os=-linux-gnu
;;
mips*-linux*)
basic_machine=mips-unknown
os=-linux-gnu
;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
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
;;
morphos)
basic_machine=powerpc-unknown
os=-morphos
;;
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 +670,7 @@ case $basic_machine in
os=-netbsd
;;
netwinder)
basic_machine=armv4l-corel
basic_machine=armv4l-rebel
os=-linux
;;
news | news700 | news800 | news900)
@@ -572,13 +718,28 @@ case $basic_machine in
basic_machine=i960-intel
os=-mon960
;;
nonstopux)
basic_machine=mips-compaq
os=-nonstopux
;;
np1)
basic_machine=np1-gould
;;
nv1)
basic_machine=nv1-cray
os=-unicosmp
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
;;
or32 | or32-*)
basic_machine=or32-unknown
os=-coff
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
os=-ose
@@ -601,45 +762,65 @@ case $basic_machine in
pbb)
basic_machine=m68k-tti
;;
pc532 | pc532-*)
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
pentium | p5 | k5 | k6 | nexen)
pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc
;;
pentiumpro | p6 | 6x86)
pentiumpro | p6 | 6x86 | athlon | athlon_*)
basic_machine=i686-pc
;;
pentiumii | pentium2)
pentiumii | pentium2 | pentiumiii | pentium3)
basic_machine=i686-pc
;;
pentium4)
basic_machine=i786-pc
;;
pentium-* | p5-* | k5-* | k6-* | nexen-*)
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
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-*)
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium4-*)
basic_machine=i786-`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
;;
;;
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
;;
;;
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
@@ -650,10 +831,26 @@ case $basic_machine in
rtpc | rtpc-*)
basic_machine=romp-ibm
;;
s390 | s390-*)
basic_machine=s390-ibm
;;
s390x | s390x-*)
basic_machine=s390x-ibm
;;
sa29200)
basic_machine=a29k-amd
os=-udi
;;
sb1)
basic_machine=mipsisa64sb1-unknown
;;
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
sei)
basic_machine=mips-sei
os=-seiux
;;
sequent)
basic_machine=i386-sequent
;;
@@ -661,7 +858,10 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
sparclite-wrs)
sh64)
basic_machine=sh64-unknown
;;
sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs
os=-vxworks
;;
@@ -719,20 +919,44 @@ 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
;;
t3e)
basic_machine=t3e-cray
basic_machine=alphaev5-cray
os=-unicos
;;
t90)
basic_machine=t90-cray
os=-unicos
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
;;
tx39)
basic_machine=mipstx39-unknown
;;
tx39el)
basic_machine=mipstx39el-unknown
;;
toad1)
basic_machine=pdp10-xkl
os=-tops20
;;
tower | tower-32)
basic_machine=m68k-ncr
;;
@@ -757,8 +981,8 @@ case $basic_machine in
os=-vms
;;
vpp*|vx|vx-*)
basic_machine=f301-fujitsu
;;
basic_machine=f301-fujitsu
;;
vxworks960)
basic_machine=i960-wrs
os=-vxworks
@@ -779,13 +1003,13 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
xmp)
basic_machine=xmp-cray
os=-unicos
;;
xps | xps100)
xps | xps100)
basic_machine=xps100-honeywell
;;
ymp)
basic_machine=ymp-cray
os=-unicos
;;
z8k-*-coff)
basic_machine=z8k-unknown
os=-sim
@@ -806,13 +1030,6 @@ case $basic_machine in
op60c)
basic_machine=hppa1.1-oki
;;
mips)
if [ x$os = x-linux-gnu ]; then
basic_machine=mips-unknown
else
basic_machine=mips-mips
fi
;;
romp)
basic_machine=romp-ibm
;;
@@ -822,16 +1039,26 @@ 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 | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sh64)
basic_machine=sh64-unknown
;;
sparc | sparcv9 | sparcv9b)
basic_machine=sparc-sun
;;
cydra)
cydra)
basic_machine=cydra-cydrome
;;
orion)
@@ -846,9 +1073,8 @@ case $basic_machine in
pmac | pmac-mpw)
basic_machine=powerpc-apple
;;
c4x*)
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
@@ -906,14 +1132,34 @@ 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* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
case $basic_machine in
x86-* | i*86-*)
;;
*)
os=-nto$os
;;
esac
;;
-nto-qnx*)
;;
-nto*)
os=`echo $os | sed -e 's|nto|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 +1173,12 @@ case $os in
-sunos6*)
os=`echo $os | sed -e 's|sunos6|solaris3|'`
;;
-opened*)
os=-openedition
;;
-wince*)
os=-wince
;;
-osfrose*)
os=-osfrose
;;
@@ -942,14 +1194,23 @@ case $os in
-acis*)
os=-aos
;;
-atheos*)
os=-atheos
;;
-386bsd)
os=-bsd
;;
-ctix* | -uts*)
os=-sysv
;;
-nova*)
os=-rtmk-nova
;;
-ns2 )
os=-nextstep2
os=-nextstep2
;;
-nsk*)
os=-nsk
;;
# Preserve the version number of sinix5.
-sinix5.*)
@@ -985,8 +1246,14 @@ case $os in
-xenix)
os=-xenix
;;
-*mint | -*MiNT)
os=-mint
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint
;;
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-none)
;;
@@ -1013,13 +1280,20 @@ case $basic_machine in
*-acorn)
os=-riscix1.2
;;
arm*-corel)
arm*-rebel)
os=-linux
;;
arm*-semi)
os=-aout
;;
pdp11-*)
c4x-* | tic4x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20
;;
pdp11-*)
os=-none
;;
*-dec | vax-*)
@@ -1046,6 +1320,9 @@ case $basic_machine in
mips*-*)
os=-elf
;;
or32-*)
os=-coff
;;
*-tti) # must be before sparc entry or we get the wrong os.
os=-sysv3
;;
@@ -1109,25 +1386,25 @@ case $basic_machine in
*-next)
os=-nextstep3
;;
*-gould)
*-gould)
os=-sysv
;;
*-highlevel)
*-highlevel)
os=-bsd
;;
*-encore)
os=-bsd
;;
*-sgi)
*-sgi)
os=-irix
;;
*-siemens)
*-siemens)
os=-sysv4
;;
*-masscomp)
os=-rtu
;;
f301-fujitsu)
f30[01]-fujitsu | f700-fujitsu)
os=-uxpv
;;
*-rom68k)
@@ -1187,13 +1464,13 @@ case $basic_machine in
-genix*)
vendor=ns
;;
-mvs*)
-mvs* | -opened*)
vendor=ibm
;;
-ptx*)
vendor=sequent
;;
-vxsim* | -vxworks*)
-vxsim* | -vxworks* | -windiss*)
vendor=wrs
;;
-aux*)
@@ -1205,12 +1482,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:

View File

@@ -1,19 +1,38 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
scriptversion=2003-06-13.21
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright 1991 by the Massachusetts Institute of Technology
# Copyright (C) 1994 X Consortium
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
@@ -23,13 +42,11 @@
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
@@ -41,211 +58,229 @@ stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
transformbasename=
transform_arg=
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
chowncmd=
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
src=
dst=
dir_arg=
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
usage="Usage: $0 [OPTION]... SRCFILE DSTFILE
or: $0 -d DIR1 DIR2...
-d) dir_arg=true
shift
continue;;
In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default.
In the second, create the directory path DIR.
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
Options:
-b=TRANSFORMBASENAME
-c copy source (using $cpprog) instead of moving (using $mvprog).
-d create directories instead of installing files.
-g GROUP $chgrp installed files to GROUP.
-m MODE $chmod installed files to MODE.
-o USER $chown installed files to USER.
-s strip installed files (using $stripprog).
-t=TRANSFORM
--help display this help and exit.
--version display version info and exit.
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
while test -n "$1"; do
case $1 in
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-c) instcmd=$cpprog
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-d) dir_arg=true
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
--help) echo "$usage"; exit 0;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-s) stripcmd=$stripprog
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
--version) echo "$0 $scriptversion"; exit 0;;
*) if test -z "$src"; then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
if test -z "$src"; then
echo "$0: no input file specified." >&2
exit 1
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=mkdir
fi
if test -n "$dir_arg"; then
dst=$src
src=
if test -d "$dst"; then
instcmd=:
chmodcmd=
else
instcmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test -z "$dst"; then
echo "$0: no destination specified." >&2
exit 1
fi
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
dst=$dst/`basename "$src"`
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# (this part is taken from Noah Friedman's mkinstalldirs script.)
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
if test ! -d "$dstdir"; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
oIFS=$IFS
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS=$oIFS
pathcomp=''
pathcomp=
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
while test $# -ne 0 ; do
pathcomp=$pathcomp$1
shift
test -d "$pathcomp" || $mkdirprog "$pathcomp"
pathcomp=$pathcomp/
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if test -n "$dir_arg"; then
$doit $instcmd "$dst" \
&& { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if test -z "$transformarg"; then
dstfile=`basename "$dst"`
else
dstfile=`basename "$dst" $transformbasename \
| sed $transformarg`$transformbasename
fi
# If we're going to rename the final executable, determine the name now.
# don't allow the sed command to completely eliminate the filename.
test -z "$dstfile" && dstfile=`basename "$dst"`
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# don't allow the sed command to completely eliminate the filename
# Trap to clean up those temp files at exit.
trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
trap '(exit $?); exit' 1 2 13 15
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Move or copy the file name to the temp name
$doit $instcmd "$src" "$dsttmp" &&
# Make a temp file name in the proper directory.
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
# Now remove or move aside any old file at destination location. We
# try this two ways since rm can't unlink itself on some systems and
# the destination file might be busy for other reasons. In this case,
# the final cleanup might fail but the new file should still install
# successfully.
{
if test -f "$dstdir/$dstfile"; then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
|| $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
|| {
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
fi &&
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit
}
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

557
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,15 +69,63 @@ AC_ARG_WITH(group,
[ GROUP="$withval" ],
[ GROUP="root" ])
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
dnl -- format1 inclusion type
AC_ARG_WITH(lvm1,
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] ],
[ LVM1="$withval" ],
[ LVM1="internal" ])
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
then AC_MSG_ERROR(
--with-lvm1 parameter invalid
)
exit
fi;
if test x$LVM1 = xinternal; then
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
fi
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
dnl Enables staticly linked tools
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
echo $ac_n "checking whether to enable debugging""... $ac_c" 1>&6
dnl Enable Debugging
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging], \
DEBUG=yes, DEBUG=no)
echo "$ac_t""$DEBUG" 1>&6
echo $ac_n "checking whether to enable device-mapper""... $ac_c" 1>&6
dnl Disable devmapper
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction], \
DEVMAPPER=no, DEVMAPPER=yes)
echo "$ac_t""$DEVMAPPER" 1>&6
if test x$DEVMAPPER = xyes; then
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
fi
echo $ac_n "checking whether to enable O_DIRECT""... $ac_c" 1>&6
dnl Disable O_DIRECT
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT], \
ODIRECT=no, ODIRECT=yes)
echo "$ac_t""$ODIRECT" 1>&6
if test x$ODIRECT = xyes; then
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
fi
dnl Mess with default exec_prefix
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -99,6 +155,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, ,
@@ -112,8 +179,30 @@ package as well (which may be called readline-devel or something similar).
)
exit
)
AC_CHECK_FUNC(rl_completion_matches, HAVE_RL_COMPLETION_MATCHES=yes,
HAVE_RL_COMPLETION_MATCHES=no)
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
fi
echo $ac_n "checking whether to enable internationalisation""... $ac_c" 1>&6
dnl Internationalisation stuff
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],\
INTL=yes, INTL=no)
echo "$ac_t""$INTL" 1>&6
if test x$INTL = xyes; then
INTL_PACKAGE="lvm2"
AC_PATH_PROG(MSGFMT, msgfmt)
if [[ "x$MSGFMT" == x ]];
then AC_MSG_ERROR(
msgfmt not found in path $PATH
)
exit
fi;
AC_ARG_WITH(localedir,
[ --with-localedir=DIR Translation files in DIR [PREFIX/share/locale]],
[ LOCALEDIR="$withval" ],
[ LOCALEDIR='${prefix}/share/locale' ])
fi
if test "-f VERSION"; then
@@ -124,12 +213,19 @@ fi
AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK)
AC_SUBST(READLINE)
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
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)
AC_SUBST(MSGFMT)
AC_SUBST(LOCALEDIR)
AC_SUBST(INTL_PACKAGE)
AC_SUBST(INTL)
dnl First and last lines should not contain files to generate in order to
dnl keep utility scripts running properly
AC_OUTPUT( \
@@ -137,7 +233,9 @@ Makefile \
make.tmpl \
include/Makefile \
lib/Makefile \
lib/format1/Makefile \
man/Makefile \
po/Makefile \
tools/Makefile \
tools/version.h \
test/mm/Makefile \
@@ -146,3 +244,10 @@ test/format1/Makefile \
test/regex/Makefile \
test/filters/Makefile \
)
if test x$ODIRECT != xyes; then
echo
echo Warning: O_DIRECT disabled.
echo Use of pvmove may cause machine to lock up under low memory conditions.
echo
fi

6
debian/README.Debian vendored Normal file
View File

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

38
debian/changelog vendored
View File

@@ -1,3 +1,41 @@
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)

2
debian/conffiles vendored
View File

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

10
debian/control vendored
View File

@@ -2,8 +2,8 @@ Source: lvm2
Section: admin
Priority: optional
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
Standards-Version: 3.5.2
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
Standards-Version: 3.5.8.0
Package: lvm2
Architecture: any
@@ -11,10 +11,14 @@ Depends: ${shlibs:Depends}
Conflicts: lvm10, lvm-common
Replaces: lvm10, lvm-common
Provides: lvm-binaries
Suggests: dmsetup
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.

2
debian/copyright vendored
View File

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

3
debian/docs vendored
View File

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

2
debian/init.d vendored
View File

@@ -14,7 +14,7 @@ modprobe dm-mod >/dev/null 2>&1
# Create necessary files in /dev for device-mapper
create_devfiles() {
DIR="/dev/device-mapper"
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//')

3
debian/rules vendored
View File

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

14
debian/undocumented vendored
View File

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

View File

@@ -1,74 +1,98 @@
# This is an example configuration file for the LVM2 system. It
# contains the default settings that would be used if there was no
# 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.
#
# Refer to 'man lvm.conf' for further information including the file layout.
#
# To put this file in a different directory and override /etc/lvm set
# the environment variable LVM_SYSTEM_DIR before running the tools.
# This section allows the user to configure which block devices should
# This section allows you to configure which block devices should
# be used by the LVM system.
devices {
# where do you want your volume groups to appear ?
# 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 very important option, that allows you to tune the LVM2 system
# to just look at a restricted set of devices that you're
# interested in.
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).
# ATM you cannot use anchors (^ or $) in your regular expression.
# The first expression found to match a device name determines if
# the device will be accepted or rejected (ignored). Devices that
# don't match any patterns are accepted.
# Remember to run vgscan after you change this parameter.
# If using RAID md devices as physical volumes, you should
# set up a filter here to reject the constituent devices.
# Remember to run vgscan after you change this parameter to ensure
# that the cache file gets regenerated (see below).
# By default we accept every block device:
filter = "a/.*/"
filter = [ "a/.*/" ]
# Exclude the cdrom drive
# filter = [ "r|/dev/cdrom|" ]
# When testing I like to work with just loopback devices:
# filter = ["a/loop/", "r/.*/"]
# filter = [ "a/loop/", "r/.*/" ]
# Or maybe all loops and ide drives except hdc:
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
# The results of all the filtering are cached on disk to avoid
# Use anchors if you want to be really specific
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
# The results of the filtering are cached on disk to avoid
# rescanning dud devices (which can take a very long time). By
# default this cache file is hidden in the /etc/lvm directory, it
# is human readable to aid filter debugging.
# 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 ]
# If sysfs is mounted (2.6 kernels) restrict device scanning to
# the block devices it believes are valid.
sysfs_scan = 1
}
# A section that allows the user to configure the nature of the
# This section that allows you to configure the nature of the
# information that LVM2 reports.
log {
# Where should the log of error and debug messages go ? By
# default there is no log.
#file = "/var/log/lvm2.log"
# Should we overwrite the last log. By default we append.
overwrite = 0
# There are 9 log levels, with 9 being the most verbose.
level = 3
# Controls the messages sent to stdout or stderr while running
# LVM2. There are three levels of verbosity, 3 being the most
# verbose.
# 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
# Choose format of output messages
# Should we log error and debug messages to a file?
# By default there is no log file.
#file = "/var/log/lvm2.log"
# Should we overwrite the log file each time the program is run?
# By default we append.
overwrite = 0
# What level of log messages should we send to the log file and/or syslog?
# There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
# 7 is the most verbose (LOG_DEBUG).
level = 0
# Format of output messages
# Whether or not (1 or 0) to indent messages according to their severity
indent = 1
@@ -76,13 +100,18 @@ log {
command_names = 0
# A prefix to use before the message text (but after the command name,
# if selected)
# if selected). Default is two spaces, so you can see/grep the severity
# of each message.
prefix = " "
# To make the messages look similar to the original LVM use:
# To make the messages look similar to the original LVM tools use:
# indent = 0
# 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
@@ -93,19 +122,20 @@ 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.
# 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 ?
@@ -115,20 +145,15 @@ backup {
retain_days = 30
}
# Settings for the running LVM2 in shell mode.
# Settings for the running LVM2 in shell (readline) mode.
shell {
# Number of lines of history to store in ~/.lvm_history
history_size = 100
}
# Metadata settings
metadata {
# List of directories holding copies of text format metadata
dirs = [ "/etc/lvm/metadata" ]
}
# Miscellaneous global settings
# Miscellaneous global LVM2 settings
global {
# The file creation mask for any files and directories created.
@@ -143,10 +168,94 @@ global {
# command. Defaults to off.
test = 0
# Default metadata format commands use - "lvm1" (default) or "text"
format = "lvm1"
# 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" ]
#}

View File

@@ -1,4 +1,5 @@
../lib/activate/activate.h
../lib/cache/lvmcache.h
../lib/commands/errors.h
../lib/commands/toolcontext.h
../lib/config/config.h
@@ -8,26 +9,33 @@
../lib/datastruct/hash.h
../lib/datastruct/list.h
../lib/datastruct/lvm-types.h
../lib/datastruct/str_list.h
../lib/device/dev-cache.h
../lib/device/device.h
../lib/display/display.h
../lib/filters/filter-composite.h
../lib/filters/filter-persistent.h
../lib/filters/filter-regex.h
../lib/filters/filter-sysfs.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/label/uuid-map.h
../lib/locking/locking.h
../lib/log/log.h
../lib/metadata/lv_alloc.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/intl.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
../lib/vgcache/vgcache.h
../po/pogen.h

View File

@@ -35,9 +35,11 @@ distclean:
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
$(RM) Makefile .include_symlinks .symlinks_created
pofile: all
clean:
install:
.PHONY: clean distclean all install
.PHONY: clean distclean all install pofile

View File

@@ -8,14 +8,19 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
ifeq ("@LVM1@", "shared")
SUBDIRS = format1
endif
SOURCES=\
activate/activate.c \
activate/dev_manager.c \
activate/fs.c \
cache/lvmcache.c \
commands/toolcontext.c \
config/config.c \
datastruct/bitset.c \
datastruct/btree.c \
datastruct/hash.c \
datastruct/str_list.c \
device/dev-cache.c \
device/dev-io.c \
device/device.c \
@@ -23,22 +28,16 @@ SOURCES=\
filters/filter-composite.c \
filters/filter-persistent.c \
filters/filter-regex.c \
filters/filter-sysfs.c \
filters/filter.c \
format1/disk-rep.c \
format1/format1.c \
format1/import-export.c \
format1/import-extents.c \
format1/layout.c \
format1/lvm1_label.c \
format1/vg_number.c \
format_text/archive.c \
format_text/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 \
label/uuid-map.c \
locking/external_locking.c \
locking/file_locking.c \
locking/locking.c \
locking/no_locking.c \
@@ -46,16 +45,47 @@ SOURCES=\
metadata/lv_manip.c \
metadata/merge.c \
metadata/metadata.c \
metadata/mirror.c \
metadata/pv_map.c \
metadata/snapshot_manip.c \
misc/crc.c \
misc/lvm-file.c \
mm/dbg_malloc.c \
misc/lvm-string.c \
mm/memlock.c \
mm/pool.c \
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
uuid/uuid.c \
vgcache/vgcache.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

@@ -4,27 +4,118 @@
* 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"
/* FIXME Temporary */
#include "vgcache.h"
#include <limits.h>
#include <linux/kdev_t.h>
#include <fcntl.h>
#include <unistd.h>
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
#ifndef DEVMAPPER_SUPPORT
void set_activation(int act)
{
if (act)
log_error("Compiled without libdevmapper support. "
"Can't enable activation.");
}
int activation(void)
{
return 0;
}
int library_version(char *version, size_t size)
{
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;
}
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
{
return 1;
}
void activation_exit(void)
{
return;
}
#else /* DEVMAPPER_SUPPORT */
static int _activation = 1;
void set_activation(int act)
{
if (act == _activation)
return;
_activation = act;
if (_activation)
log_verbose("Activation enabled. Device-mapper kernel "
"driver will be used.");
else
log_verbose("Activation disabled. No device-mapper "
"interaction will be attempted.");
}
int activation(void)
{
return _activation;
}
int library_version(char *version, size_t size)
{
if (!activation())
return 0;
if (!dm_get_library_version(version, size))
return 0;
return 1;
@@ -35,6 +126,9 @@ int driver_version(char *version, size_t size)
int r = 0;
struct dm_task *dmt;
if (!activation())
return 0;
log_very_verbose("Getting driver version");
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
stack;
@@ -58,39 +152,82 @@ int driver_version(char *version, size_t size)
/*
* Returns 1 if info structure populated, else 0 on failure.
*/
int lv_info(struct logical_volume *lv, struct dm_info *info)
static int _lv_info(const struct logical_volume *lv, int mknodes,
struct lvinfo *info)
{
int r;
struct dev_manager *dm;
struct dm_info dminfo;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_info(dm, lv, info)))
if (!(r = dev_manager_info(dm, lv, mknodes, &dminfo)))
stack;
info->exists = dminfo.exists;
info->suspended = dminfo.suspended;
info->open_count = dminfo.open_count;
info->major = dminfo.major;
info->minor = dminfo.minor;
info->read_only = dminfo.read_only;
dev_manager_destroy(dm);
return r;
}
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
{
return _lv_info(lv, 0, info);
}
/*
* Returns 1 if percent set, else 0 on failure.
*/
int lv_snapshot_percentage(struct logical_volume *lv, float *percent)
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
{
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_get_snapshot_use(dm, lv, percent)))
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
stack;
dev_manager_destroy(dm);
return r;
}
/* FIXME Merge with snapshot_percent */
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
uint32_t *event_nr)
{
int r;
struct dev_manager *dm;
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
stack;
dev_manager_destroy(dm);
return r;
@@ -98,7 +235,7 @@ int lv_snapshot_percentage(struct logical_volume *lv, float *percent)
static int _lv_active(struct logical_volume *lv)
{
struct dm_info info;
struct lvinfo info;
if (!lv_info(lv, &info)) {
stack;
@@ -110,7 +247,7 @@ static int _lv_active(struct logical_volume *lv)
static int _lv_open_count(struct logical_volume *lv)
{
struct dm_info info;
struct lvinfo info;
if (!lv_info(lv, &info)) {
stack;
@@ -126,7 +263,7 @@ static int _lv_activate(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@@ -143,7 +280,7 @@ static int _lv_deactivate(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@@ -160,7 +297,7 @@ static int _lv_suspend(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@@ -182,6 +319,9 @@ int lvs_in_vg_activated(struct volume_group *vg)
struct logical_volume *lv;
int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_active(lv) == 1);
@@ -196,6 +336,9 @@ int lvs_in_vg_opened(struct volume_group *vg)
struct logical_volume *lv;
int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_open_count(lv) == 1);
@@ -204,119 +347,21 @@ int lvs_in_vg_opened(struct volume_group *vg)
return count;
}
static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
const char *lvid_s)
{
struct lv_list *lvl;
struct volume_group *vg;
union lvid *lvid;
lvid = (union lvid *) lvid_s;
log_very_verbose("Finding volume group for uuid %s", lvid_s);
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
log_error("Volume group for uuid not found: %s", lvid_s);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
log_very_verbose("Can't find logical volume id %s", lvid_s);
return NULL;
}
return lvl->lv;
}
/* These return success if the device is not active */
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
struct lvinfo info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Suspending '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && !info.suspended)
return _lv_suspend(lv);
return 1;
}
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Resuming '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && info.suspended)
return _lv_activate(lv);
return 1;
}
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Deactivating '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists)
return _lv_deactivate(lv);
return 1;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Activating '%s'.", lv->name);
return 0;
return 1;
}
if (!lv_info(lv, &info)) {
@@ -325,7 +370,145 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s)
}
if (!info.exists || info.suspended)
return _lv_activate(lv);
return 1;
memlock_inc();
if (!_lv_suspend(lv)) {
memlock_dec();
fs_unlock();
return 0;
}
return 1;
}
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;
if (info.open_count) {
log_error("LV %s/%s in use: not removing", lv->vg->name,
lv->name);
return 0;
}
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;
}
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
{
struct lvinfo info;
int r = 1;
if (!_lv_info(lv, 1, &info)) {
stack;
return 0;
}
if (info.exists)
r = dev_manager_mknodes(lv);
else
r = dev_manager_rmnodes(lv);
fs_unlock();
return r;
}
void activation_exit(void)
{
dev_manager_exit();
}
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,18 @@
#define _LVM_DEV_MANAGER_H
#include "metadata.h"
#include <libdevmapper.h>
#include "config.h"
struct dev_manager;
struct dm_info;
/*
* Constructor and destructor.
*/
struct dev_manager *dev_manager_create(const char *vg_name);
struct dev_manager *dev_manager_create(const char *vg_name,
struct config_tree *cf);
void dev_manager_destroy(struct dev_manager *dm);
void dev_manager_exit(void);
/*
* The device handler is responsible for creating all the layered
@@ -25,14 +27,19 @@ void dev_manager_destroy(struct dev_manager *dm);
* (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, struct logical_volume *lv,
struct dm_info *info);
int dev_manager_get_snapshot_use(struct dev_manager *dm,
struct logical_volume *lv, float *percent);
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
int mknodes, 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);
int dev_manager_mknodes(const struct logical_volume *lv);
int dev_manager_rmnodes(const struct logical_volume *lv);
/*
* Put the desired changes into effect.

View File

@@ -4,28 +4,26 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "fs.h"
#include "log.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "lvm-file.h"
#include "memlock.h"
#include <sys/types.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>
static int _mk_dir(struct volume_group *vg)
static int _mk_dir(const char *dev_dir, const char *vg_name)
{
char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
vg->cmd->dev_dir, vg->name) == -1) {
dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
return 0;
@@ -43,12 +41,12 @@ static int _mk_dir(struct volume_group *vg)
return 1;
}
static int _rm_dir(struct volume_group *vg)
static int _rm_dir(const char *dev_dir, const char *vg_name)
{
char vg_path[PATH_MAX];
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
vg->cmd->dev_dir, vg->name) == -1) {
dev_dir, vg_name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
return 0;
@@ -62,32 +60,100 @@ static int _rm_dir(struct volume_group *vg)
return 1;
}
static int _mk_link(struct logical_volume *lv, const char *dev)
static void _rm_blks(const char *dir)
{
char lv_path[PATH_MAX], link_path[PATH_MAX];
const char *name;
char path[PATH_MAX];
struct dirent *dirent;
struct stat buf;
DIR *d;
if (!(d = opendir(dir))) {
log_sys_error("opendir", dir);
return;
}
while ((dirent = readdir(d))) {
name = dirent->d_name;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
log_error("Couldn't create path for %s", name);
continue;
}
if (!lstat(path, &buf)) {
if (!S_ISBLK(buf.st_mode))
continue;
log_very_verbose("Removing %s", path);
if (unlink(path) < 0)
log_sys_error("unlink", path);
}
}
}
static int _mk_link(const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev)
{
char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
char vg_path[PATH_MAX];
struct stat buf;
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
lv->vg->cmd->dev_dir, lv->vg->name, lv->name) == -1) {
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);
"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);
"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)) {
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;
@@ -103,23 +169,26 @@ static int _mk_link(struct logical_volume *lv, const char *dev)
return 1;
}
static int _rm_link(struct logical_volume *lv, const char *lv_name)
static int _rm_link(const char *dev_dir, const char *vg_name,
const char *lv_name)
{
struct stat buf;
char lv_path[PATH_MAX];
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) {
dev_dir, vg_name, lv_name) == -1) {
log_error("Couldn't determine link pathname.");
return 0;
}
log_very_verbose("Removing link %s", lv_path);
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
log_error("%s not symbolic link - not removing", lv_path);
if (errno != ENOENT)
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;
@@ -128,35 +197,143 @@ static int _rm_link(struct logical_volume *lv, const char *lv_name)
return 1;
}
int fs_add_lv(struct logical_volume *lv, const char *dev)
typedef enum {
FS_ADD,
FS_DEL,
FS_RENAME
} fs_op_t;
static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev,
const char *old_lv_name)
{
if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) {
stack;
return 0;
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;
if (!_mk_link(dev_dir, vg_name, lv_name, dev))
stack;
}
return 1;
}
int fs_del_lv(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)
{
if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) {
stack;
strcpy(*pos, str);
*ptr = *pos;
*pos += strlen(*ptr) + 1;
}
static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev,
const char *old_lv_name)
{
struct fs_op_parms *fsp;
size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
strlen(dev) + strlen(old_lv_name) + 5;
char *pos;
if (!(fsp = dbg_malloc(sizeof(*fsp) + len))) {
log_error("No space to stack fs operation");
return 0;
}
pos = fsp->names;
fsp->type = type;
_store_str(&pos, &fsp->dev_dir, dev_dir);
_store_str(&pos, &fsp->vg_name, vg_name);
_store_str(&pos, &fsp->lv_name, lv_name);
_store_str(&pos, &fsp->dev, dev);
_store_str(&pos, &fsp->old_lv_name, old_lv_name);
list_add(&_fs_ops, &fsp->list);
return 1;
}
/* FIXME Use rename() */
static void _pop_fs_ops(void)
{
struct list *fsph, *fspht;
struct fs_op_parms *fsp;
list_iterate_safe(fsph, fspht, &_fs_ops) {
fsp = list_item(fsph, struct fs_op_parms);
_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
fsp->dev, fsp->old_lv_name);
list_del(&fsp->list);
dbg_free(fsp);
}
}
static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
const char *lv_name, const char *dev, const char *old_lv_name)
{
if (memlock()) {
if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
old_lv_name)) {
stack;
return 0;
}
return 1;
}
return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name);
}
int fs_add_lv(const 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(const struct logical_volume *lv)
{
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)
{
if (old_name && !_rm_link(lv, old_name))
stack;
if (!_mk_link(lv, dev))
stack;
return 1;
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

@@ -14,10 +14,10 @@
* 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_add_lv(const struct logical_volume *lv, const char *dev);
int fs_del_lv(const struct logical_volume *lv);
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name);
void fs_unlock(void);
#endif

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

@@ -0,0 +1,572 @@
/*
* 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"
#include "str_list.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 *vgnames;
struct lvmcache_vginfo *vgi;
lvmcache_label_scan(cmd, full_scan);
if (!(vgnames = str_list_create(cmd->mem))) {
log_error("vgnames list allocation failed");
return NULL;
}
list_iterate_items(vgi, &_vginfos) {
if (!str_list_add(cmd->mem, vgnames,
pool_strdup(cmd->mem, vgi->vgname))) {
log_error("strlist allocation failed");
return NULL;
}
}
return vgnames;
}
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
{
struct label *label;
struct lvmcache_info *info;
/* Already cached ? */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct lvmcache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
lvmcache_label_scan(cmd, 0);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct lvmcache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
if (memlock())
return NULL;
lvmcache_label_scan(cmd, 1);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct lvmcache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
return NULL;
}
static void _drop_vginfo(struct lvmcache_info *info)
{
if (!list_empty(&info->list)) {
list_del(&info->list);
list_init(&info->list);
}
if (info->vginfo && list_empty(&info->vginfo->infos)) {
hash_remove(_vgname_hash, info->vginfo->vgname);
if (info->vginfo->vgname)
dbg_free(info->vginfo->vgname);
if (*info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
list_del(&info->vginfo->list);
dbg_free(info->vginfo);
}
info->vginfo = NULL;
}
/* Unused
void lvmcache_del(struct lvmcache_info *info)
{
if (info->dev->pvid[0] && _pvid_hash)
hash_remove(_pvid_hash, info->dev->pvid);
_drop_vginfo(info);
info->label->labeller->ops->destroy_label(info->label->labeller,
info->label);
dbg_free(info);
return;
} */
static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
{
if (!strcmp(info->dev->pvid, pvid))
return 1;
if (*info->dev->pvid) {
hash_remove(_pvid_hash, info->dev->pvid);
}
strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
if (!hash_insert(_pvid_hash, pvid, info)) {
log_error("_lvmcache_update: pvid insertion failed: %s", pvid);
return 0;
}
return 1;
}
static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
{
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
sizeof(info->vginfo->vgid)))
return 1;
if (info->vginfo && *info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
if (!vgid)
return 1;
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
if (!hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) {
log_error("_lvmcache_update: vgid hash insertion failed: %s",
info->vginfo->vgid);
return 0;
}
return 1;
}
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
{
struct lvmcache_vginfo *vginfo;
/* If vgname is NULL and we don't already have a vgname,
* assume ORPHAN - we want every entry to have a vginfo
* attached for scanning reasons.
*/
if (!vgname && !info->vginfo)
vgname = ORPHAN;
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
return 1;
/* Remove existing vginfo entry */
_drop_vginfo(info);
/* Get existing vginfo or create new one */
if (!(vginfo = vginfo_from_vgname(vgname))) {
if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
log_error("lvmcache_update_vgname: list alloc failed");
return 0;
}
memset(vginfo, 0, sizeof(*vginfo));
if (!(vginfo->vgname = dbg_strdup(vgname))) {
dbg_free(vginfo);
log_error("cache vgname alloc failed for %s", vgname);
return 0;
}
list_init(&vginfo->infos);
if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
log_error("cache_update: vg hash insertion failed: %s",
vginfo->vgname);
dbg_free(vginfo->vgname);
dbg_free(vginfo);
return 0;
}
/* Ensure orphans appear last on list_iterate */
if (!*vgname)
list_add(&_vginfos, &vginfo->list);
else
list_add_h(&_vginfos, &vginfo->list);
}
info->vginfo = vginfo;
list_add(&vginfo->infos, &info->list);
/* FIXME Check consistency of list! */
vginfo->fmt = info->fmt;
return 1;
}
int lvmcache_update_vg(struct volume_group *vg)
{
struct list *pvh;
struct physical_volume *pv;
struct lvmcache_info *info;
char pvid_s[ID_LEN + 1];
int vgid_updated = 0;
pvid_s[sizeof(pvid_s) - 1] = '\0';
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
/* FIXME Could pv->dev->pvid ever be different? */
if ((info = info_from_pvid(pvid_s))) {
lvmcache_update_vgname(info, vg->name);
if (!vgid_updated) {
_lvmcache_update_vgid(info, (char *) &vg->id);
vgid_updated = 1;
}
}
}
return 1;
}
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid)
{
struct label *label;
struct lvmcache_info *existing, *info;
char pvid_s[ID_LEN + 1];
if (!_vgname_hash && !lvmcache_init()) {
log_error("Internal cache initialisation failed");
return NULL;
}
strncpy(pvid_s, pvid, sizeof(pvid_s));
pvid_s[sizeof(pvid_s) - 1] = '\0';
if (!(existing = info_from_pvid(pvid_s)) &&
!(existing = info_from_pvid(dev->pvid))) {
if (!(label = label_create(labeller))) {
stack;
return NULL;
}
if (!(info = dbg_malloc(sizeof(*info)))) {
log_error("lvmcache_info allocation failed");
label_destroy(label);
return NULL;
}
memset(info, 0, sizeof(*info));
label->info = info;
info->label = label;
list_init(&info->list);
info->dev = dev;
} else {
if (existing->dev != dev) {
/* Is the existing entry a duplicate pvid e.g. md ? */
if (MAJOR(existing->dev->dev) == md_major() &&
MAJOR(dev->dev) != md_major()) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s - using md %s",
pvid, dev_name(dev),
dev_name(existing->dev));
return NULL;
} else if (MAJOR(existing->dev->dev) != md_major() &&
MAJOR(dev->dev) == md_major())
log_very_verbose("Duplicate PV %s on %s - "
"using md %s", pvid,
dev_name(existing->dev),
dev_name(dev));
else
log_error("Found duplicate PV %s: using %s not "
"%s", pvid, dev_name(dev),
dev_name(existing->dev));
}
info = existing;
/* Has labeller changed? */
if (info->label->labeller != labeller) {
label_destroy(info->label);
if (!(info->label = label_create(labeller))) {
/* FIXME leaves info without label! */
stack;
return NULL;
}
info->label->info = info;
}
label = info->label;
}
info->fmt = (const struct format_type *) labeller->private;
info->status |= CACHE_INVALID;
if (!_lvmcache_update_pvid(info, pvid_s)) {
if (!existing) {
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!lvmcache_update_vgname(info, vgname)) {
if (!existing) {
hash_remove(_pvid_hash, pvid_s);
strcpy(info->dev->pvid, "");
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!_lvmcache_update_vgid(info, vgid))
/* Non-critical */
stack;
return info;
}
static void _lvmcache_destroy_entry(struct lvmcache_info *info)
{
if (!list_empty(&info->list))
list_del(&info->list);
strcpy(info->dev->pvid, "");
label_destroy(info->label);
dbg_free(info);
}
static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
{
if (vginfo->vgname)
dbg_free(vginfo->vgname);
dbg_free(vginfo);
}
static void _lvmcache_destroy_lockname(int present)
{
/* Nothing to do */
}
void lvmcache_destroy(void)
{
_has_scanned = 0;
if (_vgid_hash) {
hash_destroy(_vgid_hash);
_vgid_hash = NULL;
}
if (_pvid_hash) {
hash_iter(_pvid_hash, (iterate_fn) _lvmcache_destroy_entry);
hash_destroy(_pvid_hash);
_pvid_hash = NULL;
}
if (_vgname_hash) {
hash_iter(_vgname_hash,
(iterate_fn) _lvmcache_destroy_vgnamelist);
hash_destroy(_vgname_hash);
_vgname_hash = NULL;
}
if (_lock_hash) {
hash_iter(_lock_hash, (iterate_fn) _lvmcache_destroy_lockname);
hash_destroy(_lock_hash);
_lock_hash = NULL;
}
list_init(&_vginfos);
}

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

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

View File

@@ -7,10 +7,9 @@
#ifndef _LVM_ERRORS_H
#define _LVM_ERRORS_H
#define EINVALID_CMD_LINE 1
#define ENO_SUCH_CMD 3
#define ECMD_PROCESSED 4
#define ECMD_PROCESSED 1
#define ENO_SUCH_CMD 2
#define EINVALID_CMD_LINE 3
#define ECMD_FAILED 5
#endif

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

@@ -0,0 +1,536 @@
/*
* 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 "filter-sysfs.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;
}
#define MAX_FILTERS 3
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
{
unsigned nr_filt = 0;
struct config_node *cn;
struct dev_filter *filters[MAX_FILTERS];
memset(filters, 0, sizeof(filters));
/* sysfs filter */
if (find_config_bool(cmd->cf->root, "devices/sysfs_scan", '/',
DEFAULT_SYSFS_SCAN)) {
if ((filters[nr_filt] = sysfs_filter_create(cmd->proc_dir)))
nr_filt++;
}
/* regex filter */
if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/')))
log_debug("devices/filter not found in config file: no regex "
"filter installed");
else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
log_error("Failed to create regex device filter");
return NULL;
}
/* device type filter */
cn = find_config_node(cmd->cf->root, "devices/types", '/');
if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
log_error("Failed to create lvm type filter");
return NULL;
}
/* only build a composite filter if we really need it */
return (nr_filt == 1) ?
filters[0] : composite_filter_create(nr_filt, filters);
}
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");
#ifdef INTL_PACKAGE
bindtextdomain(INTL_PACKAGE, LOCALEDIR);
#endif
init_syslog(DEFAULT_LOG_FACILITY);
if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
log_error("Failed to allocate command context");
return NULL;
}
memset(cmd, 0, sizeof(*cmd));
cmd->args = the_args;
list_init(&cmd->formats);
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
if (!_get_env_vars(cmd))
goto error;
/* Create system directory if it doesn't already exist */
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
goto error;
if (!_init_config(cmd))
goto error;
_init_logging(cmd);
if (!_process_config(cmd))
goto error;
if (!_init_dev_cache(cmd))
goto error;
if (!_init_filters(cmd))
goto error;
if (!(cmd->mem = pool_create(4 * 1024))) {
log_error("Command memory pool creation failed");
return 0;
}
memlock_init(cmd);
if (!_init_formats(cmd))
goto error;
cmd->current_settings = cmd->default_settings;
return cmd;
error:
dbg_free(cmd);
return NULL;
}
static void _destroy_formats(struct list *formats)
{
struct list *fmtl, *tmp;
struct format_type *fmt;
void *lib;
list_iterate_safe(fmtl, tmp, formats) {
fmt = list_item(fmtl, struct format_type);
list_del(&fmt->list);
lib = fmt->library;
fmt->ops->destroy(fmt);
#ifdef HAVE_LIBDL
if (lib)
dlclose(lib);
#endif
}
}
void destroy_toolcontext(struct cmd_context *cmd)
{
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
activation_exit();
lvmcache_destroy();
label_exit();
_destroy_formats(&cmd->formats);
cmd->filter->destroy(cmd->filter);
pool_destroy(cmd->mem);
dev_cache_exit();
destroy_config_tree(cmd->cf);
dbg_free(cmd);
release_log_memory();
dump_memory();
fin_log();
fin_syslog();
if (_log)
fclose(_log);
}

View File

@@ -13,25 +13,61 @@
#include "pool.h"
#include "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;
struct format_type *fmt; /* Current format to use by default */
const struct format_type *fmt; /* Current format to use by default */
struct format_type *fmt_backup; /* Format to use for backups */
/* FIXME Move into dynamic list */
struct format_type *fmt1; /* Format1 */
struct format_type *fmtt; /* Format_text */
struct list formats; /* Available formats */
char *cmd_line;
char *dev_dir;
struct dev_filter *filter;
struct config_file *cf;
struct command *command;
struct uuid_map *um;
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,18 +4,17 @@
* 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,
@@ -32,10 +31,10 @@ enum {
};
struct parser {
const char *fb, *fe; /* file limits */
char *fb, *fe; /* file limits */
int t; /* token limits and type */
const char *tb, *te;
char *tb, *te;
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
@@ -44,11 +43,13 @@ struct parser {
};
struct cs {
struct config_file cf;
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);
@@ -81,7 +82,7 @@ static int _tok_match(const char *str, const char *b, const char *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);
@@ -99,20 +100,25 @@ struct config_file *create_config_file(void)
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);
}
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;
int r = 0;
int use_mmap = 1;
off_t mmap_offset = 0;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
@@ -120,50 +126,195 @@ int read_config(struct config_file *cf, const char *file)
}
p->mem = c->mem;
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
/* Only use mmap with regular files */
if (!(dev->flags & DEV_REGULAR) || size2)
use_mmap = 0;
if (use_mmap) {
mmap_offset = offset % getpagesize();
/* memory map the file */
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", dev_name(dev));
goto out;
}
p->fb = p->fb + mmap_offset;
} else {
if (!(p->fb = dbg_malloc(size + size2))) {
stack;
return 0;
}
if (!dev_read(dev, (uint64_t) offset, size, p->fb)) {
log_error("Read from %s failed", dev_name(dev));
goto out;
}
if (size2) {
if (!dev_read(dev, (uint64_t) offset2, size2,
p->fb + size)) {
log_error("Circular read from %s failed",
dev_name(dev));
goto out;
}
}
}
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
p->fb + size, size2))) {
log_error("%s: Checksum error", dev_name(dev));
goto out;
}
p->fe = p->fb + size + size2;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p, TOK_SECTION_E);
if (!(cf->root = _file(p))) {
stack;
goto out;
}
r = 1;
out:
if (!use_mmap)
dbg_free(p->fb);
else {
/* unmap the file */
if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
log_sys_error("munmap", dev_name(dev));
r = 0;
}
}
return r;
}
int read_config_file(struct config_tree *cf, const char *file)
{
struct cs *c = (struct cs *) cf;
struct stat info;
struct device *dev;
int r = 1;
if (stat(file, &info)) {
log_sys_error("stat", file);
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 ((fd = open(file, O_RDONLY)) < 0) {
log_sys_error("open", file);
return 0;
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
if (!(dev = dev_create_file(file, NULL, NULL))) {
stack;
r = 0;
return 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
close(fd);
r = read_config_fd(cf, dev, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0);
dev_close(dev);
c->timestamp = info.st_mtime;
c->filename = pool_strdup(c->mem, file);
return r;
}
static void _write_value(FILE * fp, struct config_value *v)
time_t config_file_timestamp(struct config_tree *cf)
{
struct cs *c = (struct cs *) cf;
return c->timestamp;
}
/*
* Returns 1 if config file reloaded
*/
int reload_config_file(struct config_tree **cf)
{
struct config_tree *new_cf;
struct cs *c = (struct cs *) *cf;
struct cs *new_cs;
struct stat info;
struct device *dev;
int r;
if (!c->filename)
return 0;
if (stat(c->filename, &info) == -1) {
if (errno == ENOENT)
return 1;
log_sys_error("stat", c->filename);
log_error("Failed to reload configuration file");
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("Configuration file %s is not a regular file",
c->filename);
return 0;
}
/* Unchanged? */
if (c->timestamp == info.st_mtime)
return 0;
log_verbose("Detected config file change: Reloading %s", c->filename);
if (info.st_size == 0) {
log_verbose("Config file reload: %s is empty", c->filename);
return 0;
}
if (!(new_cf = create_config_tree())) {
log_error("Allocation of new config_tree failed");
return 0;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
stack;
return 0;
}
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
r = read_config_fd(new_cf, dev, 0, (size_t) info.st_size,
0, 0, (checksum_fn_t) NULL, 0);
dev_close(dev);
if (r) {
new_cs = (struct cs *) new_cf;
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
new_cs->timestamp = info.st_mtime;
destroy_config_tree(*cf);
*cf = new_cf;
}
return r;
}
static void _write_value(FILE *fp, struct config_value *v)
{
switch (v->type) {
case CFG_STRING:
@@ -177,10 +328,18 @@ 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)
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;
@@ -190,7 +349,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\t';
space[i] = '\0';
while (n) {
@@ -223,20 +382,28 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
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) {
FILE *fp;
if (!file) {
fp = stdout;
file = "stdout";
} else if (!(fp = fopen(file, "w"))) {
log_sys_error("open", file);
return 0;
}
log_verbose("Dumping configuration to %s", file);
if (!_write_config(cf->root, fp, 0)) {
stack;
log_error("Failure while writing configuration");
r = 0;
}
fclose(fp);
if (fp != stdout)
fclose(fp);
return r;
}
@@ -306,7 +473,7 @@ static struct config_node *_section(struct parser *p)
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
struct config_value *h = NULL, *l, *ll = NULL;
if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
@@ -325,6 +492,16 @@ static struct config_value *_value(struct parser *p)
match(TOK_COMMA);
}
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);
@@ -333,19 +510,22 @@ static struct config_value *_value(struct parser *p)
static struct config_value *_type(struct parser *p)
{
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p);
if (!v)
return NULL;
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
match(TOK_FLOAT);
break;
@@ -373,22 +553,29 @@ 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)
{
int values_allowed = 0;
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
if (p->tb == p->fe || !*p->tb) {
p->t = TOK_EOF;
return;
}
/* Should next token be interpreted as value instead of identifier? */
if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
tok_prev == TOK_COMMA)
values_allowed = 1;
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
@@ -425,13 +612,24 @@ static void _get_token(struct parser *p)
case '"':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
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)
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;
@@ -447,22 +645,27 @@ static void _get_token(struct parser *p)
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;
case '+':
case '-':
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;
}
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
(*p->te != '}'))
p->te++;
break;
}
@@ -470,15 +673,15 @@ static void _get_token(struct parser *p)
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
while ((p->tb != p->fe) && (*p->tb)) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
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++;
@@ -511,7 +714,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;
@@ -526,7 +729,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;
@@ -558,7 +761,7 @@ struct config_node *find_config_node(struct config_node *cn,
}
const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
const char *path, const int sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
@@ -575,7 +778,7 @@ const char *find_config_str(struct config_node *cn,
}
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);
@@ -590,7 +793,7 @@ int find_config_int(struct config_node *cn, const char *path,
}
float find_config_float(struct config_node *cn, const char *path,
char sep, float fail)
const int sep, float fail)
{
struct config_node *n = find_config_node(cn, path, sep);
@@ -633,7 +836,7 @@ static int _str_to_bool(const char *str, int fail)
}
int find_config_bool(struct config_node *cn, const char *path,
char sep, int fail)
const int sep, int fail)
{
struct config_node *n = find_config_node(cn, path, sep);
struct config_value *v;
@@ -655,7 +858,7 @@ int find_config_bool(struct config_node *cn, const char *path,
}
int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t * result)
const int sep, uint32_t *result)
{
struct config_node *n;
@@ -669,7 +872,7 @@ int get_config_uint32(struct config_node *cn, const char *path,
}
int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t * result)
const int sep, uint64_t *result)
{
struct config_node *n;
@@ -682,3 +885,17 @@ int get_config_uint64(struct config_node *cn, const char *path,
*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

@@ -7,66 +7,75 @@
#ifndef _LVM_CONFIG_H
#define _LVM_CONFIG_H
#include <inttypes.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);
const int sep, float fail);
/*
* Understands (0, ~0), (y, n), (yes, no), (on,
* off), (true, false).
*/
int find_config_bool(struct config_node *cn, const char *path,
char sep, int fail);
const int sep, int fail);
int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t *result);
const int sep, uint32_t *result);
int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t *result);
const int sep, uint64_t *result);
int get_config_str(struct config_node *cn, const char *path,
const int sep, char **result);
#endif

View File

@@ -7,9 +7,6 @@
#ifndef _LVM_DEFAULTS_H
#define _LVM_DEFAULTS_H
#define DEFAULT_SYS_DIR "/etc/lvm"
#define DEFAULT_ARCHIVE_ENABLED 1
#define DEFAULT_BACKUP_ENABLED 1
@@ -19,22 +16,77 @@
#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_SYSFS_SCAN 1
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
#define DEFAULT_UMASK 0077
#define DEFAULT_FORMAT "lvm1"
#define DEFAULT_MSG_PREFIX " "
#define DEFAULT_CMD_NAME 0
#ifdef READLINE_SUPPORT
#define DEFAULT_MAX_HISTORY 100
#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)
#endif /* _LVM_DEFAULTS_H */
#define DEFAULT_MSG_PREFIX " "
#define DEFAULT_CMD_NAME 0
#define DEFAULT_OVERWRITE 0
#ifndef DEFAULT_LOG_FACILITY
# define DEFAULT_LOG_FACILITY LOG_USER
#endif
#define DEFAULT_SYSLOG 1
#define DEFAULT_VERBOSE 0
#define DEFAULT_LOGLEVEL 0
#define DEFAULT_INDENT 1
#define DEFAULT_UNITS "h"
#define DEFAULT_SUFFIX 1
#ifdef DEVMAPPER_SUPPORT
# define DEFAULT_ACTIVATION 1
# define DEFAULT_RESERVED_MEMORY 8192
# define DEFAULT_RESERVED_STACK 256
# define DEFAULT_PROCESS_PRIORITY -18
#else
# define DEFAULT_ACTIVATION 0
#endif
#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
#define DEFAULT_MIRROR_REGION_SIZE 512 /* KB */
#define DEFAULT_INTERVAL 15
#ifdef READLINE_SUPPORT
# define DEFAULT_MAX_HISTORY 100
#endif
#define DEFAULT_REP_ALIGNED 1
#define DEFAULT_REP_BUFFERED 1
#define DEFAULT_REP_HEADINGS 1
#define DEFAULT_REP_SEPARATOR " "
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,move_percent"
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,move_percent,lv_uuid"
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
#define DEFAULT_LVS_SORT "vg_name,lv_name"
#define DEFAULT_VGS_SORT "vg_name"
#define DEFAULT_PVS_SORT "pv_name"
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -4,18 +4,16 @@
* This file is released under the LGPL.
*/
#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)
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)

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;
@@ -46,7 +46,7 @@ static uint32_t _shuffle(uint32_t 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,9 +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;
@@ -26,26 +25,26 @@ static unsigned char _nums[] = {
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,
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,
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,
194,
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
139,
139,
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
43,
43,
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
71,
71,
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
109,
109,
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
209
209
};
static struct hash_node *_create_node(const char *str)
@@ -62,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++];
@@ -126,7 +125,7 @@ void hash_destroy(struct hash_table *t)
dbg_free(t);
}
static inline struct hash_node **_find(struct hash_table *t, const char *key)
static struct hash_node **_find(struct hash_table *t, const char *key)
{
unsigned h = _hash(key) & (t->num_slots - 1);
struct hash_node **c;
@@ -209,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;
@@ -227,6 +226,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
{
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,13 +10,14 @@
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);
@@ -33,4 +34,3 @@ struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
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,36 +42,62 @@ 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;
}
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
static inline int list_end(struct list *head, struct list *elem)
{
return elem->n == head;
}
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
static inline int list_size(struct list *head) {
int s = 0;
struct list *v;
list_iterate(v, head)
s++;
return s;
static inline struct list *list_next(struct list *head, struct list *elem)
{
return (list_end(head, elem) ? NULL : elem->n);
}
#define list_item(v, t) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
/* Given 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)
#define list_iterate(v, head) \
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)
#define list_iterate_items(v, head) \
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
v = list_item(v->list.n, typeof(*v)))
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;
}
#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

80
lib/datastruct/str_list.c Normal file
View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2003 Sistina Software
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "str_list.h"
struct list *str_list_create(struct pool *mem)
{
struct list *sl;
if (!(sl = pool_alloc(mem, sizeof(struct list)))) {
stack;
return NULL;
}
list_init(sl);
return sl;
}
int str_list_add(struct pool *mem, struct list *sll, const char *str)
{
struct str_list *sln;
if (!str) {
stack;
return 0;
}
/* Already in list? */
if (str_list_match_item(sll, str))
return 1;
if (!(sln = pool_alloc(mem, sizeof(*sln)))) {
stack;
return 0;
}
sln->str = str;
list_add(sll, &sln->list);
return 1;
}
int str_list_del(struct list *sll, const char *str)
{
struct list *slh, *slht;
list_iterate_safe(slh, slht, sll) {
if (!strcmp(str, list_item(slh, struct str_list)->str))
list_del(slh);
}
return 1;
}
int str_list_match_item(struct list *sll, const char *str)
{
struct str_list *sl;
list_iterate_items(sl, sll)
if (!strcmp(str, sl->str))
return 1;
return 0;
}
int str_list_match_list(struct list *sll, struct list *sll2)
{
struct str_list *sl;
list_iterate_items(sl, sll)
if (str_list_match_item(sll2, sl->str))
return 1;
return 0;
}

18
lib/datastruct/str_list.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2003 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#ifndef _LVM_STR_LIST_H
#define _LVM_STR_LIST_H
#include "pool.h"
struct list *str_list_create(struct pool *mem);
int str_list_add(struct pool *mem, struct list *sll, const char *str);
int str_list_del(struct list *sll, const char *str);
int str_list_match_item(struct list *sll, const char *str);
int str_list_match_list(struct list *sll, struct list *sll2);
#endif

View File

@@ -4,27 +4,18 @@
* 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>
#include <linux/kdev_t.h>
/*
* FIXME: really need to seperate names from the devices since
* multiple names can point to the same device.
*/
struct dev_iter {
struct btree_iter *current;
@@ -51,36 +42,163 @@ static struct {
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;
@@ -122,7 +241,7 @@ static int _insert_dev(const char *path, dev_t d)
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);
@@ -194,6 +313,17 @@ static int _insert(const char *path, int rec)
}
if (S_ISDIR(info.st_mode)) { /* add a directory */
/* check it's not a symbolic link */
if (lstat(path, &info) < 0) {
log_sys_very_verbose("lstat", path);
return 0;
}
if (S_ISLNK(info.st_mode)) {
log_debug("%s: Symbolic link to directory", path);
return 0;
}
if (rec)
r = _insert_dir(path);
@@ -229,6 +359,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;
@@ -259,7 +404,7 @@ int dev_cache_init(void)
return 0;
}
void _check_closed(struct device *dev)
static void _check_closed(struct device *dev)
{
if (dev->fd >= 0)
log_err("Device '%s' has been left open.", dev_name(dev));
@@ -272,11 +417,22 @@ static inline void _check_for_open_devices(void)
void dev_cache_exit(void)
{
_check_for_open_devices();
pool_destroy(_cache.mem);
if (_cache.names)
_check_for_open_devices();
if (_cache.mem) {
pool_destroy(_cache.mem);
_cache.mem = NULL;
}
if (_cache.names) {
hash_destroy(_cache.names);
_cache.names = NULL;
}
_cache.devices = NULL;
_cache.has_scanned = 0;
list_init(&_cache.dirs);
}
int dev_cache_add_dir(const char *path)
@@ -295,8 +451,10 @@ 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);
@@ -305,20 +463,31 @@ int dev_cache_add_dir(const char *path)
/* 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)
const char *dev_name_confirmed(struct device *dev, int quiet)
{
struct stat buf;
char *name;
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)
log_sys_error("stat", name);
log_error("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev), (int) MINOR(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);
@@ -364,8 +533,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);

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,21 +4,214 @@
* 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 "locking.h"
#include <sys/types.h>
#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h> // UGH!!! for BLKSSZGET
int dev_get_size(struct device *dev, uint64_t * size)
#ifdef linux
# define u64 uint64_t /* Missing without __KERNEL__ */
# undef WNOHANG /* Avoid redefinition */
# undef WUNTRACED /* Avoid redefinition */
# include <linux/fs.h> /* For block ioctl definitions */
# define BLKSIZE_SHIFT SECTOR_SHIFT
# ifndef BLKGETSIZE64 /* fs.h out-of-date */
# define BLKGETSIZE64 _IOR(0x12, 114, size_t)
# endif /* BLKGETSIZE64 */
#else
# include <sys/disk.h>
# define BLKBSZGET DKIOCGETBLOCKSIZE
# define BLKSSZGET DKIOCGETBLOCKSIZE
# define BLKGETSIZE64 DKIOCGETBLOCKCOUNT
# define BLKFLSBUF DKIOCSYNCHRONIZECACHE
# define BLKSIZE_SHIFT 0
#endif
#ifdef O_DIRECT_SUPPORT
# ifndef O_DIRECT
# error O_DIRECT support configured but O_DIRECT definition not found in headers
# 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 = getpagesize();
_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);
@@ -27,19 +220,18 @@ 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);
*size = (uint64_t) s;
return 1;
}
int dev_get_sectsize(struct device *dev, uint32_t * size)
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
int fd;
int s;
@@ -62,48 +254,116 @@ int dev_get_sectsize(struct device *dev, uint32_t * size)
return 1;
}
int dev_open(struct device *dev, int flags)
void dev_flush(struct device *dev)
{
if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0)
return;
if (fsync(dev->fd) >= 0)
return;
sync();
}
int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
{
struct stat buf;
const char *name = dev_name_confirmed(dev);
const char *name;
if (!name) {
if (dev->fd >= 0) {
dev->open_count++;
return 1;
}
if (memlock())
log_error("WARNING: dev_open(%s) called while suspended",
dev_name(dev));
if (dev->flags & DEV_REGULAR)
name = dev_name(dev);
else if (!(name = dev_name_confirmed(dev, quiet))) {
stack;
return 0;
}
if (dev->fd >= 0) {
log_error("Device '%s' has already been opened", name);
return 0;
}
if ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev)) {
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 ((dev->fd = open(name, flags)) < 0) {
#ifdef O_DIRECT_SUPPORT
if (direct)
flags |= O_DIRECT;
#endif
if ((dev->fd = open(name, flags, 0777)) < 0) {
log_sys_error("open", name);
return 0;
}
if ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev)) {
dev->open_count = 1;
dev->flags &= ~DEV_ACCESSED_W;
if (!(dev->flags & DEV_REGULAR) &&
((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) {
log_error("%s: fstat failed: Has device name changed?", name);
dev_close(dev);
dev->fd = -1;
return 0;
}
dev->flags = 0;
#ifndef O_DIRECT_SUPPORT
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;
}
static void _flush(int fd)
int dev_open_quiet(struct device *dev)
{
ioctl(fd, BLKFLSBUF, 0);
int flags;
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
return dev_open_flags(dev, flags, 1, 1);
}
int dev_close(struct device *dev)
int dev_open(struct device *dev)
{
int flags;
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
return dev_open_flags(dev, flags, 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);
}
}
static int _dev_close(struct device *dev, int immediate)
{
if (dev->fd < 0) {
log_error("Attempt to close device '%s' "
@@ -111,139 +371,127 @@ int dev_close(struct device *dev)
return 0;
}
#ifndef O_DIRECT_SUPPORT
if (dev->flags & DEV_ACCESSED_W)
_flush(dev->fd);
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 && (immediate || !vgs_locked()))
_close(dev);
return 1;
}
/*
* FIXME: factor common code out.
int dev_close(struct device *dev)
{
return _dev_close(dev, 0);
}
int dev_close_immediate(struct device *dev)
{
return _dev_close(dev, 1);
}
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;
#ifndef O_DIRECT_SUPPORT
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;
}
return _read(fd, buffer, len);
}
int _write(int fd, const void *buf, size_t count)
{
size_t n = 0;
int tot = 0;
/* Skip all writes */
if (test_mode())
return count;
while (tot < count) {
do
n = write(fd, buf, count - tot);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n <= 0)
return tot ? tot : n;
tot += n;
buf += n;
}
return tot;
}
int64_t dev_write(struct device * dev, uint64_t offset,
int64_t len, void *buffer)
{
const char *name = dev_name(dev);
int fd = dev->fd;
if (fd < 0) {
log_error("Attempt to write to unopened device %s", name);
return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", name);
return 0;
}
where.dev = dev;
where.start = offset;
where.size = len;
dev->flags |= DEV_ACCESSED_W;
return _write(fd, buffer, len);
return _aligned_io(&where, buffer, 1);
}
int dev_zero(struct device *dev, uint64_t offset, int64_t len)
int dev_zero(struct device *dev, uint64_t offset, size_t len)
{
int64_t r, s;
size_t s;
char buffer[4096];
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;
}
offset += s;
}
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,11 +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,22 +7,29 @@
#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 {
@@ -30,33 +37,58 @@ struct device_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);
int dev_close_immediate(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 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 const char *dev_name(struct device *dev) {
struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias);
static inline const char *dev_name(const struct device *dev)
{
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
"unknown device";
"unknown device";
}
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev);
const char *dev_name_confirmed(struct device *dev, int quiet);
static inline int is_lvm_partition(const char *name) {
/* FIXME Check partition type if appropriate */
#define is_lvm_partition(a) 1
/*
static inline int is_lvm_partition(const char *name)
{
return 1;
}
*/
#endif

View File

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

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,35 +37,32 @@ static void _destroy(struct dev_filter *f)
dbg_free(f);
}
struct dev_filter *composite_filter_create(int n, ...)
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
{
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));
struct dev_filter *cf;
va_list ap;
int i;
struct dev_filter **filters_copy, *cf;
if (!filters) {
stack;
return NULL;
}
if (!(cf = dbg_malloc(sizeof(*cf)))) {
stack;
dbg_free(filters);
if (!(filters_copy = dbg_malloc(sizeof(*filters) * (n + 1)))) {
log_error("composite filters allocation failed");
return NULL;
}
va_start(ap, n);
for (i = 0; i < n; i++) {
struct dev_filter *f = va_arg(ap, struct dev_filter *);
filters[i] = f;
memcpy(filters_copy, filters, sizeof(*filters) * n);
filters_copy[n] = NULL;
if (!(cf = dbg_malloc(sizeof(*cf)))) {
log_error("compsoite filters allocation failed");
dbg_free(filters_copy);
return NULL;
}
filters[i] = NULL;
va_end(ap);
cf->passes_filter = _and_p;
cf->destroy = _destroy;
cf->private = filters;
cf->private = filters_copy;
return cf;
}

View File

@@ -9,6 +9,6 @@
#include "dev-cache.h"
struct dev_filter *composite_filter_create(int n, ...);
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
#endif

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;
@@ -72,6 +77,8 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
if (!hash_insert(pf->devices, cv->v.str, data))
log_verbose("Couldn't add '%s' to filter ... ignoring",
cv->v.str);
/* Populate dev_cache ourselves */
dev_cache_get(cv->v.str, NULL);
}
return 1;
}
@@ -81,32 +88,39 @@ 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;
}
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out:
destroy_config_file(cf);
destroy_config_tree(cf);
return r;
}
static void _write_array(struct pfilter *pf, FILE * fp, const char *path,
static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
void *data)
{
void *d;
@@ -147,11 +161,18 @@ int persistent_filter_dump(struct dev_filter *f)
"- 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;
}
@@ -159,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);
@@ -183,7 +205,11 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
}
}
return l == PF_GOOD_DEVICE;
if (l == PF_BAD_DEVICE) {
log_debug("%s: Skipping (cached)", dev_name(dev));
return 0;
} else
return 1;
}
static void _destroy(struct dev_filter *f)

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;
@@ -137,7 +138,7 @@ 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)))
count)))
stack;
r = 1;
@@ -161,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);
}

273
lib/filters/filter-sysfs.c Normal file
View File

@@ -0,0 +1,273 @@
/*
* Copyright (C) 2004 Red Hat Inc
*
* This file is released under the GPL.
*/
#include "lib.h"
#include "filter-sysfs.h"
#include "lvm-string.h"
#include "pool.h"
#include <sys/sysmacros.h>
#include <sys/param.h>
#include <sys/types.h>
#include <dirent.h>
static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
{
char proc_mounts[PATH_MAX];
int r = 0;
FILE *fp;
char *split[2], buffer[PATH_MAX + 16];
if (!*proc) {
log_verbose("No proc filesystem found: skipping sysfs filter");
return 0;
}
if (lvm_snprintf(proc_mounts, sizeof(proc_mounts),
"%s/mounts", proc) < 0) {
log_error("Failed to create /proc/mounts string");
return 0;
}
if (!(fp = fopen(proc_mounts, "r"))) {
log_sys_error("fopen %s", proc_mounts);
return 0;
}
while (fgets(buffer, sizeof(buffer), fp)) {
if (split_words(buffer, 2, split) == 2 &&
!strcmp(split[0], "sysfs")) {
if (lvm_snprintf(path, len, "%s/%s", split[1],
"block") >= 0) {
r = 1;
}
break;
}
}
fclose(fp);
return r;
}
/*----------------------------------------------------------------
* We need to store a set of dev_t.
*--------------------------------------------------------------*/
struct entry {
struct entry *next;
dev_t dev;
};
#define SET_BUCKETS 64
struct dev_set {
struct pool *mem;
const char *sys_block;
int initialised;
struct entry *slots[SET_BUCKETS];
};
static struct dev_set *_dev_set_create(struct pool *mem, const char *sys_block)
{
struct dev_set *ds;
if (!(ds = pool_zalloc(mem, sizeof(*ds))))
return NULL;
ds->mem = mem;
ds->sys_block = pool_strdup(mem, sys_block);
ds->initialised = 0;
return ds;
}
static inline unsigned _hash_dev(dev_t dev)
{
return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
}
/*
* Doesn't check that the set already contains dev.
*/
static int _set_insert(struct dev_set *ds, dev_t dev)
{
struct entry *e;
unsigned h = _hash_dev(dev);
if (!(e = pool_alloc(ds->mem, sizeof(*e))))
return 0;
e->next = ds->slots[h];
e->dev = dev;
ds->slots[h] = e;
return 1;
}
static int _set_lookup(struct dev_set *ds, dev_t dev)
{
unsigned h = _hash_dev(dev);
struct entry *e;
for (e = ds->slots[h]; e; e = e->next)
if (e->dev == dev)
return 1;
return 0;
}
/*----------------------------------------------------------------
* filter methods
*--------------------------------------------------------------*/
static int _parse_dev(const char *file, FILE *fp, dev_t *result)
{
unsigned major, minor;
char buffer[64];
if (!fgets(buffer, sizeof(buffer), fp)) {
log_error("Empty sysfs device file: %s", file);
return 0;
}
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
log_info("sysfs device file not correct format");
return 0;
}
*result = makedev(major, minor);
return 1;
}
static int _read_dev(const char *file, dev_t *result)
{
int r;
FILE *fp;
if (!(fp = fopen(file, "r"))) {
log_sys_error("fopen", file);
return 0;
}
r = _parse_dev(file, fp, result);
fclose(fp);
return r;
}
/*
* Recurse through sysfs directories, inserting any devs found.
*/
static int _read_devs(struct dev_set *ds, const char *dir)
{
struct dirent *d;
DIR *dr;
char path[PATH_MAX];
dev_t dev;
int r = 1;
if (!(dr = opendir(dir))) {
log_sys_error("opendir", dir);
return 0;
}
while ((d = readdir(dr))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir,
d->d_name) < 0) {
log_error("sysfs path name too long: %s in %s",
d->d_name, dir);
continue;
}
if (d->d_type == DT_DIR) {
if (!_read_devs(ds, path)) {
r = 0;
break;
}
}
if ((d->d_type == DT_REG && !strcmp(d->d_name, "dev")))
if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) {
r = 0;
break;
}
}
if (closedir(dr))
log_sys_error("closedir", dir);
return r;
}
static int _init_devs(struct dev_set *ds)
{
if (!_read_devs(ds, ds->sys_block)) {
ds->initialised = -1;
return 0;
}
ds->initialised = 1;
return 1;
}
static int _accept_p(struct dev_filter *f, struct device *dev)
{
struct dev_set *ds = (struct dev_set *) f->private;
if (!ds->initialised)
_init_devs(ds);
/* Pass through if initialisation failed */
if (ds->initialised != 1)
return 1;
return _set_lookup(ds, dev->dev);
}
static void _destroy(struct dev_filter *f)
{
struct dev_set *ds = (struct dev_set *) f->private;
pool_destroy(ds->mem);
}
struct dev_filter *sysfs_filter_create(const char *proc)
{
char sys_block[PATH_MAX];
struct pool *mem;
struct dev_set *ds;
struct dev_filter *f;
if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block)))
return NULL;
if (!(mem = pool_create(256))) {
log_error("sysfs pool creation failed");
return NULL;
}
if (!(ds = _dev_set_create(mem, sys_block))) {
log_error("sysfs dev_set creation failed");
goto bad;
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
}
f->passes_filter = _accept_p;
f->destroy = _destroy;
f->private = ds;
return f;
bad:
pool_destroy(mem);
return NULL;
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright (C) 2004 Red Hat Inc
*
* This file is released under the GPL.
*/
#ifndef _LVM_FILTER_SYSFS_H
#define _LVM_FILTER_SYSFS_H
#include "config.h"
#include "dev-cache.h"
struct dev_filter *sysfs_filter_create(const char *proc);
#endif

View File

@@ -18,32 +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 int _md_major = -1;
static device_info_t device_info[] = {
int md_major(void)
{
return _md_major;
}
/* This list can be supplemented with devices/types in the config file */
static const device_info_t device_info[] = {
{"ide", 16}, /* IDE disk */
{"sd", 16}, /* SCSI disk */
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
@@ -55,24 +57,27 @@ static device_info_t device_info[] = {
{"cciss", 16}, /* Compaq CCISS array */
{"ubd", 16}, /* User-mode virtual block device */
{"ataraid", 16}, /* ATA Raid */
{"drbd", 16}, /* Distributed Replicated Block Device */
{NULL, 0}
};
static int *scan_proc_dev(const char *proc);
static int passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
static int _passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
{
int fd;
const char *name = dev_name(dev);
/* Is this a recognised device type? */
if (!(((int *) f->private)[MAJOR(dev->dev)]))
if (!(((int *) f->private)[MAJOR(dev->dev)])) {
log_debug("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev));
return 0;
}
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno));
log_debug("%s: Skipping: open failed: %s", name,
strerror(errno));
return 0;
}
@@ -81,48 +86,18 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
return 1;
}
struct dev_filter *lvm_type_filter_create(const char *proc)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
f->passes_filter = passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
if (!(f->private = scan_proc_dev(proc)))
return NULL;
return f;
}
int md_major(void)
{
return _md_major;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}
static int *scan_proc_dev(const char *proc)
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
{
char line[80];
char proc_devices[PATH_MAX];
FILE *pd = NULL;
int ret = 0;
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))) {
@@ -130,6 +105,14 @@ static int *scan_proc_dev(const char *proc)
return NULL;
}
if (!*proc) {
log_verbose("No proc filesystem found: using all block device "
"types");
for (i = 0; i < NUMBER_OF_MAJORS; i++)
max_partitions_by_major[i] = 1;
return max_partitions_by_major;
}
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
@@ -173,12 +156,44 @@ static int *scan_proc_dev(const char *proc)
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;
}
}
@@ -186,3 +201,31 @@ static int *scan_proc_dev(const char *proc)
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,11 +21,23 @@
#ifndef _LVM_FILTER_H
#define _LVM_FILTER_H
struct dev_filter *lvm_type_filter_create(const char *proc);
#include "config.h"
#include <sys/stat.h>
#ifdef linux
# include <linux/kdev_t.h>
#else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
#endif
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn);
void lvm_type_filter_destroy(struct dev_filter *f);
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: liblvm2format1.so
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2format1.so.$(LIB_VERSION)
$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so
.PHONY: install

View File

@@ -4,18 +4,14 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h"
#include "xlate.h"
#include "log.h"
#include "vgcache.h"
#include "filter.h"
#include "lvmcache.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/kdev_t.h>
#define fail do {stack; return 0;} while(0)
#define xx16(v) disk->v = xlate16(disk->v)
@@ -96,7 +92,7 @@ static void _xlate_vgd(struct vg_disk *disk)
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;
@@ -116,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;
@@ -132,9 +128,9 @@ static int _munge_formats(struct pv_disk *pvd)
return 1;
}
int read_pvd(struct device *dev, struct pv_disk *pvd)
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
@@ -143,23 +139,27 @@ int read_pvd(struct device *dev, struct pv_disk *pvd)
_xlate_pvd(pvd);
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
log_very_verbose("%s does not have a valid PV identifier",
log_very_verbose("%s does not have a valid LVM1 PV identifier",
dev_name(dev));
return 0;
}
if (!_munge_formats(pvd)) {
log_very_verbose("Unknown metadata version %d found on %s",
pvd->version, dev_name(dev));
log_very_verbose("format1: Unknown metadata version %d "
"found on %s", pvd->version, dev_name(dev));
return 0;
}
/* If UUID is missing, create one */
if (pvd->pv_uuid[0] == '\0')
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
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);
@@ -170,12 +170,16 @@ 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;
ulong 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);
/* If UUID is missing, create one */
if (vgd->vg_uuid[0] == '\0')
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
return 1;
}
@@ -184,12 +188,11 @@ 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))
if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
fail;
if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
@@ -214,8 +217,8 @@ static inline int _check_lvd(struct lv_disk *lvd)
static int _read_lvs(struct disk_list *data)
{
int i, read = 0;
ulong pos;
unsigned int i, read = 0;
uint64_t pos;
struct lvd_list *ll;
struct vg_disk *vgd = &data->vgd;
@@ -243,12 +246,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);
ulong 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);
@@ -260,28 +263,30 @@ static int _read_extents(struct disk_list *data)
/*
* If exported, remove "PV_EXP" from end of VG name
*/
static void _munge_exported_vg(struct disk_list *data)
void munge_exported_vg(struct pv_disk *pvd)
{
int l, s;
int l;
size_t s;
/* Return if PV not in a VG or VG not exported */
if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED))
/* Return if PV not in a VG */
if ((!*pvd->vg_name))
return;
l = strlen(data->pvd.vg_name);
l = strlen(pvd->vg_name);
s = sizeof(EXPORTED_TAG);
if (!strncmp(data->pvd.vg_name + l - s + 1, EXPORTED_TAG, s))
data->pvd.vg_name[l - s + 1] = '\0';
data->pvd.pv_status |= VG_EXPORTED;
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(struct format_type *fmt,
static struct disk_list *__read_disk(const struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name)
{
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
const char *name = dev_name(dev);
struct lvmcache_info *info;
if (!dl) {
stack;
@@ -293,11 +298,23 @@ static struct disk_list *__read_disk(struct format_type *fmt,
list_init(&dl->uuids);
list_init(&dl->lvds);
if (!read_pvd(dev, &dl->pvd)) {
if (!_read_pvd(dev, &dl->pvd)) {
stack;
goto bad;
}
/* If VG is exported, set VG name back to the real name */
munge_exported_vg(&dl->pvd);
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 ?
*/
@@ -305,7 +322,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
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);
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
return (vg_name) ? NULL : dl;
}
@@ -315,11 +332,8 @@ static struct disk_list *__read_disk(struct format_type *fmt,
goto bad;
}
/* If VG is exported, set VG name back to the real name */
_munge_exported_vg(dl);
/* Update VG cache with what we found */
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt);
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s",
@@ -353,12 +367,12 @@ static struct disk_list *__read_disk(struct format_type *fmt,
return NULL;
}
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name)
{
struct disk_list *r;
if (!dev_open(dev, O_RDONLY)) {
if (!dev_open(dev)) {
stack;
return NULL;
}
@@ -400,21 +414,22 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
* We keep track of the first object allocated form the pool
* so we can free off all the memory if something goes wrong.
*/
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_filter *filter, struct pool *mem,
struct list *head)
{
struct dev_iter *iter;
struct device *dev;
struct disk_list *data = NULL;
struct list *pvdh, *pvdh2;
struct list *vgih;
struct lvmcache_vginfo *vginfo;
/* Fast path if we already saw this VG and cached the list of PVs */
if ((pvdh = vgcache_find(vg_name))) {
list_iterate(pvdh2, pvdh) {
dev = list_item(pvdh2, struct pvdev_list)->dev;
if (!(data = read_disk(fmt, dev, mem, vg_name)))
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);
}
@@ -422,11 +437,12 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
/* 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;
list_size(head) == data->vgd.pv_cur))
return 1;
/* Something changed. Remove the hints. */
/* Failed */
list_init(head);
vgcache_del(vg_name);
/* vgcache_del(vg_name); */
}
if (!(iter = dev_iter_create(filter))) {
@@ -451,10 +467,10 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
static int _write_vgd(struct disk_list *data)
{
struct vg_disk *vgd = &data->vgd;
ulong pos = data->pvd.vg_on_disk.base;
uint64_t pos = data->pvd.vg_on_disk.base;
_xlate_vgd(vgd);
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
fail;
_xlate_vgd(vgd);
@@ -466,8 +482,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) {
@@ -477,7 +493,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;
@@ -486,10 +502,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);
@@ -500,7 +516,7 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
static int _write_lvs(struct disk_list *data)
{
struct list *lvh;
ulong pos;
uint64_t pos, offset;
pos = data->pvd.lv_on_disk.base;
@@ -513,10 +529,14 @@ static int _write_lvs(struct disk_list *data)
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;
@@ -526,10 +546,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;
ulong 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);
@@ -540,8 +560,8 @@ static int _write_extents(struct disk_list *data)
static int _write_pvd(struct disk_list *data)
{
char *buf;
ulong pos = data->pvd.pv_on_disk.base;
ulong size = data->pvd.pv_on_disk.size;
uint64_t pos = data->pvd.pv_on_disk.base;
size_t size = data->pvd.pv_on_disk.size;
if (size < sizeof(struct pv_disk)) {
log_error("Invalid PV structure size.");
@@ -561,7 +581,7 @@ static int _write_pvd(struct disk_list *data)
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
_xlate_pvd((struct pv_disk *) buf);
if (dev_write(data->dev, pos, size, buf) != size) {
if (!dev_write(data->dev, pos, size, buf)) {
dbg_free(buf);
fail;
}
@@ -573,7 +593,8 @@ static int _write_pvd(struct disk_list *data)
/*
* assumes the device has been opened.
*/
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
static int __write_all_pvd(const struct format_type *fmt,
struct disk_list *data)
{
const char *pv_name = dev_name(data->dev);
@@ -582,19 +603,19 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
return 0;
}
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt);
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
/*
* Stop here for orphan pv's.
*/
if (data->pvd.vg_name[0] == '\0') {
if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt);
/* 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 (!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);
@@ -622,11 +643,11 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
/*
* opens the device and hands to the above fn.
*/
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
{
int r;
if (!dev_open(data->dev, O_WRONLY)) {
if (!dev_open(data->dev)) {
stack;
return 0;
}
@@ -644,7 +665,7 @@ static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
* little sanity checking, so make sure correct
* data is passed to here.
*/
int write_disks(struct format_type *fmt, struct list *pvs)
int write_disks(const struct format_type *fmt, struct list *pvs)
{
struct list *pvh;
struct disk_list *dl;

View File

@@ -11,20 +11,18 @@
#include "metadata.h"
#include "pool.h"
#define SECTOR_SIZE 512
#define MAX_PV 256
#define MAX_LV 256
#define MAX_VG 99
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
#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_LE_TOTAL 65534 /* 2^16 - 2 */
#define MAX_PE_TOTAL ((uint32_t) -2)
#define LVM_BLK_MAJOR 58
#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
@@ -60,86 +58,84 @@
#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;
@@ -163,7 +159,6 @@ struct disk_list {
struct pe_disk *extents;
};
/*
* Layout constants.
*/
@@ -173,29 +168,26 @@ struct disk_list {
#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, uint64_t pe_start);
/*
* Low level io routines which read/write
* disk_lists.
*/
int read_pvd(struct device *dev, struct pv_disk *pvd);
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name);
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
struct dev_filter *filter,
struct pool *mem, struct list *results);
int write_disks(struct format_type *fmt, struct list *pvds);
int write_disks(const struct format_type *fmt, struct list *pvds);
/*
* Functions to translate to between disk and in
@@ -208,27 +200,21 @@ 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,
int partial);
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,
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 format_instance *fid, struct pool *mem,
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);
@@ -240,6 +226,7 @@ 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);
/* blech */
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
@@ -247,5 +234,4 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter);
#endif

View File

@@ -4,15 +4,19 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h"
#include "hash.h"
#include "limits.h"
#include "list.h"
#include "log.h"
#include "display.h"
#include "toolcontext.h"
#include "lvmcache.h"
#include "lvm1-label.h"
#include "format1.h"
#define FMT_LVM1_NAME "lvm1"
/* VG consistency checks */
static int _check_vgs(struct list *pvs, int *partial)
@@ -21,8 +25,9 @@ static int _check_vgs(struct list *pvs, int *partial)
struct disk_list *dl = NULL;
struct disk_list *first = NULL;
int pv_count = 0;
int exported = -1;
uint32_t pv_count = 0;
uint32_t exported = 0;
int first_time = 1;
*partial = 0;
@@ -34,8 +39,9 @@ static int _check_vgs(struct list *pvs, int *partial)
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
if (exported < 0) {
if (first_time) {
exported = dl->pvd.pv_status & VG_EXPORTED;
first_time = 0;
continue;
}
@@ -60,6 +66,35 @@ static int _check_vgs(struct list *pvs, int *partial)
else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) {
log_error("VG data differs between PVs %s and %s",
dev_name(first->dev), dev_name(dl->dev));
log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
PRIu32 " %" PRIu32 " %" PRIu32,
dev_name(first->dev), first->vgd.vg_uuid,
first->vgd.vg_name_dummy,
first->vgd.vg_number, first->vgd.vg_access,
first->vgd.vg_status, first->vgd.lv_max,
first->vgd.lv_cur, first->vgd.lv_open,
first->vgd.pv_max, first->vgd.pv_cur,
first->vgd.pv_act, first->vgd.dummy,
first->vgd.vgda, first->vgd.pe_size,
first->vgd.pe_total, first->vgd.pe_allocated,
first->vgd.pvg_total);
log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
PRIu32 " %" PRIu32 " %" PRIu32,
dev_name(dl->dev), dl->vgd.vg_uuid,
dl->vgd.vg_name_dummy, dl->vgd.vg_number,
dl->vgd.vg_access, dl->vgd.vg_status,
dl->vgd.lv_max, dl->vgd.lv_cur,
dl->vgd.lv_open, dl->vgd.pv_max,
dl->vgd.pv_cur, dl->vgd.pv_act, dl->vgd.dummy,
dl->vgd.vgda, dl->vgd.pe_size,
dl->vgd.pe_total, dl->vgd.pe_allocated,
dl->vgd.pvg_total);
list_del(pvh);
if (partial_mode()) {
*partial = 1;
@@ -71,9 +106,9 @@ static int _check_vgs(struct list *pvs, int *partial)
}
/* On entry to fn, list known to be non-empty */
if (pv_count != dl->vgd.pv_cur) {
if (pv_count != first->vgd.pv_cur) {
log_error("%d PV(s) found for VG %s: expected %d",
pv_count, dl->pvd.vg_name, dl->vgd.pv_cur);
pv_count, first->pvd.vg_name, first->vgd.pv_cur);
if (!partial_mode())
return 0;
*partial = 1;
@@ -113,7 +148,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
if (!import_vg(mem, vg, dl, partial))
goto bad;
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count))
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
goto bad;
if (!import_lvs(mem, vg, pvs))
@@ -134,7 +169,8 @@ static struct volume_group *_build_vg(struct format_instance *fid,
}
static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name, void *mda)
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
@@ -185,8 +221,7 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
if (!export_pv(mem, vg, &dl->pvd, pv) ||
!export_vg(&dl->vgd, vg) ||
!export_uuids(dl, vg) ||
!export_lvs(dl, vg, pv, dev_dir) ||
!calculate_layout(dl)) {
!export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
stack;
pool_free(mem, dl);
return NULL;
@@ -227,7 +262,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
}
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
void *mdl)
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvds;
@@ -243,26 +278,28 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
fid->fmt->cmd->filter) &&
write_disks(fid->fmt, &pvds));
lvmcache_update_vg(vg);
pool_destroy(mem);
return r;
}
int _pv_read(struct format_type *fmt, const char *name,
struct physical_volume *pv)
static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct disk_list *dl;
struct device *dev;
int r = 0;
log_very_verbose("Reading physical volume data %s from disk", name);
log_very_verbose("Reading physical volume data %s from disk", pv_name);
if (!mem) {
stack;
return 0;
}
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) {
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
stack;
goto out;
}
@@ -277,7 +314,7 @@ int _pv_read(struct format_type *fmt, const char *name,
goto out;
}
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL);
pv->fmt = fmt;
r = 1;
@@ -286,144 +323,42 @@ int _pv_read(struct format_type *fmt, const char *name,
return r;
}
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
static int _pv_setup(const struct format_type *fmt,
uint64_t pe_start, uint32_t extent_count,
uint32_t extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas,
struct physical_volume *pv, struct volume_group *vg)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
uint32_t count;
if (!mem) {
stack;
return NULL;
}
list_init(&pvs);
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
stack;
goto bad;
}
pool_destroy(mem);
return results;
bad:
pool_destroy(mem);
return NULL;
}
static int _find_vg_name(struct list *names, const char *vg)
{
struct list *nh;
struct name_list *nl;
list_iterate(nh, names) {
nl = list_item(nh, struct name_list);
if (!strcmp(nl->name, vg))
return 1;
}
return 0;
}
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct list *pvh;
struct list *pvs;
struct name_list *nl;
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
log_error("PV list allocation failed");
goto err;
}
list_init(pvs);
if (!_get_pvs(fmt, pvs)) {
stack;
goto err;
}
list_iterate(pvh, pvs) {
struct pv_list *pvl = list_item(pvh, struct pv_list);
if (!(*pvl->pv->vg_name) ||
_find_vg_name(names, pvl->pv->vg_name))
continue;
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
goto err;
}
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
stack;
goto err;
}
list_add(names, &nl->list);
}
if (list_empty(names))
pool_free(fmt->cmd->mem, pvs);
return names;
err:
pool_free(fmt->cmd->mem, pvs);
return NULL;
}
static int _pv_setup(struct format_instance *fid, struct physical_volume *pv,
struct volume_group *vg)
{
/* setup operations for the PV structure */
if (pv->size > MAX_PV_SIZE)
pv->size--;
if (pv->size > MAX_PV_SIZE) {
/* FIXME Limit hardcoded */
log_error("Physical volumes cannot be bigger than 2TB");
log_error("Physical volumes cannot be bigger than %s",
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE / 2,
SIZE_SHORT));
return 0;
}
/* Nothing more to do if pe_size isn't known */
if (!vg)
/* Nothing more to do if extent size isn't provided */
if (!extent_size)
return 1;
/*
* This works out pe_start and pe_count.
*/
if (!calculate_extent_count(pv)) {
if (!calculate_extent_count(pv, extent_size, extent_count, pe_start)) {
stack;
return 0;
}
return 1;
}
static int _find_free_lvnum(struct logical_volume *lv)
{
int lvnum_used[MAX_LV];
int i = 0;
struct list *lvh;
struct lv_list *lvl;
memset(&lvnum_used, 0, sizeof(lvnum_used));
list_iterate(lvh, &lv->vg->lvs) {
lvl = list_item(lvh, struct lv_list);
lvnum_used[lvnum_from_lvid(&lvl->lv->lvid)] = 1;
/* Retain existing extent locations exactly */
if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
(extent_count && (extent_count != pv->pe_count))) {
log_error("Metadata would overwrite physical extents");
return 0;
}
while (lvnum_used[i])
i++;
return i;
return 1;
}
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
@@ -431,7 +366,7 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
uint64_t max_size = UINT_MAX;
if (!*lv->lvid.s)
lvid_from_lvnum(&lv->lvid, &lv->vg->id, _find_free_lvnum(lv));
lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv));
if (lv->le_count > MAX_LE_TOTAL) {
log_error("logical volumes cannot contain more than "
@@ -439,29 +374,36 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
return 0;
}
if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
dbg_free(dummy);
log_error("logical volumes cannot be larger than %s",
display_size(fid->fmt->cmd, max_size / 2,
SIZE_SHORT));
return 0;
}
return 1;
}
static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
void *mdl)
static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
struct list *mdas, int64_t sector)
{
struct pool *mem;
struct disk_list *dl;
struct list pvs;
struct label *label;
struct lvmcache_info *info;
list_init(&pvs);
if (*pv->vg_name || pv->pe_alloc_count) {
log_error("Assertion failed: can't _pv_write non-orphan PV "
"(in VG %s)", pv->vg_name);
if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
pv->vg_name, NULL))) {
stack;
return 0;
}
label = info->label;
info->device_size = pv->size << SECTOR_SHIFT;
info->fmt = fmt;
list_init(&info->mdas);
list_init(&pvs);
/* Ensure any residual PE structure is gone */
pv->pe_size = pv->pe_count = 0;
@@ -488,10 +430,10 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
dev_write in order to make other disk tools happy */
dl->pvd.pv_on_disk.base = METADATA_BASE;
dl->pvd.pv_on_disk.size = PV_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN * SECTOR_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
list_add(&pvs, &dl->list);
if (!write_disks(fid->fmt, &pvs)) {
if (!write_disks(fmt, &pvs)) {
stack;
goto bad;
}
@@ -504,32 +446,32 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
return 0;
}
int _vg_setup(struct format_instance *fid, struct volume_group *vg)
static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
{
/* just check max_pv and max_lv */
if (vg->max_lv >= MAX_LV)
if (!vg->max_lv || vg->max_lv >= MAX_LV)
vg->max_lv = MAX_LV - 1;
if (vg->max_pv >= MAX_PV)
if (!vg->max_pv || vg->max_pv >= MAX_PV)
vg->max_pv = MAX_PV - 1;
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
char *dummy, *dummy2;
log_error("Extent size must be between %s and %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE
/ 2,
SIZE_SHORT), display_size(fid->fmt->cmd,
(uint64_t)
MAX_PE_SIZE
/ 2,
SIZE_SHORT));
dbg_free(dummy);
dbg_free(dummy2);
return 0;
}
if (vg->extent_size % MIN_PE_SIZE) {
char *dummy;
log_error("Extent size must be multiple of %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
dbg_free(dummy);
display_size(fid->fmt->cmd,
(uint64_t) MIN_PE_SIZE / 2, SIZE_SHORT));
return 0;
}
@@ -542,8 +484,14 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
return 1;
}
struct format_instance *_create_instance(struct format_type *fmt,
const char *vgname, void *private)
static struct metadata_area_ops _metadata_format1_ops = {
vg_read:_vg_read,
vg_write:_vg_write,
};
static struct format_instance *_create_instance(const struct format_type *fmt,
const char *vgname,
void *private)
{
struct format_instance *fid;
struct metadata_area *mda;
@@ -563,38 +511,40 @@ struct format_instance *_create_instance(struct format_type *fmt,
return NULL;
}
mda->ops = &_metadata_format1_ops;
mda->metadata_locn = NULL;
list_add(&fid->metadata_areas, &mda->list);
return fid;
}
void _destroy_instance(struct format_instance *fid)
static void _destroy_instance(struct format_instance *fid)
{
return;
}
void _destroy(struct format_type *fmt)
static void _destroy(const struct format_type *fmt)
{
dbg_free(fmt);
dbg_free((void *) fmt);
}
static struct format_handler _format1_ops = {
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_setup: _vg_setup,
vg_write: _vg_write,
pv_read:_pv_read,
pv_setup:_pv_setup,
pv_write:_pv_write,
lv_setup:_lv_setup,
vg_setup:_vg_setup,
create_instance:_create_instance,
destroy_instance:_destroy_instance,
destroy: _destroy,
destroy:_destroy,
};
struct format_type *create_lvm1_format(struct cmd_context *cmd)
#ifdef LVM1_INTERNAL
struct format_type *init_lvm1_format(struct cmd_context *cmd)
#else /* Shared */
struct format_type *init_format(struct cmd_context *cmd);
struct format_type *init_format(struct cmd_context *cmd)
#endif
{
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
@@ -606,8 +556,19 @@ struct format_type *create_lvm1_format(struct cmd_context *cmd)
fmt->cmd = cmd;
fmt->ops = &_format1_ops;
fmt->name = FMT_LVM1_NAME;
fmt->features = 0;
fmt->alias = NULL;
fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE;
fmt->private = NULL;
if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
log_error("Couldn't create lvm1 label handler.");
return NULL;
}
if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
log_error("Couldn't register lvm1 label handler.");
return NULL;
}
return fmt;
}

View File

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

View File

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

View File

@@ -4,12 +4,12 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "pool.h"
#include "disk-rep.h"
#include "lv_alloc.h"
/*
* After much thought I have decided it is easier,
@@ -192,42 +192,33 @@ static int _check_maps_are_complete(struct hash_table *maps)
return 1;
}
static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
{
struct stripe_segment *seg;
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) {
stack;
return NULL;
}
return seg;
}
static int _read_linear(struct pool *mem, struct lv_map *lvm)
{
uint32_t le = 0;
struct stripe_segment *seg;
struct lv_segment *seg;
while (le < lvm->lv->le_count) {
seg = _alloc_seg(mem, 1);
seg = alloc_lv_segment(mem, 1);
seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
seg->le = le;
seg->len = 0;
seg->area_len = 0;
seg->stripe_size = 0;
seg->stripes = 1;
seg->area_count = 1;
seg->area[0].pv = lvm->map[le].pv;
seg->area[0].pe = lvm->map[le].pe;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = lvm->map[le].pv;
seg->area[0].u.pv.pe = lvm->map[le].pe;
do
do {
seg->len++;
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
(lvm->map[le + seg->len].pe == seg->area[0].pe +
seg->len));
seg->area_len++;
} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
(seg->area[0].u.pv.pv &&
lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
seg->len));
le += seg->len;
@@ -237,7 +228,7 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
return 1;
}
static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
uint32_t base_le, uint32_t len)
{
uint32_t le, st;
@@ -247,9 +238,11 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
/*
* Is the next physical extent in every stripe adjacent to the last?
*/
for (st = 0; st < seg->stripes; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].pv) ||
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
for (st = 0; st < seg->area_count; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
(seg->area[st].u.pv.pv &&
lvm->map[le + st * len].pe !=
seg->area[st].u.pv.pe + seg->len))
return 0;
return 1;
@@ -258,7 +251,7 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
{
uint32_t st, le = 0, len;
struct stripe_segment *seg;
struct lv_segment *seg;
/*
* Work out overall striped length
@@ -271,34 +264,38 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
len = lvm->lv->le_count / lvm->stripes;
while (le < len) {
if (!(seg = _alloc_seg(mem, lvm->stripes))) {
if (!(seg = alloc_lv_segment(mem, lvm->stripes))) {
stack;
return 0;
}
seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
seg->stripe_size = lvm->stripe_size;
seg->stripes = lvm->stripes;
seg->le = seg->stripes * le;
seg->area_count = lvm->stripes;
seg->le = seg->area_count * le;
seg->len = 1;
seg->area_len = 1;
/*
* Set up start positions of each stripe in this segment
*/
for (st = 0; st < seg->stripes; st++) {
seg->area[st].pv = lvm->map[le + st * len].pv;
seg->area[st].pe = lvm->map[le + st * len].pe;
for (st = 0; st < seg->area_count; st++) {
seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
}
/*
* Find how many blocks are contiguous in all stripes
* and so can form part of this segment
*/
while (_check_stripe(lvm, seg, le, len))
while (_check_stripe(lvm, seg, le, len)) {
seg->len++;
seg->area_len++;
}
le += seg->len;
seg->len *= seg->stripes;
seg->len *= seg->area_count;
list_add(&lvm->lv->segments, &seg->list);
}

View File

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "lvm-string.h"
@@ -14,14 +14,15 @@
* converted into arrays of strings.
*/
struct flag {
int mask;
char *description;
const int mask;
const char *description;
};
static struct flag _vg_flags[] = {
{EXPORTED_VG, "EXPORTED"},
{RESIZEABLE_VG, "RESIZEABLE"},
{PARTIAL_VG, "PARTIAL"},
{PVMOVE, "PVMOVE"},
{LVM_READ, "READ"},
{LVM_WRITE, "WRITE"},
{CLUSTERED, "CLUSTERED"},
@@ -38,10 +39,10 @@ static struct flag _pv_flags[] = {
static struct flag _lv_flags[] = {
{LVM_READ, "READ"},
{LVM_WRITE, "WRITE"},
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
{ALLOC_STRICT, "ALLOC_STRICT"},
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
{FIXED_MINOR, "FIXED_MINOR"},
{VISIBLE_LV, "VISIBLE"},
{PVMOVE, "PVMOVE"},
{LOCKED, "LOCKED"},
{0, NULL}
};
@@ -62,23 +63,6 @@ static struct flag *_get_flags(int type)
return NULL;
}
static int _emit(char **buffer, size_t * size, const char *fmt, ...)
{
size_t n;
va_list ap;
va_start(ap, fmt);
n = vsnprintf(*buffer, *size, fmt, ap);
va_end(ap);
if (n < 0 || (n == *size))
return 0;
*buffer += n;
*size -= n;
return 1;
}
/*
* Converts a bitset to an array of string values,
* using one of the tables defined at the top of
@@ -94,27 +78,27 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
return 0;
}
if (!_emit(&buffer, &size, "["))
if (!emit_to_buffer(&buffer, &size, "["))
return 0;
for (f = 0; flags[f].mask; f++) {
if (status & flags[f].mask) {
if (!first) {
if (!_emit(&buffer, &size, ", "))
if (!emit_to_buffer(&buffer, &size, ", "))
return 0;
} else
first = 0;
if (!_emit(&buffer, &size, "\"%s\"",
flags[f].description))
if (!emit_to_buffer(&buffer, &size, "\"%s\"",
flags[f].description))
return 0;
status &= ~flags[f].mask;
}
}
if (!_emit(&buffer, &size, "]"))
if (!emit_to_buffer(&buffer, &size, "]"))
return 0;
if (status)
@@ -124,7 +108,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
return 1;
}
int read_flags(uint32_t * status, int type, struct config_value *cv)
int read_flags(uint32_t *status, int type, struct config_value *cv)
{
int f;
uint32_t s = 0;
@@ -135,6 +119,9 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
return 0;
}
if (cv->type == CFG_EMPTY_ARRAY)
goto out;
while (cv) {
if (cv->type != CFG_STRING) {
log_err("Status value is not a string.");
@@ -155,6 +142,7 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
cv = cv->next;
}
out:
*status = s;
return 1;
}

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,8 +9,10 @@
#include "uuid.h"
#include "config.h"
int init_locking(int type, struct config_file *cf);
int init_locking(int type, struct config_tree *cf);
void fin_locking(void);
void reset_locking(void);
int vg_write_lock_held(void);
/*
* LCK_VG:
@@ -24,31 +26,36 @@ void fin_locking(void);
*/
int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
/*
* Does the LVM1 driver have this VG active?
*/
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
/*
* Lock type - these numbers are the same as VMS and the IBM DLM
*/
#define LCK_TYPE_MASK 0x000000FF
#define LCK_TYPE_MASK 0x00000007
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */
/* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000010 /* This is ours */
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */
/* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000006 /* This is ours */
/*
* Lock scope
*/
#define LCK_SCOPE_MASK 0x0000FF00
#define LCK_SCOPE_MASK 0x00000008
#define LCK_VG 0x00000000
#define LCK_LV 0x00000100
#define LCK_LV 0x00000008
/*
* Lock bits
*/
#define LCK_NONBLOCK 0x00010000 /* Don't block waiting for lock? */
#define LCK_HOLD 0x00020000 /* Hold lock when lock_vol returns? */
#define LCK_NONBLOCK 0x00000010 /* Don't block waiting for lock? */
#define LCK_HOLD 0x00000020 /* Hold lock when lock_vol returns? */
/*
* Common combinations
@@ -64,4 +71,3 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)

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