1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-11-02 04:23:50 +03:00

Compare commits

...

77 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
85 changed files with 1788 additions and 584 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 @@
1.95.07-cvs (2002-04-30)
1.95.10-cvs (2002-05-31)

30
debian/changelog vendored
View File

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

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

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;

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;
@@ -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)
{

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

@@ -177,6 +177,13 @@ 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");
}
}
@@ -190,7 +197,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\t';
space[i] = '\0';
while (n) {
@@ -306,7 +313,7 @@ static struct config_node *_section(struct parser *p)
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
struct config_value *h = NULL, *l, *ll = NULL;
if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
@@ -325,6 +332,16 @@ static struct config_value *_value(struct parser *p)
match(TOK_COMMA);
}
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);
@@ -335,17 +352,19 @@ static struct config_value *_type(struct parser *p)
{
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p);
if (!v)
return NULL;
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
match(TOK_FLOAT);
break;
@@ -682,3 +701,18 @@ int get_config_uint64(struct config_node *cn, const char *path,
*result = (uint64_t) n->v->v.i;
return 1;
}
int get_config_str(struct config_node *cn, const char *path,
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

@@ -28,6 +28,10 @@
#define DEFAULT_FORMAT "lvm1"
#define DEFAULT_MSG_PREFIX " "
#define DEFAULT_CMD_NAME 0
#ifdef READLINE_SUPPORT
#define DEFAULT_MAX_HISTORY 100
#endif

View File

@@ -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,17 +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)
{
ioctl(fd, BLKFLSBUF, 0);
}
int dev_close(struct device *dev)
{
if (dev->fd < 0) {

View File

@@ -207,16 +207,50 @@ void lvdisplay_colons(struct logical_volume *lv)
/* FIXME lv->lv_number, */
inkernel ? info.open_count : 0, lv->size, lv->le_count,
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
((lv->status & ALLOC_STRICT) +
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
((lv->alloc == ALLOC_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];
@@ -224,6 +258,8 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
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;
@@ -241,79 +277,47 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
lv->vg->name, lv->name);
log_print("VG Name %s", lv->vg->name);
/* Not in LVM1 format
/* Not in LVM1 format
log_print("LV UUID %s", uuid);
**/
log_print("LV Write Access %s",
(lv->status & LVM_WRITE) ? "read/write" : "read only");
/* see if this LV is an origina for a snapshot */
/* see if this LV is an origin for a snapshot */
if ((snap = find_origin(lv))) {
struct list *slh, *snaplist = find_snapshots(lv);
log_print("LV snapshot status source of");
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name, snap->cow->name,
"active");
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");
}
/* 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)))
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",
"active", lv->vg->cmd->dev_dir, lv->vg->name,
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
/******* FIXME Snapshot
if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
ret = -LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV;
goto lv_show_end;
}
printf("LV snapshot status ");
if (vg_check_active(vg_name) == TRUE) {
vg_t *vg_core;
if ((ret = vg_status_with_pv_and_lv(vg_name, &vg_core)) == 0) {
lv_t *lv_ptr =
vg_core->
lv[lv_get_index_by_name(vg_core, lv->lv_name)];
if (lv_ptr->lv_access & LV_SNAPSHOT) {
if (lv_ptr->lv_status & LV_ACTIVE)
printf("active ");
else
printf("INACTIVE ");
}
if (lv_ptr->lv_access & LV_SNAPSHOT_ORG) {
printf("source of\n");
while (lv_ptr->lv_snapshot_next != NULL) {
lv_ptr = lv_ptr->lv_snapshot_next;
printf(" %s [%s]\n",
lv_ptr->lv_name,
(lv_ptr->
lv_status & LV_ACTIVE) ? "active" :
"INACTIVE");
}
vg_free(vg_core, TRUE);
} else {
printf("destination for %s\n",
lv_ptr->lv_snapshot_org->lv_name);
}
}
} else {
printf("INACTIVE ");
if (lv->lv_access & LV_SNAPSHOT_ORG)
printf("original\n");
else
printf("snapshot\n");
}
}
***********/
if (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 - not sure that we're going to bother with this
log_print("LV # %u", lv->lv_number + 1);
@@ -322,7 +326,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
/* 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
/* 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);
*/
@@ -342,74 +346,49 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
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", origin->le_count);
/********** FIXME allocation - is there anytime the allocated LEs will not
* equal the current LEs? */
log_print("Allocated LE %u", origin->le_count);
/**********/
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);
log_print("Stripe size (KByte) %u",
seg->stripe_size/2);
}
/* only want the first segment for LVM1 format output */
break;
}
if(snap) {
/*char *s1, *s2;*/
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);
/* s1 = display_size();*/
log_print("Allocated to snapshot %s [%s/%s]", "NA", "NA", size);
dbg_free(size);
/* size = display_size(snap->cow->size / 2, SIZE_SHORT); */
log_print("Allocated to COW-table %s", "NA");
/* dbg_free(size); */
}
/********** 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);
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));
@@ -429,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)
@@ -554,7 +524,7 @@ void vgdisplay_full(struct volume_group *vg)
vg->status & SHARED ? "yes" : "no");
}
/****** FIXME VG # - we aren't implementing this because people should
* use the UUID for this anyway
* use the UUID for this anyway
log_print("VG # %u", vg->vg_number);
*******/
log_print("MAX LV %u", vg->max_lv);

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

