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

Compare commits

...

87 Commits

Author SHA1 Message Date
Alasdair Kergon
e2adc28cff Only functions listed in libdevmapper.h should get exported. 2002-11-14 19:26:28 +00:00
Alasdair Kergon
0fef6a6ecc Fix includes after DM_DIR definition move. 2002-11-14 14:44:42 +00:00
Alasdair Kergon
f2fd4b8a1f Don't let LVM2 access a VG if the original LVM driver appears to be using it. 2002-11-01 19:57:25 +00:00
Alasdair Kergon
95bd5605a8 Improve missing-kernel-driver error message. 2002-11-01 16:16:42 +00:00
Andres Salomon
497cca7eca agk, I recall you saying you had a massive commit pending; if you need me
to back this out so you can do that commit, let me know.  Also, if there's
an issue with the error message that's displayed, just change it in tools.h.

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

   typedef enum {
        ALLOC_NEXT_FREE,
        ALLOC_STRICT,
        ALLOC_CONTIGUOUS
   } alloc_policy_t;

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

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

ii) Updated the text format so this also has the alloc_policy field.
2002-07-11 14:21:49 +00:00
Alasdair Kergon
1ee3e7997e tidy 2002-07-11 14:09:26 +00:00
Alasdair Kergon
50fd61d91f Add get_config_str 2002-07-11 14:07:43 +00:00
Patrick Caulfield
e4cdc051a9 Don't log an error if we can't write the cache file because the FS is read-only.
Gets rid of that annoying error at shutdown.
2002-07-11 09:23:29 +00:00
Alasdair Kergon
778e846e96 Add --ignorelockingfailure 2002-07-10 20:43:32 +00:00
Alasdair Kergon
a27759b647 Merge adjacent "Missing" segments. 2002-07-10 13:54:17 +00:00
Joe Thornber
b75eceab41 o Add version number to text format. 2002-07-02 18:47:43 +00:00
Alasdair Kergon
e748a5d5f4 Tidy up for another release: updated documentation; removed old files;
module build fix.
2002-06-26 21:50:53 +00:00
Patrick Caulfield
99c5a3ae46 Flush on open as well as close. 2002-06-25 14:02:28 +00:00
Alasdair Kergon
51da710f5a o Long-awaited ioctl interface clean-up. *** Not backwardly compatible ***
o Various other kernel side tidy-ups.
o Version number changes so we have the option of adding new ioctl commands
  in future without affecting the use of existing ones should you later
  revert to an older kernel but not revert the userspace library/tools.
o Better separation of kernel/userspace elements in the build process to
  prepare for independent distribution of the kernel driver.
2002-06-19 13:07:05 +00:00
Joe Thornber
569d69b3d2 o Knock the version check out of the makefile, Alasdair will no doubt put it back :)
o  Change to new ioctl names.
2002-06-17 15:50:17 +00:00
Patrick Caulfield
059a6b1d90 Get rid of compile warnings on 64bit platforms. 2002-06-07 08:37:07 +00:00
Alasdair Kergon
990af7548a Increment version. 2002-05-31 19:33:30 +00:00
Alasdair Kergon
a38aefdfc8 Add vgsplit. 2002-05-31 19:30:51 +00:00
Alasdair Kergon
3bcb12e7d1 Tidy/fix segment rounding. 2002-05-31 19:29:43 +00:00
Alasdair Kergon
7904ecb462 Tidy 2002-05-31 19:28:37 +00:00
Alasdair Kergon
9ba4d45109 Remember to update VG free_count when reducing size of an LV. 2002-05-30 16:08:19 +00:00
Alasdair Kergon
56b8afe19d Fix vgcfgrestore segfault (wrong variable used). 2002-05-30 16:03:26 +00:00
Alasdair Kergon
f7aed9a94c update 2002-05-27 13:00:18 +00:00
AJ Lewis
e12a7e881d o fix changed function names 2002-05-23 14:13:21 +00:00
Alasdair Kergon
5afb65325d Fix LVM1 backwards compatibility issue when LV with a low LV number is deleted. 2002-05-23 11:37:51 +00:00
Joe Thornber
135f520f32 o Remove ext3 incompatibility bug
o	Mention 2.4.18 VM problem
2002-05-23 08:20:44 +00:00
Andres Salomon
bc251f4ff6 update for .08 2002-05-23 07:49:25 +00:00
Alasdair Kergon
b8769751f6 Rename; add some FIXMEs. 2002-05-22 14:03:45 +00:00
Alasdair Kergon
eff96d839e Revert to standard linux macros (for correct behaviour on rare architectures). 2002-05-21 12:37:07 +00:00
Alasdair Kergon
aa34c23807 Update version. 2002-05-21 12:14:05 +00:00
Andres Salomon
195acdac8c ack, missing include 2002-05-19 04:11:34 +00:00
Andres Salomon
903e03c56c update create_dir() comment 2002-05-19 03:52:38 +00:00
Andres Salomon
0892767b8a support recursive mkdir in create_dir() 2002-05-19 03:46:34 +00:00
Andres Salomon
83ebfa772c synch w/ -3 "oh shit" release 2002-05-14 03:56:40 +00:00
Joe Thornber
1583641322 Drop the default chunk size for snapshots down to 8k 2002-05-13 15:14:21 +00:00
Alasdair Kergon
9510e2c256 Rewrite missing/corrupt metadata in more cases. 2002-05-13 12:38:54 +00:00
AJ Lewis
a9dbabe07e o the _status fxns now take more arguments - this way i don't get the
preparsed status info, shove it all into a string, and then parse it
   again to get the info back out (which is what i was doing before)
 o basically that's it...i like this *much* better than the previous
   method and i think it makes the _status fxn more flexible if we need
   to use it to get other info out.
2002-05-10 16:06:06 +00:00
Alasdair Kergon
12884008fa Import snapshot status & persistence + indent etc. 2002-05-10 15:25:38 +00:00
AJ Lewis
02543bad1c o Actually read snapshot percentage from the kernel - what a pain! :)
o Not sure if the code in dev_manager is really optimal, but it works..
   will look at adjusting it a bit now.
 o I *think* it works right when one snapshot if full but others aren't,
   but I haven't really been able to test it because the full snapshot
   somehow resets itself and weird things start happening to the system...
2002-05-09 21:17:57 +00:00
Alasdair Kergon
a8c56a5251 Remove a no-op. 2002-05-09 12:03:55 +00:00
AJ Lewis
4e5a855f3f o header should only be printed once... 2002-05-08 17:58:52 +00:00
AJ Lewis
7e497a951e o Added function find_snapshots to snapshot_manip.c that returns a list
of snapshots whose origin is the lv passed in.
 o Used this new function to make lvdisplay properly display all snapshots
   attached to a origin.
2002-05-08 16:57:46 +00:00
Joe Thornber
cd08eabbfa i) Put back chunksize_ARG for lvcreate. 2002-05-08 14:36:10 +00:00
Alasdair Kergon
f7e62d9f81 Always call init_log() to initialise logging defaults. 2002-05-08 12:26:45 +00:00
Andres Salomon
9a3761e86e implement our own swabbing functions, instead of relying on the kernel's. 2002-05-07 15:28:59 +00:00
Alasdair Kergon
3619a68693 log/{prefix,command_names} use defaults.h & reset between shell cmds 2002-05-07 13:00:01 +00:00
Alasdair Kergon
efaf3c3bf9 Default values for some display output settings 2002-05-07 12:50:01 +00:00
Alasdair Kergon
0e4e6a6f67 Tweaks 2002-05-07 12:47:11 +00:00
Andres Salomon
42458e6278 updated. 2002-05-07 06:13:03 +00:00
Andres Salomon
41ec995377 Make lvm2 compile on big endian archs; use the kernel/glibc's endian
conversion stuff, instead of implementing our own.  Tested on a little
endian system (x86); I'll let the debian handle big endian testing.  :)
2002-05-07 05:54:14 +00:00
AJ Lewis
4f37599326 o Will now correctly remove expired achive files from the system when
archive_vg is called.
 o Added a #define to the top of the file - not sure if this is the
   appropriate place for it though
2002-05-03 19:28:07 +00:00
Patrick Caulfield
4144520e5c Add features to get table/status & wait for next event. 2002-05-03 11:55:58 +00:00
Andres Salomon
6c4800546c forgot to add Conflicts against lvm1 packages 2002-05-03 04:57:49 +00:00
Andres Salomon
733733c8a7 updated for 0.95.05-2. 2002-05-03 04:43:46 +00:00
Andres Salomon
2aa67cc946 ditto 2002-05-03 04:43:24 +00:00
Andres Salomon
9385981a9d dh_installinit makes a perfectly find postrm script.. 2002-05-03 04:13:02 +00:00
Alasdair Kergon
fff780035d Update. 2002-04-30 17:13:43 +00:00
Alasdair Kergon
46127e673d Some partial VG support with format_text. 2002-04-30 17:12:37 +00:00
Alasdair Kergon
70df59b224 get_vgs must check for text format VGs when no lvm1 format VGs present 2002-04-30 12:27:13 +00:00
AJ Lewis
0fdbaa803f o Updated *display output for LVM1 compatibility
o There is still a bit missing
   + all are missing the {PV,VG,LV} # - that is not applicable in LVM2
   + pvdisplay doesn't show how many LVs are contained on it
   + much of the snapshot information isn't available for lvdisplay
 o Look at the code for other potiential FIXMEs  :)
2002-04-29 21:43:14 +00:00
Heinz Mauelshagen
6af1830eff Changed DEFAULT_PV and DEFAULT_LV to 256 (has been fixed in LVM1 before) 2002-04-25 10:53:58 +00:00
Andres Salomon
6f860e2bd5 Updated for new release 2002-04-25 06:12:07 +00:00
Alasdair Kergon
20a492f7ee Update example config 2002-04-24 18:41:02 +00:00
Alasdair Kergon
63875e7591 Merge with text format branch.
Lots of changes/very little testing so far => there'll be bugs!

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

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

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

Plenty of refinements still in the pipeline.
2002-04-24 18:20:51 +00:00
Patrick Caulfield
0ad98cabde add setlocale() call so that localisation of things like number entry
and display will work correctly.
2002-04-24 10:42:09 +00:00
Joe Thornber
668879d2e1 o Stop printing errors if flushing fails (could be an unconfigured device). 2002-04-24 08:37:34 +00:00
129 changed files with 4300 additions and 2361 deletions

3
BUGS
View File

@@ -1 +1,2 @@
LVM2's device-mapper driver and ext3 are incompatible at the moment.
Snapshots under 2.4.18 can deadlock due to a bug in the VM system.
2.4.19-pre8 is fine.

View File

@@ -1 +1 @@
0.95.05-cvs (2002-04-23)
1.95.10-cvs (2002-05-31)

36
debian/changelog vendored
View File

@@ -1,3 +1,39 @@
lvm2 (1.95.10-2) unstable; urgency=low
* Fix software raid problems by ensuring lvm init script runs after
raidtools init script. (Closes: #152569)
-- Andres Salomon <dilinger@mp3revolution.net> Tue, 3 Sep 2002 04:05:43 -0400
lvm2 (1.95.10-1) unstable; urgency=low
* New upstream release (Beta 3.2).
* Change all references to /dev/device-mapper/control to
/dev/mapper/control.
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 1 Sep 2002 18:55:12 -0400
lvm2 (0.95.05-3) unstable; urgency=low
* Get rid of awk dependency in init script. (Closes: #146257)
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 12 May 2002 04:39:06 -0500
lvm2 (0.95.05-2) unstable; urgency=low
* Use ${shlibs:Depends} in Depends.
* Get rid of postinst/postrm scripts, use debhelper's init script instead.
* Add Conflicts against lvm10, lvm-common.
* Fix endian issues on big-endian machines.
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 2 May 2002 23:53:53 -0500
lvm2 (0.95.05-1) unstable; urgency=low
* New release (Beta2).
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 25 Apr 2002 00:37:41 -0500
lvm2 (0.95.04cvs20020306-1) unstable; urgency=low
* CVS updated.

5
debian/control vendored
View File

@@ -2,12 +2,13 @@ Source: lvm2
Section: admin
Priority: optional
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
Standards-Version: 3.5.2
Package: lvm2
Architecture: any
Depends: libdevmapper0
Depends: ${shlibs:Depends}
Conflicts: lvm10, lvm-common
Replaces: lvm10, lvm-common
Provides: lvm-binaries
Suggests: dmsetup

4
debian/docs vendored
View File

@@ -3,6 +3,4 @@ INTRO
README
TODO
VERSION
doc/example.conf
doc/pvmove_outline.txt
doc/testing.txt
doc/*

9
debian/init.d vendored
View File

@@ -14,10 +14,10 @@ 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=$(awk '$2 ~ /^misc$/ {print $1}' /proc/devices)
minor=$(awk "\$2 ~ /^$DM_NAME\$/ {print \$1}" /proc/misc)
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
if test ! -d $DIR; then
mkdir --mode=755 $DIR >/dev/null 2>&1
@@ -56,8 +56,7 @@ case "$1" in
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac

49
debian/postinst vendored
View File

@@ -1,49 +0,0 @@
#! /bin/sh
# postinst script for lvm2
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
#
# quoting from the policy:
# Any necessary prompting should almost always be confined to the
# post-installation script, and should be protected with a conditional
# so that unnecessary prompting doesn't happen if a package's
# installation fails and the `postinst' is called with `abort-upgrade',
# `abort-remove' or `abort-deconfigure'.
case "$1" in
configure)
update-rc.d lvm2 start 25 S . start 50 0 6 . >/dev/null
/etc/init.d/lvm2 start
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

39
debian/postrm vendored
View File

@@ -1,39 +0,0 @@
#! /bin/sh
# postrm script for lvm2
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge)
rm -f /etc/init.d/lvm2
update-rc.d lvm2 remove >/dev/null
;;
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

2
debian/rules vendored
View File

@@ -98,7 +98,7 @@ binary-arch: build install
# dh_installemacsen -a
# dh_installpam -a
# dh_installmime -a
dh_installinit -n
dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
dh_installcron
dh_installman
dh_installinfo

View File

@@ -22,7 +22,6 @@ 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.
# Remember to run vgscan after you change this parameter.
@@ -35,6 +34,9 @@ devices {
# Or maybe all loops and ide drives except hdc:
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
# Use anchors if you want to be really specific
# filter = ["a|^/dev/hda8$|", "r/.*/"]
# The results of all 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
@@ -122,6 +124,12 @@ shell {
history_size = 100
}
# Metadata settings
metadata {
# List of directories holding copies of text format metadata
dirs = [ "/etc/lvm/metadata" ]
}
# Miscellaneous global settings
global {
@@ -136,4 +144,11 @@ global {
# will be made. Equivalent to having the -t option on every
# command. Defaults to off.
test = 0
# Default metadata format commands use - "lvm1" (default) or "text"
format = "lvm1"
# Location of proc filesystem
proc = "/proc"
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "ll-activate.h"
#include "lvm-string.h"
#include "log.h"
#include <libdevmapper.h>
/*
* Emit a target for a given segment.
* FIXME: tidy this function.
*/
static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
{
char params[1024];
uint64_t esize = seg->lv->vg->extent_size;
uint32_t s, stripes = seg->stripes;
int w = 0, tw = 0, error = 0;
const char *no_space =
"Insufficient space to write target parameters.";
char *filler = "/dev/ioerror";
char *target;
if (stripes == 1) {
if (!seg->area[0].pv) {
target = "error";
error = 1;
}
else
target = "linear";
}
if (stripes > 1) {
target = "striped";
tw = lvm_snprintf(params, sizeof(params), "%u %u ",
stripes, seg->stripe_size);
if (tw < 0) {
log_err(no_space);
return 0;
}
w = tw;
}
if (!error) {
for (s = 0; s < stripes; s++, w += tw) {
if (!seg->area[s].pv)
tw = lvm_snprintf(
params + w, sizeof(params) - w,
"%s 0%s", filler,
s == (stripes - 1) ? "" : " ");
else
tw = lvm_snprintf(
params + w, sizeof(params) - w,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].pv->dev),
(seg->area[s].pv->pe_start +
(esize * seg->area[s].pe)),
s == (stripes - 1) ? "" : " ");
if (tw < 0) {
log_err(no_space);
return 0;
}
}
}
log_very_verbose("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
esize * seg->le, esize * seg->len,
target, params);
if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len,
target, params)) {
stack;
return 0;
}
return 1;
}
int device_populate_lv(struct dm_task *dmt, struct logical_volume *lv)
{
struct list *segh;
struct stripe_segment *seg;
log_very_verbose("Generating devmapper table for %s", lv->name);
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
if (!_emit_target(dmt, seg)) {
log_error("Unable to build table for '%s'", lv->name);
return 0;
}
}
return 1;
}

View File

@@ -75,6 +75,27 @@ int lv_info(struct logical_volume *lv, struct dm_info *info)
return r;
}
/*
* Returns 1 if percent set, else 0 on failure.
*/
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
{
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
}
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
stack;
dev_manager_destroy(dm);
return r;
}
static int _lv_active(struct logical_volume *lv)
{
struct dm_info info;
@@ -189,24 +210,18 @@ static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
struct lv_list *lvl;
struct volume_group *vg;
union lvid *lvid;
char *vgname;
lvid = (union lvid *) lvid_s;
/* FIXME Change vgread to accept vgid directly - can't rely on cache */
if (!(vgname = vgname_from_vgid(cmd, &lvid->id[0]))) {
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("Finding volume group \"%s\"", vgname);
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, vgname))) {
log_error("Volume group \"%s\" doesn't exist", vgname);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vgname);
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}

View File

@@ -16,6 +16,10 @@ 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_percent(struct logical_volume *lv, float *percent);
/*
* These should eventually use config file

View File

@@ -329,6 +329,69 @@ static int _info(const char *name, const char *uuid, struct dm_info *info,
return 0;
}
/* FIXME Interface must cope with multiple targets */
static int _status_run(const char *name, const char *uuid,
unsigned long long *s, unsigned long long *l,
char **t, uint32_t t_size, char **p, uint32_t p_size)
{
int r = 0;
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *type = NULL;
char *params = NULL;
if (!(dmt = _setup_task(name, uuid, DM_DEVICE_STATUS))) {
stack;
return 0;
}
if (!dm_task_run(dmt)) {
stack;
goto out;
}
do {
next = dm_get_next_target(dmt, next, &start, &length,
&type, &params);
if (type) {
*s = start;
*l = length;
/* Make sure things are null terminated */
strncpy(*t, type, t_size);
(*t)[t_size - 1] = '\0';
strncpy(*p, params, p_size);
(*p)[p_size - 1] = '\0';
r = 1;
/* FIXME Cope with multiple targets! */
break;
}
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
static int _status(const char *name, const char *uuid,
unsigned long long *start, unsigned long long *length,
char **type, uint32_t type_size, char **params,
uint32_t param_size)
{
if (uuid && *uuid && _status_run(NULL, uuid, start, length, type,
type_size, params, param_size)
&& *params)
return 1;
if (name && _status_run(name, NULL, start, length, type, type_size,
params, param_size))
return 1;
return 0;
}
static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname)
{
int r = 1;
@@ -538,7 +601,7 @@ static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
}
for (s = 0; s < stripes; s++, w += tw) {
if (!seg->area[s].pv)
if (!seg->area[s].pv || !seg->area[s].pv->dev)
tw = lvm_snprintf(params + w, sizeof(params) - w,
"%s 0%s", filler,
s == (stripes - 1) ? "" : " ");
@@ -640,7 +703,7 @@ static int _populate_snapshot(struct dev_manager *dm,
return 0;
}
if (snprintf(params, sizeof(params), "%s/%s %s/%s P %d 128",
if (snprintf(params, sizeof(params), "%s/%s %s/%s P %d",
dm_dir(), origin, dm_dir(), cow, s->chunk_size) == -1) {
stack;
return 0;
@@ -729,6 +792,56 @@ int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
return 1;
}
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent)
{
char *name, *type, *params;
unsigned long long start, length;
/* FIXME: Use #defines - & move allocations into _status_run ? */
uint32_t type_size = 32;
uint32_t param_size = 32;
if (!(type = pool_alloc(dm->mem, sizeof(*type) * type_size))) {
stack;
return 0;
}
if (!(params = pool_alloc(dm->mem, sizeof(*params) * param_size))) {
stack;
return 0;
}
/*
* Build a name for the top layer.
*/
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
stack;
return 0;
}
/*
* Try and get some info on this device.
*/
log_debug("Getting device status for %s", name);
if (!(_status(name, lv->lvid.s, &start, &length, &type, type_size,
&params, param_size))) {
stack;
return 0;
}
/* FIXME Ensure this is a *snapshot* target with percentage! */
/* FIXME pool_free ? */
/* If the snapshot isn't available, percent will be -1 */
*percent = -1;
if (!params)
return 0;
return sscanf(params, "%f", percent);
}
static struct dev_layer *_create_dev(struct dev_manager *dm, char *name,
char *dlid)
{
@@ -1413,8 +1526,9 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
/* Remove any snapshots with given origin */
list_iterate(sh, active_head) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && s->origin == lv)
if ((s = find_cow(active)) && s->origin == lv) {
_remove_lv(active_head, active);
}
}
_remove_lv(active_head, lv);
@@ -1427,8 +1541,9 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
/* Was this the last active snapshot with this origin? */
list_iterate(sh, active_head) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && s->origin == old_origin)
if ((s = find_cow(active)) && s->origin == old_origin) {
return 1;
}
}
return _add_lvs(dm->mem, &dm->reload_list, old_origin);

View File

@@ -27,11 +27,12 @@ void dev_manager_destroy(struct dev_manager *dm);
*/
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
struct dm_info *info);
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent);
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
/*
* Put the desired changes into effect.
*/

View File

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

View File

