1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-12-25 20:23:49 +03:00

Compare commits

...

40 Commits

Author SHA1 Message Date
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
35 changed files with 823 additions and 282 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)

21
debian/changelog vendored
View File

@@ -1,3 +1,24 @@
lvm2 (1.95.08-1) unstable; urgency=low
* New upstream release (Beta3).
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 23 May 2002 03:46:37 -0500
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).

3
debian/control vendored
View File

@@ -7,7 +7,8 @@ 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/*

13
debian/init.d vendored
View File

@@ -16,8 +16,8 @@ modprobe dm-mod >/dev/null 2>&1
create_devfiles() {
DIR="/dev/device-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
@@ -33,12 +33,6 @@ case "$1" in
echo -n "Initializing $DESC: "
create_devfiles
vgchange -a y
# # Mount all LVM devices
# for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do
# MTPT=$( grep $vg /etc/fstab | awk '{print $2}' )
# mount $MTPT
# done
echo "$NAME."
;;
stop)
@@ -56,8 +50,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 25 S . start 50 0 6 ."
dh_installcron
dh_installman
dh_installinfo

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

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

@@ -224,6 +224,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;
@@ -247,73 +249,41 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
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);
@@ -359,57 +329,32 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
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));

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

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

@@ -477,6 +477,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

@@ -394,6 +394,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

@@ -35,9 +35,19 @@ static char *dm_cmd_list[] = {
"info",
"deps",
"rename",
"version"
"version",
"status",
"table",
"waitevent"
};
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;
@@ -74,6 +84,49 @@ int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
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;
}
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
{
if (!dmt->dmi)
@@ -121,8 +174,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 +207,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;
@@ -334,6 +380,19 @@ int dm_task_run(struct dm_task *dmt)
command = DM_VERSION;
break;
case DM_DEVICE_STATUS:
command = DM_GET_STATUS;
break;
case DM_DEVICE_TABLE:
dmi->flags |= DM_STATUS_TABLE_FLAG;
command = DM_GET_STATUS;
break;
case DM_DEVICE_WAITEVENT:
command = DM_WAIT_EVENT;
break;
default:
log_error("Internal error: unknown device-mapper task %d",
dmt->type);
@@ -360,6 +419,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

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

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

@@ -87,8 +87,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,
@@ -533,13 +533,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}
};

View File

@@ -192,7 +192,7 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
* Set the defaults.
*/
memset(lp, 0, sizeof(*lp));
lp->chunk_size = 2 * arg_int_value(cmd, chunksize_ARG, 32);
lp->chunk_size = 2 * arg_int_value(cmd, chunksize_ARG, 8);
log_verbose("setting chunksize to %d sectors.", lp->chunk_size);
if (!_read_name_params(lp, cmd, &argc, &argv) ||

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 ? */
@@ -682,6 +684,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 +744,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 +817,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 +836,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 +1111,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

@@ -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;
@@ -256,12 +256,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

@@ -13,5 +13,4 @@ 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

289
tools/vgsplit.c Normal file
View File

@@ -0,0 +1,289 @@
/*
* 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;
}
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;
}