@@ -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;
}

View File

@@ -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;

View File

@@ -297,12 +297,12 @@ 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;
@@ -350,10 +350,10 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
if (lv->status & BADBLOCK_ON)
lvd->lv_badblock = LV_BADBLOCK_ON;
if (lv->status & ALLOC_STRICT)
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;
}

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;

View File

@@ -23,6 +23,8 @@
#include <fcntl.h>
#include <time.h>
#define SECS_PER_DAY 86400 /* 24*60*60 */
/*
* The format instance is given a directory path upon creation.
* Each file in this directory whose name is of the form
@@ -135,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;
@@ -146,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 ? */
@@ -185,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;
@@ -228,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;
@@ -237,16 +278,22 @@ 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.");
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;
}

View File

@@ -11,15 +11,13 @@
#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) */
@@ -177,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);
@@ -357,12 +358,15 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
_out(f, "id = \"%s\"", buffer);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
if (!print_flags(lv->status, LV_FLAGS,
buffer, sizeof(buffer))) {
stack;
return 0;
}
_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);

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}
};
@@ -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

@@ -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,

View File

@@ -11,6 +11,7 @@
#include "uuid.h"
#include "hash.h"
#include "toolcontext.h"
#include "display.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn,
@@ -26,23 +27,72 @@ typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
#define _read_int64(root, path, result) \
get_config_uint64(root, path, '/', result)
/*
* Logs an attempt to read an invalid format file.
*/
static void _invalid_format(const char *str)
{
log_error("Can't process text format file (%s)", str);
}
/*
* Checks that the config file contains vg metadata, and that it
* we recognise the version number,
*/
static int _check_version(struct config_file *cf)
{
struct config_node *cn;
struct config_value *cv;
/*
* Check the contents field.
*/
if (!(cn = find_config_node(cf->root, CONTENTS_FIELD, '/'))) {
_invalid_format("missing contents field");
return 0;
}
cv = cn->v;
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE))
{
_invalid_format("unrecognised contents field");
return 0;
}
/*
* Check the version number.
*/
if (!(cn = find_config_node(cf->root, FORMAT_VERSION_FIELD, '/'))) {
_invalid_format("missing version number");
return 0;
}
cv = cn->v;
if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
_invalid_format("unrecognised version number");
return 0;
}
return 1;
}
static int _read_id(struct id *id, struct config_node *cn, const char *path)
{
struct config_value *cv;
if (!(cn = find_config_node(cn, path, '/'))) {
log_err("Couldn't find uuid.");
log_error("Couldn't find uuid.");
return 0;
}
cv = cn->v;
if (!cv || !cv->v.str) {
log_err("uuid must be a string.");
log_error("uuid must be a string.");
return 0;
}
if (!id_read_format(id, cv->v.str)) {
log_err("Invalid uuid.");
log_error("Invalid uuid.");
return 0;
}
@@ -76,12 +126,12 @@ static int _read_pv(struct format_instance *fid, 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;
}
@@ -92,9 +142,9 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
char buffer[64];
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_err("Couldn't find device.");
log_error("Couldn't find device.");
else
log_err("Couldn't find device with uuid '%s'.", buffer);
log_error("Couldn't find device with uuid '%s'.", buffer);
if (partial_mode())
vg->status |= PARTIAL_VG;
@@ -108,22 +158,22 @@ static int _read_pv(struct format_instance *fid, 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;
}
@@ -174,12 +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,26 +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);
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;
}
@@ -271,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;
}
@@ -306,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;
}
@@ -358,7 +408,7 @@ static int _read_lv(struct format_instance *fid, struct pool *mem,
}
if (!(lvn = lvn->child)) {
log_err("Empty logical volume section.");
log_error("Empty logical volume section.");
return 0;
}
@@ -366,19 +416,19 @@ static int _read_lv(struct format_instance *fid, 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;
}
@@ -389,8 +439,24 @@ static int _read_lv(struct format_instance *fid, 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;
}
@@ -418,33 +484,33 @@ static int _read_snapshot(struct format_instance *fid, 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;
}
@@ -468,7 +534,7 @@ static int _read_sections(struct format_instance *fid,
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;
}
@@ -498,7 +564,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
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;
}
@@ -533,29 +599,29 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
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_err("Couldn't read 'seqno' for volume group %s.", vg->name);
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;
}
@@ -566,13 +632,13 @@ static struct volume_group *_read_vg(struct format_instance *fid,
*/
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;
}
@@ -582,14 +648,14 @@ static struct volume_group *_read_vg(struct format_instance *fid,
* 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(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;
}
@@ -597,7 +663,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
list_init(&vg->lvs);
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all logical volumes for volume "
log_error("Couldn't read all logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
@@ -605,7 +671,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
list_init(&vg->snapshots);
if (!_read_sections(fid, "snapshots", _read_snapshot, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all snapshots for volume group %s.",
log_error("Couldn't read all snapshots for volume group %s.",
vg->name);
goto bad;
}
@@ -664,6 +730,9 @@ struct volume_group *text_vg_import(struct format_instance *fid,
goto out;
}
if (!_check_version(cf))
goto out;
if (!(vg = _read_vg(fid, cf, um))) {
stack;
goto out;

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];
@@ -233,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 */
@@ -244,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

@@ -302,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 {
@@ -362,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,
@@ -422,6 +423,7 @@ 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;
@@ -477,6 +479,7 @@ 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->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;

View File

@@ -426,8 +426,8 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
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))) {
stack;
return NULL;
inconsistent = 1;
continue;
}
if (first_time) {
correct_vg = vg;
@@ -441,6 +441,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
}
}
/* 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);
@@ -452,7 +458,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
return vg;
return correct_vg;
}
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)

View File

@@ -29,34 +29,43 @@
/* 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: 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 */
/*
* 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 */
#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;
@@ -147,6 +156,7 @@ struct logical_volume {
struct volume_group *vg;
uint32_t status;
alloc_policy_t alloc;
uint32_t read_ahead;
int32_t minor;
@@ -320,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,
@@ -394,6 +405,7 @@ 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

@@ -64,6 +64,37 @@ 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)

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