@@ -18,7 +18,11 @@ struct cmd_context {
/* format handler allocates all objects from here */
struct pool *mem;
struct format_instance *fid;
struct format_type *fmt; /* Current format to use by default */
/* FIXME Move into dynamic list */
struct format_type *fmt1; /* Format1 */
struct format_type *fmtt; /* Format_text */
char *cmd_line;
char *dev_dir;

View File

@@ -18,34 +18,34 @@
#include "log.h"
enum {
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_COMMA,
TOK_EOF
};
struct parser {
const char *fb, *fe; /* file limits */
const char *fb, *fe; /* file limits */
int t; /* token limits and type */
const char *tb, *te;
int t; /* token limits and type */
const char *tb, *te;
int fd; /* descriptor for file being parsed */
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
struct pool *mem;
struct pool *mem;
};
struct cs {
struct config_file cf;
struct pool *mem;
struct config_file cf;
struct pool *mem;
};
static void _get_token(struct parser *p);
@@ -68,7 +68,6 @@ static char *_dup_tok(struct parser *p);
} \
} while(0);
static int _tok_match(const char *str, const char *b, const char *e)
{
while (*str && (b != e)) {
@@ -79,88 +78,92 @@ static int _tok_match(const char *str, const char *b, const char *e)
return !(*str || (b != e));
}
/*
* public interface
*/
struct config_file *create_config_file(void)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
if (!mem) {
stack;
return 0;
}
if (!mem) {
stack;
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
}
c->mem = mem;
c->cf.root = (struct config_node *)NULL;
return &c->cf;
c->mem = mem;
c->cf.root = (struct config_node *) NULL;
return &c->cf;
}
void destroy_config_file(struct config_file *cf)
{
pool_destroy(((struct cs *) cf)->mem);
pool_destroy(((struct cs *) cf)->mem);
}
int read_config(struct config_file *cf, const char *file)
{
struct cs *c = (struct cs *) cf;
struct parser *p;
struct stat info;
int r = 1, fd;
struct parser *p;
struct stat info;
int r = 1, fd;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
p->mem = c->mem;
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
log_sys_error("stat", file);
return 0;
}
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
log_sys_error("stat", file);
return 0;
}
if ((fd = open(file, O_RDONLY)) < 0) {
log_sys_error("open", file);
return 0;
}
if (info.st_size == 0) {
log_verbose("%s is empty", file);
return 1;
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == MAP_FAILED) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
if ((fd = open(file, O_RDONLY)) < 0) {
log_sys_error("open", file);
return 0;
}
/* parse */
p->tb = p->te = p->fb;
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
}
close(fd);
return r;
close(fd);
return r;
}
static void _write_value(FILE *fp, struct config_value *v)
static void _write_value(FILE * fp, struct config_value *v)
{
switch (v->type) {
case CFG_STRING:
@@ -174,24 +177,31 @@ 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_err("Unknown value 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;
int i;
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
int i;
if (!n)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\0';
for (i = 0; i < l; i++)
space[i] = '\t';
space[i] = '\0';
while (n) {
fprintf(fp, "%s%s", space, n->key);
while (n) {
fprintf(fp, "%s%s", space, n->key);
if (!n->v) {
/* it's a sub section */
fprintf(fp, " {\n");
@@ -214,8 +224,8 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
_write_value(fp, v);
}
fprintf(fp, "\n");
n = n->sib;
}
n = n->sib;
}
/* FIXME: add error checking */
return 1;
}
@@ -223,17 +233,17 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
int write_config(struct config_file *cf, const char *file)
{
int r = 1;
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_error("open", file);
return 0;
}
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_error("open", file);
return 0;
}
if (!_write_config(cf->root, fp, 0)) {
if (!_write_config(cf->root, fp, 0)) {
stack;
r = 0;
}
fclose(fp);
fclose(fp);
return r;
}
@@ -260,7 +270,7 @@ static struct config_node *_file(struct parser *p)
static struct config_node *_section(struct parser *p)
{
/* IDENTIFIER '{' VALUE* '}' */
/* IDENTIFIER '{' VALUE* '}' */
struct config_node *root, *n, *l = NULL;
if (!(root = _create_node(p))) {
stack;
@@ -272,7 +282,7 @@ static struct config_node *_section(struct parser *p)
return 0;
}
match (TOK_IDENTIFIER);
match(TOK_IDENTIFIER);
if (p->t == TOK_SECTION_B) {
match(TOK_SECTION_B);
@@ -297,17 +307,17 @@ static struct config_node *_section(struct parser *p)
}
}
return root;
return root;
}
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
if (p->t == TOK_ARRAY_B) {
match (TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
/* '[' TYPE* ']' | TYPE */
struct config_value *h = NULL, *l, *ll = NULL;
if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
stack;
return 0;
}
@@ -321,48 +331,60 @@ static struct config_value *_value(struct parser *p)
if (p->t == TOK_COMMA)
match(TOK_COMMA);
}
match(TOK_ARRAY_E);
} else
match(TOK_ARRAY_E);
/*
* Special case an empty array.
*/
if (!h) {
if (!(h = _create_value(p)))
return NULL;
h->type = CFG_EMPTY_ARRAY;
}
} else
h = _type(p);
return h;
return h;
}
static struct config_value *_type(struct parser *p)
{
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p);
if (!v)
return NULL;
switch (p->t) {
case TOK_INT:
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
match(TOK_INT);
break;
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
match(TOK_FLOAT);
break;
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
match(TOK_FLOAT);
break;
case TOK_STRING:
case TOK_STRING:
v->type = CFG_STRING;
p->tb++, p->te--; /* strip "'s */
p->tb++, p->te--; /* strip "'s */
if (!(v->v.str = _dup_tok(p))) {
stack;
return 0;
}
p->te++;
match(TOK_STRING);
break;
match(TOK_STRING);
break;
default:
default:
log_error("Parse error at line %d: expected a value", p->line);
return 0;
}
return v;
return 0;
}
return v;
}
static int _match_aux(struct parser *p, int t)
@@ -379,106 +401,114 @@ static int _match_aux(struct parser *p, int t)
*/
static void _get_token(struct parser *p)
{
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
p->t = TOK_EOF;
return;
}
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
break;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
p->te++;
p->te++;
}
break;
if (p->te != p->fe)
p->te++;
break;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '.':
p->t = TOK_FLOAT;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
p->te++;
while (p->te != p->fe) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++;
}
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
}
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
p->te++;
p->te++;
}
if (p->te != p->fe)
p->te++;
break;
case '.':
p->t = TOK_FLOAT;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
p->te++;
while (p->te != p->fe) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++;
}
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
}
}
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
p->te++;
while (p->tb != p->fe) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*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) && isspace(*p->te)) {
if (*p->te == '\n')
p->line++;
p->te++;
p->te++;
}
}
else
return;
else
return;
p->tb = p->te;
}
p->tb = p->te;
}
}
/*
@@ -525,8 +555,7 @@ struct config_node *find_config_node(struct config_node *cn,
path++;
/* find the end of this segment */
for (e = path; *e && (*e != sep); e++)
;
for (e = path; *e && (*e != sep); e++) ;
/* hunt for the node */
while (cn) {
@@ -547,20 +576,20 @@ struct config_node *find_config_node(struct config_node *cn,
return cn;
}
const char *
find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
if (n && n->v->type == CFG_STRING) {
log_very_verbose("Setting %s to %s", path, n->v->v.str);
if (*n->v->v.str)
log_very_verbose("Setting %s to %s", path, n->v->v.str);
return n->v->v.str;
}
if (fail)
log_very_verbose("%s not found in config: defaulting to %s",
path, fail);
path, fail);
return fail;
}
@@ -574,7 +603,7 @@ int find_config_int(struct config_node *cn, const char *path,
return n->v->v.i;
}
log_very_verbose("%s not found in config: defaulting to %d",
log_very_verbose("%s not found in config: defaulting to %d",
path, fail);
return fail;
}
@@ -590,7 +619,7 @@ float find_config_float(struct config_node *cn, const char *path,
}
log_very_verbose("%s not found in config: defaulting to %f",
path, fail);
path, fail);
return fail;
@@ -609,8 +638,9 @@ static int _str_in_array(const char *str, const char *values[])
static int _str_to_bool(const char *str, int fail)
{
static const char *_true_values[] = {"y", "yes", "on", "true", NULL};
static const char *_false_values[] = {"n", "no", "off", "false", NULL};
static const char *_true_values[] = { "y", "yes", "on", "true", NULL };
static const char *_false_values[] =
{ "n", "no", "off", "false", NULL };
if (_str_in_array(str, _true_values))
return 1;
@@ -622,7 +652,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)
char sep, int fail)
{
struct config_node *n = find_config_node(cn, path, sep);
struct config_value *v;
@@ -644,7 +674,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)
char sep, uint32_t * result)
{
struct config_node *n;
@@ -658,7 +688,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)
char sep, uint64_t * result)
{
struct config_node *n;
@@ -672,3 +702,17 @@ int get_config_uint64(struct config_node *cn, const char *path,
return 1;
}
int get_config_str(struct config_node *cn, const char *path,
char 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

@@ -13,6 +13,7 @@ enum {
CFG_STRING,
CFG_FLOAT,
CFG_INT,
CFG_EMPTY_ARRAY
};
struct config_value {
@@ -68,5 +69,8 @@ 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);
int get_config_str(struct config_node *cn, const char *path,
char sep, char **result);
#endif

View File

@@ -26,6 +26,12 @@
#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
#endif

View File

@@ -12,7 +12,7 @@
/* 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;
@@ -33,7 +33,7 @@ void bitset_destroy(bitset_t bs)
void bit_union(bitset_t out, bitset_t in1, bitset_t in2)
{
int i;
for(i = (in1[0] / BITS_PER_INT) + 1; i; i--)
for (i = (in1[0] / BITS_PER_INT) + 1; i; i--)
out[i] = in1[i] | in2[i];
}
@@ -58,7 +58,7 @@ int bit_get_next(bitset_t bs, int last_bit)
last_bit++; /* otherwise we'll return the same bit again */
while(last_bit < bs[0]) {
while (last_bit < bs[0]) {
word = last_bit >> INT_SHIFT;
test = bs[word + 1];
bit = last_bit & (BITS_PER_INT - 1);
@@ -66,8 +66,8 @@ int bit_get_next(bitset_t bs, int last_bit)
if ((bit = _test_word(test, bit)) >= 0)
return (word * BITS_PER_INT) + bit;
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
BITS_PER_INT;
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
BITS_PER_INT;
}
return -1;

View File

@@ -40,8 +40,7 @@ static uint32_t _shuffle(uint32_t k)
#if 1
return ((k & 0xff) << 24 |
(k & 0xff00) << 8 |
(k & 0xff0000) >> 8 |
(k & 0xff000000) >> 24);
(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
#else
return k;
#endif

View File

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

View File

@@ -46,7 +46,6 @@ static struct {
} _cache;
#define _alloc(x) pool_alloc(_cache.mem, (x))
#define _free(x) pool_free(_cache.mem, (x))
@@ -194,7 +193,7 @@ static int _insert(const char *path, int rec)
return 0;
}
if (S_ISDIR(info.st_mode)) { /* add a directory */
if (S_ISDIR(info.st_mode)) { /* add a directory */
if (rec)
r = _insert_dir(path);
@@ -255,7 +254,7 @@ int dev_cache_init(void)
return 1;
bad:
bad:
dev_cache_exit();
return 0;
}
@@ -268,7 +267,7 @@ void _check_closed(struct device *dev)
static inline void _check_for_open_devices(void)
{
hash_iter(_cache.names, (iterate_fn)_check_closed);
hash_iter(_cache.names, (iterate_fn) _check_closed);
}
void dev_cache_exit(void)
@@ -313,8 +312,8 @@ const char *dev_name_confirmed(struct device *dev)
char *name;
int r;
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
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);
@@ -342,7 +341,6 @@ const char *dev_name_confirmed(struct device *dev)
return dev_name(dev);
}
struct device *dev_cache_get(const char *name, struct dev_filter *f)
{
struct stat buf;
@@ -399,4 +397,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
return NULL;
}

View File

@@ -13,9 +13,9 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h> // UGH!!! for BLKSSZGET
#include <linux/fs.h> // UGH!!! for BLKSSZGET
int dev_get_size(struct device *dev, uint64_t *size)
int dev_get_size(struct device *dev, uint64_t * size)
{
int fd;
long s;
@@ -39,7 +39,7 @@ int dev_get_size(struct device *dev, uint64_t *size)
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,6 +62,12 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
return 1;
}
static void _flush(int fd)
{
ioctl(fd, BLKFLSBUF, 0);
}
int dev_open(struct device *dev, int flags)
{
struct stat buf;
@@ -92,16 +98,12 @@ int dev_open(struct device *dev, int flags)
dev_close(dev);
return 0;
}
_flush(dev->fd);
dev->flags = 0;
return 1;
}
static void _flush(int fd)
{
if (ioctl(fd, BLKFLSBUF, 0))
log_error("couldn't flush device.");
}
int dev_close(struct device *dev)
{
if (dev->fd < 0) {
@@ -110,7 +112,8 @@ int dev_close(struct device *dev)
return 0;
}
_flush(dev->fd);
if (dev->flags & DEV_ACCESSED_W)
_flush(dev->fd);
if (close(dev->fd))
log_sys_error("close", dev_name(dev));
@@ -143,7 +146,7 @@ int _read(int fd, void *buf, size_t count)
return tot;
}
int64_t dev_read(struct device *dev, uint64_t offset,
int64_t dev_read(struct device * dev, uint64_t offset,
int64_t len, void *buffer)
{
const char *name = dev_name(dev);
@@ -186,7 +189,7 @@ int _write(int fd, const void *buf, size_t count)
return tot;
}
int64_t dev_write(struct device *dev, uint64_t offset,
int64_t dev_write(struct device * dev, uint64_t offset,
int64_t len, void *buffer)
{
const char *name = dev_name(dev);
@@ -202,6 +205,8 @@ int64_t dev_write(struct device *dev, uint64_t offset,
return 0;
}
dev->flags |= DEV_ACCESSED_W;
return _write(fd, buffer, len);
}
@@ -238,6 +243,8 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
}
}
dev->flags |= DEV_ACCESSED_W;
/* FIXME: Always display error */
return (len == 0);
}

View File

@@ -38,8 +38,6 @@
#include <linux/major.h>
#include <linux/genhd.h>
#if 0
int _get_partition_type(struct dev_filter *filter, struct device *d);

View File

@@ -10,6 +10,8 @@
#include "lvm-types.h"
#include "list.h"
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
/*
* All devices in LVM will be represented by one of these.
* pointer comparisons are valid.
@@ -20,6 +22,7 @@ struct device {
/* private */
int fd;
uint32_t flags;
};
struct device_list {
@@ -44,7 +47,8 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len);
static inline const char *dev_name(struct device *dev) {
return list_item(dev->aliases.n, struct str_list)->str;
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
"unknown device";
}
/* Return a valid device name from the alias list; NULL otherwise */

View File

@@ -79,12 +79,12 @@ void pvdisplay_colons(struct physical_volume *pv)
dev_name(pv->dev), pv->vg_name, pv->size,
/* FIXME pv->pv_number, Derive or remove? */
pv->status, /* FIXME Support old or new format here? */
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
/* FIXME pv->lv_cur, Remove? */
pv->pe_size / 2,
pv->pe_count,
pv->pe_count - pv->pe_allocated,
pv->pe_allocated, *uuid ? uuid : "none");
pv->pe_count - pv->pe_alloc_count,
pv->pe_alloc_count, *uuid ? uuid : "none");
return;
}
@@ -104,6 +104,18 @@ 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,
@@ -114,12 +126,14 @@ void pvdisplay_full(struct physical_volume *pv)
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
/ 2, SIZE_SHORT);
/******** FIXME display LVM on-disk data size
/******** FIXME display LVM on-disk data size - static for now...
size2 = display_size(pv->size / 2, SIZE_SHORT);
********/
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
size, size1); /* , size2); */
log_print("PV Size %s [%llu secs]" " / not "
"usable %s [LVM: %s]",
size, (uint64_t) pv->size, size1, "151 KB");
/* , size2); */
dbg_free(size1);
/* dbg_free(size2); */
@@ -127,24 +141,27 @@ void pvdisplay_full(struct physical_volume *pv)
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);
**********/
pe_free = pv->pe_count - pv->pe_allocated;
pe_free = pv->pe_count - pv->pe_alloc_count;
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
log_print("Allocatable yes %s",
(!pe_free && pv->pe_count) ? "(but full)" : "");
else
log_print("Allocatable NO");
/*********FIXME
log_print("Cur LV %u", pv->lv_cur);
*********/
/*********FIXME Erm...where is this stored?
log_print("Cur LV %u", vg->lv_count);
*/
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
log_print("Total PE %u", pv->pe_count);
log_print("Free PE %" PRIu64, pe_free);
log_print("Allocated PE %u", pv->pe_allocated);
log_print("Allocated PE %u", pv->pe_alloc_count);
#ifdef LVM_FUTURE
printf("Stale PE %u", pv->pe_stale);
@@ -156,7 +173,8 @@ void pvdisplay_full(struct physical_volume *pv)
return;
}
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv)
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv)
{
if (!pv)
return 0;
@@ -166,12 +184,14 @@ int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct phy
log_print("PV Status %sallocatable",
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
log_print("Total PE / Free PE %u / %u",
pv->pe_count, pv->pe_count - pv->pe_allocated);
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
log_print(" ");
return 0;
}
void lvdisplay_colons(struct logical_volume *lv)
{
int inkernel;
@@ -183,27 +203,63 @@ void lvdisplay_colons(struct logical_volume *lv)
lv->vg->name,
lv->name,
lv->vg->name,
(lv->status & (LVM_READ | LVM_WRITE)) >> 8,
inkernel ? 1 : 0,
(lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
/* 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,
inkernel ? info.major : -1,
inkernel ? info.minor : -1
);
((lv->alloc == ALLOC_STRICT) +
(lv->alloc == ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
inkernel ? info.major : -1, inkernel ? info.minor : -1);
return;
}
static struct {
alloc_policy_t alloc;
const char *str;
} _policies[] = {
{ALLOC_NEXT_FREE, "next free"},
{ALLOC_STRICT, "strict"},
{ALLOC_CONTIGUOUS, "contiguous"}
};
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
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;
}
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_warn("Unknown allocation policy, defaulting to next free");
return ALLOC_NEXT_FREE;
}
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
{
char *size;
uint32_t alloc;
struct dm_info info;
int inkernel;
char uuid[64];
struct snapshot *snap;
struct stripe_segment *seg;
struct list *lvseg;
struct logical_volume *origin;
float snap_percent;
int snap_active;
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
stack;
@@ -212,78 +268,68 @@ 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");
if ((snap = find_cow(lv)))
log_print("Snapshot of %s", snap->origin->name);
/* see if this LV is an origin for a snapshot */
if ((snap = find_origin(lv))) {
struct list *slh, *snaplist = find_snapshots(lv);
/******* FIXME Snapshot
if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
ret = -LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV;
goto lv_show_end;
}
printf("LV snapshot status ");
if (vg_check_active(vg_name) == TRUE) {
vg_t *vg_core;
if ((ret = vg_status_with_pv_and_lv(vg_name, &vg_core)) == 0) {
lv_t *lv_ptr =
vg_core->
lv[lv_get_index_by_name(vg_core, lv->lv_name)];
if (lv_ptr->lv_access & LV_SNAPSHOT) {
if (lv_ptr->lv_status & LV_ACTIVE)
printf("active ");
else
printf("INACTIVE ");
log_print("LV snapshot status source of");
list_iterate(slh, snaplist) {
snap = list_item(slh, struct snapshot_list)->snapshot;
snap_active = lv_snapshot_percent(snap->cow,
&snap_percent);
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
}
if (lv_ptr->lv_access & LV_SNAPSHOT_ORG) {
printf("source of\n");
while (lv_ptr->lv_snapshot_next != NULL) {
lv_ptr = lv_ptr->lv_snapshot_next;
printf(" %s [%s]\n",
lv_ptr->lv_name,
(lv_ptr->
lv_status & LV_ACTIVE) ? "active" :
"INACTIVE");
}
vg_free(vg_core, TRUE);
} else {
printf("destination for %s\n",
lv_ptr->lv_snapshot_org->lv_name);
}
}
} else {
printf("INACTIVE ");
if (lv->lv_access & LV_SNAPSHOT_ORG)
printf("original\n");
else
printf("snapshot\n");
/* 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_percent(lv, &snap_percent);
log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
}
if (inkernel && info.suspended)
log_print("LV Status suspended");
else
log_print("LV Status %savailable",
inkernel ? "" : "NOT ");
!inkernel || (snap && (snap_active < 1))
? "NOT " : "");
/********* FIXME lv_number
/********* FIXME lv_number - not sure that we're going to bother with this
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);
@@ -296,49 +342,57 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
#endif
********/
size = display_size(lv->size / 2, SIZE_SHORT);
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("Current LE %u", lv->le_count);
log_print("Current LE %u", origin->le_count);
/********** FIXME allocation
log_print("Allocated LE %u", lv->allocated_le);
**********/
/********** FIXME allocation - is there anytime the allocated LEs will not
* equal the current LEs? */
log_print("Allocated LE %u", origin->le_count);
/**********/
/********** FIXME Snapshot
if (lv->lv_access & LV_SNAPSHOT) {
printf("snapshot chunk size %s\n",
(dummy = lvm_show_size(lv->lv_chunk_size / 2, SHORT)));
dbg_free(dummy);
dummy = NULL;
if (lv->lv_remap_end > 0) {
lv_remap_ptr = lv->lv_remap_ptr;
if (lv_remap_ptr > lv->lv_remap_end)
lv_remap_ptr = lv->lv_remap_end;
dummy = lvm_show_size(lv_remap_ptr *
lv->lv_chunk_size / 2, SHORT);
dummy1 = lvm_show_size(lv->lv_remap_end *
lv->lv_chunk_size / 2, SHORT);
printf("Allocated to snapshot %.2f%% [%s/%s]\n",
(float) lv_remap_ptr * 100 / lv->lv_remap_end,
dummy, dummy1);
dbg_free(dummy);
dbg_free(dummy1);
dummy =
lvm_show_size((vg->
lv[lv_get_index_by_number
(vg,
lv->lv_number)]->lv_size -
lv->lv_remap_end * lv->lv_chunk_size) / 2,
SHORT);
printf("Allocated to COW-table %s\n", dummy);
dbg_free(dummy);
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;
}
}
******************/
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);
@@ -354,16 +408,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
#endif
***************/
/* 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("Allocation %s", get_alloc_string(lv->alloc));
log_print("Read ahead sectors %u", lv->read_ahead);
if (lv->status & FIXED_MINOR)
@@ -380,7 +425,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
*************/
if (inkernel)
log_print("Block device %d:%d", info.major,
log_print("Block device %d:%d", info.major,
info.minor);
log_print(" ");
@@ -397,7 +442,7 @@ void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
if (seg->area[s].pv)
log_print("%sphysical extents\t%d to %d", pre,
seg->area[s].pe, seg->area[s].pe + len - 1);
seg->area[s].pe, seg->area[s].pe + len - 1);
}
int lvdisplay_segments(struct logical_volume *lv)
@@ -408,7 +453,7 @@ int lvdisplay_segments(struct logical_volume *lv)
log_print("--- Segments ---");
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
log_print("logical extent %d to %d:",
@@ -433,8 +478,6 @@ int lvdisplay_segments(struct logical_volume *lv)
return 1;
}
void vgdisplay_extents(struct volume_group *vg)
{
return;
@@ -445,10 +488,27 @@ void vgdisplay_full(struct volume_group *vg)
uint32_t access;
char *s1;
char uuid[64];
uint32_t active_pvs;
struct list *pvlist;
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++;
}
}
else
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);
*******/
access = vg->status & (LVM_READ | LVM_WRITE);
log_print("VG Access %s%s%s%s",
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
@@ -456,33 +516,28 @@ 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/" : "",
vg->status & EXPORTED_VG ? "exported/" : "available/",
vg->status & RESIZEABLE_VG ? "" : "NOT ");
/******* FIXME vg number
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);
/****** FIXME Open LVs
log_print ( "Open LV %u", vg->lv_open);
*******/
/****** 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("Open LV %u", lvs_in_vg_opened(vg));
log_print("MAX LV Size 256 TB");
log_print("Max PV %u", vg->max_pv);
log_print("Cur PV %u", vg->pv_count);
/******* FIXME act PVs
log_print ( "Act PV %u", vg->pv_act);
*********/
log_print("Act PV %u", active_pvs);
s1 = display_size((uint64_t) vg->extent_count * (vg->extent_size / 2), SIZE_SHORT);
s1 =
display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
SIZE_SHORT);
log_print("VG Size %s", s1);
dbg_free(s1);
@@ -492,15 +547,16 @@ void vgdisplay_full(struct volume_group *vg)
log_print("Total PE %u", vg->extent_count);
s1 =
display_size(((uint64_t)
vg->extent_count - vg->free_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);
s1 = display_size((uint64_t) 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);

View File

@@ -44,4 +44,15 @@ void vgdisplay_full(struct volume_group *vg);
void vgdisplay_colons(struct volume_group *vg);
void vgdisplay_short(struct volume_group *vg);
/*
* Retrieve a text description of the allocation policy. Only
* extern because it's used by lvscan.
*/
const char *get_alloc_string(alloc_policy_t alloc);
/*
* FIXME: put this somewhere more sensible.
*/
alloc_policy_t get_alloc_from_string(const char *str);
#endif

View File

@@ -36,7 +36,6 @@ static void _destroy(struct dev_filter *f)
dbg_free(f);
}
struct dev_filter *composite_filter_create(int n, ...)
{
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));

View File

@@ -54,7 +54,7 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
if (!(cn = find_config_node(cf->root, path, '/'))) {
log_very_verbose("Couldn't find %s array in '%s'",
path, pf->file);
path, pf->file);
return 0;
}
@@ -65,13 +65,13 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_verbose("Devices array contains a value "
"which is not a string ... ignoring");
"which is not a string ... ignoring");
continue;
}
if (!hash_insert(pf->devices, cv->v.str, data))
log_verbose("Couldn't add '%s' to filter ... ignoring",
cv->v.str);
cv->v.str);
}
return 1;
}
@@ -101,12 +101,12 @@ int persistent_filter_load(struct dev_filter *f)
if (hash_get_num_entries(pf->devices))
r = 1;
out:
out:
destroy_config_file(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;
@@ -151,7 +151,8 @@ int persistent_filter_dump(struct dev_filter *f)
fp = fopen(pf->file, "w");
if (!fp) {
log_sys_error("fopen", pf->file);
if (errno != EROFS)
log_sys_error("fopen", pf->file);
return 0;
}
@@ -175,7 +176,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
if (!l) {
l = pf->real->passes_filter(pf->real, dev) ?
PF_GOOD_DEVICE : PF_BAD_DEVICE;
PF_GOOD_DEVICE : PF_BAD_DEVICE;
list_iterate(ah, &dev->aliases) {
sl = list_item(ah, struct str_list);
@@ -232,7 +233,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
return f;
bad:
bad:
dbg_free(pf->file);
if (pf->devices)
hash_destroy(pf->devices);

View File

@@ -128,8 +128,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
* the matcher gives.
*/
for (v = val, i = count - 1; v; v = v->next, i--)
if (!_extract_pattern(scratch, v->v.str,
regex, rf->accept, i)) {
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
log_info("invalid filter pattern");
goto out;
}
@@ -137,12 +136,12 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
/*
* build the matcher.
*/
if (!(rf->engine = matcher_create(rf->mem,
(const char **) regex, count)))
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
count)))
stack;
r = 1;
out:
out:
pool_destroy(scratch);
return r;
}
@@ -221,8 +220,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
f->private = rf;
return f;
bad:
bad:
pool_destroy(mem);
return NULL;
}

View File