@@ -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

@@ -330,20 +330,33 @@ struct matcher *matcher_create(struct pool *mem, const char **patterns, int num)
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

@@ -22,6 +22,14 @@ struct parse_sp { /* scratch pad for the parsing process */
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.
* Returns: 1 success, 0 end of input, -1 error.
@@ -125,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;

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;

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

@@ -234,10 +234,9 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
struct format_instance *tf;
void *context;
if (!(context = create_text_context(vg->cmd->fmtt, file,
if (!(context = create_text_context(cmd->fmtt, file,
cmd->cmd_line)) ||
!(tf = vg->cmd->fmtt->ops->create_instance(cmd->fmtt, NULL,
context))) {
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
log_error("Couldn't create text format object.");
return NULL;
}

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)

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,8 +75,8 @@ xx(lvcreate,
"\t[--version]\n"
"\tVolumeGroupName [PhysicalVolumePath...]\n\n",
autobackup_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,
@@ -103,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",
@@ -230,7 +218,7 @@ xx(lvscan,
"\t[-v|--verbose] " "\n"
"\t[--version]\n",
blockdevice_ARG, disk_ARG, partial_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",
@@ -334,7 +322,8 @@ xx(pvscan,
"\t[-v|--verbose] " "\n"
"\t[--version]\n",
exported_ARG, novolumegroup_ARG, partial_ARG, short_ARG, uuid_ARG)
exported_ARG, novolumegroup_ARG, partial_ARG, short_ARG, uuid_ARG,
ignorelockingfailure_ARG)
xx(vgcfgbackup,
"Backup volume group configuration(s)",
@@ -342,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",
@@ -379,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)",
@@ -418,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",
@@ -524,7 +515,7 @@ xx(vgscan,
"\t[-h/-?/--help]\n"
"\t[-P/--partial] " "\n"
"\t[-v/--verbose]\n" ,
partial_ARG)
partial_ARG, ignorelockingfailure_ARG)
xx(vgsplit,
"Move physical volumes into a new volume group",
@@ -533,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);
}
@@ -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);
}
@@ -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;

View File

@@ -77,6 +77,12 @@ static int _read_name_params(struct lvcreate_params *lp,
}
} else {
if (strrchr(argv[0], '/')) {
log_error("Volume group name expected "
"(no slash)");
return 0;
}
/*
* Ensure lv_name doesn't contain a
* different VG.
@@ -188,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) ||
@@ -294,14 +312,13 @@ 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;
@@ -379,7 +396,13 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!(lv = lv_create(vg->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;
@@ -457,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);
}

View File

@@ -66,6 +66,8 @@ struct config_info {
int verbose;
int test;
int syslog;
const char *msg_prefix;
int cmd_name; /* Show command name? */
int archive; /* should we archive ? */
int backup; /* should we backup ? */
@@ -638,6 +640,11 @@ static int process_common_commands(struct command *com)
} else
init_partial(0);
if (arg_count(cmd, ignorelockingfailure_ARG))
init_ignorelockingfailure(1);
else
init_ignorelockingfailure(0);
/* Handle synonyms */
if (!merge_synonym(resizable_ARG, resizeable_ARG) ||
!merge_synonym(allocation_ARG, allocatable_ARG) ||
@@ -682,6 +689,9 @@ static void _use_settings(struct config_info *settings)
init_verbose(settings->verbose);
init_test(settings->test);
init_msg_prefix(_default_settings.msg_prefix);
init_cmd_name(_default_settings.cmd_name);
archive_enable(settings->archive);
backup_enable(settings->backup);
@@ -739,9 +749,6 @@ static int run_command(int argc, char **argv)
set_cmd_name(cmd->command->name);
/* FIXME: not sure that this is the best place for this... */
init_msg_prefix(find_config_str(cmd->cf->root, "log/prefix", '/', 0));
if ((ret = process_common_commands(cmd->command)))
return ret;
@@ -815,7 +822,7 @@ static void __init_log(struct config_file *cf)
{
char *open_mode = "a";
const char *log_file, *prefix;
const char *log_file;
_default_settings.syslog =
find_config_int(cf->root, "log/syslog", '/', 1);
@@ -834,10 +841,15 @@ static void __init_log(struct config_file *cf)
init_verbose(_default_settings.verbose);
init_indent(find_config_int(cf->root, "log/indent", '/', 1));
if ((prefix = find_config_str(cf->root, "log/prefix", '/', 0)))
init_msg_prefix(prefix);
init_cmd_name(find_config_int(cf->root, "log/command_names", '/', 0));
_default_settings.msg_prefix = find_config_str(cf->root, "log/prefix",
'/', DEFAULT_MSG_PREFIX);
init_msg_prefix(_default_settings.msg_prefix);
_default_settings.cmd_name = find_config_int(cf->root,
"log/command_names", '/',
DEFAULT_CMD_NAME);
init_cmd_name(_default_settings.cmd_name);
_default_settings.test = find_config_int(cf->root, "global/test",
'/', 0);
@@ -1104,16 +1116,14 @@ static int init(void)
return 0;
}
if (stat(config_file, &info) != -1) {
/* we've found a config file */
if (!read_config(cmd->cf, config_file)) {
log_error("Failed to load config file %s", config_file);
return 0;
}
__init_log(cmd->cf);
if (stat(config_file, &info) != -1 &&
!read_config(cmd->cf, config_file)) {
log_error("Failed to load config file %s", config_file);
return 0;
}
__init_log(cmd->cf);
_default_settings.umask = find_config_int(cmd->cf->root,
"global/umask", '/',
DEFAULT_UMASK);

View File

@@ -29,6 +29,9 @@ int lvremove(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, &lvremove_single);
}

View File

@@ -24,23 +24,37 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
{
int maxlen;
char *lv_name_old, *lv_name_new;
char *vg_name, *vg_name_new;
char *vg_name, *vg_name_new, *vg_name_old;
char *st;
struct volume_group *vg;
struct logical_volume *lv;
struct lv_list *lvl;
if (argc != 2) {
log_error("Old and new logical volume required");
if (argc == 3) {
vg_name = argv[0];
if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir)))
vg_name += strlen(cmd->dev_dir);
lv_name_old = argv[1];
lv_name_new = argv[2];
if (strchr(lv_name_old, '/') &&
(vg_name_old = extract_vgname(cmd, lv_name_old)) &&
strcmp(vg_name_old, vg_name)) {
log_error("Please use a single volume group name "
"(\"%s\" or \"%s\")", vg_name, vg_name_old);
return EINVALID_CMD_LINE;
}
} else if (argc == 2) {
lv_name_old = argv[0];
lv_name_new = argv[1];
vg_name = extract_vgname(cmd, lv_name_old);
} else {
log_error("Old and new logical volume names required");
return EINVALID_CMD_LINE;
}
lv_name_old = argv[0];
lv_name_new = argv[1];
if (!(vg_name = extract_vgname(cmd, lv_name_old))) {
log_error("Please provide a volume group name");
if (!is_valid_chars(vg_name)) {
log_error("Please provide a valid volume group name");
return EINVALID_CMD_LINE;
}
@@ -84,6 +98,9 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
log_verbose("Checking for existing volume group \"%s\"", vg_name);
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {

View File

@@ -27,7 +27,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
struct dm_info info;
uint32_t extents = 0;
uint32_t size = 0;
uint32_t stripes = 0, stripesize = 0;
uint32_t stripes = 0, stripesize = 0, stripesize_extents = 0;
uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
uint32_t extents_used = 0;
uint32_t size_rest;
@@ -94,6 +94,9 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
if ((st = strrchr(lv_name, '/')))
lv_name = st + 1;
if (!driver_is_loaded())
return ECMD_FAILED;
/* does VG exist? */
log_verbose("Finding volume group %s", vg_name);
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
@@ -256,12 +259,19 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
if (stripes > 1 && !stripesize) {
log_error("Stripesize for striped segment should not be 0!");
} else if ((stripes > 1) &&
(size_rest = seg_size % (stripes * stripesize))) {
log_print("Rounding size (%d extents) down to stripe boundary "
"size for segment (%d extents)", extents,
extents - size_rest);
extents = extents - size_rest;
goto error_cmdline;
}
if ((stripes > 1)) {
if (!(stripesize_extents = stripesize / vg->extent_size))
stripesize_extents = 1;
if ((size_rest = seg_size % (stripes * stripesize_extents))) {
log_print("Rounding size (%d extents) down to stripe "
"boundary size for segment (%d extents)",
extents, extents - size_rest);
extents = extents - size_rest;
}
}
if (extents == lv->le_count) {

View File

@@ -86,10 +86,9 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv)
***********/
dummy = display_size(lv->size / 2, SIZE_SHORT);
log_print("%s%s '%s%s/%s' [%s]%s%s", active_str, snapshot_str,
log_print("%s%s '%s%s/%s' [%s]%s", active_str, snapshot_str,
cmd->dev_dir, lv->vg->name, lv->name, dummy,
(lv->status & ALLOC_STRICT) ? " strict" : "",
(lv->status & ALLOC_CONTIGUOUS) ? " contiguous" : "");
get_alloc_string(lv->alloc));
dbg_free(dummy);

View File

@@ -6,12 +6,10 @@
#define unimplemented \
{ log_error("Command not implemented yet."); return ECMD_FAILED;}
int e2fsadm(struct cmd_context *cmd, int argc, char **argv) unimplemented
int lvmsadc(struct cmd_context *cmd, int argc, char **argv) unimplemented
int lvmsar(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvdata(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvmove(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvresize(struct cmd_context *cmd, int argc, char **argv) unimplemented
int vgmknodes(struct cmd_context *cmd, int argc, char **argv) unimplemented
int vgsplit(struct cmd_context *cmd, int argc, char **argv) unimplemented

View File

@@ -151,4 +151,13 @@ static inline const char *command_name(struct cmd_context *cmd)
return cmd->command->name;
}
static inline int driver_is_loaded(void)
{
int i = driver_version(NULL, 0);
if (!i)
log_error("device-mapper driver/module not loaded?");
return i;
}
#endif

View File

@@ -58,5 +58,8 @@ static int vg_backup_single(struct cmd_context *cmd, const char *vg_name)
int vgcfgbackup(struct cmd_context *cmd, int argc, char **argv)
{
if (!driver_is_loaded())
return ECMD_FAILED;
return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vg_backup_single);
}

View File

@@ -13,6 +13,9 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (!driver_is_loaded())
return ECMD_FAILED;
/*
* FIXME: overloading the -l arg for now to display a
* list of archive files for a particular vg

View File

@@ -63,12 +63,21 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, ignorelockingfailure_ARG) &&
!arg_count(cmd, available_ARG)) {
log_error("--ignorelockingfailure only available with -a");
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, available_ARG) == 1
&& arg_count(cmd, autobackup_ARG)) {
log_error("-A option not necessary with -a option");
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
return process_each_vg(cmd, argc, argv,
(arg_count(cmd, available_ARG)) ?
LCK_VG_READ : LCK_VG_WRITE, &vgchange_single);

View File

@@ -79,6 +79,9 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (!driver_is_loaded())
return ECMD_FAILED;
/* Create the new VG */
if (!(vg = vg_create(cmd, vg_name, extent_size, max_pv, max_lv,
argc - 1, argv + 1)))

View File

@@ -34,6 +34,9 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
/* FIXME -D disk_ARG is now redundant */
/********* FIXME: Do without this - or else 2(+) passes!

View File

@@ -34,6 +34,9 @@ int vgexport(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (!driver_is_loaded())
return ECMD_FAILED;
return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgexport_single);
}

View File

@@ -36,6 +36,9 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
vg_name = argv[0];
argc--;
argv++;

View File

@@ -34,6 +34,9 @@ int vgimport(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (!driver_is_loaded())
return ECMD_FAILED;
return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, &vgimport_single);
}

View File

@@ -34,6 +34,9 @@ int vgmerge(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
vg_name_to = argv[0];
argc--;
argv++;

View File

@@ -46,6 +46,9 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (!driver_is_loaded())
return ECMD_FAILED;
vg_name = argv[0];
argv++;
argc--;

View File

@@ -26,6 +26,9 @@ int vgremove(struct cmd_context *cmd, int argc, char **argv)
{
int ret;
if (!driver_is_loaded())
return ECMD_FAILED;
if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
log_error("Can't get lock for orphan PVs");
return ECMD_FAILED;

View File

@@ -67,6 +67,9 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (!driver_is_loaded())
return ECMD_FAILED;
log_verbose("Checking for existing volume group \"%s\"", vg_name_old);
if (!lock_vol(cmd, vg_name_old, LCK_VG_WRITE)) {

292
tools/vgsplit.c Normal file
View File

@@ -0,0 +1,292 @@
/*
* Copyright (C) 2001 Sistina Software
*
* LVM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* LVM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LVM; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "tools.h"
static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
char *pv_name)
{
struct pv_list *pvl;
struct physical_volume *pv;
if (!(pvl = find_pv_in_vg(vg_from, pv_name))) {
log_error("Physical volume %s not in volume group %s",
pv_name, vg_from->name);
return 0;
}
list_del(&pvl->list);
list_add(&vg_to->pvs, &pvl->list);
vg_from->pv_count--;
vg_to->pv_count++;
pv = list_item(pvl, struct pv_list)->pv;
vg_from->extent_count -= pv->pe_count;
vg_to->extent_count += pv->pe_count;
vg_from->free_count -= pv->pe_count - pv->pe_alloc_count;
vg_to->free_count += pv->pe_count - pv->pe_alloc_count;
return 1;
}
static int _pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
{
struct list *pvh;
list_iterate(pvh, &vg->pvs) {
if (pv == list_item(pvh, struct pv_list)->pv)
return 1;
}
return 0;
}
static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
{
struct list *lvh, *lvht, *segh;
struct logical_volume *lv;
struct stripe_segment *seg;
struct physical_volume *pv;
struct volume_group *vg_with;
int s;
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
/* Ensure all the PVs used by this LV remain in the same */
/* VG as each other */
vg_with = NULL;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
for (s = 0; s < seg->stripes; s++) {
pv = seg->area[s].pv;
if (vg_with) {
if (!_pv_is_in_vg(vg_with, pv)) {
log_error("Logical Volume %s "
"split between "
"Volume Groups",
lv->name);
return 0;
}
continue;
}
if (_pv_is_in_vg(vg_from, pv)) {
vg_with = vg_from;
continue;
}
if (_pv_is_in_vg(vg_to, pv)) {
vg_with = vg_to;
continue;
}
log_error("Physical Volume %s not found",
dev_name(pv->dev));
return 0;
}
}
if (vg_with == vg_from)
continue;
/* Move this LV */
list_del(lvh);
list_add(&vg_to->lvs, lvh);
vg_from->lv_count--;
vg_to->lv_count++;
}
return 1;
}
static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
{
struct list *lvh;
list_iterate(lvh, &vg->lvs) {
if (lv == list_item(lvh, struct lv_list)->lv)
return 1;
}
return 0;
}
static int _move_snapshots(struct volume_group *vg_from,
struct volume_group *vg_to)
{
struct list *slh, *slth;
struct snapshot *snap;
int cow_from, origin_from;
list_iterate_safe(slh, slth, &vg_from->snapshots) {
snap = list_item(slh, struct snapshot_list)->snapshot;
cow_from = _lv_is_in_vg(vg_from, snap->cow);
origin_from = _lv_is_in_vg(vg_from, snap->origin);
if (cow_from && origin_from)
return 1;
if ((!cow_from && origin_from) || (cow_from && !origin_from)) {
log_error("Snapshot %s split", snap->cow->name);
return 0;
}
vg_from->snapshot_count--;
vg_to->snapshot_count++;
list_del(slh);
list_add(&vg_to->snapshots, slh);
}
return 1;
}
int vgsplit(struct cmd_context *cmd, int argc, char **argv)
{
char *vg_name_from, *vg_name_to;
struct volume_group *vg_to, *vg_from;
int opt;
int active;
if (argc < 3) {
log_error("Existing VG, new VG and physical volumes required.");
return EINVALID_CMD_LINE;
}
vg_name_from = argv[0];
vg_name_to = argv[1];
argc -= 2;
argv += 2;
if (!strcmp(vg_name_to, vg_name_from)) {
log_error("Duplicate volume group name \"%s\"", vg_name_from);
return ECMD_FAILED;
}
if (!driver_is_loaded())
return ECMD_FAILED;
log_verbose("Checking for volume group \"%s\"", vg_name_from);
if (!lock_vol(cmd, vg_name_from, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", vg_name_from);
return ECMD_FAILED;
}
if (!(vg_from = vg_read(cmd, vg_name_from))) {
log_error("Volume group \"%s\" doesn't exist", vg_name_from);
unlock_vg(cmd, vg_name_from);
return ECMD_FAILED;
}
if (vg_from->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg_from->name);
unlock_vg(cmd, vg_name_from);
return ECMD_FAILED;
}
if (!(vg_from->status & LVM_WRITE)) {
log_error("Volume group \"%s\" is read-only", vg_from->name);
unlock_vg(cmd, vg_name_from);
return ECMD_FAILED;
}
log_verbose("Checking for volume group \"%s\"", vg_name_to);
if (!lock_vol(cmd, vg_name_to, LCK_VG_WRITE | LCK_NONBLOCK)) {
log_error("Can't get lock for %s", vg_name_to);
unlock_vg(cmd, vg_name_from);
return ECMD_FAILED;
}
if ((vg_to = vg_read(cmd, vg_name_to))) {
/* FIXME Remove this restriction */
log_error("Volume group \"%s\" already exists", vg_name_to);
goto error;
}
if ((active = lvs_in_vg_activated(vg_from))) {
/* FIXME Remove this restriction */
log_error("Logical volumes in \"%s\" must be inactive",
vg_name_from);
goto error;
}
/* Create new VG structure */
if (!(vg_to = vg_create(cmd, vg_name_to, vg_from->extent_size,
vg_from->max_pv, vg_from->max_lv, 0, NULL)))
goto error;
/* Archive vg_from before changing it */
if (!archive(vg_from))
goto error;
/* Move PVs across to new structure */
for (opt = 0; opt < argc; opt++) {
if (!_move_pv(vg_from, vg_to, argv[opt]))
goto error;
}
/* Move required LVs across, checking consistency */
if (!(_move_lvs(vg_from, vg_to)))
goto error;
/* Move required snapshots across */
if (!(_move_snapshots(vg_from, vg_to)))
goto error;
/* store it on disks */
log_verbose("Writing out updated volume groups");
/* Write out new VG as EXPORTED */
vg_to->status |= EXPORTED_VG;
if (!archive(vg_to))
goto error;
if (!vg_write(vg_to))
goto error;
backup(vg_to);
/* Write out updated old VG */
if (!vg_write(vg_from))
goto error;
backup(vg_from);
/* Remove EXPORTED flag from new VG */
vg_to->status &= ~EXPORTED_VG;
if (!vg_write(vg_to))
goto error;
backup(vg_to);
unlock_vg(cmd, vg_name_from);
unlock_vg(cmd, vg_name_to);
log_print("Volume group \"%s\" successfully split from \"%s\"",
vg_to->name, vg_from->name);
return 0;
error:
unlock_vg(cmd, vg_name_from);
unlock_vg(cmd, vg_name_to);
return ECMD_FAILED;
}