@@ -71,12 +71,12 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
return 0;
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno));
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno));
return 0;
}
close(fd);
close(fd);
return 1;
}
@@ -85,7 +85,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof (struct dev_filter)))) {
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
@@ -124,12 +124,13 @@ static int *scan_proc_dev(const char *proc)
int *max_partitions_by_major;
if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
log_error("Filter failed to allocate max_partitions_by_major");
return NULL;
}
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return NULL;
@@ -140,7 +141,7 @@ static int *scan_proc_dev(const char *proc)
return NULL;
}
memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
while (fgets(line, 80, pd) != NULL) {
i = 0;
while (line[i] == ' ' && line[i] != '\0')
@@ -168,7 +169,7 @@ static int *scan_proc_dev(const char *proc)
_md_major = line_maj;
/* Go through the valid device names and if there is a
match store max number of partitions */
match store max number of partitions */
for (j = 0; device_info[j].name != NULL; j++) {
dev_len = strlen(device_info[j].name);

View File

@@ -21,7 +21,7 @@
#ifndef _LVM_FILTER_H
#define _LVM_FILTER_H
struct dev_filter *lvm_type_filter_create(const char *);
struct dev_filter *lvm_type_filter_create(const char *proc);
void lvm_type_filter_destroy(struct dev_filter *f);

View File

@@ -135,7 +135,7 @@ static int _munge_formats(struct pv_disk *pvd)
int read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
log_very_verbose("Failed to read PV data from %s",
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
}
@@ -265,35 +265,35 @@ static void _munge_exported_vg(struct disk_list *data)
int l, s;
/* Return if PV not in a VG or VG not exported */
if ((!*data->pvd.vg_name) ||
!(data->vgd.vg_status & VG_EXPORTED))
if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED))
return;
l = strlen(data->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.vg_name[l - s + 1] = '\0';
data->pvd.pv_status |= VG_EXPORTED;
}
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
static struct disk_list *__read_disk(struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name)
{
struct disk_list *data = pool_alloc(mem, sizeof(*data));
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
const char *name = dev_name(dev);
if (!data) {
if (!dl) {
stack;
return NULL;
}
data->dev = dev;
data->mem = mem;
list_init(&data->uuids);
list_init(&data->lvds);
dl->dev = dev;
dl->mem = mem;
list_init(&dl->uuids);
list_init(&dl->lvds);
if (!read_pvd(dev, &data->pvd)) {
if (!read_pvd(dev, &dl->pvd)) {
stack;
goto bad;
}
@@ -301,60 +301,60 @@ static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
/*
* is it an orphan ?
*/
if (!*data->pvd.vg_name) {
log_very_verbose("%s is not a member of any VG", name);
if (!*dl->pvd.vg_name) {
log_very_verbose("%s is not a member of any format1 VG", name);
/* Update VG cache */
vgcache_add(data->pvd.vg_name, NULL, dev);
vgcache_add(dl->pvd.vg_name, NULL, dev, fmt);
return (vg_name) ? NULL : data;
return (vg_name) ? NULL : dl;
}
if (!_read_vgd(data)) {
if (!_read_vgd(dl)) {
log_error("Failed to read VG data from PV (%s)", name);
goto bad;
}
/* If VG is exported, set VG name back to the real name */
_munge_exported_vg(data);
_munge_exported_vg(dl);
/* Update VG cache with what we found */
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, dev);
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt);
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s",
name, vg_name);
goto bad;
}
if (!_read_uuids(data)) {
if (!_read_uuids(dl)) {
log_error("Failed to read PV uuid list from %s", name);
goto bad;
}
if (!_read_lvs(data)) {
if (!_read_lvs(dl)) {
log_error("Failed to read LV's from %s", name);
goto bad;
}
if (!_read_extents(data)) {
if (!_read_extents(dl)) {
log_error("Failed to read extents from %s", name);
goto bad;
}
log_very_verbose("Found %s in %sVG %s", name,
(data->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
data->pvd.vg_name);
log_very_verbose("Found %s in %sVG %s", name,
(dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
dl->pvd.vg_name);
return data;
return dl;
bad:
pool_free(data->mem, data);
pool_free(dl->mem, dl);
return NULL;
}
struct disk_list *read_disk(struct device *dev, struct pool *mem,
const char *vg_name)
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name)
{
struct disk_list *r;
@@ -363,7 +363,7 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem,
return NULL;
}
r = __read_disk(dev, mem, vg_name);
r = __read_disk(fmt, dev, mem, vg_name);
if (!dev_close(dev))
stack;
@@ -378,16 +378,16 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
list_iterate(pvdh, head) {
pvd = &list_item(pvdh, struct disk_list)->pvd;
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
sizeof(pvd->pv_uuid))) {
if (MAJOR(data->dev->dev) != md_major()) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s", pvd->pv_uuid,
"%s", pvd->pv_uuid,
dev_name(data->dev));
return;
}
log_very_verbose("Duplicate PV %s - using md %s",
pvd->pv_uuid, dev_name(data->dev));
log_very_verbose("Duplicate PV %s - using md %s",
pvd->pv_uuid, dev_name(data->dev));
list_del(pvdh);
break;
}
@@ -400,8 +400,9 @@ 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(const char *vg_name, struct dev_filter *filter,
struct pool *mem, struct list *head)
int read_pvs_in_vg(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;
@@ -413,7 +414,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
if ((pvdh = vgcache_find(vg_name))) {
list_iterate(pvdh2, pvdh) {
dev = list_item(pvdh2, struct pvdev_list)->dev;
if (!(data = read_disk(dev, mem, vg_name)))
if (!(data = read_disk(fmt, dev, mem, vg_name)))
break;
_add_pv_to_list(head, data);
}
@@ -421,8 +422,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
/* 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. */
list_init(head);
@@ -436,7 +436,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
/* Otherwise do a complete scan */
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
if ((data = read_disk(dev, mem, vg_name))) {
if ((data = read_disk(fmt, dev, mem, vg_name))) {
_add_pv_to_list(head, data);
}
}
@@ -500,7 +500,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;
ulong pos, offset;
pos = data->pvd.lv_on_disk.base;
@@ -513,10 +513,15 @@ 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;
@@ -543,16 +548,16 @@ static int _write_pvd(struct disk_list *data)
ulong pos = data->pvd.pv_on_disk.base;
ulong size = data->pvd.pv_on_disk.size;
if(size < sizeof(struct pv_disk)) {
if (size < sizeof(struct pv_disk)) {
log_error("Invalid PV structure size.");
return 0;
}
/* Make sure that the gap between the PV structure and
/* Make sure that the gap between the PV structure and
the next one is zeroed in order to make non LVM tools
happy (idea from AED) */
buf = dbg_malloc(size);
if(!buf) {
if (!buf) {
log_err("Couldn't allocate temporary PV buffer.");
return 0;
}
@@ -560,7 +565,7 @@ static int _write_pvd(struct disk_list *data)
memset(buf, 0, size);
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
_xlate_pvd((struct pv_disk *)buf);
_xlate_pvd((struct pv_disk *) buf);
if (dev_write(data->dev, pos, size, buf) != size) {
dbg_free(buf);
fail;
@@ -573,7 +578,7 @@ static int _write_pvd(struct disk_list *data)
/*
* assumes the device has been opened.
*/
static int __write_all_pvd(struct disk_list *data)
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
{
const char *pv_name = dev_name(data->dev);
@@ -582,18 +587,19 @@ static int __write_all_pvd(struct disk_list *data)
return 0;
}
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev);
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt);
/*
* 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);
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);
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);
@@ -621,7 +627,7 @@ static int __write_all_pvd(struct disk_list *data)
/*
* opens the device and hands to the above fn.
*/
static int _write_all_pvd(struct disk_list *data)
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
{
int r;
@@ -630,7 +636,7 @@ static int _write_all_pvd(struct disk_list *data)
return 0;
}
r = __write_all_pvd(data);
r = __write_all_pvd(fmt, data);
if (!dev_close(data->dev))
stack;
@@ -643,17 +649,17 @@ static int _write_all_pvd(struct disk_list *data)
* little sanity checking, so make sure correct
* data is passed to here.
*/
int write_disks(struct list *pvs)
int write_disks(struct format_type *fmt, struct list *pvs)
{
struct list *pvh;
struct disk_list *dl;
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
if (!(_write_all_pvd(dl)))
if (!(_write_all_pvd(fmt, dl)))
fail;
log_very_verbose("Successfully wrote data to %s",
log_very_verbose("Successfully wrote data to %s",
dev_name(dl->dev));
}

View File

@@ -168,7 +168,6 @@ struct disk_list {
* Layout constants.
*/
#define METADATA_ALIGN 4096UL
#define PE_ALIGN (65536UL / SECTOR_SIZE)
#define METADATA_BASE 0UL
#define PV_SIZE 1024UL
@@ -188,13 +187,14 @@ int calculate_extent_count(struct physical_volume *pv);
*/
int read_pvd(struct device *dev, struct pv_disk *pvd);
struct disk_list *read_disk(struct device *dev, struct pool *mem,
const char *vg_name);
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name);
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
struct dev_filter *filter,
struct pool *mem, struct list *results);
int write_disks(struct list *pvds);
int write_disks(struct format_type *fmt, struct list *pvds);
/*
@@ -223,7 +223,8 @@ int export_extents(struct disk_list *dl, int lv_num,
struct logical_volume *lv,
struct physical_volume *pv);
int import_pvs(struct pool *mem, struct volume_group *vg,
int import_pvs(struct format_instance *fid, 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,
@@ -241,10 +242,10 @@ void export_numbers(struct list *pvds, struct volume_group *vg);
void export_pv_act(struct list *pvds);
/* blech */
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
int *result);
int export_vg_number(struct list *pvds, const char *vg_name,
struct dev_filter *filter);
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
const char *candidate_vg, int *result);
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter);
#endif

View File

@@ -50,7 +50,6 @@ static int _check_vgs(struct list *pvs, int *partial)
}
}
/* Remove any PVs with VG structs that differ from the first */
list_iterate_safe(pvh, t, pvs) {
dl = list_item(pvh, struct disk_list);
@@ -83,10 +82,10 @@ static int _check_vgs(struct list *pvs, int *partial)
return 1;
}
static struct volume_group *_build_vg(struct cmd_context *cmd,
static struct volume_group *_build_vg(struct format_instance *fid,
struct list *pvs)
{
struct pool *mem = cmd->mem;
struct pool *mem = fid->fmt->cmd->mem;
struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
struct disk_list *dl;
int partial;
@@ -99,7 +98,9 @@ static struct volume_group *_build_vg(struct cmd_context *cmd,
memset(vg, 0, sizeof(*vg));
vg->cmd = cmd;
vg->cmd = fid->fmt->cmd;
vg->fid = fid;
vg->seqno = 0;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
@@ -112,7 +113,7 @@ static struct volume_group *_build_vg(struct cmd_context *cmd,
if (!import_vg(mem, vg, dl, partial))
goto bad;
if (!import_pvs(mem, vg, pvs, &vg->pvs, &vg->pv_count))
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count))
goto bad;
if (!import_lvs(mem, vg, pvs))
@@ -126,14 +127,14 @@ static struct volume_group *_build_vg(struct cmd_context *cmd,
return vg;
bad:
bad:
stack;
pool_free(mem, vg);
return NULL;
}
static struct volume_group *_vg_read(struct format_instance *fi,
const char *vg_name)
static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name, void *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
@@ -145,20 +146,21 @@ static struct volume_group *_vg_read(struct format_instance *fi,
return NULL;
}
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
if (!read_pvs_in_vg(vg_name, fi->cmd->filter, mem, &pvs)) {
if (!read_pvs_in_vg
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!(vg = _build_vg(fi->cmd, &pvs))) {
if (!(vg = _build_vg(fid, &pvs))) {
stack;
goto bad;
}
bad:
bad:
pool_destroy(mem);
return vg;
}
@@ -193,7 +195,8 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
return dl;
}
static int _flatten_vg(struct pool *mem, struct volume_group *vg,
static int _flatten_vg(struct format_instance *fid, struct pool *mem,
struct volume_group *vg,
struct list *pvds, const char *dev_dir,
struct dev_filter *filter)
{
@@ -215,7 +218,7 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
export_numbers(pvds, vg);
export_pv_act(pvds);
if (!export_vg_number(pvds, vg->name, filter)) {
if (!export_vg_number(fid, pvds, vg->name, filter)) {
stack;
return 0;
}
@@ -223,7 +226,8 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
return 1;
}
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
void *mdl)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvds;
@@ -234,65 +238,58 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
return 0;
}
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
vg->name);
return 0;
}
list_init(&pvds);
r = (_flatten_vg(mem, vg, &pvds, fi->cmd->dev_dir, fi->cmd->filter) &&
write_disks(&pvds));
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
fid->fmt->cmd->filter) &&
write_disks(fid->fmt, &pvds));
pool_destroy(mem);
return r;
}
static struct physical_volume *_pv_read(struct format_instance *fi,
const char *name)
int _pv_read(struct format_type *fmt, const char *name,
struct physical_volume *pv)
{
struct pool *mem = pool_create(1024);
struct physical_volume *pv = NULL;
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", name);
if (!mem) {
stack;
return NULL;
return 0;
}
if (!(dev = dev_cache_get(name, fi->cmd->filter))) {
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) {
stack;
goto out;
}
if (!(dl = read_disk(dev, mem, NULL))) {
if (!(dl = read_disk(fmt, dev, mem, NULL))) {
stack;
goto out;
}
if (!(pv = pool_alloc(fi->cmd->mem, sizeof(*pv)))) {
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
stack;
goto out;
}
if (!import_pv(fi->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
stack;
pool_free(fi->cmd->mem, pv);
pv = NULL;
}
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL);
out:
r = 1;
out:
pool_destroy(mem);
return pv;
return r;
}
static struct list *_get_pvs(struct format_instance *fi)
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs, *results;
struct list pvs;
uint32_t count;
if (!mem) {
@@ -300,21 +297,14 @@ static struct list *_get_pvs(struct format_instance *fi)
return NULL;
}
if (!(results = pool_alloc(fi->cmd->mem, sizeof(*results)))) {
stack;
pool_destroy(mem);
return NULL;
}
list_init(&pvs);
list_init(results);
if (!read_pvs_in_vg(NULL, fi->cmd->filter, mem, &pvs)) {
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!import_pvs(fi->cmd->mem, NULL, &pvs, results, &count)) {
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
stack;
goto bad;
}
@@ -322,8 +312,7 @@ static struct list *_get_pvs(struct format_instance *fi)
pool_destroy(mem);
return results;
bad:
pool_free(fi->cmd->mem, results);
bad:
pool_destroy(mem);
return NULL;
}
@@ -342,56 +331,55 @@ static int _find_vg_name(struct list *names, const char *vg)
return 0;
}
static struct list *_get_vgs(struct format_instance *fi)
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct list *pvh;
struct list *pvs, *names = pool_alloc(fi->cmd->mem, sizeof(*names));
struct list *pvs;
struct name_list *nl;
if (!names) {
stack;
return NULL;
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
log_error("PV list allocation failed");
goto err;
}
list_init(names);
list_init(pvs);
if (!(pvs = _get_pvs(fi))) {
if (!_get_pvs(fmt, pvs)) {
stack;
goto bad;
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))
_find_vg_name(names, pvl->pv->vg_name))
continue;
if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
goto bad;
goto err;
}
if (!(nl->name = pool_strdup(fi->cmd->mem,
pvl->pv->vg_name))) {
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
stack;
goto bad;
goto err;
}
list_add(names, &nl->list);
}
if (list_empty(names))
goto bad;
pool_free(fmt->cmd->mem, pvs);
return names;
bad:
pool_free(fi->cmd->mem, names);
err:
pool_free(fmt->cmd->mem, pvs);
return NULL;
}
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
static int _pv_setup(struct format_instance *fid, struct physical_volume *pv,
struct volume_group *vg)
{
/* setup operations for the PV structure */
@@ -404,7 +392,7 @@ static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
}
/* Nothing more to do if pe_size isn't known */
if (!vg)
if (!vg)
return 1;
/*
@@ -438,11 +426,7 @@ static int _find_free_lvnum(struct logical_volume *lv)
return i;
}
/*
* Validate/populate LV structure for format1.
* Supplied LV structure can be for a new LV or for an already-existing one.
*/
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
{
uint64_t max_size = UINT_MAX;
@@ -455,7 +439,7 @@ static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
return 0;
}
if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT);
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
dbg_free(dummy);
return 0;
@@ -464,7 +448,8 @@ static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
return 1;
}
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
void *mdl)
{
struct pool *mem;
struct disk_list *dl;
@@ -472,14 +457,15 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
list_init(&pvs);
if (*pv->vg_name || pv->pe_allocated ) {
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);
return 0;
}
/* Ensure any residual PE structure is gone */
pv->pe_size = pv->pe_count = pv->pe_start = 0;
pv->pe_size = pv->pe_count = 0;
pv->pe_start = PE_ALIGN;
if (!(mem = pool_create(1024))) {
stack;
@@ -502,9 +488,10 @@ static int _pv_write(struct format_instance *fi, 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;
list_add(&pvs, &dl->list);
if (!write_disks(&pvs)) {
if (!write_disks(fid->fmt, &pvs)) {
stack;
goto bad;
}
@@ -512,26 +499,26 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
pool_destroy(mem);
return 1;
bad:
bad:
pool_destroy(mem);
return 0;
}
int _vg_setup(struct format_instance *fi, struct volume_group *vg)
int _vg_setup(struct format_instance *fid, struct volume_group *vg)
{
/* just check max_pv and max_lv */
if (vg->max_lv >= MAX_LV)
vg->max_lv = MAX_LV - 1;
if (vg->max_pv >= MAX_PV)
if (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)));
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
dbg_free(dummy);
dbg_free(dummy2);
@@ -541,7 +528,7 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
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)));
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
dbg_free(dummy);
return 0;
}
@@ -555,37 +542,72 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
return 1;
}
void _destroy(struct format_instance *fi)
struct format_instance *_create_instance(struct format_type *fmt,
const char *vgname, void *private)
{
dbg_free(fi);
}
struct format_instance *fid;
struct metadata_area *mda;
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,
destroy: _destroy,
};
struct format_instance *create_lvm1_format(struct cmd_context *cmd)
{
struct format_instance *fi = dbg_malloc(sizeof(*fi));
if (!fi) {
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
stack;
return NULL;
}
fi->cmd = cmd;
fi->ops = &_format1_ops;
fi->private = NULL;
fid->fmt = fmt;
list_init(&fid->metadata_areas);
return fi;
/* Define a NULL metadata area */
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
pool_free(fmt->cmd->mem, fid);
return NULL;
}
mda->metadata_locn = NULL;
list_add(&fid->metadata_areas, &mda->list);
return fid;
}
void _destroy_instance(struct format_instance *fid)
{
return;
}
void _destroy(struct format_type *fmt)
{
dbg_free(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,
create_instance:_create_instance,
destroy_instance:_destroy_instance,
destroy: _destroy,
};
struct format_type *create_lvm1_format(struct cmd_context *cmd)
{
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
if (!fmt) {
stack;
return NULL;
}
fmt->cmd = cmd;
fmt->ops = &_format1_ops;
fmt->name = FMT_LVM1_NAME;
fmt->features = 0;
fmt->private = NULL;
return fmt;
}

View File

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

View File

@@ -53,13 +53,13 @@ int import_pv(struct pool *mem, struct device *dev,
/* Store system_id from first PV if PV belongs to a VG */
if (vg && !*vg->system_id)
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
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
@@ -75,7 +75,7 @@ int import_pv(struct pool *mem, struct device *dev,
pv->pe_size = pvd->pe_size;
pv->pe_start = pvd->pe_start;
pv->pe_count = pvd->pe_total;
pv->pe_allocated = pvd->pe_allocated;
pv->pe_alloc_count = pvd->pe_allocated;
return 1;
}
@@ -163,7 +163,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);
@@ -174,15 +174,14 @@ int export_pv(struct pool *mem, struct volume_group *vg,
pvd->lv_cur = 0; /* this is set when exporting the lv list */
pvd->pe_size = pv->pe_size;
pvd->pe_total = pv->pe_count;
pvd->pe_allocated = pv->pe_allocated;
pvd->pe_allocated = pv->pe_alloc_count;
pvd->pe_start = pv->pe_start;
return 1;
}
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)
{
struct vg_disk *vgd = &dl->vgd;
memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
@@ -274,7 +273,7 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
{
lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number);
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
stack;
return 0;
}
@@ -298,16 +297,16 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
lv->status |= BADBLOCK_ON;
if (lvd->lv_allocation & LV_STRICT)
lv->status |= ALLOC_STRICT;
lv->alloc = ALLOC_STRICT;
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;
lv->le_count = lvd->lv_allocated_le;
lv->size = lvd->lv_size;
lv->le_count = lvd->lv_allocated_le;
list_init(&lv->segments);
@@ -343,42 +342,41 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
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;
struct stripe_segment)->stripe_size;
lvd->lv_size = lv->size;
lvd->lv_allocated_le = lv->le_count;
lvd->lv_size = lv->size;
lvd->lv_allocated_le = lv->le_count;
if (lv->status & BADBLOCK_ON)
lvd->lv_badblock = LV_BADBLOCK_ON;
if (lv->status & ALLOC_STRICT)
if (lv->alloc == 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,
struct logical_volume *lv,
struct physical_volume *pv)
struct logical_volume *lv, struct physical_volume *pv)
{
struct list *segh;
struct pe_disk *ped;
struct stripe_segment *seg;
uint32_t pe, s;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
for (s = 0; s < seg->stripes; s++) {
if (seg->area[s].pv != pv)
continue; /* not our pv */
continue; /* not our pv */
for (pe = 0; pe < (seg->len / seg->stripes); pe++) {
ped = &dl->extents[pe + seg->area[s].pe];
ped->lv_num = lv_num;
ped->le_num = (seg->le / seg->stripes) + pe +
s * (lv->le_count / seg->stripes);
s * (lv->le_count / seg->stripes);
}
}
}
@@ -386,7 +384,8 @@ int export_extents(struct disk_list *dl, int lv_num,
return 1;
}
int import_pvs(struct pool *mem, struct volume_group *vg,
int import_pvs(struct format_instance *fid, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count)
{
struct list *pvdh;
@@ -409,6 +408,7 @@ int import_pvs(struct pool *mem, struct volume_group *vg,
return 0;
}
pvl->pv->fid = fid;
list_add(results, &pvl->list);
(*count)++;
}
@@ -442,8 +442,7 @@ static struct logical_volume *_add_lv(struct pool *mem,
return lv;
}
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)
{
struct disk_list *dl;
struct lvd_list *ll;
@@ -493,7 +492,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
}
memset(dl->extents, 0, len);
list_iterate (lvh, &vg->lvs) {
list_iterate(lvh, &vg->lvs) {
ll = list_item(lvh, struct lv_list);
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
stack;
@@ -524,7 +523,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
* Now we need to run through the snapshots, exporting
* the SNAPSHOT_ORG flags etc.
*/
list_iterate (sh, &vg->snapshots) {
list_iterate(sh, &vg->snapshots) {
struct lv_disk *org, *cow;
struct snapshot *s = list_item(sh,
struct snapshot_list)->snapshot;
@@ -549,7 +548,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
r = 1;
out:
out:
hash_destroy(lvd_hash);
return r;
}
@@ -569,10 +568,10 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
/* build an index of lv numbers */
memset(lvs, 0, sizeof(lvs));
list_iterate (pvdh, pvds) {
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate (lvdh, &dl->lvds) {
list_iterate(lvdh, &dl->lvds) {
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
lvnum = lvd->lv_number;
@@ -595,10 +594,10 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
/*
* Now iterate through yet again adding the snapshots.
*/
list_iterate (pvdh, pvds) {
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate (lvdh, &dl->lvds) {
list_iterate(lvdh, &dl->lvds) {
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
if (!(lvd->lv_access & LV_SNAPSHOT))
@@ -617,8 +616,7 @@ 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, lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot.");
return 0;
}
@@ -628,8 +626,6 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
return 1;
}
int export_uuids(struct disk_list *dl, struct volume_group *vg)
{
struct uuid_list *ul;
@@ -688,14 +684,14 @@ void export_pv_act(struct list *pvds)
}
}
int export_vg_number(struct list *pvds, const char *vg_name,
struct dev_filter *filter)
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter)
{
struct list *pvdh;
struct disk_list *dl;
int vg_num;
if (!get_free_vg_number(filter, vg_name, &vg_num)) {
if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) {
stack;
return 0;
}
@@ -707,4 +703,3 @@ int export_vg_number(struct list *pvds, const char *vg_name,
return 1;
}

View File

@@ -226,7 +226,8 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
seg->len++;
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
(lvm->map[le + seg->len].pe == seg->area[0].pe +
(seg->area[0].pv &&
lvm->map[le + seg->len].pe == seg->area[0].pe +
seg->len));
le += seg->len;
@@ -249,7 +250,8 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
*/
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))
(seg->area[st].pv &&
lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
return 0;
return 1;
@@ -266,8 +268,7 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
if (lvm->lv->le_count % lvm->stripes) {
log_error("Number of stripes (%u) incompatible "
"with logical extent count (%u) for %s",
lvm->stripes, lvm->lv->le_count,
lvm->lv->name);
lvm->stripes, lvm->lv->le_count, lvm->lv->name);
}
len = lvm->lv->le_count / lvm->stripes;

View File

@@ -8,7 +8,6 @@
#include "log.h"
#include "dbg_malloc.h"
/*
* Only works with powers of 2.
*/
@@ -51,17 +50,17 @@ static void _calc_simple_layout(struct pv_disk *pvd)
pvd->pv_on_disk.base = METADATA_BASE;
pvd->pv_on_disk.size = PV_SIZE;
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
pvd->vg_on_disk.size = VG_SIZE;
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
pvd->vg_on_disk.size = VG_SIZE;
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
}
int _check_vg_limits(struct disk_list *dl)
@@ -103,7 +102,6 @@ int calculate_layout(struct disk_list *dl)
return 1;
}
/*
* 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
@@ -133,16 +131,15 @@ int calculate_extent_count(struct physical_volume *pv)
return 0;
}
do {
pvd->pe_total--;
_calc_simple_layout(pvd);
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + \
SECTOR_SIZE - 1) / SECTOR_SIZE);
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
SECTOR_SIZE - 1) / SECTOR_SIZE);
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 * pv->pe_size)) > pv->size);
if (pvd->pe_total > MAX_PE_TOTAL) {
log_error("Metadata extent limit (%u) exceeded for %s - "

View File

@@ -25,21 +25,20 @@ 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;
}
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
if (!dev_close(dev))
stack;
return r;
}
static int _write(struct labeller *l,
struct device *dev, struct label *label)
static int _write(struct labeller *l, struct device *dev, struct label *label)
{
_not_supported("write");
return 0;
@@ -81,15 +80,15 @@ 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;
}
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
if (!dev_close(dev))
stack;
if (!r) {
stack;
@@ -118,15 +117,14 @@ 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
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)

View File

@@ -15,8 +15,8 @@
* Put in separate file so it wouldn't contaminate
* other code.
*/
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
int *result)
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
const char *candidate_vg, int *result)
{
struct list *pvh;
struct list all_pvs;
@@ -31,7 +31,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
return 0;
}
if (!read_pvs_in_vg(NULL, filter, mem, &all_pvs)) {
if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) {
stack;
goto out;
}
@@ -40,8 +40,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
list_iterate(pvh, &all_pvs) {
dl = list_item(pvh, struct disk_list);
if (!*dl->pvd.vg_name ||
!strcmp(dl->pvd.vg_name, candidate_vg))
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
continue;
numbers[dl->vgd.vg_number] = 1;
@@ -55,7 +54,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
}
}
out:
out:
pool_destroy(mem);
return r;
}

View File

@@ -23,6 +23,7 @@
#include <fcntl.h>
#include <time.h>
#define SECS_PER_DAY 86400 /* 24*60*60 */
/*
* The format instance is given a directory path upon creation.
@@ -36,7 +37,6 @@
* Backup files that have expired will be removed.
*/
/*
* A list of these is built up for our volume group. Ordered
* with the least recent at the head.
@@ -48,12 +48,11 @@ struct archive_file {
int index;
};
/*
* 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)
uint32_t * index)
{
int len, vg_len;
char *dot, *underscore;
@@ -93,7 +92,7 @@ static void _insert_file(struct list *head, struct archive_file *b)
}
/* index increases through list */
list_iterate (bh, head) {
list_iterate(bh, head) {
bf = list_item(bh, struct archive_file);
if (bf->index > b->index) {
@@ -138,6 +137,7 @@ static struct list *_scan_archive(struct pool *mem,
list_init(results);
/* Sort fails beyond 5-digit indexes */
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
log_err("Couldn't scan archive directory.");
return 0;
@@ -149,8 +149,8 @@ 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, vg_name, sizeof(vg_name),
&index))
continue;
/* is it the vg we're interested in ? */
@@ -180,7 +180,7 @@ static struct list *_scan_archive(struct pool *mem,
_insert_file(results, af);
}
out:
out:
for (i = 0; i < count; i++)
free(dirent[i]);
free(dirent);
@@ -188,11 +188,50 @@ static struct list *_scan_archive(struct pool *mem,
return results;
}
static void _remove_expired(struct list *archives, uint32_t archives_size,
uint32_t retain_days, uint32_t min_archive)
{
struct list *bh;
struct archive_file *bf;
struct stat sb;
time_t retain_time;
/* Make sure there are enough archives to even bother looking for
* expired ones... */
if (archives_size <= min_archive)
return;
/* Convert retain_days into the time after which we must retain */
retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY;
/* Assume list is ordered oldest first (by index) */
list_iterate(bh, archives) {
bf = list_item(bh, struct archive_file);
/* Get the mtime of the file and unlink if too old */
if (stat(bf->path, &sb)) {
log_sys_error("stat", bf->path);
continue;
}
if (sb.st_mtime > retain_time)
return;
log_very_verbose("Expiring archive %s", bf->path);
if (unlink(bf->path))
log_sys_error("unlink", bf->path);
/* Don't delete any more if we've reached the minimum */
if (--archives_size <= min_archive)
return;
}
}
int archive_vg(struct volume_group *vg,
const char *dir, const char *desc,
uint32_t retain_days, uint32_t min_archive)
{
int i, fd;
int i, fd, renamed = 0;
unsigned int index = 0;
struct archive_file *last;
FILE *fp = NULL;
@@ -231,7 +270,6 @@ int archive_vg(struct volume_group *vg,
if (list_empty(archives))
index = 0;
else {
last = list_item(archives->p, struct archive_file);
index = last->index + 1;
@@ -239,36 +277,51 @@ int archive_vg(struct volume_group *vg,
for (i = 0; i < 10; i++) {
if (lvm_snprintf(archive_name, sizeof(archive_name),
"%s/%s_%05d.vg",
dir, vg->name, index) < 0) {
log_err("archive file name too long.");
"%s/%s_%05d.vg", dir, vg->name, index) < 0) {
log_error("Archive file name too long.");
return 0;
}
if (lvm_rename(temp_file, archive_name))
if ((renamed = lvm_rename(temp_file, archive_name)))
break;
index++;
}
if (!renamed)
log_error("Archive rename failed for %s", temp_file);
_remove_expired(archives, list_size(archives) + renamed, retain_days,
min_archive);
return 1;
}
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
struct archive_file *af)
{
struct volume_group *vg;
struct volume_group *vg = NULL;
struct format_instance *tf;
time_t when;
char *desc;
void *context;
log_print("path:\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))) {
log_error("Couldn't create text instance object.");
return;
}
/*
* Read the archive file to ensure that it is valid, and
* retrieve the archive time and description.
*/
if (!(vg = text_vg_import(cmd, af->path, um, &when, &desc))) {
/* FIXME Use variation on _vg_read */
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
log_print("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf);
return;
}
@@ -276,6 +329,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
log_print("time:\t\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,
@@ -292,7 +346,7 @@ int archive_list(struct cmd_context *cmd, struct uuid_map *um,
if (list_empty(archives))
log_print("No archives found.");
list_iterate (ah, archives) {
list_iterate(ah, archives) {
af = list_item(ah, struct archive_file);
_display_archive(cmd, um, af);

View File

@@ -11,19 +11,16 @@
#include "pool.h"
#include "dbg_malloc.h"
#include "lvm-string.h"
#include "display.h"
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
/*
* The first half of this file deals with
* exporting the vg, ie. writing it to a file.
*/
struct formatter {
struct pool *mem; /* pv names allocated from here */
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
FILE *fp; /* where we're writing to */
int indent; /* current level of indentation */
@@ -34,16 +31,14 @@ struct formatter {
/*
* Formatting functions.
*/
static void _out_size(struct formatter *f, uint64_t size,
const char *fmt, ...)
__attribute__ (( format (printf, 3, 4) ));
static void _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, ...)
__attribute__ (( format (printf, 2, 3) ));
__attribute__ ((format(printf, 2, 3)));
static void _out(struct formatter *f, const char *fmt, ...)
__attribute__ (( format (printf, 2, 3) ));
__attribute__ ((format(printf, 2, 3)));
#define MAX_INDENT 5
static void _inc_indent(struct formatter *f)
@@ -116,7 +111,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
"Gigabytes",
"Terrabytes",
NULL
};
};
int i;
double d = (double) sectors;
@@ -124,7 +119,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
/* to convert to K */
d /= 2.0;
for (i = 0; (d > 1024.0) && _units[i]; i++)
for (i = 0; (d > 1024.0) && _units[i]; i++)
d /= 1024.0;
return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
@@ -134,8 +129,7 @@ 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 void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
{
char buffer[64];
va_list ap;
@@ -181,7 +175,10 @@ static int _print_header(struct formatter *f,
_out(f,
"# This file was originally generated by the LVM2 library\n"
"# Generated: %s\n", ctime(&t));
"# Generated: %s", ctime(&t));
_out(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
_out(f, FORMAT_VERSION_FIELD " = %d\n", FORMAT_VERSION_VALUE);
_out(f, "description = \"%s\"", desc);
_out(f, "creation_time = %lu\n", t);
@@ -200,6 +197,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
_out(f, "id = \"%s\"", buffer);
_out(f, "seqno = %u", vg->seqno);
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
@@ -219,12 +217,11 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
* Get the pv%d name from the formatters hash
* table.
*/
static inline const char *
_get_pv_name(struct formatter *f, struct physical_volume *pv)
static inline const char *_get_pv_name(struct formatter *f,
struct physical_volume *pv)
{
return (pv) ? (const char *)
hash_lookup(f->pv_names, dev_name(pv->dev)) :
"Missing";
hash_lookup(f->pv_names, dev_name(pv->dev)) : "Missing";
}
static int _print_pvs(struct formatter *f, struct volume_group *vg)
@@ -237,7 +234,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
_out(f, "physical_volumes {");
_inc_indent(f);
list_iterate (pvh, &vg->pvs) {
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
@@ -259,8 +256,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
_nl(f);
if (!print_flags(pv->status, PV_FLAGS,
buffer, sizeof(buffer))) {
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
@@ -324,8 +320,8 @@ static int _count_segments(struct logical_volume *lv)
int r = 0;
struct list *segh;
list_iterate (segh, &lv->segments)
r++;
list_iterate(segh, &lv->segments)
r++;
return r;
}
@@ -347,7 +343,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
_out(f, "logical_volumes {");
_inc_indent(f);
list_iterate (lvh, &vg->lvs) {
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
_nl(f);
@@ -369,6 +365,8 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
}
_out(f, "status = %s", buffer);
_out(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));
_out(f, "read_ahead = %u", lv->read_ahead);
if (lv->minor >= 0)
_out(f, "minor = %d", lv->minor);
@@ -376,7 +374,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
_nl(f);
seg_count = 1;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
@@ -428,7 +426,7 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
_out(f, "snapshots {");
_inc_indent(f);
list_iterate (sh, &vg->snapshots) {
list_iterate(sh, &vg->snapshots) {
s = list_item(sh, struct snapshot_list)->snapshot;
if (!_print_snapshot(f, s, count++)) {
@@ -448,8 +446,7 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
* 'pv2' etc. This function builds a hash table
* to enable a quick lookup from device -> name.
*/
static int _build_pv_names(struct formatter *f,
struct volume_group *vg)
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
{
int count = 0;
struct list *pvh;
@@ -466,11 +463,10 @@ static int _build_pv_names(struct formatter *f,
goto bad;
}
list_iterate (pvh, &vg->pvs) {
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
if (lvm_snprintf(buffer, sizeof(buffer),
"pv%d", count++) < 0) {
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
stack;
goto bad;
}
@@ -488,7 +484,7 @@ static int _build_pv_names(struct formatter *f,
return 1;
bad:
bad:
if (f->mem)
pool_destroy(f->mem);
@@ -498,7 +494,7 @@ static int _build_pv_names(struct formatter *f,
return 0;
}
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc)
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
{
int r = 0;
struct formatter *f;
@@ -516,7 +512,6 @@ int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc)
stack;
goto out;
}
#define fail do {stack; goto out;} while(0)
if (!_print_header(f, vg, desc))
@@ -546,7 +541,7 @@ int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc)
_out(f, "}");
r = !ferror(f->fp);
out:
out:
if (f->mem)
pool_destroy(f->mem);

View File

@@ -38,10 +38,8 @@ 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"},
{0, NULL}
};
@@ -62,7 +60,7 @@ static struct flag *_get_flags(int type)
return NULL;
}
static int _emit(char **buffer, size_t *size, const char *fmt, ...)
static int _emit(char **buffer, size_t * size, const char *fmt, ...)
{
size_t n;
va_list ap;
@@ -124,7 +122,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,24 +133,29 @@ int read_flags(uint32_t *status, int type, struct config_value *cv)
return 0;
}
while (cv) {
if (cv->type != CFG_STRING) {
log_err("Status value is not a string.");
return 0;
}
for (f = 0; flags[f].description; f++)
if (!strcmp(flags[f].description, cv->v.str)) {
s |= flags[f].mask;
break;
/*
* Only scan the flags if it wasn't an empty array.
*/
if (cv->type != CFG_EMPTY_ARRAY) {
while (cv) {
if (cv->type != CFG_STRING) {
log_err("Status value is not a string.");
return 0;
}
if (!flags[f].description) {
log_err("Unknown status flag '%s'.", cv->v.str);
return 0;
}
for (f = 0; flags[f].description; f++)
if (!strcmp(flags[f].description, cv->v.str)) {
s |= flags[f].mask;
break;
}
cv = cv->next;
if (!flags[f].description) {
log_err("Unknown status flag '%s'.", cv->v.str);
return 0;
}
cv = cv->next;
}
}
*status = s;

View File

@@ -15,11 +15,14 @@
#include "display.h"
#include "dbg_malloc.h"
#include "toolcontext.h"
#include "vgcache.h"
#include "lvm-string.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <limits.h>
#include <dirent.h>
/* Arbitrary limits copied from format1/disk_rep.h */
#define MAX_PV 256
@@ -27,16 +30,21 @@
#define MAX_VG 99
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
struct dir_list {
struct list list;
char dir[0];
};
struct text_context {
char *path_live; /* Path to file holding live metadata */
char *path_edit; /* Path to file holding edited metadata */
char *desc; /* Description placed inside file */
};
/*
* NOTE: Currently there can be only one vg per file.
*/
struct text_c {
char *path;
char *desc;
struct uuid_map *um;
};
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
struct volume_group *vg)
{
@@ -61,6 +69,11 @@ static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
if (vg->max_pv >= MAX_PV)
vg->max_pv = MAX_PV - 1;
if (vg->extent_size & (vg->extent_size - 1)) {
log_error("Extent size must be power of 2");
return 0;
}
return 1;
}
@@ -68,6 +81,9 @@ static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
{
uint64_t max_size = UINT_MAX;
if (!*lv->lvid.s)
lvid_create(&lv->lvid, &lv->vg->id);
if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
@@ -79,14 +95,15 @@ static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
}
static struct volume_group *_vg_read(struct format_instance *fi,
const char *vg_name)
const char *vgname, void *mdl)
{
struct text_c *tc = (struct text_c *) fi->private;
struct text_context *tc = (struct text_context *) mdl;
struct volume_group *vg;
time_t when;
char *desc;
if (!(vg = text_vg_import(fi->cmd, tc->path, tc->um, &when, &desc))) {
if (!(vg = text_vg_import(fi, tc->path_live, fi->fmt->cmd->um, &when,
&desc))) {
stack;
return NULL;
}
@@ -96,32 +113,33 @@ static struct volume_group *_vg_read(struct format_instance *fi,
* text file (this restriction may remain). We need to
* check that it contains the correct volume group.
*/
if (strcmp(vg_name, vg->name)) {
pool_free(fi->cmd->mem, vg);
if (strcmp(vgname, vg->name)) {
pool_free(fi->fmt->cmd->mem, vg);
log_err("'%s' does not contain volume group '%s'.",
tc->path, vg_name);
tc->path_live, vgname);
return NULL;
}
return vg;
}
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
static int _vg_write(struct format_instance *fi, struct volume_group *vg,
void *mdl)
{
struct text_c *tc = (struct text_c *) fi->private;
struct text_context *tc = (struct text_context *) mdl;
FILE *fp;
int fd;
char *slash;
char temp_file[PATH_MAX], temp_dir[PATH_MAX];
slash = rindex(tc->path, '/');
slash = rindex(tc->path_edit, '/');
if (slash == 0)
strcpy(temp_dir, ".");
else if (slash - tc->path < PATH_MAX) {
strncpy(temp_dir, tc->path, slash - tc->path);
temp_dir[slash - tc->path] = '\0';
else if (slash - tc->path_edit < PATH_MAX) {
strncpy(temp_dir, tc->path_edit, slash - tc->path_edit);
temp_dir[slash - tc->path_edit] = '\0';
} else {
log_error("Text format failed to determine directory.");
@@ -145,113 +163,196 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
return 0;
}
if (fclose(fp)) {
log_sys_error("fclose", tc->path);
if (fsync(fd)) {
log_sys_error("fsync", tc->path_edit);
fclose(fp);
return 0;
}
if (rename(temp_file, tc->path)) {
log_error("%s: rename to %s failed: %s", temp_file, tc->path,
strerror(errno));
if (fclose(fp)) {
log_sys_error("fclose", tc->path_edit);
return 0;
}
if (rename(temp_file, tc->path_edit)) {
log_error("%s: rename to %s failed: %s", temp_file,
tc->path_edit, strerror(errno));
return 0;
}
return 1;
}
static struct list *_get_vgs(struct format_instance *fi)
static int _pv_commit(struct format_instance *fi, struct physical_volume *pv,
void *mdl)
{
struct text_c *tc = (struct text_c *) fi->private;
struct list *names = pool_alloc(fi->cmd->mem, sizeof(*names));
// struct text_context *tc = (struct text_context *) mdl;
return 1;
}
static int _vg_commit(struct format_instance *fi, struct volume_group *vg,
void *mdl)
{
struct text_context *tc = (struct text_context *) mdl;
if (rename(tc->path_edit, tc->path_live)) {
log_error("%s: rename to %s failed: %s", tc->path_edit,
tc->path_edit, strerror(errno));
return 0;
}
sync();
return 1;
}
static int _vg_remove(struct format_instance *fi, struct volume_group *vg,
void *mdl)
{
struct text_context *tc = (struct text_context *) mdl;
if (path_exists(tc->path_edit) && unlink(tc->path_edit)) {
log_sys_error("unlink", tc->path_edit);
return 0;
}
if (path_exists(tc->path_live) && unlink(tc->path_live)) {
log_sys_error("unlink", tc->path_live);
return 0;
}
sync();
return 1;
}
/* Add vgname to list if it's not already there */
static int _add_vgname(struct format_type *fmt, struct list *names,
char *vgname)
{
struct list *nlh;
struct name_list *nl;
list_iterate(nlh, names) {
nl = list_item(nlh, struct name_list);
if (!strcmp(vgname, nl->name))
return 1;
}
vgcache_add(vgname, NULL, NULL, fmt);
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
return 0;
}
if (!(nl->name = pool_strdup(fmt->cmd->mem, vgname))) {
log_error("strdup %s failed", vgname);
return 0;
}
list_add(names, &nl->list);
return 1;
}
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct dirent *dirent;
struct dir_list *dl;
struct list *dlh, *dir_list;
char *tmp;
DIR *d;
dir_list = (struct list *) fmt->private;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
if (!(d = opendir(dl->dir))) {
log_sys_error("opendir", dl->dir);
continue;
}
while ((dirent = readdir(d)))
if (strcmp(dirent->d_name, ".") &&
strcmp(dirent->d_name, "..") &&
(!(tmp = strstr(dirent->d_name, ".tmp")) ||
tmp != dirent->d_name + strlen(dirent->d_name)
- 4))
if (!_add_vgname(fmt, names, dirent->d_name))
return NULL;
if (closedir(d))
log_sys_error("closedir", dl->dir);
}
return names;
}
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
{
struct pv_list *pvl, *rhl;
struct list *vgh;
struct list *pvh;
struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
struct list *rh;
struct name_list *nl;
struct volume_group *vg;
char *slash;
char *vgname;
if (!names) {
list_init(names);
if (!_get_vgs(fmt, names)) {
stack;
return NULL;
}
list_init(names);
/* Determine the VG name from the file name */
slash = rindex(tc->path, '/');
if (slash) {
vgname = pool_alloc(fi->cmd->mem, strlen(slash));
strcpy(vgname, slash + 1);
} else {
vgname = pool_alloc(fi->cmd->mem, strlen(tc->path) + 1);
strcpy(vgname, tc->path);
}
vg = _vg_read(fi, vgname);
if (vg) {
pool_free(fi->cmd->mem, vg);
if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
stack;
goto bad;
}
nl->name = vgname;
list_add(names, &nl->list);
}
return names;
bad:
pool_free(fi->cmd->mem, names);
return NULL;
}
static struct list *_get_pvs(struct format_instance *fi)
{
struct pv_list *pvl;
struct list *vgh;
struct list *pvh;
struct list *results = pool_alloc(fi->cmd->mem, sizeof(*results));
struct list *vgs = _get_vgs(fi);
list_init(results);
list_iterate(vgh, vgs) {
struct volume_group *vg;
struct name_list *nl;
list_iterate(vgh, names) {
nl = list_item(vgh, struct name_list);
vg = _vg_read(fi, nl->name);
if (vg) {
list_iterate(pvh, &vg->pvs) {
struct pv_list *vgpv =
list_item(pvh, struct pv_list);
if (!(vg = vg_read(fmt->cmd, nl->name))) {
log_error("format_text: _get_pvs failed to read VG %s",
nl->name);
continue;
}
/* FIXME Use temp hash! */
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
pvl = pool_alloc(fi->cmd->mem, sizeof(*pvl));
if (!pvl) {
stack;
goto bad;
/* If in use, remove from list of orphans */
list_iterate(rh, results) {
rhl = list_item(rh, struct pv_list);
if (id_equal(&rhl->pv->id, &pvl->pv->id)) {
if (*rhl->pv->vg_name)
log_err("PV %s in two VGs "
"%s and %s",
dev_name(rhl->pv->dev),
rhl->pv->vg_name,
vg->name);
else
memcpy(&rhl->pv, &pvl->pv,
sizeof(struct
physical_volume));
}
/* ?? do we need to clone the pv structure...really? Nah. */
pvl->pv = vgpv->pv;
list_add(results, &pvl->list);
}
}
}
return results;
bad:
pool_free(fi->cmd->mem, vgs);
return NULL;
pool_free(fmt->cmd->mem, names);
return results;
}
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
static int _pv_write(struct format_instance *fi, struct physical_volume *pv,
void *mdl)
{
/* No on-disk PV structure change required! */
/* FIXME vgcache could be wrong */
return 1;
//return (fi->fmt->cmd->fmt1->ops->pv_write(fi, pv, NULL));
/*** FIXME Not required?
struct volume_group *vg;
struct list *pvh;
vg = _vg_read(fi, pv->vg_name);
/* Find the PV in this VG */
// Find the PV in this VG
if (vg) {
list_iterate(pvh, &vg->pvs) {
struct pv_list *vgpv = list_item(pvh, struct pv_list);
@@ -260,85 +361,190 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
vgpv->pv->status = pv->status;
vgpv->pv->size = pv->size;
/* Not sure if it's worth doing these */
// Not sure if it's worth doing these
vgpv->pv->pe_size = pv->pe_size;
vgpv->pv->pe_count = pv->pe_count;
vgpv->pv->pe_start = pv->pe_start;
vgpv->pv->pe_allocated = pv->pe_allocated;
vgpv->pv->pe_alloc_count = pv->pe_alloc_count;
/* Write it back */
// Write it back
_vg_write(fi, vg);
pool_free(fi->cmd->mem, vg);
pool_free(fi->fmt->cmd->mem, vg);
return 1;
}
}
pool_free(fi->cmd->mem, vg);
pool_free(fi->fmt->cmd->mem, vg);
}
/* Can't handle PVs not in a VG */
// Can't handle PVs not in a VG
return 0;
***/
}
static struct physical_volume *_pv_read(struct format_instance *fi,
const char *pv_name)
static int _pv_read(struct format_type *fmt, const char *pv_name,
struct physical_volume *pv)
{
struct list *vgs = _get_vgs(fi);
struct pv_list *pvl;
struct list *vgh;
struct list *pvh;
struct physical_volume *pv;
struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
struct name_list *nl;
struct volume_group *vg;
struct id *id;
/* Look for the PV */
list_iterate(vgh, vgs) {
struct volume_group *vg;
struct name_list *nl;
/* FIXME Push up to pv_read */
if (!(id = uuid_map_lookup_label(fmt->cmd->mem, fmt->cmd->um, pv_name))) {
stack;
return 0;
}
list_init(names);
if (!_get_vgs(fmt, names)) {
stack;
return 0;
}
list_iterate(vgh, names) {
nl = list_item(vgh, struct name_list);
vg = _vg_read(fi, nl->name);
if (vg) {
list_iterate(pvh, &vg->pvs) {
struct pv_list *vgpv =
list_item(pvh, struct pv_list);
if (!strcmp(dev_name(vgpv->pv->dev), pv_name)) {
pv = pool_alloc(fi->cmd->mem,
sizeof(*pv));
if (!pv) {
stack;
pool_free(fi->cmd->mem, vg);
return NULL;
}
/* Memberwise copy */
*pv = *vgpv->pv;
pv->vg_name =
pool_alloc(fi->cmd->mem,
strlen(vgpv->pv->
vg_name) + 1);
if (!pv->vg_name) {
stack;
pool_free(fi->cmd->mem, vg);
return NULL;
}
strcpy(pv->vg_name, vgpv->pv->vg_name);
pool_free(fi->cmd->mem, vg);
return pv;
}
if (!(vg = vg_read(fmt->cmd, nl->name))) {
log_error("format_text: _pv_read failed to read VG %s",
nl->name);
return 0;
}
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, id)) {
memcpy(pv, pvl->pv, sizeof(*pv));
break;
}
pool_free(fi->cmd->mem, vg);
}
}
return NULL;
pool_free(fmt->cmd->mem, names);
return 1;
}
static void _destroy(struct format_instance *fi)
static void _destroy_instance(struct format_instance *fid)
{
struct text_c *tc = (struct text_c *) fi->private;
return;
}
dbg_free(tc->path);
dbg_free(tc->desc);
dbg_free(tc);
dbg_free(fi);
static void _free_dirs(struct list *dir_list)
{
struct list *dl, *tmp;
list_iterate_safe(dl, tmp, dir_list) {
list_del(dl);
dbg_free(dl);
}
}
static void _destroy(struct format_type *fmt)
{
if (fmt->private) {
_free_dirs((struct list *) fmt->private);
dbg_free(fmt->private);
}
dbg_free(fmt);
}
static struct format_instance *_create_text_instance(struct format_type *fmt,
const char *vgname,
void *context)
{
struct format_instance *fid;
struct metadata_area *mda;
struct dir_list *dl;
struct list *dlh, *dir_list;
char path[PATH_MAX];
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
log_error("Couldn't allocate format instance object.");
return NULL;
}
fid->fmt = fmt;
list_init(&fid->metadata_areas);
if (!vgname) {
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
return NULL;
}
mda->metadata_locn = context;
list_add(&fid->metadata_areas, &mda->list);
} else {
dir_list = (struct list *) fmt->private;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
dl->dir, vgname) < 0) {
log_error("Name too long %s/%s", dl->dir,
vgname);
return NULL;
}
context = create_text_context(fmt, path, NULL);
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
return NULL;
}
mda->metadata_locn = context;
list_add(&fid->metadata_areas, &mda->list);
}
}
return fid;
}
void *create_text_context(struct format_type *fmt, const char *path,
const char *desc)
{
struct text_context *tc;
char *tmp;
if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) {
log_error("%s: Volume group filename may not end in .tmp",
path);
return NULL;
}
if (!(tc = pool_alloc(fmt->cmd->mem, sizeof(*tc)))) {
stack;
return NULL;
}
if (!(tc->path_live = pool_strdup(fmt->cmd->mem, path))) {
stack;
goto no_mem;
}
if (!(tc->path_edit = pool_alloc(fmt->cmd->mem, strlen(path) + 5))) {
stack;
goto no_mem;
}
sprintf(tc->path_edit, "%s.tmp", path);
if (!desc)
desc = "";
if (!(tc->desc = pool_strdup(fmt->cmd->mem, desc))) {
stack;
goto no_mem;
}
return (void *) tc;
no_mem:
pool_free(fmt->cmd->mem, tc);
log_err("Couldn't allocate text format context object.");
return NULL;
}
static struct format_handler _text_handler = {
@@ -347,62 +553,86 @@ static struct format_handler _text_handler = {
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
pv_commit: _pv_commit,
vg_setup: _vg_setup,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_write: _vg_write,
vg_remove: _vg_remove,
vg_commit: _vg_commit,
create_instance:_create_text_instance,
destroy_instance:_destroy_instance,
destroy: _destroy
};
struct format_instance *text_format_create(struct cmd_context *cmd,
const char *file,
struct uuid_map *um,
const char *desc)
static int _add_dir(const char *dir, struct list *dir_list)
{
struct format_instance *fi;
char *path, *d;
struct text_c *tc;
struct dir_list *dl;
if (!(fi = dbg_malloc(sizeof(*fi)))) {
stack;
goto no_mem;
if (create_dir(dir)) {
if (!(dl = dbg_malloc(sizeof(struct list) + strlen(dir) + 1))) {
log_error("_add_dir allocation failed");
return 0;
}
strcpy(dl->dir, dir);
list_add(dir_list, &dl->list);
return 1;
}
if (!(path = dbg_strdup(file))) {
return 0;
}
struct format_type *create_text_format(struct cmd_context *cmd)
{
struct format_type *fmt;
struct config_node *cn;
struct config_value *cv;
struct list *dir_list;
if (!(fmt = dbg_malloc(sizeof(*fmt)))) {
stack;
goto no_mem;
return NULL;
}
if (!(d = dbg_strdup(desc))) {
stack;
goto no_mem;
fmt->cmd = cmd;
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
fmt->features = FMT_SEGMENTS;
if (!(dir_list = dbg_malloc(sizeof(struct list)))) {
log_error("Failed to allocate dir_list");
return NULL;
}
if (!(tc = dbg_malloc(sizeof(*tc)))) {
stack;
goto no_mem;
list_init(dir_list);
fmt->private = (void *) dir_list;
if (!(cn = find_config_node(cmd->cf->root, "metadata/dirs", '/'))) {
log_verbose("metadata/dirs not in config file: Defaulting "
"to /etc/lvm/metadata");
_add_dir("/etc/lvm/metadata", dir_list);
return fmt;
}
tc->path = path;
tc->desc = d;
tc->um = um;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"metadata/dirs");
goto err;
}
fi->cmd = cmd;
fi->ops = &_text_handler;
fi->private = tc;
if (!_add_dir(cv->v.str, dir_list)) {
log_error("Failed to add %s to internal device cache",
cv->v.str);
goto err;
}
}
return fi;
return fmt;
no_mem:
if (fi)
dbg_free(fi);
err:
_free_dirs(dir_list);
if (path)
dbg_free(path);
if (d)
dbg_free(path);
log_err("Couldn't allocate text format object.");
dbg_free(fmt);
return NULL;
}

View File

@@ -32,9 +32,8 @@ int archive_list(struct cmd_context *cmd, struct uuid_map *um,
/*
* The text format can read and write a volume_group to a file.
*/
struct format_instance *text_format_create(struct cmd_context *cmd,
const char *file,
struct uuid_map *um,
const char *desc);
struct format_type *create_text_format(struct cmd_context *cmd);
void *create_text_context(struct format_type *fmt, const char *path,
const char *desc);
#endif

View File

@@ -14,6 +14,19 @@
#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,
@@ -25,7 +38,8 @@ 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 cmd_context *cmd, const char *file,
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um,
time_t *when, char **desc);

View File

@@ -11,12 +11,12 @@
#include "uuid.h"
#include "hash.h"
#include "toolcontext.h"
#include "display.h"
typedef int (*section_fn)(struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um);
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)
@@ -27,34 +27,82 @@ typedef int (*section_fn)(struct pool *mem,
#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)
/*
* 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_file *cf)
{
struct config_node *cn;
struct config_value *cv;
if (!(cn = find_config_node(cn, path, '/'))) {
log_err("Couldn't find uuid.");
/*
* 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->v.str) {
log_err("uuid must be a string.");
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE))
{
_invalid_format("unrecognised contents field");
return 0;
}
if (!id_read_format(id, cv->v.str)) {
log_err("Invalid uuid.");
/*
* 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_pv(struct pool *mem,
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 uuid_map *um)
struct hash_table *pv_hash, struct uuid_map *um)
{
struct physical_volume *pv;
struct pv_list *pvl;
@@ -78,12 +126,12 @@ static int _read_pv(struct pool *mem,
}
if (!(pvn = pvn->child)) {
log_err("Empty pv section.");
log_error("Empty pv section.");
return 0;
}
if (!_read_id(&pv->id, pvn, "id")) {
log_err("Couldn't read uuid for volume group.");
log_error("Couldn't read uuid for volume group.");
return 0;
}
@@ -93,13 +141,15 @@ static int _read_pv(struct pool *mem,
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.");
return 0;
}
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);
log_err("Couldn't find device with uuid '%s'.", buffer);
return 0;
if (partial_mode())
vg->status |= PARTIAL_VG;
else
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
@@ -108,22 +158,22 @@ static int _read_pv(struct pool *mem,
}
if (!(cn = find_config_node(pvn, "status", '/'))) {
log_err("Couldn't find status flags for physical volume.");
log_error("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.");
log_error("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.");
log_error("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 "
log_error("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
}
@@ -134,7 +184,8 @@ static int _read_pv(struct pool *mem,
pv->pe_size = vg->extent_size;
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
pv->pe_allocated = 0;
pv->pe_alloc_count = 0;
pv->fid = fid;
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
@@ -148,7 +199,7 @@ static void _insert_segment(struct logical_volume *lv,
struct list *segh;
struct stripe_segment *comp;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
comp = list_item(segh, struct stripe_segment);
if (comp->le > seg->le) {
@@ -173,13 +224,12 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
const char *seg_name = sn->key;
if (!(sn = sn->child)) {
log_err("Empty segment section.");
log_error("Empty segment section.");
return 0;
}
if (!_read_int32(sn, "stripes", &stripes)) {
log_err("Couldn't read 'stripes' for segment '%s'.",
sn->key);
log_error("Couldn't read 'stripes' for segment '%s'.", sn->key);
return 0;
}
@@ -192,32 +242,32 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
seg->lv = lv;
if (!_read_int32(sn, "start_extent", &seg->le)) {
log_err("Couldn't read 'start_extent' for segment '%s'.",
log_error("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'.",
log_error("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'.",
log_error("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'.",
log_error("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'.",
log_error("Couldn't find 'areas' array for segment '%s'.",
sn->key);
return 0;
}
@@ -234,27 +284,26 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
uint32_t allocated;
if (cv->type != CFG_STRING) {
log_err(bad, sn->key);
log_error(bad, sn->key);
return 0;
}
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
log_err("Couldn't find physical volume '%s' for "
log_error("Couldn't find physical volume '%s' for "
"segment '%s'.",
cn->v->v.str ? cn->v->v.str : "NULL",
seg_name);
return 0;
cv->v.str ? cv->v.str : "NULL", seg_name);
return 0;
}
seg->area[s].pv = pv;
if (!(cv = cv->next)) {
log_err(bad, sn->key);
log_error(bad, sn->key);
return 0;
}
if (cv->type != CFG_INT) {
log_err(bad, sn->key);
log_error(bad, sn->key);
return 0;
}
@@ -264,7 +313,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
* Adjust the extent counts in the pv and vg.
*/
allocated = seg->len / seg->stripes;
pv->pe_allocated += allocated;
pv->pe_alloc_count += allocated;
vg->free_count -= allocated;
}
@@ -272,7 +321,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->stripes)) {
log_err("Incorrect number of stripes in 'area' array "
log_error("Incorrect number of stripes in 'area' array "
"for segment '%s'.", seg_name);
return 0;
}
@@ -307,12 +356,12 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
}
if (!_read_int32(lvn, "segment_count", &seg_count)) {
log_err("Couldn't read segment count for logical volume.");
log_error("Couldn't read segment count for logical volume.");
return 0;
}
if (seg_count != count) {
log_err("segment_count and actual number of segments "
log_error("segment_count and actual number of segments "
"disagree.");
return 0;
}
@@ -336,7 +385,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
return 1;
}
static int _read_lv(struct pool *mem,
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)
@@ -359,7 +408,7 @@ static int _read_lv(struct pool *mem,
}
if (!(lvn = lvn->child)) {
log_err("Empty logical volume section.");
log_error("Empty logical volume section.");
return 0;
}
@@ -367,20 +416,19 @@ static int _read_lv(struct pool *mem,
/* 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);
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 (!(cn = find_config_node(lvn, "status", '/'))) {
log_err("Couldn't find status flags for logical volume.");
log_error("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.");
log_error("Couldn't read status flags for logical volume.");
return 0;
}
@@ -391,8 +439,24 @@ static int _read_lv(struct pool *mem,
return 0;
}
/*
* allocation_policy is optional since it is meaning less
* for things like mirrors and snapshots. Where it isn't
* specified we default to the next free policy.
*/
lv->alloc = ALLOC_NEXT_FREE;
if ((cn = find_config_node(lvn, "allocation_policy", '/'))) {
struct config_value *cv = cn->v;
if (!cv || !cv->v.str) {
log_err("allocation_policy must be a string.");
return 0;
}
lv->alloc = get_alloc_from_string(cv->v.str);
}
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
log_err("Couldn't read 'read_ahead' value for "
log_error("Couldn't read 'read_ahead' value for "
"logical volume.");
return 0;
}
@@ -410,7 +474,7 @@ static int _read_lv(struct pool *mem,
return 1;
}
static int _read_snapshot(struct pool *mem,
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)
@@ -420,33 +484,33 @@ static int _read_snapshot(struct pool *mem,
struct logical_volume *org, *cow;
if (!(sn = sn->child)) {
log_err("Empty snapshot section.");
log_error("Empty snapshot section.");
return 0;
}
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_err("Couldn't read chunk size for snapshot.");
log_error("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.");
log_error("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
log_err("Snapshot origin not specified.");
log_error("Snapshot origin not specified.");
return 0;
}
if (!(cow = find_lv(vg, cow_name))) {
log_err("Unknown logical volume specified for "
log_error("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_err("Unknown logical volume specified for "
log_error("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
@@ -459,18 +523,18 @@ static int _read_snapshot(struct pool *mem,
return 1;
}
static int _read_sections(const char *section, section_fn fn,
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 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);
log_error("Couldn't find section '%s'.", section);
return 0;
}
@@ -478,7 +542,7 @@ static int _read_sections(const char *section, section_fn fn,
}
for (n = n->child; n; n = n->sib) {
if (!fn(mem, vg, n, vgn, pv_hash, um)) {
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
stack;
return 0;
}
@@ -487,21 +551,20 @@ static int _read_sections(const char *section, section_fn fn,
return 1;
}
static struct volume_group *_read_vg(struct cmd_context *cmd,
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 = cmd->mem;
struct pool *mem = fid->fmt->cmd->mem;
/* skip any top-level values */
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib)
;
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
if (!vgn) {
log_err("Couldn't find volume group in file.");
log_error("Couldn't find volume group in file.");
return NULL;
}
@@ -509,7 +572,11 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
stack;
return NULL;
}
vg->cmd = cmd;
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;
@@ -532,25 +599,29 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
}
if (!_read_id(&vg->id, vgn, "id")) {
log_err("Couldn't read uuid for volume group %s.",
vg->name);
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_err("Couldn't find status flags for volume group %s.",
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_err("Couldn't read status flags for volume group %s.",
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_err("Couldn't read extent size for volume group %s.",
log_error("Couldn't read extent size for volume group %s.",
vg->name);
goto bad;
}
@@ -561,13 +632,13 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
*/
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
log_err("Couldn't read 'max_lv' for volume group %s.",
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_err("Couldn't read 'max_pv' for volume group %s.",
log_error("Couldn't read 'max_pv' for volume group %s.",
vg->name);
goto bad;
}
@@ -577,42 +648,47 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
* structures.
*/
if (!(pv_hash = hash_create(32))) {
log_err("Couldn't create hash table.");
log_error("Couldn't create hash table.");
goto bad;
}
list_init(&vg->pvs);
if (!_read_sections("physical_volumes", _read_pv, mem, vg,
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 "
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->lvs);
if (!_read_sections("logical_volumes", _read_lv, mem, vg,
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 "
log_error("Couldn't read all logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->snapshots);
if (!_read_sections("snapshots", _read_snapshot, mem, vg,
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.",
log_error("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:
bad:
if (pv_hash)
hash_destroy(pv_hash);
@@ -621,7 +697,7 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
}
static void _read_desc(struct pool *mem,
struct config_file *cf, time_t *when, char **desc)
struct config_file *cf, time_t * when, char **desc)
{
const char *d;
unsigned int u = 0u;
@@ -633,10 +709,10 @@ static void _read_desc(struct pool *mem,
*when = u;
}
struct volume_group *text_vg_import(struct cmd_context *cmd,
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um,
time_t *when, char **desc)
time_t * when, char **desc)
{
struct volume_group *vg = NULL;
struct config_file *cf;
@@ -654,16 +730,17 @@ struct volume_group *text_vg_import(struct cmd_context *cmd,
goto out;
}
if (!(vg = _read_vg(cmd, cf, um))) {
if (!_check_version(cf))
goto out;
if (!(vg = _read_vg(fid, cf, um))) {
stack;
goto out;
}
vg->cmd = cmd;
_read_desc(fid->fmt->cmd->mem, cf, when, desc);
_read_desc(cmd->mem, cf, when, desc);
out:
out:
destroy_config_file(cf);
return vg;
}

View File

@@ -21,7 +21,6 @@ struct labeller_i {
static struct list _labellers;
static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
{
struct labeller_i *li;
@@ -45,7 +44,6 @@ static void _free_li(struct labeller_i *li)
dbg_free(li);
}
int label_init(void)
{
list_init(&_labellers);
@@ -82,7 +80,7 @@ struct labeller *label_get_handler(const char *name)
struct list *lih;
struct labeller_i *li;
list_iterate (lih, &_labellers) {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (!strcmp(li->name, name))
return li->l;
@@ -96,7 +94,7 @@ static struct labeller *_find_labeller(struct device *dev)
struct list *lih;
struct labeller_i *li;
list_iterate (lih, &_labellers) {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, dev))
return li->l;
@@ -124,7 +122,7 @@ int label_read(struct device *dev, struct label **result)
struct list *lih;
struct labeller_i *li;
list_iterate (lih, &_labellers) {
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;

View File

@@ -27,324 +27,337 @@
#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;
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];
uint32_t version[3];
char disk_type[32];
};
struct filter_private
{
void *mem;
char disk_type[32];
uint32_t version[3];
int version_match;
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 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;
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;
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;
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);
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;
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)
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
long *first, long *second)
{
*first = sectsize;
*second = size*BLOCK_SIZE - sectsize;
*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)
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];
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)
{
if (!dev_get_size(dev, &size))
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);
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Make sure datalen is a sensible size too */
if (incore->extra_len > sectsize)
continue;
if (!dev_open(dev, O_RDONLY))
return 0;
/* 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)
{
block = dbg_malloc(sectsize);
if (!block) {
stack;
return 0;
}
memcpy(incore->extra_info, block + sizeof(struct label_ondisk), incore->extra_len);
dbg_free(block);
dev_close(dev);
return 1;
}
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
dbg_free(block);
dev_close(dev);
/* 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;
return 0;
/* 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)
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];
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_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
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;
/* 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;
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]);
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));
/* 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");
}
/* Write metadata to disk */
if (!dev_open(dev, O_RDWR))
{
dbg_free(block);
return 0;
}
dev_close(dev);
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 ((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;
struct label *label;
int status;
status = lvm2_label_read(l, dev, &label);
if (status) label_free(label);
status = lvm2_label_read(l, dev, &label);
if (status)
label_free(label);
return status;
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;
struct label *l;
int status;
struct filter_private *fp = (struct filter_private *) f->private;
status = lvm2_label_read(NULL, dev, &l);
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;
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_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_LESSEQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] <= fp->version[1])
return 1;
break;
case VERSION_MATCH_ANY:
return 1;
}
case VERSION_MATCH_ANY:
return 1;
}
}
label_free(l);
}
label_free(l);
}
return 0;
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);
return lvm2_is_labelled(NULL, dev);
}
static void _destroy(struct dev_filter *f)
{
struct filter_private *fp = (struct filter_private *) f->private;
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 dev_filter *lvm2_label_format_filter_create(char *disk_type,
uint32_t version[3],
int match_type)
{
struct pool *mem;
struct pool *mem;
struct filter_private *fp;
struct dev_filter *f;
@@ -353,7 +366,7 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
match_type != VERSION_MATCH_LESSTHAN &&
match_type != VERSION_MATCH_LESSEQUAL &&
match_type != VERSION_MATCH_ANY)
return 0;
return 0;
mem = pool_create(10 * 1024);
if (!mem) {
@@ -362,13 +375,13 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
stack;
goto bad;
}
fp->mem = mem;
@@ -383,7 +396,7 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
return f;
bad:
bad:
pool_destroy(mem);
return NULL;
}
@@ -401,13 +414,13 @@ struct dev_filter *lvm2_label_filter_create()
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
stack;
goto bad;
}
fp->mem = mem;
@@ -417,7 +430,7 @@ struct dev_filter *lvm2_label_filter_create()
return f;
bad:
bad:
pool_destroy(mem);
return NULL;
}
@@ -425,137 +438,132 @@ struct dev_filter *lvm2_label_filter_create()
/* 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];
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_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
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;
}
block1 = dbg_malloc(sectsize);
if (!block1) {
stack;
return 0;
}
block2 = dbg_malloc(sectsize);
if (!block2)
{
stack;
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 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;
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];
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_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDWR))
{
dbg_free(block);
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);
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");
/* 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");
/* ...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);
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
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 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,
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);
label_register_handler("LVM2", &this_labeller);
}

View File

@@ -12,12 +12,12 @@
#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;
@@ -67,4 +67,33 @@ struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
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

@@ -9,6 +9,7 @@
#include "uuid.h"
#include "dev-cache.h"
#include "pool.h"
/*
* Holds a mapping from uuid -> device.
@@ -22,5 +23,7 @@ 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

@@ -25,39 +25,39 @@
#include <signal.h>
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 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);
else
return 0;
if (lock_fn)
return lock_fn(cmd, resource, flags);
else
return 0;
}
static void fin_external_locking(void)
{
if (end_fn)
end_fn();
if (end_fn)
end_fn();
dlclose(locking_module);
dlclose(locking_module);
locking_module = NULL;
end_fn = NULL;
lock_fn = NULL;
locking_module = NULL;
end_fn = NULL;
lock_fn = NULL;
}
int init_external_locking(struct locking_type *locking, struct config_file *cf)
{
char _lock_lib[PATH_MAX];
char _lock_lib[PATH_MAX];
if (locking_module)
{
log_error("External locking already initialised\n");
return 1;
if (locking_module) {
log_error("External locking already initialised");
return 1;
}
locking->lock_resource = lock_resource;
locking->fin_locking = fin_external_locking;
@@ -67,51 +67,47 @@ int init_external_locking(struct locking_type *locking, struct config_file *cf)
'/', "lvm2_locking.so"),
sizeof(_lock_lib));
/* 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];
if (_lock_lib[0] != '/') {
struct stat st;
char _lock_lib1[PATH_MAX];
lvm_snprintf(_lock_lib1, sizeof(_lock_lib1),
"%s/%s",
find_config_str(cf->root, "global/module_dir",
'/', "RUBBISH"),
_lock_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);
}
/* 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\n", _lock_lib);
return 0;
if (!locking_module) {
log_error("Unable to open external locking module %s",
_lock_lib);
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");
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\n", _lock_lib);
dlclose(locking_module);
return 0;
if (!end_fn || !init_fn || !lock_fn) {
log_error ("Shared library %s does not contain locking "
"functions", _lock_lib);
dlclose(locking_module);
return 0;
}
log_verbose("Opened external locking module %s", _lock_lib);

View File

@@ -181,7 +181,7 @@ static int _lock_file(const char *file, int flags)
return 0;
}
int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
int file_lock_resource(struct cmd_context *cmd, const char *resource, int flags)
{
char lockfile[PATH_MAX];
@@ -197,6 +197,10 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int 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:
if (!lv_resume_if_active(cmd, resource))
@@ -229,7 +233,7 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
int init_file_locking(struct locking_type *locking, struct config_file *cf)
{
locking->lock_resource = lock_resource;
locking->lock_resource = file_lock_resource;
locking->fin_locking = fin_file_locking;
/* Get lockfile directory from config file */
@@ -240,6 +244,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

@@ -10,8 +10,12 @@
#include "locking_types.h"
#include "lvm-string.h"
#include "activate.h"
#include "toolcontext.h"
#include "defaults.h"
#include <signal.h>
#include <sys/stat.h>
#include <limits.h>
static struct locking_type _locking;
static sigset_t _oldset;
@@ -75,24 +79,33 @@ int init_locking(int type, struct config_file *cf)
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;
case 2:
if (!init_external_locking(&_locking, cf))
return 0;
break;
log_very_verbose("External locking enabled.");
break;
return 1;
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,6 +114,33 @@ 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];
if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s",
find_config_str(cmd->cf->root, "global/proc", '/',
DEFAULT_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.
@@ -125,8 +165,13 @@ 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. */
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, (char *) vol, sizeof(resource));
break;
default:

View File

@@ -24,18 +24,23 @@ 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_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 0x00000010 /* This is ours */
/*
* Lock scope
@@ -64,4 +69,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)

View File

@@ -18,6 +18,7 @@ static int _syslog = 0;
static int _indent = 1;
static int _log_cmd_name = 0;
static int _log_suppress = 0;
static int _ignorelockingfailure = 0;
static char _cmd_name[30] = "";
static char _msg_prefix[30] = " ";
@@ -66,6 +67,11 @@ void init_partial(int level)
_partial = level;
}
void init_ignorelockingfailure(int level)
{
_ignorelockingfailure = level;
}
void init_cmd_name(int status)
{
_log_cmd_name = status;
@@ -100,6 +106,11 @@ int partial_mode()
return _partial;
}
int ignorelockingfailure()
{
return _ignorelockingfailure;
}
void init_debug(int level)
{
_debug_level = level;

View File

@@ -52,12 +52,14 @@ void init_debug(int level);
void init_cmd_name(int status);
void init_msg_prefix(const char *prefix);
void init_indent(int indent);
void init_ignorelockingfailure(int level);
void set_cmd_name(const char *cmd_name);
int test_mode(void);
int partial_mode(void);
int debug_level(void);
int ignorelockingfailure(void);
/* Suppress messages to stdout/stderr */
void log_suppress(int suppress);

View File

@@ -25,7 +25,7 @@ static void _get_extents(struct stripe_segment *seg)
for (s = 0; s < seg->stripes; s++) {
pv = seg->area[s].pv;
count = seg->len / seg->stripes;
pv->pe_allocated += count;
pv->pe_alloc_count += count;
}
}
@@ -38,8 +38,8 @@ static void _put_extents(struct stripe_segment *seg)
pv = seg->area[s].pv;
count = seg->len / seg->stripes;
assert(pv->pe_allocated >= count);
pv->pe_allocated -= count;
assert(pv->pe_alloc_count >= count);
pv->pe_alloc_count -= count;
}
}
@@ -58,7 +58,7 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
uint32_t stripe_size,
struct pv_area **areas, uint32_t *index)
struct pv_area **areas, uint32_t * index)
{
uint32_t count = lv->le_count - *index;
uint32_t per_area = count / stripes;
@@ -117,8 +117,8 @@ static int _alloc_striped(struct logical_volume *lv,
struct pv_map *pvm;
size_t len;
list_iterate (pvmh, pvms)
pv_count++;
list_iterate(pvmh, pvms)
pv_count++;
/* allocate an array of pv_areas, one candidate per pv */
len = sizeof(*areas) * pv_count;
@@ -130,7 +130,7 @@ static int _alloc_striped(struct logical_volume *lv,
while (allocated != lv->le_count) {
index = 0;
list_iterate (pvmh, pvms) {
list_iterate(pvmh, pvms) {
pvm = list_item(pvmh, struct pv_map);
if (list_empty(&pvm->areas))
@@ -143,8 +143,7 @@ static int _alloc_striped(struct logical_volume *lv,
if (index < stripes) {
log_error("Insufficient allocatable extents suitable "
"for striping for logical volume "
"%s: %u required",
lv->name, lv->le_count);
"%s: %u required", lv->name, lv->le_count);
goto out;
}
@@ -159,19 +158,18 @@ static int _alloc_striped(struct logical_volume *lv,
}
r = 1;
out:
out:
dbg_free(areas);
return r;
}
/*
* The heart of the allocation code. This function takes a
* pv_area and allocates it to the lv. If the lv doesn't need
* the complete area then the area is split, otherwise the area
* is unlinked from the pv_map.
*/
static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
struct pv_map *map, struct pv_area *pva)
{
uint32_t count, remaining;
@@ -268,7 +266,7 @@ static int _alloc_simple(struct logical_volume *lv,
}
}
done:
done:
if (allocated != lv->le_count) {
log_error("Insufficient allocatable logical extents (%u) "
"for logical volume %s: %u required",
@@ -304,10 +302,10 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
if (stripes > 1)
r = _alloc_striped(lv, pvms, allocated, stripes, stripe_size);
else if (lv->status & ALLOC_CONTIGUOUS)
else if (lv->alloc == ALLOC_CONTIGUOUS)
r = _alloc_contiguous(lv, pvms, allocated);
else if (lv->status & ALLOC_SIMPLE)
else if (lv->alloc == ALLOC_NEXT_FREE)
r = _alloc_simple(lv, pvms, allocated);
else {
@@ -364,6 +362,7 @@ static char *_generate_lv_name(struct volume_group *vg,
struct logical_volume *lv_create(struct format_instance *fi,
const char *name,
uint32_t status,
alloc_policy_t alloc,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents,
@@ -396,7 +395,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
if (stripes > list_size(acceptable_pvs)) {
log_error("Number of stripes (%u) must not exceed "
"number of physical volumes (%d)", stripes,
list_size(acceptable_pvs));
list_size(acceptable_pvs));
return NULL;
}
@@ -424,9 +423,10 @@ struct logical_volume *lv_create(struct format_instance *fi,
}
lv->status = status;
lv->alloc = alloc;
lv->read_ahead = 0;
lv->minor = -1;
lv->size = (uint64_t) extents * vg->extent_size;
lv->size = (uint64_t) extents *vg->extent_size;
lv->le_count = extents;
list_init(&lv->segments);
@@ -435,7 +435,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
goto bad;
}
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
goto bad;
}
@@ -445,7 +445,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
return lv;
bad:
bad:
if (ll)
pool_free(cmd->mem, ll);
@@ -460,8 +460,7 @@ int lv_reduce(struct format_instance *fi,
uint32_t count = extents;
for (segh = lv->segments.p;
(segh != &lv->segments) && count;
segh = segh->p) {
(segh != &lv->segments) && count; segh = segh->p) {
seg = list_item(segh, struct stripe_segment);
if (seg->len <= count) {
@@ -480,8 +479,9 @@ int lv_reduce(struct format_instance *fi,
lv->le_count -= extents;
lv->size = (uint64_t) lv->le_count * lv->vg->extent_size;
lv->vg->free_count += extents;
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
return 0;
}
@@ -492,16 +492,13 @@ int lv_reduce(struct format_instance *fi,
int lv_extend(struct format_instance *fi,
struct logical_volume *lv,
uint32_t stripes, uint32_t stripe_size,
uint32_t extents,
struct list *acceptable_pvs)
uint32_t extents, struct list *acceptable_pvs)
{
uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size;
lv->le_count += extents;
lv->size += (uint64_t) extents * lv->vg->extent_size;
/* FIXME: Format1 must ensure stripes is consistent with 1st seg */
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count,
stripes, stripe_size)) {
@@ -516,7 +513,7 @@ int lv_extend(struct format_instance *fi,
return 0;
}
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
return 0;
}
@@ -536,8 +533,8 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
}
/* iterate through the lv's segments freeing off the pe's */
list_iterate (segh, &lv->segments)
_put_extents(list_item(segh, struct stripe_segment));
list_iterate(segh, &lv->segments)
_put_extents(list_item(segh, struct stripe_segment));
vg->lv_count--;
vg->free_count += lv->le_count;

View File

@@ -41,7 +41,7 @@ int lv_merge_segments(struct logical_volume *lv)
struct list *segh;
struct stripe_segment *current, *prev = NULL;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
current = list_item(segh, struct stripe_segment);
if (_merge(prev, current))

View File

@@ -12,6 +12,7 @@
#include "toolcontext.h"
#include "lvm-string.h"
#include "uuid.h"
#include "vgcache.h"
#include <string.h>
@@ -20,17 +21,17 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
{
struct pv_list *pvl;
struct physical_volume *pv;
struct pool *mem = fi->cmd->mem;
struct pool *mem = fi->fmt->cmd->mem;
log_verbose("Adding physical volume '%s' to volume group '%s'",
pv_name, vg->name);
if (!(pvl = pool_alloc(mem, sizeof (*pvl)))) {
if (!(pvl = pool_alloc(mem, sizeof(*pvl)))) {
log_error("pv_list allocation for '%s' failed", pv_name);
return 0;
}
if (!(pv = fi->ops->pv_read(fi, pv_name))) {
if (!(pv = pv_read(fi->fmt->cmd, pv_name))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
@@ -50,16 +51,20 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
/* Units of 512-byte sectors */
pv->pe_size = vg->extent_size;
/* FIXME Do proper rounding-up alignment? */
/* Reserved space for label; this holds 0 for PVs created by LVM1 */
if (pv->pe_start < PE_ALIGN)
pv->pe_start = PE_ALIGN;
/*
* The next two fields should be corrected
* by fi->pv_setup.
*/
pv->pe_start = 0;
pv->pe_count = pv->size / pv->pe_size;
pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size;
pv->pe_allocated = 0;
pv->pe_alloc_count = 0;
if (!fi->ops->pv_setup(fi, pv, vg)) {
if (!fi->fmt->ops->pv_setup(fi, pv, vg)) {
log_error("Format-specific setup of physical volume '%s' "
"failed.", pv_name);
return 0;
@@ -113,42 +118,43 @@ const char *strip_dir(const char *vg_name, const char *dev_dir)
return vg_name;
}
struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
uint32_t extent_size, int max_pv, int max_lv,
int pv_count, char **pv_names)
{
struct volume_group *vg;
struct pool *mem = fi->cmd->mem;
struct pool *mem = cmd->mem;
if (!(vg = pool_alloc(mem, sizeof (*vg)))) {
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
return NULL;
}
/* is this vg name already in use ? */
init_partial(1);
if (fi->ops->vg_read(fi, vg_name)) {
if (vg_read(cmd, vg_name)) {
log_err("A volume group called '%s' already exists.", vg_name);
goto bad;
}
init_partial(0);
if (!id_create(&vg->id)) {
log_err("Couldn't create uuid for volume group '%s'.",
vg_name);
log_err("Couldn't create uuid for volume group '%s'.", vg_name);
goto bad;
}
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
vg_name = strip_dir(vg_name, cmd->dev_dir);
vg->cmd = fi->cmd;
vg->cmd = cmd;
if (!(vg->name = pool_strdup(mem, vg_name))) {
stack;
goto bad;
}
vg->seqno = 0;
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
vg->system_id = pool_alloc(mem, NAME_LEN);
*vg->system_id = '\0';
@@ -169,30 +175,35 @@ struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
vg->snapshot_count = 0;
list_init(&vg->snapshots);
if (!fi->ops->vg_setup(fi, vg)) {
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
NULL))) {
log_error("Failed to create format instance");
goto bad;
}
if (!vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
log_error("Format specific setup of volume group '%s' failed.",
vg_name);
goto bad;
}
/* attach the pv's */
if (!vg_extend(fi, vg, pv_count, pv_names))
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
goto bad;
return vg;
bad:
bad:
pool_free(mem, vg);
return NULL;
}
struct physical_volume *pv_create(struct format_instance *fi,
struct physical_volume *pv_create(struct format_instance *fid,
const char *name,
struct id *id,
uint64_t size)
struct id *id, uint64_t size)
{
struct pool *mem = fi->cmd->mem;
struct physical_volume *pv = pool_alloc(mem, sizeof (*pv));
struct pool *mem = fid->fmt->cmd->mem;
struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
if (!pv) {
stack;
@@ -204,7 +215,7 @@ struct physical_volume *pv_create(struct format_instance *fi,
else
memcpy(&pv->id, id, sizeof(*id));
if (!(pv->dev = dev_cache_get(name, fi->cmd->filter))) {
if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) {
log_error("%s: Couldn't find device.", name);
goto bad;
}
@@ -225,14 +236,14 @@ struct physical_volume *pv_create(struct format_instance *fi,
if (size) {
if (size > pv->size)
log_print("WARNING: %s: Overriding real size. "
"You could lose data.", name);
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
"You could lose data.", name);
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
name, size);
pv->size = size;
}
if (pv->size < PV_MIN_SIZE) {
log_error("%s: Size must exceed minimum of %lu sectors.",
log_error("%s: Size must exceed minimum of %lu sectors.",
name, PV_MIN_SIZE);
goto bad;
}
@@ -240,9 +251,10 @@ struct physical_volume *pv_create(struct format_instance *fi,
pv->pe_size = 0;
pv->pe_start = 0;
pv->pe_count = 0;
pv->pe_allocated = 0;
pv->pe_alloc_count = 0;
pv->fid = fid;
if (!fi->ops->pv_setup(fi, pv, NULL)) {
if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) {
log_error("%s: Format-specific setup of physical volume "
"failed.", name);
goto bad;
@@ -324,3 +336,249 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
return NULL;
}
int vg_remove(struct volume_group *vg)
{
struct list *mdah;
void *mdl;
if (!vg->fid->fmt->ops->vg_remove)
return 1;
/* FIXME Improve recovery situation? */
/* Remove each copy of the metadata */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_remove(vg->fid, vg, mdl)) {
stack;
return 0;
}
}
return 1;
}
int vg_write(struct volume_group *vg)
{
struct list *mdah;
void *mdl;
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
vg->name);
return 0;
}
vg->seqno++;
/* Write to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_write(vg->fid, vg, mdl)) {
stack;
return 0;
}
}
if (!vg->fid->fmt->ops->vg_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_commit(vg->fid, vg, mdl)) {
stack;
return 0;
}
}
return 1;
}
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
{
struct format_instance *fid;
struct format_type *fmt;
struct volume_group *vg, *correct_vg;
struct list *mdah, *names;
void *mdl;
int inconsistent = 0, first_time = 1;
/* create format instance with appropriate metadata area */
if (!(fmt = vgcache_find_format(vg_name))) {
/* Do full scan */
if (!(names = get_vgs(cmd))) {
stack;
return NULL;
}
pool_free(cmd->mem, names);
if (!(fmt = vgcache_find_format(vg_name))) {
stack;
return NULL;
}
}
if (!(fid = fmt->ops->create_instance(fmt, vg_name, NULL))) {
log_error("Failed to create format instance");
return NULL;
}
/* Ensure contents of all metadata areas match - else do recovery */
list_iterate(mdah, &fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!(vg = fid->fmt->ops->vg_read(fid, vg_name, mdl))) {
inconsistent = 1;
continue;
}
if (first_time) {
correct_vg = vg;
first_time = 0;
continue;
}
if (correct_vg->seqno != vg->seqno) {
inconsistent = 1;
if (vg->seqno > correct_vg->seqno)
correct_vg = vg;
}
}
/* Failed to find VG */
if (first_time) {
stack;
return NULL;
}
if (inconsistent) {
log_print("Inconsistent metadata copies found - updating "
"to use version %u", correct_vg->seqno);
if (!vg_write(correct_vg)) {
log_error("Automatic metadata correction failed");
return NULL;
}
}
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
return correct_vg;
}
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
{
char *vgname;
struct list *vgs, *vgh;
struct volume_group *vg;
if (!(vgs = get_vgs(cmd))) {
log_error("vg_read_by_vgid: get_vgs failed");
return NULL;
}
list_iterate(vgh, vgs) {
vgname = list_item(vgh, struct name_list)->name;
if ((vg = vg_read(cmd, vgname)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) return vg;
}
pool_free(cmd->mem, vgs);
return NULL;
}
/* FIXME Use label functions instead of PV functions? */
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
{
struct physical_volume *pv;
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
log_error("pv_list allocation for '%s' failed", pv_name);
return 0;
}
/* Member of a format1 VG? */
if (!(cmd->fmt1->ops->pv_read(cmd->fmt1, pv_name, pv))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
}
/* Member of a format_text VG? */
if (!(cmd->fmtt->ops->pv_read(cmd->fmtt, pv_name, pv))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
}
if (!pv->size)
return NULL;
else
return pv;
}
struct list *get_vgs(struct cmd_context *cmd)
{
struct list *names;
if (!(names = pool_alloc(cmd->mem, sizeof(*names)))) {
log_error("VG name list allocation failed");
return NULL;
}
list_init(names);
if (!cmd->fmt1->ops->get_vgs(cmd->fmt1, names) ||
!cmd->fmtt->ops->get_vgs(cmd->fmtt, names) ||
list_empty(names)) {
pool_free(cmd->mem, names);
return NULL;
}
return names;
}
struct list *get_pvs(struct cmd_context *cmd)
{
struct list *results;
if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) {
log_error("PV list allocation failed");
return NULL;
}
list_init(results);
/* fmtt modifies fmt1 output */
if (!cmd->fmt1->ops->get_pvs(cmd->fmt1, results) ||
!cmd->fmtt->ops->get_pvs(cmd->fmtt, results)) {
pool_free(cmd->mem, results);
return NULL;
}
return results;
}
int pv_write(struct cmd_context *cmd, struct physical_volume *pv)
{
struct list *mdah;
void *mdl;
/* Write to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_write(pv->fid, pv, mdl)) {
stack;
return 0;
}
}
if (!pv->fid->fmt->ops->pv_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_commit(pv->fid, pv, mdl)) {
stack;
return 0;
}
}
return 1;
}

View File

@@ -23,38 +23,53 @@
#define STRIPE_SIZE_MIN ( PAGE_SIZE/SECTOR_SIZE) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MAX ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
#define PV_MIN_SIZE ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
#define PE_ALIGN (65536UL / SECTOR_SIZE) /* PE alignment */
/* Various flags */
/* Note that the bits no longer necessarily correspond to LVM1 disk format */
#define EXPORTED_VG 0x00000002 /* VG PV */
#define RESIZEABLE_VG 0x00000004 /* VG */
#define PARTIAL_VG 0x00000040 /* VG */
#define BIT(x) (1 << x)
#define EXPORTED_VG BIT(0) /* VG PV */
#define RESIZEABLE_VG BIT(1) /* VG */
#define PARTIAL_VG BIT(2) /* VG */
/* May any free extents on this PV be used or must they be left free? */
#define ALLOCATABLE_PV 0x00000008 /* PV */
/*
* May any free extents on this PV be used or must they be left
* free?
*/
#define ALLOCATABLE_PV BIT(3) /* PV */
#define SPINDOWN_LV 0x00000010 /* LV */
#define BADBLOCK_ON 0x00000020 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */
#define SPINDOWN_LV BIT(4) /* LV */
#define BADBLOCK_ON BIT(5) /* LV */
#define FIXED_MINOR BIT(6) /* LV */
#define VISIBLE_LV BIT(7) /* LV */
/* FIXME: do we really set read/write for a whole vg ? */
#define LVM_READ 0x00000100 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */
#define CLUSTERED 0x00000400 /* VG */
#define SHARED 0x00000800 /* VG */
/*
* FIXME: do we really set read/write for a whole vg ?
*/
#define LVM_READ BIT(8) /* LV VG */
#define LVM_WRITE BIT(9) /* LV VG */
#define CLUSTERED BIT(10) /* VG */
#define SHARED BIT(11) /* VG */
/* FIXME: This should be an enum rather than a bitset,
remove from status - EJT */
#define ALLOC_SIMPLE 0x00001000 /* LV */
#define ALLOC_STRICT 0x00002000 /* LV */
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */
#define FMT_TEXT_NAME "text"
#define FMT_LVM1_NAME "lvm1"
typedef enum {
ALLOC_NEXT_FREE,
ALLOC_STRICT,
ALLOC_CONTIGUOUS
} alloc_policy_t;
struct physical_volume {
struct id id;
struct device *dev;
struct format_instance *fid;
char *vg_name;
uint32_t status;
@@ -64,13 +79,33 @@ struct physical_volume {
uint64_t pe_size;
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_allocated; /* FIXME: change the name to alloc_count ? */
uint32_t pe_alloc_count;
};
struct cmd_context;
struct format_type {
struct cmd_context *cmd;
struct format_handler *ops;
const char *name;
uint32_t features;
void *private;
};
struct metadata_area {
struct list list;
void *metadata_locn;
};
struct format_instance {
struct format_type *fmt;
struct list metadata_areas; /* e.g. metadata locations */
};
struct volume_group {
struct cmd_context *cmd;
struct format_instance *fid;
uint32_t seqno; /* Metadata sequence number */
struct id id;
char *name;
@@ -121,6 +156,7 @@ struct logical_volume {
struct volume_group *vg;
uint32_t status;
alloc_policy_t alloc;
uint32_t read_ahead;
int32_t minor;
@@ -159,11 +195,6 @@ struct snapshot_list {
struct snapshot *snapshot;
};
struct format_instance {
struct cmd_context *cmd;
struct format_handler *ops;
void *private;
};
/*
@@ -173,18 +204,19 @@ struct format_handler {
/*
* Returns a name_list of vg's.
*/
struct list *(*get_vgs)(struct format_instance *fi);
struct list *(*get_vgs)(struct format_type *fmt, struct list *names);
/*
* Returns pv_list of fully-populated pv structures.
*/
struct list *(*get_pvs)(struct format_instance *fi);
struct list *(*get_pvs)(struct format_type *fmt, struct list *results);
/*
* Return PV with given path.
*/
struct physical_volume *(*pv_read)(struct format_instance *fi,
const char *pv_name);
int (*pv_read)(struct format_type *fmt,
const char *pv_name,
struct physical_volume *pv);
/*
* Tweak an already filled out a pv ready for importing into a
@@ -197,8 +229,10 @@ struct format_handler {
* Write a PV structure to disk. Fails if the PV is in a VG ie
* pv->vg_name must be null.
*/
int (*pv_write)(struct format_instance *fi,
struct physical_volume *pv);
int (*pv_write)(struct format_instance *fi, struct physical_volume *pv,
void *mdl);
int (*pv_commit)(struct format_instance *fid,
struct physical_volume *pv, void *mdl);
/*
* Tweak an already filled out a lv eg, check there
@@ -211,13 +245,16 @@ struct format_handler {
* specific.
*/
int (*vg_setup)(struct format_instance *fi, struct volume_group *vg);
int (*vg_remove)(struct format_instance *fi, struct volume_group *vg,
void *mdl);
/*
* The name may be prefixed with the dev_dir from the
* job_context.
* mdl is the metadata location to use
*/
struct volume_group *(*vg_read)(struct format_instance *fi,
const char *vg_name);
const char *vg_name, void *mdl);
/*
* Write out complete VG metadata. You must ensure internal
@@ -233,25 +270,50 @@ struct format_handler {
* in the volume_group structure it is handed. Note: format1
* does read all pv's currently.
*/
int (*vg_write)(struct format_instance *fi, struct volume_group *vg);
int (*vg_write)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
int (*vg_commit)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
/*
* Create format instance with a particular metadata area
*/
struct format_instance *(*create_instance)(struct format_type *fmt,
const char *vgname,
void *context);
/*
* Destructor for this object.
* Destructor for format instance
*/
void (*destroy)(struct format_instance *fi);
void (*destroy_instance)(struct format_instance *fid);
/*
* Destructor for format type
*/
void (*destroy)(struct format_type *fmt);
};
/*
* Utility functions
*/
int vg_write(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name);
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name);
struct list *get_pvs(struct cmd_context *cmd);
struct list *get_vgs(struct cmd_context *cmd);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv);
struct physical_volume *pv_create(struct format_instance *fi,
const char *name,
struct id *id,
uint64_t size);
struct volume_group *vg_create(struct format_instance *fi, const char *name,
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, int max_pv, int max_lv,
int pv_count, char **pv_names);
int vg_remove(struct volume_group *vg);
/*
* This needs the format instance to check the
@@ -268,6 +330,7 @@ int vg_extend(struct format_instance *fi,
struct logical_volume *lv_create(struct format_instance *fi,
const char *name,
uint32_t status,
alloc_policy_t alloc,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents,
@@ -341,6 +404,8 @@ int lv_is_origin(struct logical_volume *lv);
int lv_is_cow(struct logical_volume *lv);
struct snapshot *find_cow(struct logical_volume *lv);
struct snapshot *find_origin(struct logical_volume *lv);
struct list *find_snapshots(struct logical_volume *lv);
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,

View File

@@ -82,7 +82,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
}
/* populate the hash table */
list_iterate (pvmh, maps) {
list_iterate(pvmh, maps) {
pvm = list_item(pvmh, struct pv_map);
if (!hash_insert(hash, dev_name(pvm->pv->dev), pvm)) {
stack;
@@ -91,18 +91,18 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
}
/* iterate through all the lv's setting bit's for used pe's */
list_iterate (lvh, &vg->lvs) {
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
for (s = 0; s < seg->stripes; s++) {
for (pe = 0; pe < (seg->len / seg->stripes);
pe++) {
if (!_set_allocated(hash,
seg->area[s].pv,
seg->area[s].pe
seg->area[s].pv,
seg->area[s].pe
+ pe)) {
stack;
goto out;
@@ -113,7 +113,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
}
r = 1;
out:
out:
hash_destroy(hash);
return r;
}
@@ -131,7 +131,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
return;
}
list_iterate (pvah, head) {
list_iterate(pvah, head) {
pva = list_item(pvah, struct pv_area);
if (pva->count < a->count)
@@ -142,7 +142,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
}
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
uint32_t *extent)
uint32_t * extent)
{
uint32_t e = *extent, b, count = pvm->pv->pe_count;
struct pv_area *pva;

View File

@@ -13,7 +13,7 @@ int lv_is_origin(struct logical_volume *lv)
struct list *slh;
struct snapshot *s;
list_iterate (slh, &lv->vg->snapshots) {
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->origin == lv)
return 1;
@@ -27,7 +27,7 @@ int lv_is_cow(struct logical_volume *lv)
struct list *slh;
struct snapshot *s;
list_iterate (slh, &lv->vg->snapshots) {
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->cow == lv)
return 1;
@@ -36,12 +36,26 @@ int lv_is_cow(struct logical_volume *lv)
return 0;
}
struct snapshot *find_origin(struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->origin == lv)
return s;
}
return NULL;
}
struct snapshot *find_cow(struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate (slh, &lv->vg->snapshots) {
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->cow == lv)
return s;
@@ -50,10 +64,40 @@ struct snapshot *find_cow(struct logical_volume *lv)
return NULL;
}
struct list *find_snapshots(struct logical_volume *lv)
{
struct list *slh;
struct list *snaplist;
struct snapshot *s;
struct snapshot_list *newsl;
struct pool *mem = lv->vg->cmd->mem;
if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) {
log_error("snapshot name list allocation failed");
return NULL;
}
list_init(snaplist);
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (!(s->origin == lv))
continue;
if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) {
log_error("snapshot_list structure allocation failed");
pool_free(mem, snaplist);
return NULL;
}
newsl->snapshot = s;
list_add(snaplist, &newsl->list);
}
return snaplist;
}
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent,
uint32_t chunk_size)
int persistent, uint32_t chunk_size)
{
struct snapshot *s;
struct snapshot_list *sl;
@@ -94,7 +138,7 @@ int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
struct list *slh;
struct snapshot_list *sl;
list_iterate (slh, &vg->snapshots) {
list_iterate(slh, &vg->snapshots) {
sl = list_item(slh, struct snapshot_list);
if (sl->snapshot->cow == cow) {

View File

@@ -7,6 +7,7 @@
#include "log.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <stdlib.h>
#include <unistd.h>
@@ -128,7 +129,37 @@ int dir_exists(const char *path)
return 1;
}
/* FIXME: Make this create directories recursively */
static int _create_dir_recursive(const char *dir)
{
char *orig, *s;
int rc;
log_verbose("Creating directory \"%s\"", dir);
/* Create parent directories */
orig = s = dbg_strdup(dir);
while ((s = strchr(s, '/')) != NULL) {
*s = '\0';
if (*orig) {
rc = mkdir(orig, 0777);
if (rc < 0 && errno != EEXIST) {
log_sys_error("mkdir", orig);
dbg_free(orig);
return 0;
}
}
*s++ = '/';
}
dbg_free(orig);
/* Create final directory */
rc = mkdir(dir, 0777);
if (rc < 0 && errno != EEXIST) {
log_sys_error("mkdir", dir);
return 0;
}
return 1;
}
int create_dir(const char *dir)
{
struct stat info;
@@ -136,13 +167,8 @@ int create_dir(const char *dir)
if (!*dir)
return 1;
if (stat(dir, &info) < 0) {
log_verbose("Creating directory \"%s\"", dir);
if (!mkdir(dir, 0777))
return 1;
log_sys_error("mkdir", dir);
return 0;
}
if (stat(dir, &info) < 0)
return _create_dir_recursive(dir);
if (S_ISDIR(info.st_mode))
return 1;

View File

@@ -28,7 +28,7 @@ int dir_exists(const char *path);
int is_empty_dir(const char *dir);
/*
* Create directory (but not recursively) if necessary
* Return 1 if directory exists on return, else 0
* Create directory (recursively) if necessary. Return 1
* if directory was successfully created (or already exists), else 0.
*/
int create_dir(const char *dir);

View File

@@ -14,19 +14,20 @@
#include "log.h"
struct memblock {
struct memblock *prev, *next; /* All allocated blocks are linked */
size_t length; /* Size of the requested block */
int id; /* Index of the block */
const char *file; /* File that allocated */
int line; /* Line that allocated */
void *magic; /* Address of this block */
struct memblock *prev, *next; /* All allocated blocks are linked */
size_t length; /* Size of the requested block */
int id; /* Index of the block */
const char *file; /* File that allocated */
int line; /* Line that allocated */
void *magic; /* Address of this block */
};
static struct {
unsigned int blocks, mblocks;
unsigned int bytes, mbytes;
} _mem_stats = {0, 0, 0, 0};
} _mem_stats = {
0, 0, 0, 0};
static struct memblock *_head = 0;
static struct memblock *_tail = 0;
@@ -104,7 +105,7 @@ void free_aux(void *p)
/* check data at the far boundary */
ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
for (i = 0; i < sizeof(unsigned long); i++)
if(*ptr++ != (char) mb->id)
if (*ptr++ != (char) mb->id)
assert(!"Damage at far end of block");
/* have we freed this before ? */
@@ -159,7 +160,7 @@ int dump_memory(void)
log_very_verbose("You have a memory leak:");
for (mb = _head; mb; mb = mb->next) {
print_log(_LOG_INFO, mb->file, mb->line,
print_log(_LOG_INFO, mb->file, mb->line,
"block %d at %p, size %" PRIdPTR,
mb->id, mb->magic, mb->length);
tot += mb->length;

View File

@@ -18,11 +18,11 @@ struct chunk {
};
struct pool {
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
list to stop 'bobbling' */
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
list to stop 'bobbling' */
size_t chunk_size;
size_t object_len;
unsigned object_alignment;
unsigned object_alignment;
};
void _align_chunk(struct chunk *c, unsigned alignment);
@@ -75,12 +75,12 @@ void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
struct chunk *c = p->chunk;
void *r;
/* realign begin */
/* realign begin */
if (c)
_align_chunk(c, alignment);
/* have we got room ? */
if(!c || (c->begin > c->end) || (c->end - c->begin < s)) {
if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
/* allocate new chunk */
int needed = s + alignment + sizeof(struct chunk);
c = _new_chunk(p, (needed > p->chunk_size) ?
@@ -225,7 +225,8 @@ struct chunk *_new_chunk(struct pool *p, size_t s)
p->spare_chunk = 0;
} else {
if (!(c = dbg_malloc(s))) {
log_err("Out of memory. Requested %" PRIuPTR " bytes.", s);
log_err("Out of memory. Requested %" PRIuPTR " bytes.",
s);
return NULL;
}
@@ -238,4 +239,3 @@ struct chunk *_new_chunk(struct pool *p, size_t s)
return c;
}

View File

@@ -1,32 +1,17 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
* This file is released under the LGPL.
*
*/
#ifndef _LVM_XLATE_H
#define _LVM_XLATE_H
/* FIXME: finish these as inlines */
#include <asm/byteorder.h>
uint16_t shuffle16(uint16_t n);
uint32_t shuffle32(uint32_t n);
uint64_t shuffle64(uint64_t n);
/* xlate functions move data between core and disk */
#if __BYTE_ORDER == __BIG_ENDIAN
# define xlate16(x) shuffle16(x)
# define xlate32(x) shuffle32(x)
# define xlate64(x) shuffle64(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
# define xlate16(x) (x)
# define xlate32(x) (x)
# define xlate64(x) (x)
#else
# error "__BYTE_ORDER must be defined as __LITTLE_ENDIAN or __BIG_ENDIAN"
#endif
#define xlate16(x) __cpu_to_le16((x));
#define xlate32(x) __cpu_to_le32((x));
#define xlate64(x) __cpu_to_le64((x));
#endif

View File

@@ -25,7 +25,7 @@ struct state_queue {
struct state_queue *next;
};
struct matcher { /* Instance variables for the lexer */
struct matcher { /* Instance variables for the lexer */
struct dfa_state *start;
int num_nodes, nodes_entered;
struct rx_node **nodes;
@@ -38,10 +38,10 @@ static int _count_nodes(struct rx_node *rx)
{
int r = 1;
if(rx->left)
if (rx->left)
r += _count_nodes(rx->left);
if(rx->right)
if (rx->right)
r += _count_nodes(rx->right);
return r;
@@ -51,10 +51,10 @@ static void _fill_table(struct matcher *m, struct rx_node *rx)
{
assert((rx->type != OR) || (rx->left && rx->right));
if(rx->left)
if (rx->left)
_fill_table(m, rx->left);
if(rx->right)
if (rx->right)
_fill_table(m, rx->right);
m->nodes[m->nodes_entered++] = rx;
@@ -64,7 +64,7 @@ static void _create_bitsets(struct matcher *m)
{
int i;
for(i = 0; i < m->num_nodes; i++) {
for (i = 0; i < m->num_nodes; i++) {
struct rx_node *n = m->nodes[i];
n->firstpos = bitset_create(m->scratch, m->num_nodes);
n->lastpos = bitset_create(m->scratch, m->num_nodes);
@@ -77,23 +77,23 @@ static void _calc_functions(struct matcher *m)
int i, j, final = 1;
struct rx_node *rx, *c1, *c2;
for(i = 0; i < m->num_nodes; i++) {
for (i = 0; i < m->num_nodes; i++) {
rx = m->nodes[i];
c1 = rx->left;
c2 = rx->right;
if(bit(rx->charset, TARGET_TRANS))
if (bit(rx->charset, TARGET_TRANS))
rx->final = final++;
switch(rx->type) {
switch (rx->type) {
case CAT:
if(c1->nullable)
if (c1->nullable)
bit_union(rx->firstpos,
c1->firstpos, c2->firstpos);
else
bit_copy(rx->firstpos, c1->firstpos);
if(c2->nullable)
if (c2->nullable)
bit_union(rx->lastpos,
c1->lastpos, c2->lastpos);
else
@@ -136,10 +136,10 @@ static void _calc_functions(struct matcher *m)
* because PLUS and STAR do the
* same thing.
*/
switch(rx->type) {
switch (rx->type) {
case CAT:
for(j = 0; j < m->num_nodes; j++) {
if(bit(c1->lastpos, j)) {
for (j = 0; j < m->num_nodes; j++) {
if (bit(c1->lastpos, j)) {
struct rx_node *n = m->nodes[j];
bit_union(n->followpos,
n->followpos, c2->firstpos);
@@ -149,8 +149,8 @@ static void _calc_functions(struct matcher *m)
case PLUS:
case STAR:
for(j = 0; j < m->num_nodes; j++) {
if(bit(rx->lastpos, j)) {
for (j = 0; j < m->num_nodes; j++) {
if (bit(rx->lastpos, j)) {
struct rx_node *n = m->nodes[j];
bit_union(n->followpos,
n->followpos, rx->firstpos);
@@ -178,7 +178,7 @@ static struct state_queue *_create_state_queue(struct pool *mem,
}
r->s = dfa;
r->bits = bitset_create(mem, bits[0]); /* first element is the size */
r->bits = bitset_create(mem, bits[0]); /* first element is the size */
bit_copy(r->bits, bits);
r->next = 0;
return r;
@@ -218,28 +218,30 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
/* iterate through all the inputs for this state */
bit_clear_all(bs);
for(a = 0; a < 256; a++) {
for (a = 0; a < 256; a++) {
/* iterate through all the states in firstpos */
for(i = bit_get_first(dfa_bits);
i >=0;
i = bit_get_next(dfa_bits, i)) {
if(bit(m->nodes[i]->charset, a)) {
if(a == TARGET_TRANS)
for (i = bit_get_first(dfa_bits);
i >= 0; i = bit_get_next(dfa_bits, i)) {
if (bit(m->nodes[i]->charset, a)) {
if (a == TARGET_TRANS)
dfa->final = m->nodes[i]->final;
bit_union(bs, bs, m->nodes[i]->followpos);
bit_union(bs, bs,
m->nodes[i]->followpos);
set_bits = 1;
}
}
if(set_bits) {
if (set_bits) {
ldfa = ttree_lookup(tt, bs + 1);
if(!ldfa) {
if (!ldfa) {
/* push */
ldfa = _create_dfa_state(m->mem);
ttree_insert(tt, bs + 1, ldfa);
tmp = _create_state_queue(m->scratch, ldfa, bs);
if(!h)
tmp =
_create_state_queue(m->scratch,
ldfa, bs);
if (!h)
h = t = tmp;
else {
t->next = tmp;
@@ -260,8 +262,7 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
return 1;
}
struct matcher *matcher_create(struct pool *mem,
const char **patterns, int num)
struct matcher *matcher_create(struct pool *mem, const char **patterns, int num)
{
char *all, *ptr;
int i, len = 0;
@@ -282,7 +283,7 @@ struct matcher *matcher_create(struct pool *mem,
memset(m, 0, sizeof(*m));
/* join the regexps together, delimiting with zero */
for(i = 0; i < num; i++)
for (i = 0; i < num; i++)
len += strlen(patterns[i]) + 8;
ptr = all = pool_alloc(scratch, len + 1);
@@ -292,15 +293,14 @@ struct matcher *matcher_create(struct pool *mem,
goto bad;
}
for(i = 0; i < num; i++) {
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i],
TARGET_TRANS);
if(i < (num - 1))
for (i = 0; i < num; i++) {
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
if (i < (num - 1))
*ptr++ = '|';
}
/* parse this expression */
if(!(rx = rx_parse_tok(scratch, all, ptr))) {
if (!(rx = rx_parse_tok(scratch, all, ptr))) {
log_error("Couldn't parse regex");
goto bad;
}
@@ -324,26 +324,39 @@ struct matcher *matcher_create(struct pool *mem,
return m;
bad:
bad:
pool_destroy(scratch);
pool_destroy(mem);
return NULL;
}
static inline struct dfa_state *
_step_matcher(unsigned char c, struct dfa_state *cs, int *r)
{
if (!(cs = cs->lookup[c]))
return NULL;
if (cs->final && (cs->final > *r))
*r = cs->final;
return cs;
}
int matcher_run(struct matcher *m, const char *b)
{
struct dfa_state *cs = m->start;
int r = 0;
for (; *b; b++) {
if (!(cs = _step_matcher(HAT_CHAR, cs, &r)))
goto out;
if (!(cs = cs->lookup[(int) (unsigned char) *b]))
break;
for (; *b; b++)
if (!(cs = _step_matcher(*b, cs, &r)))
goto out;
if (cs->final && (cs->final > r))
r = cs->final;
}
_step_matcher(DOLLAR_CHAR, cs, &r);
out:
/* subtract 1 to get back to zero index */
return r - 1;
}

View File

@@ -12,7 +12,6 @@
#include <stdlib.h>
#include <stdio.h>
struct parse_sp { /* scratch pad for the parsing process */
struct pool *mem;
int type; /* token type, 0 indicates a charset */
@@ -21,9 +20,15 @@ struct parse_sp { /* scratch pad for the parsing process */
const char *rx_end; /* 1pte for the expression being parsed */
};
static struct rx_node *_or_term(struct parse_sp *ps);
static void _single_char(struct parse_sp *ps, unsigned int c, const char *ptr)
{
ps->type = 0;
ps->cursor = ptr + 1;
bit_clear_all(ps->charset);
bit_set(ps->charset, c);
}
/*
* Get the next token from the regular expression.
@@ -34,16 +39,16 @@ static int _get_token(struct parse_sp *ps)
int neg = 0, range = 0;
char c, lc = 0;
const char *ptr = ps->cursor;
if(ptr == ps->rx_end) { /* end of input ? */
if (ptr == ps->rx_end) { /* end of input ? */
ps->type = -1;
return 0;
}
switch(*ptr) {
/* charsets and ncharsets */
switch (*ptr) {
/* charsets and ncharsets */
case '[':
ptr++;
if(*ptr == '^') {
if (*ptr == '^') {
bit_set_all(ps->charset);
/* never transition on zero */
@@ -54,40 +59,46 @@ static int _get_token(struct parse_sp *ps)
} else
bit_clear_all(ps->charset);
while((ptr < ps->rx_end) && (*ptr != ']')) {
if(*ptr == '\\') {
while ((ptr < ps->rx_end) && (*ptr != ']')) {
if (*ptr == '\\') {
/* an escaped character */
ptr++;
switch(*ptr) {
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
switch (*ptr) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
default:
c = *ptr;
}
} else if(*ptr == '-' && lc) {
} else if (*ptr == '-' && lc) {
/* we've got a range on our hands */
range = 1;
ptr++;
if(ptr == ps->rx_end) {
if (ptr == ps->rx_end) {
log_error("Incomplete range"
"specification");
"specification");
return -1;
}
c = *ptr;
} else
c = *ptr;
if(range) {
if (range) {
/* add lc - c into the bitset */
if(lc > c) {
if (lc > c) {
char tmp = c;
c = lc;
lc = tmp;
}
for(; lc <= c; lc++) {
if(neg)
for (; lc <= c; lc++) {
if (neg)
bit_clear(ps->charset, lc);
else
bit_set(ps->charset, lc);
@@ -95,7 +106,7 @@ static int _get_token(struct parse_sp *ps)
range = 0;
} else {
/* add c into the bitset */
if(neg)
if (neg)
bit_clear(ps->charset, c);
else
bit_set(ps->charset, c);
@@ -104,7 +115,7 @@ static int _get_token(struct parse_sp *ps)
lc = c;
}
if(ptr >= ps->rx_end) {
if (ptr >= ps->rx_end) {
ps->type = -1;
return -1;
}
@@ -122,12 +133,18 @@ static int _get_token(struct parse_sp *ps)
case '+':
case '?':
case '|':
case '^':
case '$':
ps->type = (int) *ptr;
ps->cursor = ptr + 1;
break;
case '^':
_single_char(ps, HAT_CHAR, ptr);
break;
case '$':
_single_char(ps, DOLLAR_CHAR, ptr);
break;
case '.':
/* The 'all but newline' character set */
ps->type = 0;
@@ -141,7 +158,7 @@ static int _get_token(struct parse_sp *ps)
case '\\':
/* escaped character */
ptr++;
if(ptr >= ps->rx_end) {
if (ptr >= ps->rx_end) {
log_error("Badly quoted character at end "
"of expression");
ps->type = -1;
@@ -151,10 +168,16 @@ static int _get_token(struct parse_sp *ps)
ps->type = 0;
ps->cursor = ptr + 1;
bit_clear_all(ps->charset);
switch(*ptr) {
case 'n': bit_set(ps->charset, (int) '\n'); break;
case 'r': bit_set(ps->charset, (int) '\r'); break;
case 't': bit_set(ps->charset, (int) '\t'); break;
switch (*ptr) {
case 'n':
bit_set(ps->charset, (int) '\n');
break;
case 'r':
bit_set(ps->charset, (int) '\r');
break;
case 't':
bit_set(ps->charset, (int) '\t');
break;
default:
bit_set(ps->charset, (int) *ptr);
}
@@ -195,7 +218,7 @@ static struct rx_node *_term(struct parse_sp *ps)
{
struct rx_node *n;
switch(ps->type) {
switch (ps->type) {
case 0:
if (!(n = _node(ps->mem, CHARSET, NULL, NULL))) {
stack;
@@ -203,17 +226,17 @@ static struct rx_node *_term(struct parse_sp *ps)
}
bit_copy(n->charset, ps->charset);
_get_token(ps); /* match charset */
_get_token(ps); /* match charset */
break;
case '(':
_get_token(ps); /* match '(' */
_get_token(ps); /* match '(' */
n = _or_term(ps);
if(ps->type != ')') {
if (ps->type != ')') {
log_error("missing ')' in regular expression");
return 0;
}
_get_token(ps); /* match ')' */
_get_token(ps); /* match ')' */
break;
default:
@@ -227,11 +250,11 @@ static struct rx_node *_closure_term(struct parse_sp *ps)
{
struct rx_node *l, *n;
if(!(l = _term(ps)))
if (!(l = _term(ps)))
return NULL;
for (;;) {
switch(ps->type) {
switch (ps->type) {
case '*':
n = _node(ps->mem, STAR, l, NULL);
break;
@@ -289,7 +312,7 @@ static struct rx_node *_or_term(struct parse_sp *ps)
if (ps->type != '|')
return l;
_get_token(ps); /* match '|' */
_get_token(ps); /* match '|' */
if (!(r = _or_term(ps))) {
log_error("Badly formed 'or' expression");
@@ -317,7 +340,7 @@ struct rx_node *rx_parse_tok(struct pool *mem,
ps->charset = bitset_create(mem, 256);
ps->cursor = begin;
ps->rx_end = end;
_get_token(ps); /* load the first token */
_get_token(ps); /* load the first token */
if (!(r = _or_term(ps))) {
log_error("Parse error in regex");

View File

@@ -15,11 +15,17 @@ enum {
PLUS,
OR,
QUEST,
CHARSET,
HAT,
DOLLAR
CHARSET
};
/*
* We're never going to be running the regex on non-printable
* chars, so we can use a couple of these chars to represent the
* start and end of a string.
*/
#define HAT_CHAR 0x2
#define DOLLAR_CHAR 0x2
struct rx_node {
int type;
bitset_t charset;

View File

@@ -74,7 +74,6 @@ int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
} while (*c && count);
if (!*c) {
count++;

View File

@@ -19,6 +19,14 @@ static unsigned char _c[] =
static int _built_inverse;
static unsigned char _inverse_c[256];
int lvid_create(union lvid *lvid, struct id *vgid)
{
memcpy(lvid->id, vgid, sizeof(*lvid->id));
id_create(&lvid->id[1]);
return 1;
}
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num)
{
int i;
@@ -116,7 +124,7 @@ int id_write_format(struct id *id, char *buffer, size_t size)
{
int i, tot;
static int group_size[] = {6, 4, 4, 4, 4, 4, 6};
static int group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
assert(ID_LEN == 32);

View File

@@ -28,6 +28,7 @@ union lvid {
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num);
int lvnum_from_lvid(union lvid *lvid);
int lvid_create(union lvid *lvid, struct id *vgid);
int id_create(struct id *id);
int id_valid(struct id *id);
int id_equal(struct id *lhs, struct id *rhs);

View File

@@ -50,6 +50,22 @@ struct list *vgcache_find(const char *vg_name)
return &vgn->pvdevs;
}
struct format_type *vgcache_find_format(const char *vg_name)
{
struct vgname_entry *vgn;
if (!_vghash)
return NULL;
if (!vg_name)
vg_name = all_devices;
if (!(vgn = hash_lookup(_vghash, vg_name)))
return NULL;
return vgn->fmt;
}
struct list *vgcache_find_by_vgid(const char *vgid)
{
struct vgname_entry *vgn;
@@ -78,7 +94,8 @@ void vgcache_del_orphan(struct device *dev)
}
}
int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev)
int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt)
{
const char *pv_name;
struct vgname_entry *vgn;
@@ -92,6 +109,7 @@ int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev)
}
memset(vgn, 0, sizeof(struct vgname_entry));
vgn->fmt = fmt;
pvdevs = &vgn->pvdevs;
list_init(pvdevs);
@@ -104,19 +122,26 @@ int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev)
log_error("vgcache_add: VG hash insertion failed");
return 0;
}
} else if (!(vgn = hash_lookup(_vghash, vg_name))) {
log_error("vgcache_add: VG name entry %s not found", vg_name);
return 0;
}
if (vgid) {
memcpy(vgn->vgid, vgid, ID_LEN);
vgn->vgid[ID_LEN] = '\0';
if (vgid && strncmp(vgid, vgn->vgid, ID_LEN)) {
hash_remove(_vgidhash, vgn->vgid);
if (!hash_insert(_vgidhash, vgn->vgid, vgn)) {
log_error("vgcache_add: vgid hash insertion "
"failed");
return 0;
}
memcpy(vgn->vgid, vgid, ID_LEN);
vgn->vgid[ID_LEN] = '\0';
if (!hash_insert(_vgidhash, vgn->vgid, vgn)) {
log_error("vgcache_add: vgid hash insertion " "failed");
return 0;
}
}
if (!dev)
return 1;
list_iterate(pvdh, pvdevs) {
pvdev = list_item(pvdh, struct pvdev_list);
if (dev == pvdev->dev)
@@ -150,21 +175,25 @@ int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev)
}
/* vg_name of "\0" is an orphan PV; NULL means only add to all_devices */
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev)
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt)
{
if (!_vghash && !vgcache_init())
return 0;
/* If orphan PV remove it */
if (vg_name && !*vg_name)
if (dev && vg_name && !*vg_name)
vgcache_del_orphan(dev);
/* Add PV if vg_name supplied */
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, vgid, dev))
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, vgid, dev, fmt))
return 0;
/* Always add to all_devices */
return vgcache_add_entry(all_devices, NULL, dev);
/* Add to all_devices */
if (dev)
return vgcache_add_entry(all_devices, NULL, dev, fmt);
return 1;
}
void vgcache_destroy_entry(struct vgname_entry *vgn)
@@ -208,7 +237,6 @@ void vgcache_del(const char *vg_name)
vgcache_destroy_entry(vgn);
}
void vgcache_del_by_vgid(const char *vgid)
{
struct vgname_entry *vgn;
@@ -230,11 +258,10 @@ void vgcache_del_by_vgid(const char *vgid)
vgcache_destroy_entry(vgn);
}
void vgcache_destroy()
{
if (_vghash) {
hash_iter(_vghash, (iterate_fn)vgcache_destroy_entry);
hash_iter(_vghash, (iterate_fn) vgcache_destroy_entry);
hash_destroy(_vghash);
_vghash = NULL;
}
@@ -266,4 +293,3 @@ char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid)
return pool_strdup(cmd->mem, vgn->vgname);
}

View File

@@ -19,6 +19,7 @@ struct vgname_entry {
struct list pvdevs;
char *vgname;
char vgid[ID_LEN + 1];
struct format_type *fmt;
};
struct pvdev_list {
@@ -31,13 +32,15 @@ void vgcache_destroy();
/* Return list of PVs in named VG */
struct list *vgcache_find(const char *vg_name);
struct format_type *vgcache_find_format(const char *vg_name);
struct list *vgcache_find_by_vgid(const char *vgid);
/* FIXME Temporary function */
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid);
/* Add/delete a device */
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev);
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt);
void vgcache_del(const char *vg_name);
#endif

24
libdm/.export.sym Normal file
View File

@@ -0,0 +1,24 @@
{
global:
dm_log_init;
dm_task_create;
dm_task_destroy;
dm_task_set_name;
dm_task_set_uuid;
dm_get_library_version;
dm_task_get_driver_version;
dm_task_get_info;
dm_task_get_deps;
dm_task_get_uuid;
dm_task_set_ro;
dm_task_set_newname;
dm_task_set_minor;
dm_task_add_target;
dm_get_next_target;
dm_task_run;
dm_set_dev_dir;
dm_dir;
local:
*;
};

View File

@@ -31,23 +31,12 @@ install_fs: fs/libdevmapper.so
install_ioctl: ioctl/libdevmapper.so
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/libdevmapper.so.$(LIB_VERSION).$(IOCTL_VERSION)
$(LN_S) -f libdevmapper.so.$(LIB_VERSION).$(IOCTL_VERSION) \
$(libdir)/libdevmapper.so.$(LIB_VERSION)
ioctl/libdevmapper.o: ioctl_version
ioctl_version: ioctl/libdevmapper.c
@echo Checking library version compatible with kernel version in dm-ioctl.h
test "$(IOCTL_VERSION)" = \
"$(shell $(CC) -E -dM $(INCLUDES) $(CFLAGS) \
ioctl/libdevmapper.c | \
awk -F '[ \t\"]+' '/DM_IOCTL_VERSION/ {print $$3}' )"
$(libdir)/libdevmapper.so.$(LIB_VERSION)
distclean_lib:
$(RM) libdm-common.h
distclean: distclean_lib
.PHONY: ioctl_version distclean_lib distclean
.PHONY: distclean_lib distclean

View File

@@ -16,7 +16,7 @@
#include <errno.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/limits.h>
#include <sys/ioctl.h>
#include <linux/dm-ioctl.h>
@@ -25,19 +25,41 @@
#define ALIGNMENT sizeof(int)
static char *dm_cmd_list[] = {
"create",
"reload",
"remove",
"remove_all",
"suspend",
"resume",
"info",
"deps",
"rename",
"version"
/*
* Ensure build compatibility. The hard-coded version here (major, minor)
* is the highest present in the _cmd_data array below.
*/
#if DM_VERSION_MAJOR != 1 || DM_VERSION_MINOR < 0
#error The version of dm-ioctl.h included is incompatible.
#endif
static struct {
char *name;
int cmd;
int version[3];
} _cmd_data[] = {
{ "create", DM_DEV_CREATE, {1, 0, 0} },
{ "reload", DM_DEV_RELOAD, {1, 0, 0} },
{ "remove", DM_DEV_REMOVE, {1, 0, 0} },
{ "remove_all", DM_REMOVE_ALL, {1, 0, 0} },
{ "suspend", DM_DEV_SUSPEND, {1, 0, 0} },
{ "resume", DM_DEV_SUSPEND, {1, 0, 0} },
{ "info", DM_DEV_STATUS, {1, 0, 0} },
{ "deps", DM_DEV_DEPS, {1, 0, 0} },
{ "rename", DM_DEV_RENAME, {1, 0, 0} },
{ "version", DM_VERSION, {1, 0, 0} },
{ "status", DM_TARGET_STATUS, {1, 0, 0} },
{ "table", DM_TARGET_STATUS, {1, 0, 0} },
{ "waitevent", DM_TARGET_WAIT, {1, 0, 0} },
};
static void *_align(void *ptr, unsigned int a)
{
register unsigned long align = --a;
return (void *) (((unsigned long) ptr + align) & ~align);
}
void dm_task_destroy(struct dm_task *dmt)
{
struct target *t, *n;
@@ -66,10 +88,55 @@ void dm_task_destroy(struct dm_task *dmt)
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
{
unsigned int *v;
if (!dmt->dmi)
return 0;
strncpy(version, dmt->dmi->version, size);
v = dmt->dmi->version;
snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
return 1;
}
void *dm_get_next_target(struct dm_task *dmt, void *next,
uint64_t *start, uint64_t *length,
char **target_type, char **params)
{
struct target *t = (struct target *) next;
if (!t)
t = dmt->head;
if (!t)
return NULL;
*start = t->start;
*length = t->length;
*target_type = t->type;
*params = t->params;
return t->next;
}
/* Unmarshall the target info returned from a status call */
static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
{
char *outbuf = (char *) dmi + sizeof(struct dm_ioctl);
char *outptr = outbuf;
int i;
for (i = 0; i < dmi->target_count; i++) {
struct dm_target_spec *spec = (struct dm_target_spec *) outptr;
if (!dm_task_add_target(dmt, spec->sector_start, spec->length,
spec->target_type,
outptr + sizeof(*spec)))
return 0;
outptr += sizeof(struct dm_target_spec);
outptr += strlen(outptr) + 1;
_align(outptr, ALIGNMENT);
}
return 1;
}
@@ -121,8 +188,8 @@ int dm_task_set_newname(struct dm_task *dmt, const char *newname)
return 1;
}
struct target *create_target(uint64_t start,
uint64_t len, const char *type, const char *params)
struct target *create_target(uint64_t start, uint64_t len, const char *type,
const char *params)
{
struct target *t = malloc(sizeof(*t));
@@ -154,13 +221,6 @@ struct target *create_target(uint64_t start,
return NULL;
}
static void *_align(void *ptr, unsigned int a)
{
register unsigned long align = --a;
return (void *) (((unsigned long) ptr + align) & ~align);
}
static void *_add_target(struct target *t, void *out, void *end)
{
void *out_sp = out;
@@ -235,7 +295,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
memset(dmi, 0, len);
strncpy(dmi->version, DM_IOCTL_VERSION, sizeof(dmi->version));
dmi->version[0] = _cmd_data[dmt->type].version[0];
dmi->version[1] = _cmd_data[dmt->type].version[1];
dmi->version[2] = _cmd_data[dmt->type].version[2];
dmi->data_size = len;
dmi->data_start = sizeof(struct dm_ioctl);
@@ -289,62 +351,28 @@ int dm_task_run(struct dm_task *dmt)
snprintf(control, sizeof(control), "%s/control", dm_dir());
if ((fd = open(control, O_RDWR)) < 0) {
log_error("Couldn't open device-mapper control device");
log_error("%s: open failed: %s", control, strerror(errno));
log_error("Is device-mapper driver missing from kernel?");
goto bad;
}
switch (dmt->type) {
case DM_DEVICE_CREATE:
command = DM_CREATE;
break;
case DM_DEVICE_RELOAD:
command = DM_RELOAD;
break;
case DM_DEVICE_REMOVE:
command = DM_REMOVE;
break;
case DM_DEVICE_REMOVE_ALL:
command = DM_REMOVE_ALL;
break;
case DM_DEVICE_SUSPEND:
command = DM_SUSPEND;
break;
case DM_DEVICE_RESUME:
command = DM_SUSPEND;
break;
case DM_DEVICE_INFO:
command = DM_INFO;
break;
case DM_DEVICE_DEPS:
command = DM_DEPS;
break;
case DM_DEVICE_RENAME:
command = DM_RENAME;
break;
case DM_DEVICE_VERSION:
command = DM_VERSION;
break;
default:
if (dmt->type >= (sizeof(_cmd_data) / sizeof(*_cmd_data))) {
log_error("Internal error: unknown device-mapper task %d",
dmt->type);
goto bad;
}
log_debug("dm %s %s %s %s", dm_cmd_list[dmt->type], dmi->name,
command = _cmd_data[dmt->type].cmd;
if (dmt->type == DM_DEVICE_TABLE)
dmi->flags |= DM_STATUS_TABLE_FLAG;
log_debug("dm %s %s %s %s", _cmd_data[dmt->type].name, dmi->name,
dmi->uuid, dmt->newname ? dmt->newname : "");
if (ioctl(fd, command, dmi) < 0) {
log_error("device-mapper ioctl cmd %d failed: %s", dmt->type,
strerror(errno));
log_error("device-mapper ioctl cmd %d failed: %s",
_IOC_NR(command), strerror(errno));
goto bad;
}
@@ -360,6 +388,12 @@ int dm_task_run(struct dm_task *dmt)
case DM_DEVICE_RENAME:
rename_dev_node(dmt->dev_name, dmt->newname);
break;
case DM_DEVICE_STATUS:
case DM_DEVICE_TABLE:
if (!_unmarshal_status(dmt, dmi))
goto bad;
break;
}
dmt->dmi = dmi;

View File

@@ -4,6 +4,11 @@
* This file is released under the LGPL.
*/
#ifndef LIB_DMTARGETS_H
#define LIB_DMTARGETS_H
#include "libdevmapper.h"
struct target {
uint64_t start;
uint64_t length;
@@ -27,3 +32,5 @@ struct dm_task {
char *uuid;
};
#endif

View File

@@ -44,6 +44,10 @@ enum {
DM_DEVICE_RENAME,
DM_DEVICE_VERSION,
DM_DEVICE_STATUS,
DM_DEVICE_TABLE,
DM_DEVICE_WAITEVENT
};
struct dm_task;
@@ -91,6 +95,11 @@ int dm_task_add_target(struct dm_task *dmt,
uint64_t start,
uint64_t size, const char *ttype, const char *params);
/* Use this to retrive target information returned from a STATUS call */
void *dm_get_next_target(struct dm_task *dmt,
void *next, uint64_t *start, uint64_t *length,
char **target_type, char **params);
/*
* Call this to actually run the ioctl.
*/

View File

@@ -4,6 +4,8 @@
* This file is released under the LGPL.
*/
#include "libdm-targets.h"
#include "libdm-common.h"
#include "libdevmapper.h"
#include <stdio.h>
@@ -17,10 +19,7 @@
#include <sys/types.h>
#include <errno.h>
#include <linux/kdev_t.h>
#include <linux/device-mapper.h>
#include "libdm-targets.h"
#include "libdm-common.h"
#include <linux/dm-ioctl.h>
#define DEV_DIR "/dev/"
@@ -30,7 +29,8 @@ static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
* Library users can provide their own logging
* function.
*/
void _default_log(int level, const char *file, int line, const char *f, ...)
static void _default_log(int level, const char *file, int line,
const char *f, ...)
{
va_list ap;
@@ -56,7 +56,7 @@ void dm_log_init(dm_log_fn fn)
_log = fn;
}
void _build_dev_path(char *buffer, size_t len, const char *dev_name)
static void _build_dev_path(char *buffer, size_t len, const char *dev_name)
{
/* If there's a /, assume caller knows what they're doing */
if (strchr(dev_name, '/'))

View File

@@ -4,6 +4,9 @@
* This file is released under the LGPL.
*/
#ifndef LIB_DMCOMMON_H
#define LIB_DMCOMMON_H
#define _LOG_DEBUG 7
#define _LOG_INFO 6
#define _LOG_NOTICE 5
@@ -11,7 +14,7 @@
#define _LOG_ERR 3
#define _LOG_FATAL 2
extern dm_log_fn _log;
dm_log_fn _log;
#define log_error(msg, x...) _log(_LOG_ERR, __FILE__, __LINE__, msg, ## x)
#define log_print(msg, x...) _log(_LOG_WARN, __FILE__, __LINE__, msg, ## x)
@@ -19,9 +22,9 @@ extern dm_log_fn _log;
#define log_very_verbose(msg, x...) _log(_LOG_INFO, __FILE__, __LINE__, msg, ## x)
#define log_debug(msg, x...) _log(_LOG_DEBUG, __FILE__, __LINE__, msg, ## x)
extern struct target *create_target(uint64_t start,
uint64_t len,
const char *type, const char *params);
struct target *create_target(uint64_t start,
uint64_t len,
const char *type, const char *params);
int add_dev_node(const char *dev_name, dev_t dev);
int rm_dev_node(const char *dev_name);
@@ -29,3 +32,4 @@ int rename_dev_node(const char *old_name, const char *new_name);
#define DM_LIB_VERSION @DM_LIB_VERSION@
#endif

View File

@@ -57,7 +57,7 @@ CFLAGS+=-g -fno-omit-frame-pointer
#CFLAGS+=-pg
#LD_FLAGS=-pg
CFLAGS+=-DDEBUG_MEM -DDEBUG
CFLAGS+=-D_REENTRANT -DDEBUG_MEM -DDEBUG -D_GNU_SOURCE
#CFLAGS+=-DDEBUG_POOL
#CFLAGS+=-DBOUNDS_CHECK

View File

@@ -4,11 +4,14 @@ dmsetup \- low level logical volume management
.SH SYNOPSIS
.ad l
.B dmsetup create
.I device_name table_file
.I device_name table_file [uuid]
.br
.B dmsetup remove
.I device_name
.br
.B dmsetup rename
.I device_name new_name
.br
.B dmsetup suspend
.I device_name
.br
@@ -20,6 +23,23 @@ dmsetup \- low level logical volume management
.br
.B dmsetup info
.I device_name
.br
.B dmsetup deps
.I device_name
.br
.B dmsetup status
.I device_name
.br
.B dmsetup table
.I device_name
.br
.B dmsetup wait
.I device_name
.br
.B dmsetup remove_all
.I device_name
.br
.B dmsetup version
.ad b
.SH DESCRIPTION
dmsetup manages logical devices that use the device-mapper driver.
@@ -27,19 +47,25 @@ Devices are created by loading a table that specifies a target for
each sector in the logical device.
The first argument to dmsetup is a command.
The second argument is the logical device name.
The second argument is the logical device name or uuid.
.SH COMMANDS
.IP \fBcreate
.I device_name table_file
.I device_name table_file [uuid]
.br
Attempts to create a device using the table file given. If
Attempts to create a device using the table file given.
The optional uuid can be used in place of
device_name in subsequent dmsetup commands. If
successful a device will appear as
/dev/device-mapper/<device-name>. See below for information
on the table file format.
.IP \fBremove
.I device_name
.br
Removes the device
Removes a device
.IP \fBrename
.I device_name new_name
.br
Renames a device
.IP \fBsuspend
.I device_name
.br
@@ -67,14 +93,40 @@ Outputs some brief information about the device in the form:
major,minor
.br
target_count
.IP \fBdeps
.I device_name
.br
Outputs a list of (major, minor) pairs for devices referenced by the
specified device.
.IP \fBstatus
.I device_name
.br
Outputs status information for each of the device's targets.
.IP \fBtable
.I device_name
.br
Outputs the current table for the device in a format than can be fed
back in using the create or reload commands.
.IP \fBwait
.I device_name
.br
Sleeps until an event is triggered against a device.
.IP \fBremove_all
.br
Attempts to remove all device definitions i.e. reset the driver.
Use with care!
.IP \fBversion
.I device_name
.br
Outputs version information.
.SH TABLE FORMAT
Each line of the table specifies a single target and is of the form:
.br
logical_start_sector num_sectors target_type target_args
.br
.br
At the moment there are 3 simple target types available - though your
system might have more in the form of modules.
There are currently three simple target types available together
with more complex optional ones that implement snapshots and mirrors.
.IP \fBlinear
.I destination_device start_sector

View File

@@ -0,0 +1,5 @@
config_t: config_t.c
gcc -g -I../../include config_t.c -L../../lib -llvm -o config_t
clean:
rm config_t

View File

@@ -0,0 +1,38 @@
/*
* Test program that reads, then writes a config file.
*/
#include <stdio.h>
#include "dbg_malloc.h"
#include "config.h"
int main(int argc, char **argv)
{
struct config_file *cf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <config_file>\n", argv[0]);
exit(1);
}
cf = create_config_file();
if (cf == NULL) {
fprintf(stderr, "Couldn't create config_file object.\n");
exit(1);
}
if (!read_config(cf, argv[1])) {
fprintf(stderr, "Couldn't read config file '%s'\n", argv[0]);
exit(1);
}
if (!write_config(cf, "out")) {
fprintf(stderr, "Couldn't write config file 'out'\n");
exit(1);
}
destroy_config_file(cf);
dump_memory();
return 0;
}

View File

@@ -0,0 +1 @@
foo = []

169
old-tests/config/vg0 Normal file
View File

@@ -0,0 +1,169 @@
# This file was originally generated by the LVM2 library
# Generated: Wed Jul 17 22:41:37 2002
description = "Created *after* executing 'lvcreate --quiet -s -n snap -c 512k -L200M vg0/origin /dev/hda8'"
creation_time = 1026942097
vg0 {
id = "Qmd96y-771S-Esbb-Zp6u-8xo9-Cfmt-YvndHY"
seqno = 2
status = ["RESIZEABLE", "READ", "WRITE"]
system_id = "reti1014805292"
extent_size = 8192 # 4 Megabytes
max_lv = 255
max_pv = 255
physical_volumes {
pv0 {
id = "8nRQub-EquY-VR1C-Ipdv-6hEO-FuFT-wnlN5R"
device = "/dev/discs/disc0/part8" # Hint only
status = ["ALLOCATABLE"]
pe_start = 256
pe_count = 501 # 1.95703 Gigabytes
}
pv1 {
id = "mRU6Mf-z1Sv-Kuqw-Ct1v-eC42-mnqs-YD1RrL"
device = "/dev/discs/disc1/part2" # Hint only
status = ["ALLOCATABLE"]
pe_start = 384
pe_count = 7269 # 28.3945 Gigabytes
}
}
logical_volumes {
music {
id = "000000-0000-0000-0000-0000-0000-000000"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 2
segment1 {
start_extent = 0
extent_count = 1024 # 4 Gigabytes
stripes = 1
areas = [
"pv1", 0
]
}
segment2 {
start_extent = 1024
extent_count = 2560 # 10 Gigabytes
stripes = 1
areas = [
"pv1", 3584
]
}
}
photos {
id = "000000-0000-0000-0000-0000-0000-000002"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 1024 # 4 Gigabytes
stripes = 1
areas = [
"pv1", 2048
]
}
}
repositories {
id = "000000-0000-0000-0000-0000-0000-000003"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 512 # 2 Gigabytes
stripes = 1
areas = [
"pv1", 3072
]
}
}
origin {
id = "000000-0000-0000-0000-0000-0000-000004"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 50 # 200 Megabytes
stripes = 1
areas = [
"pv1", 6144
]
}
}
packages {
id = "000000-0000-0000-0000-0000-0000-000006"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 2
segment1 {
start_extent = 0
extent_count = 451 # 1.76172 Gigabytes
stripes = 1
areas = [
"pv0", 50
]
}
segment2 {
start_extent = 451
extent_count = 573 # 2.23828 Gigabytes
stripes = 1
areas = [
"pv1", 6194
]
}
}
snap {
id = "000000-0000-0000-0000-0000-0000-000001"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 50 # 200 Megabytes
stripes = 1
areas = [
"pv0", 0
]
}
}
}
snapshots {
snapshot0 {
chunk_size = 1024
origin = "origin"
cow_store = "snap"
}
}
}

View File

@@ -52,7 +52,8 @@ SOURCES=\
vgreduce.c \
vgremove.c \
vgrename.c \
vgscan.c
vgscan.c \
vgsplit.c
TARGETS=\
.commands \

View File

@@ -157,6 +157,7 @@ static int __backup(struct volume_group *vg)
struct format_instance *tf;
char name[PATH_MAX];
char *desc;
void *context;
if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) {
stack;
@@ -172,15 +173,19 @@ static int __backup(struct volume_group *vg)
log_verbose("Creating volume group backup \"%s\"", name);
if (!(tf = text_format_create(vg->cmd, name, vg->cmd->um, desc))) {
if (!(context = create_text_context(vg->cmd->fmtt, name, desc)) ||
!(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL,
context))) {
stack;
return 0;
}
if (!(r = tf->ops->vg_write(tf, vg)))
if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) ||
!(r = tf->fmt->ops->vg_commit(tf, vg, context)))
stack;
tf->ops->destroy(tf);
tf->fmt->ops->destroy_instance(tf);
return r;
}
@@ -227,16 +232,19 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
{
struct volume_group *vg;
struct format_instance *tf;
void *context;
if (!(tf = text_format_create(cmd, file, cmd->um, cmd->cmd_line))) {
if (!(context = create_text_context(cmd->fmtt, file,
cmd->cmd_line)) ||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
log_error("Couldn't create text format object.");
return NULL;
}
if (!(vg = tf->ops->vg_read(tf, vg_name)))
if (!(vg = tf->fmt->ops->vg_read(tf, vg_name, context)))
stack;
tf->ops->destroy(tf);
tf->fmt->ops->destroy_instance(tf);
return vg;
}
@@ -264,7 +272,15 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
/*
* Write the vg.
*/
if (!cmd->fid->ops->vg_write(cmd->fid, vg)) {
/* FIXME How do I find what format to write out the VG in? */
/* Must store the format type inside the backup? */
if (!(vg->fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
log_error("Failed to allocate format1 instance");
return 0;
}
if (!vg_write(vg)) {
stack;
return 0;
}

View File

@@ -11,6 +11,7 @@
arg(version_ARG, '\0', "version", NULL)
arg(quiet_ARG, '\0', "quiet", NULL)
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_arg)
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -46,6 +47,7 @@ arg(list_ARG, 'l', "list", NULL)
arg(size_ARG, 'L', "size", size_arg)
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign)
arg(persistent_ARG, 'M', "persistent", yes_no_arg)
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg)
arg(minor_ARG, 'm', "minor", minor_arg)
arg(maps_ARG, 'm', "maps", NULL)
arg(name_ARG, 'n', "name", string_arg)

View File

@@ -18,19 +18,6 @@
*
*/
xx(e2fsadm,
"Resize logical volume and ext2 filesystem",
"e2fsadm "
"[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n"
"\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n"
"\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtT]}" "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version] " "\n"
"\tLogicalVolumePath" "\n",
extents_ARG, size_ARG, nofsck_ARG, test_ARG)
xx(help,
"Display help for commands",
"help <command>" "\n")
@@ -63,7 +50,8 @@ xx(lvchange,
autobackup_ARG, available_ARG, contiguous_ARG,
minor_ARG, persistent_ARG, partial_ARG,
permission_ARG, readahead_ARG, test_ARG)
permission_ARG, readahead_ARG, test_ARG,
ignorelockingfailure_ARG)
xx(lvcreate,
"Create a logical volume",
@@ -87,9 +75,8 @@ xx(lvcreate,
"\t[--version]\n"
"\tVolumeGroupName [PhysicalVolumePath...]\n\n",
autobackup_ARG, chunksize_ARG,
contiguous_ARG, extents_ARG, minor_ARG, name_ARG,
permission_ARG, persistent_ARG, readahead_ARG, size_ARG,
autobackup_ARG, chunksize_ARG, contiguous_ARG, extents_ARG, minor_ARG,
name_ARG, permission_ARG, persistent_ARG, readahead_ARG, size_ARG,
snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, zero_ARG)
xx(lvdisplay,
@@ -104,7 +91,7 @@ xx(lvdisplay,
"\t[-v/--verbose]\n"
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
colon_ARG, disk_ARG, maps_ARG, partial_ARG)
colon_ARG, disk_ARG, maps_ARG, partial_ARG, ignorelockingfailure_ARG)
xx(lvextend,
"Add space to a logical volume",
@@ -227,10 +214,11 @@ xx(lvscan,
"\t[-d|--debug] " "\n"
"\t[-D|--disk]" "\n"
"\t[-h|--help] " "\n"
"\t[-P|--partial] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version]\n",
blockdevice_ARG, disk_ARG)
blockdevice_ARG, disk_ARG, partial_ARG, ignorelockingfailure_ARG);
xx(pvchange,
"Change attributes of physical volume(s)",
@@ -291,7 +279,7 @@ xx(pvdisplay,
"\t[-v/--verbose]\n"
"\tPhysicalVolumePath [PhysicalVolumePath...]\n",
colon_ARG, maps_ARG, short_ARG)
colon_ARG, maps_ARG, short_ARG, ignorelockingfailure_ARG)
xx(pvmove,
"Move extents from one physical volume to another",
@@ -328,12 +316,14 @@ xx(pvscan,
"\t[-d|--debug] " "\n"
"\t{-e|--exported | -n/--novolumegroup} " "\n"
"\t[-h|--help]" "\n"
"\t[-P|--partial] " "\n"
"\t[-s|--short] " "\n"
"\t[-u|--uuid] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version]\n",
exported_ARG, novolumegroup_ARG, short_ARG, uuid_ARG)
exported_ARG, novolumegroup_ARG, partial_ARG, short_ARG, uuid_ARG,
ignorelockingfailure_ARG)
xx(vgcfgbackup,
"Backup volume group configuration(s)",
@@ -341,10 +331,11 @@ xx(vgcfgbackup,
"\t[-d|--debug] " "\n"
"\t[-f|--file filename] " "\n"
"\t[-h|--help] " "\n"
"\t[-P|--partial] " "\n"
"\t[-v|--verbose]" "\n"
"\t[-V|--version] " "\n"
"\t[VolumeGroupName...]\n",
file_ARG)
file_ARG, partial_ARG, ignorelockingfailure_ARG)
xx(vgcfgrestore,
"Restore volume group configuration",
@@ -378,7 +369,7 @@ xx(vgchange,
autobackup_ARG, available_ARG, logicalvolume_ARG, partial_ARG,
resizeable_ARG, resizable_ARG, allocation_ARG,
test_ARG)
test_ARG, ignorelockingfailure_ARG)
xx(vgck,
"Check the consistency of volume group(s)",
@@ -393,9 +384,10 @@ xx(vgcreate,
"vgcreate" "\n"
"\t[-A|--autobackup {y|n}] " "\n"
"\t[-d|--debug]" "\n"
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
"\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n"
"\t[-h|--help]" "\n"
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
"\t[-M|--metadatatype lvm1/text] " "\n"
"\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n"
"\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtT]] " "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose]" "\n"
@@ -403,7 +395,7 @@ xx(vgcreate,
"\tVolumeGroupName PhysicalVolume [PhysicalVolume...]\n",
autobackup_ARG, maxlogicalvolumes_ARG, maxphysicalvolumes_ARG,
physicalextentsize_ARG, test_ARG)
metadatatype_ARG, physicalextentsize_ARG, test_ARG)
xx(vgdisplay,
"Display volume group information",
@@ -416,7 +408,8 @@ xx(vgdisplay,
"\t[--version]" "\n"
"\t[VolumeGroupName...] ]\n",
activevolumegroups_ARG, colon_ARG, disk_ARG, short_ARG, partial_ARG)
activevolumegroups_ARG, colon_ARG, disk_ARG, short_ARG, partial_ARG,
ignorelockingfailure_ARG)
xx(vgexport,
"Unregister volume group(s) from the system",
@@ -520,7 +513,9 @@ xx(vgscan,
"vgscan "
"\t[-d/--debug]\n"
"\t[-h/-?/--help]\n"
"\t[-v/--verbose]\n" )
"\t[-P/--partial] " "\n"
"\t[-v/--verbose]\n" ,
partial_ARG, ignorelockingfailure_ARG)
xx(vgsplit,
"Move physical volumes into a new volume group",
@@ -529,13 +524,14 @@ xx(vgsplit,
"\t[-d|--debug] " "\n"
"\t[-h|--help] " "\n"
"\t[-l|--list]" "\n"
"\t[-M|--metadatatype lvm1/text] " "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version]" "\n"
"\tExistingVolumeGroupName NewVolumeGroupName" "\n"
"\tPhysicalVolumePath [PhysicalVolumePath...]\n",
autobackup_ARG, list_ARG, test_ARG)
autobackup_ARG, list_ARG, metadatatype_ARG, test_ARG)
xx(version,
"Display software and driver version information",

View File

@@ -227,6 +227,53 @@ static int _resume(int argc, char **argv)
return _simple(DM_DEVICE_RESUME, argv[1]);
}
static int _wait(int argc, char **argv)
{
return _simple(DM_DEVICE_WAITEVENT, argv[1]);
}
static int _status(int argc, char **argv)
{
int r = 0;
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
int cmd;
if (!strcmp(argv[0], "status"))
cmd = DM_DEVICE_STATUS;
else
cmd = DM_DEVICE_TABLE;
if (!(dmt = dm_task_create(cmd)))
return 0;
if (!dm_task_set_name(dmt, argv[1]))
goto out;
if (!dm_task_run(dmt))
goto out;
/* Fetch targets and print 'em */
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (target_type) {
printf("%"PRIu64" %"PRIu64" %s %s\n",
start, length, target_type, params);
}
} while (next);
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
static int _info(int argc, char **argv)
{
int r = 0;
@@ -345,6 +392,9 @@ static struct command _commands[] = {
{"info", "<dev_name>", 1, 1, _info},
{"deps", "<dev_name>", 1, 1, _deps},
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
{"status", "<dev_name>", 1, 1, _status},
{"table", "<dev_name>", 1, 1, _status},
{"wait", "<dev_name>", 1, 1, _wait},
{"version", "", 0, 0, _version},
{NULL, NULL, 0, 0, NULL}
};
@@ -373,7 +423,7 @@ static struct command *_find_command(const char *name)
static int _process_switches(int *argc, char ***argv)
{
int index;
char c;
int c;
static struct option long_options[] = {
{"read-only", 0, NULL, READ_ONLY},

View File

@@ -41,6 +41,13 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, ignorelockingfailure_ARG) &&
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
log_error("Only -a permitted with --ignorelockingfailure");
return EINVALID_CMD_LINE;
}
if (!argc) {
log_error("Please give logical volume path(s)");
return EINVALID_CMD_LINE;
@@ -51,6 +58,9 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, &lvchange_single);
}
@@ -159,19 +169,19 @@ static int lvchange_permission(struct cmd_context *cmd,
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
if (!(lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
return 0;
}
backup(lv->vg);
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
return 1;
}
@@ -205,39 +215,37 @@ static int lvchange_availability(struct cmd_context *cmd,
static int lvchange_contiguous(struct cmd_context *cmd,
struct logical_volume *lv)
{
int lv_allocation = 0;
int want_contiguous = 0;
if (strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"))
lv_allocation |= ALLOC_CONTIGUOUS;
want_contiguous = 1;
if ((lv_allocation & ALLOC_CONTIGUOUS) &&
(lv->status & ALLOC_CONTIGUOUS)) {
if (want_contiguous && lv->alloc == ALLOC_CONTIGUOUS) {
log_error("Allocation policy of logical volume \"%s\" is "
"already contiguous", lv->name);
return 0;
}
if (!(lv_allocation & ALLOC_CONTIGUOUS) &&
!(lv->status & ALLOC_CONTIGUOUS)) {
if (!want_contiguous && lv->alloc != ALLOC_CONTIGUOUS) {
log_error
("Allocation policy of logical volume \"%s\" is already"
" not contiguous", lv->name);
return 0;
}
/******** FIXME lv_check_contiguous?
/******** FIXME lv_check_contiguous?
if ((lv_allocation & ALLOC_CONTIGUOUS)
&& (ret = lv_check_contiguous(vg, lv_index + 1)) == FALSE) {
log_error("No contiguous logical volume \"%s\"", lv->name);
return 0;
*********/
if (lv_allocation & ALLOC_CONTIGUOUS) {
lv->status |= ALLOC_CONTIGUOUS;
if (want_contiguous) {
lv->alloc = ALLOC_CONTIGUOUS;
log_verbose("Setting contiguous allocation policy for \"%s\"",
lv->name);
} else {
lv->status &= ~ALLOC_CONTIGUOUS;
lv->alloc = ALLOC_NEXT_FREE;
log_verbose("Removing contiguous allocation policy for \"%s\"",
lv->name);
}
@@ -248,18 +256,18 @@ static int lvchange_contiguous(struct cmd_context *cmd,
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
if (!vg_write(lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
return 0;
}
backup(lv->vg);
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
return 1;
@@ -272,7 +280,7 @@ static int lvchange_readahead(struct cmd_context *cmd,
read_ahead = arg_int_value(cmd, readahead_ARG, 0);
/******* FIXME Ranges?
/******* FIXME Ranges?
if (read_ahead < LVM_MIN_READ_AHEAD || read_ahead > LVM_MAX_READ_AHEAD) {
log_error("read ahead sector argument is invalid");
return 0;
@@ -296,18 +304,18 @@ static int lvchange_readahead(struct cmd_context *cmd,
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
if (!vg_write(lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
return 0;
}
backup(lv->vg);
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
return 1;
}
@@ -348,18 +356,18 @@ static int lvchange_persistent(struct cmd_context *cmd,
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
if (!vg_write(lv->vg)) {
/* FIXME: Attempt reversion? */
unlock_lv(cmd, lv->lvid.s);
return 0;
}
backup(lv->vg);
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
if (!unlock_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
return 1;
}

View File

@@ -36,8 +36,7 @@ struct lvcreate_params {
};
static int _read_name_params(struct lvcreate_params *lp,
struct cmd_context *cmd, int *pargc,
char ***pargv)
struct cmd_context *cmd, int *pargc, char ***pargv)
{
int argc = *pargc;
char **argv = *pargv, *ptr;
@@ -56,7 +55,7 @@ static int _read_name_params(struct lvcreate_params *lp,
lp->origin = argv[0];
(*pargv)++, (*pargc)--;
if (!(lp->vg_name = extract_vgname(cmd->fid, lp->origin))) {
if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
log_err("The origin name should include the "
"volume group.");
return 0;
@@ -72,20 +71,25 @@ static int _read_name_params(struct lvcreate_params *lp,
* environment.
*/
if (!argc) {
if (!(lp->vg_name =
extract_vgname(cmd->fid, lp->lv_name))) {
if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
log_err("Please provide a volume group name");
return 0;
}
} else {
if (strrchr(argv[0], '/')) {
log_error("Volume group name expected "
"(no slash)");
return 0;
}
/*
* Ensure lv_name doesn't contain a
* different VG.
*/
if (lp->lv_name && strchr(lp->lv_name, '/')) {
if (!(lp->vg_name =
extract_vgname(cmd->fid, lp->lv_name)))
extract_vgname(cmd, lp->lv_name)))
return 0;
if (strcmp(lp->vg_name, argv[0])) {
@@ -109,8 +113,7 @@ static int _read_name_params(struct lvcreate_params *lp,
}
static int _read_size_params(struct lvcreate_params *lp,
struct cmd_context *cmd, int *pargc,
char ***pargv)
struct cmd_context *cmd, int *pargc, char ***pargv)
{
/*
* There are two mutually exclusive ways of specifying
@@ -191,12 +194,24 @@ static int _read_stripe_params(struct lvcreate_params *lp,
static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
int argc, char **argv)
{
/*
* Set the defaults.
*/
memset(lp, 0, sizeof(*lp));
lp->chunk_size = 2 * arg_int_value(cmd, chunksize_ARG, 32);
log_verbose("setting chunksize to %d sectors.", lp->chunk_size);
/*
* Check selected options are compatible and set defaults
*/
if (arg_count(cmd, snapshot_ARG)) {
if (arg_count(cmd, zero_ARG)) {
log_error("-s and -Z are incompatible");
return 0;
}
lp->chunk_size = 2 * arg_int_value(cmd, chunksize_ARG, 8);
log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
} else {
if (arg_count(cmd, chunksize_ARG)) {
log_error("-c is only available with -s");
return 0;
}
}
if (!_read_name_params(lp, cmd, &argc, &argv) ||
!_read_size_params(lp, cmd, &argc, &argv) ||
@@ -297,21 +312,20 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
{
uint32_t size_rest;
uint32_t status = 0;
alloc_policy_t alloc = ALLOC_NEXT_FREE;
struct volume_group *vg;
struct logical_volume *lv, *org;
struct list *pvh;
if (lp->contiguous)
status |= ALLOC_CONTIGUOUS;
else
status |= ALLOC_SIMPLE;
alloc = ALLOC_CONTIGUOUS;
status |= lp->permission;
/* does VG exist? */
log_verbose("Finding volume group \"%s\"", lp->vg_name);
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, lp->vg_name))) {
if (!(vg = vg_read(cmd, lp->vg_name))) {
log_error("Volume group \"%s\" doesn't exist", lp->vg_name);
return 0;
}
@@ -382,7 +396,13 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!(lv = lv_create(cmd->fid, lp->lv_name, status,
/*
* For now all logical volumes are visible.
*/
status |= VISIBLE_LV;
if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc,
lp->stripes, lp->stripe_size, lp->extents,
vg, pvh))) return 0;
@@ -401,7 +421,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
/* store vg on disk(s) */
if (!cmd->fid->ops->vg_write(cmd->fid, vg))
if (!vg_write(vg))
return 0;
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE))
@@ -429,7 +449,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
}
/* store vg on disk(s) */
if (!cmd->fid->ops->vg_write(cmd->fid, vg))
if (!vg_write(vg))
return 0;
if (!unlock_lv(cmd, org->lvid.s)) {
@@ -460,6 +480,9 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
if (!_read_params(&lp, cmd, argc, argv))
return -EINVALID_CMD_LINE;
if (!driver_is_loaded())
return ECMD_FAILED;
if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", lp.vg_name);
return 0;

View File

@@ -42,5 +42,8 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvdisplay_single);
}

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