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

Compare commits

...

44 Commits

Author SHA1 Message Date
Alasdair Kergon
9812657777 Support new target message ioctl. 2004-06-08 20:34:40 +00:00
Alasdair Kergon
0b09312fc6 mark pool support read-only; fix makefile typo 2004-06-07 19:26:13 +00:00
Alasdair Kergon
d0a7ac6b74 Add read-only GFS pool support. 2004-06-07 19:10:21 +00:00
Alasdair Kergon
ff9a238fbd lvm2create_initrd submitted by Jeff Layton <jtlayton@poochiereds.net>
sourced from http://poochiereds.net/svn/lvm2/
2004-06-07 16:20:05 +00:00
Alasdair Kergon
359fffa5f1 Fix rounding of large displayed sizes. 2004-06-07 15:22:43 +00:00
Alasdair Kergon
5bf92ced1a i2o_block 2004-06-01 18:33:50 +00:00
Alasdair Kergon
340bcc7b45 Suppress decimal point when using units of sectors/bytes. 2004-05-28 12:47:57 +00:00
Alasdair Kergon
ef03742bd4 Additional kernel target checks before pvmove & snapshot creation. 2004-05-24 20:51:56 +00:00
Alasdair Kergon
20431ec16d v2.00.16 2004-05-24 19:20:57 +00:00
Alasdair Kergon
becba8157b Set area_count within alloc_lv_segment 2004-05-24 17:30:00 +00:00
Alasdair Kergon
51fd3bb0eb Remove error labels. 2004-05-24 15:58:50 +00:00
Alasdair Kergon
4bbd3acb4e Fix a pvs error path. 2004-05-24 14:14:10 +00:00
Alasdair Kergon
3bc930ea7b xxchange -ae to activation exclusively 2004-05-24 13:44:10 +00:00
Alasdair Kergon
d1b26f8e86 Don't return non-zero status if there aren't any volume groups 2004-05-20 16:18:58 +00:00
Alasdair Kergon
fdf15caaff Rename allocation policies; add --alloc to cmdline; LV inherits from VG. 2004-05-18 22:12:53 +00:00
Alasdair Kergon
c7b4a53c0b Add reset_fn to external_locking. 2004-05-18 21:57:24 +00:00
Alasdair Kergon
af78dc0308 indent 2004-05-18 21:55:55 +00:00
Alasdair Kergon
5ad39493c4 Ensure presence of virtual targets before attempting activation. 2004-05-12 20:43:34 +00:00
Alasdair Kergon
61f597b408 Attempt to fix resizing of snapshot origins. 2004-05-12 20:40:34 +00:00
Alasdair Kergon
2162825240 Restructure lvresize, bringing it closer to lvcreate. 2004-05-11 18:47:40 +00:00
Alasdair Kergon
2b780e70d1 indent 2004-05-11 18:45:11 +00:00
Alasdair Kergon
a3823f818e update comment 2004-05-11 18:18:14 +00:00
Alasdair Kergon
1f7c47bcaf A quick sanity check on vg_disk struct when read in. More checks needed. 2004-05-11 17:18:42 +00:00
Alasdair Kergon
ec53c365a2 Only include visible LVs in active/open counts. 2004-05-11 17:09:09 +00:00
Alasdair Kergon
793ad1f2d4 Add --type to lvcreate/resize.
Add virtual segment types, zero and error.

A large sparse device can be constructed as a writeable snapshot of a large
zero device.
2004-05-11 16:01:58 +00:00
Alasdair Kergon
9bc733b76c Push lv_create & alloc policy up to tool level. 2004-05-05 18:49:21 +00:00
Alasdair Kergon
21b28f0217 fix return code 2004-05-05 18:39:30 +00:00
Alasdair Kergon
d3e23caa52 comments 2004-05-05 18:35:04 +00:00
Alasdair Kergon
9e7518de67 Skip mirror LV. Comments. 2004-05-05 18:33:01 +00:00
Alasdair Kergon
679f0047aa Detect invalid LV names in arg lists. 2004-05-05 18:31:38 +00:00
Alasdair Kergon
d77d5ce14b stray space 2004-05-05 18:27:56 +00:00
Alasdair Kergon
33ec22a2af Reporting uses line-at-a-time output. 2004-05-05 18:23:11 +00:00
Alasdair Kergon
353053225f lvm2 format sets unlimited_vols format flag. 2004-05-05 18:17:48 +00:00
Alasdair Kergon
b7f3d6f7f7 Internal-only metadata flag support. 2004-05-05 18:15:47 +00:00
Alasdair Kergon
e34577499d Some basic checking for presence of device-mapper targets. 2004-05-05 18:11:43 +00:00
Alasdair Kergon
4cf8960c0c Separate out polldaemon. 2004-05-05 17:56:20 +00:00
Alasdair Kergon
1f93ea0675 Revise internal locking semantics. 2004-05-05 12:03:07 +00:00
Alasdair Kergon
25b705c3a8 move find_pv_by_name to lib 2004-05-05 11:04:28 +00:00
Alasdair Kergon
0725588731 Add devices to segments report; some move->copy renaming. 2004-05-05 10:58:44 +00:00
Alasdair Kergon
fc5c61cc8b Begin to separate out segment types. 2004-05-04 21:25:57 +00:00
Alasdair Kergon
ac282e63c6 Compress any (obsolete) long LVM1 pvids encountered. 2004-05-04 18:38:11 +00:00
Alasdair Kergon
c3941941ce Support tagged config files. 2004-05-04 18:28:15 +00:00
Alasdair Kergon
46cdd53323 Don't abort operations if selinux is present but disabled. 2004-05-04 15:29:26 +00:00
Alasdair Kergon
3ff3e302c3 Missing $ => HAVE_LIBDL unset 2004-05-04 12:14:20 +00:00
110 changed files with 6798 additions and 1989 deletions

View File

@@ -26,6 +26,9 @@ SUBDIRS += lib tools
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += lib/format1 \
lib/format_pool \
lib/mirror \
lib/snapshot \
po \
test/mm test/device test/format1 test/regex test/filters
endif

View File

@@ -1 +1 @@
2.00.15-cvs (2004-04-19)
2.00.16-cvs (2004-05-24)

View File

@@ -1,3 +1,51 @@
Version 2.00.17 -
=============================
Add read-only GFS pool support.
Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/
Fix rounding of large diplayed sizes.
Suppress decimal point when using units of sectors/bytes.
Additional kernel target checks before pvmove & snapshot creation.
Add i2o_block.
Version 2.00.16 - 24 May 2004
=============================
Set area_count within alloc_lv_segment.
Remove error labels from lvresize.
Fix a pvs error path.
xxchange -ae for exclusive activation.
Don't return non-zero status if there aren't any volume groups.
Add --alloc argument to tools.
Rename allocation policies to contiguous, normal, anywhere, inherit.
nextfree becomes normal; anywhere isn't implemented yet.
LV inherits allocation policy from VG. Defaults: LV - inherit; VG - normal
Additional status character added to vgs to indicate allocation policy.
Add reset_fn to external_locking.
Ensure presence of virtual targets before attempting activating.
Attempt to fix resizing of snapshot origins.
Restructure lvresize, bringing it closer to lvcreate.
A quick sanity check on vg_disk struct when read in. More checks needed.
Only include visible LVs in active/open counts.
Add virtual segment types, zero and error. A large sparse device can be
constructed as a writeable snapshot of a large zero segment.
Add --type to lvcreate/resize.
Push lv_create & alloc policy up to tool level.
Fix pvdisplay return code.
Detect invalid LV names in arg lists.
Reporting uses line-at-a-time output.
lvm2 format sets unlimited_vols format flag.
Internal-only metadata flag support.
Basic checking for presence of device-mapper targets.
Separate out polldaemon.
Revise internal locking semantics.
Move find_pv_by_name to library.
Rename move->copy.
Add devices to segments report.
Begin separating out segment code. There's a lot of change here.
Compress any (obsolete) long LVM1 pvids encountered.
Support for tagged config files.
Don't abort operations if selinux present but disabled.
Fix typo in configure which left HAVE_LIBDL unset.
Version 2.00.15 - 19 Apr 2004
=============================
configure --with-owner= --with-group= to avoid -o and -g args to 'install'

View File

@@ -1,3 +1,7 @@
Version 1.00.18
=============================
Add target message-passing ioctl.
Version 1.00.17 - 17 Apr 2004
=============================
configure --with-owner= --with-group= to avoid -o and -g args to 'install'

92
configure vendored
View File

@@ -309,7 +309,7 @@ ac_includes_default="\
#endif"
ac_default_prefix=/usr
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os MSGFMT JOBS STATIC_LINK LVM1 OWNER GROUP CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LD_DEPS LD_FLAGS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL LIBOBJS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os MSGFMT JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LD_DEPS LD_FLAGS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -864,6 +864,12 @@ Optional Packages:
--with-group=GROUP Set the group owner of installed files
--with-lvm1=TYPE LVM1 metadata support: internal/shared/none
TYPE=internal
--with-pool=TYPE GFS pool read-only support: internal/shared/none
TYPE=internal
--with-snapshots=TYPE Snapshot support: internal/shared/none
TYPE=internal
--with-mirrors=TYPE Mirror support: internal/shared/none
TYPE=internal
--with-localedir=DIR Translation files in DIR PREFIX/share/locale
--with-confdir=DIR Configuration files in DIR /etc
--with-staticdir=DIR Static binary in DIR EXEC_PREFIX/sbin
@@ -3966,6 +3972,29 @@ if test x$LVM1 = xinternal; then
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
fi
# Check whether --with-pool or --without-pool was given.
if test "${with_pool+set}" = set; then
withval="$with_pool"
POOL="$withval"
else
POOL="internal"
fi;
if [ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ];
then { { echo "$as_me:$LINENO: error: --with-pool parameter invalid
" >&5
echo "$as_me: error: --with-pool parameter invalid
" >&2;}
{ (exit 1); exit 1; }; }
exit
fi;
if test x$POOL = xinternal; then
CFLAGS="$CFLAGS -DPOOL_INTERNAL"
fi
# Check whether --enable-jobs or --disable-jobs was given.
if test "${enable_jobs+set}" = set; then
enableval="$enable_jobs"
@@ -3974,6 +4003,50 @@ else
JOBS=-j2
fi;
# Check whether --with-snapshots or --without-snapshots was given.
if test "${with_snapshots+set}" = set; then
withval="$with_snapshots"
SNAPSHOTS="$withval"
else
SNAPSHOTS="internal"
fi;
if [ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ];
then { { echo "$as_me:$LINENO: error: --with-snapshots parameter invalid
" >&5
echo "$as_me: error: --with-snapshots parameter invalid
" >&2;}
{ (exit 1); exit 1; }; }
exit
fi;
if test x$SNAPSHOTS = xinternal; then
CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL"
fi
# Check whether --with-mirrors or --without-mirrors was given.
if test "${with_mirrors+set}" = set; then
withval="$with_mirrors"
MIRRORS="$withval"
else
MIRRORS="internal"
fi;
if [ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ];
then { { echo "$as_me:$LINENO: error: --with-mirrors parameter invalid
" >&5
echo "$as_me: error: --with-mirrors parameter invalid
" >&2;}
{ (exit 1); exit 1; }; }
exit
fi;
if test x$MIRRORS = xinternal; then
CFLAGS="$CFLAGS -DMIRRORED_INTERNAL"
fi
# Check whether --enable-static_link or --disable-static_link was given.
if test "${enable_static_link+set}" = set; then
enableval="$enable_static_link"
@@ -4607,14 +4680,16 @@ else
fi
if [ "x$HAVE_LIBDL" = xyes -a "xSTATIC_LINK" = xno ]; then
if [ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]; then
CFLAGS="$CFLAGS -DHAVE_LIBDL"
LIBS="-ldl $LIBS"
else
HAVE_LIBDL=no
fi
if [ "x$LVM1" = xshared -a "x$STATIC_LINK" = xyes ];
if [ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o \
"x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
\) -a "x$STATIC_LINK" = xyes ];
then { { echo "$as_me:$LINENO: error: Features cannot be 'shared' when building statically
" >&5
echo "$as_me: error: Features cannot be 'shared' when building statically
@@ -5117,7 +5192,10 @@ fi
ac_config_files="$ac_config_files Makefile make.tmpl doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -5674,6 +5752,9 @@ do
"include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
"lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
"lib/format1/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/format1/Makefile" ;;
"lib/format_pool/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/format_pool/Makefile" ;;
"lib/mirror/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/mirror/Makefile" ;;
"lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
"man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
"po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
"tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
@@ -5799,6 +5880,9 @@ s,@MSGFMT@,$MSGFMT,;t t
s,@JOBS@,$JOBS,;t t
s,@STATIC_LINK@,$STATIC_LINK,;t t
s,@LVM1@,$LVM1,;t t
s,@POOL@,$POOL,;t t
s,@SNAPSHOTS@,$SNAPSHOTS,;t t
s,@MIRRORS@,$MIRRORS,;t t
s,@OWNER@,$OWNER,;t t
s,@GROUP@,$GROUP,;t t
s,@CLDFLAGS@,$CLDFLAGS,;t t

View File

@@ -121,8 +121,63 @@ if test x$LVM1 = xinternal; then
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
fi
dnl -- format_pool inclusion type
AC_ARG_WITH(pool,
[ --with-pool=TYPE GFS pool read-only support: internal/shared/none
[TYPE=internal] ],
[ POOL="$withval" ],
[ POOL="internal" ])
if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]];
then AC_MSG_ERROR(
--with-pool parameter invalid
)
exit
fi;
if test x$POOL = xinternal; then
CFLAGS="$CFLAGS -DPOOL_INTERNAL"
fi
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
dnl -- snapshots inclusion type
AC_ARG_WITH(snapshots,
[ --with-snapshots=TYPE Snapshot support: internal/shared/none
[TYPE=internal] ],
[ SNAPSHOTS="$withval" ],
[ SNAPSHOTS="internal" ])
if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]];
then AC_MSG_ERROR(
--with-snapshots parameter invalid
)
exit
fi;
if test x$SNAPSHOTS = xinternal; then
CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL"
fi
dnl -- mirrors inclusion type
AC_ARG_WITH(mirrors,
[ --with-mirrors=TYPE Mirror support: internal/shared/none
[TYPE=internal] ],
[ MIRRORS="$withval" ],
[ MIRRORS="internal" ])
if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]];
then AC_MSG_ERROR(
--with-mirrors parameter invalid
)
exit
fi;
if test x$MIRRORS = xinternal; then
CFLAGS="$CFLAGS -DMIRRORED_INTERNAL"
fi
dnl Enables staticly-linked tools
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to their libraries
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
@@ -202,7 +257,7 @@ fi
dnl Check for dlopen
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
if [[ "x$HAVE_LIBDL" = xyes -a "xSTATIC_LINK" = xno ]]; then
if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; then
CFLAGS="$CFLAGS -DHAVE_LIBDL"
LIBS="-ldl $LIBS"
else
@@ -210,7 +265,9 @@ else
fi
dnl Check for shared/static conflicts
if [[ "x$LVM1" = xshared -a "x$STATIC_LINK" = xyes ]];
if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o \
"x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
\) -a "x$STATIC_LINK" = xyes ]];
then AC_MSG_ERROR(
Features cannot be 'shared' when building statically
)
@@ -287,6 +344,9 @@ fi
AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK)
AC_SUBST(LVM1)
AC_SUBST(POOL)
AC_SUBST(SNAPSHOTS)
AC_SUBST(MIRRORS)
AC_SUBST(OWNER)
AC_SUBST(GROUP)
AC_SUBST(CFLAGS)
@@ -320,6 +380,9 @@ doc/Makefile \
include/Makefile \
lib/Makefile \
lib/format1/Makefile \
lib/format_pool/Makefile \
lib/mirror/Makefile \
lib/snapshot/Makefile \
man/Makefile \
po/Makefile \
tools/Makefile \

View File

@@ -1,4 +1,5 @@
../lib/activate/activate.h
../lib/activate/targets.h
../lib/cache/lvmcache.h
../lib/commands/errors.h
../lib/commands/toolcontext.h
@@ -20,12 +21,16 @@
../lib/filters/filter-sysfs.h
../lib/filters/filter.h
../lib/format1/format1.h
../lib/format_pool/format_pool.h
../lib/format_text/format-text.h
../lib/format_text/text_export.h
../lib/format_text/text_import.h
../lib/label/label.h
../lib/locking/locking.h
../lib/log/log.h
../lib/metadata/lv_alloc.h
../lib/metadata/metadata.h
../lib/metadata/segtypes.h
../lib/mm/dbg_malloc.h
../lib/mm/memlock.h
../lib/mm/pool.h

View File

@@ -20,6 +20,18 @@ ifeq ("@LVM1@", "shared")
SUBDIRS = format1
endif
ifeq ("@POOL@", "shared")
SUBDIRS += format_pool
endif
ifeq ("@SNAPSHOTS@", "shared")
SUBDIRS += snapshot
endif
ifeq ("@MIRRORS@", "shared")
SUBDIRS += mirror
endif
SOURCES =\
activate/activate.c \
cache/lvmcache.c \
@@ -33,6 +45,7 @@ SOURCES =\
device/dev-io.c \
device/device.c \
display/display.c \
error/errseg.c \
filters/filter-composite.c \
filters/filter-persistent.c \
filters/filter-regex.c \
@@ -57,6 +70,7 @@ SOURCES =\
metadata/metadata.c \
metadata/mirror.c \
metadata/pv_map.c \
metadata/segtypes.c \
metadata/snapshot_manip.c \
misc/crc.c \
misc/lvm-file.c \
@@ -67,7 +81,9 @@ SOURCES =\
regex/parse_rx.c \
regex/ttree.c \
report/report.c \
uuid/uuid.c
striped/striped.c \
uuid/uuid.c \
zero/zero.c
ifeq ("@LVM1@", "internal")
SOURCES +=\
@@ -80,6 +96,22 @@ ifeq ("@LVM1@", "internal")
format1/vg_number.c
endif
ifeq ("@POOL@", "internal")
SOURCES +=\
format_pool/disk_rep.c \
format_pool/format_pool.c \
format_pool/import_export.c \
format_pool/pool_label.c
endif
ifeq ("@SNAPSHOTS@", "internal")
SOURCES += snapshot/snapshot.c
endif
ifeq ("@MIRRORS@", "internal")
SOURCES += mirror/mirrored.c
endif
ifeq ("@DEBUG@", "yes")
SOURCES += mm/dbg_malloc.c
endif

View File

@@ -25,6 +25,7 @@
#include "toolcontext.h"
#include "dev_manager.h"
#include "str_list.h"
#include "config.h"
#include <limits.h>
#include <fcntl.h>
@@ -173,13 +174,13 @@ int activation(void)
static int _passes_activation_filter(struct cmd_context *cmd,
struct logical_volume *lv)
{
struct config_node *cn;
const struct config_node *cn;
struct config_value *cv;
char *str;
char path[PATH_MAX];
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
/* If no hosts tags defined, activate */
/* If no host tags defined, activate */
if (list_empty(&cmd->tags))
return 1;
@@ -341,7 +342,7 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
stack;
return 0;
}
@@ -387,7 +388,7 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
stack;
return 0;
}
@@ -419,7 +420,7 @@ int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
if (!info.exists)
return 0;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
stack;
return 0;
}
@@ -462,7 +463,7 @@ static int _lv_activate_lv(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
stack;
return 0;
}
@@ -479,7 +480,7 @@ static int _lv_deactivate(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
stack;
return 0;
}
@@ -496,7 +497,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
stack;
return 0;
}
@@ -509,7 +510,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
}
/*
* These two functions return the number of LVs in the state,
* These two functions return the number of visible LVs in the state,
* or -1 on error.
*/
int lvs_in_vg_activated(struct volume_group *vg)
@@ -523,7 +524,8 @@ int lvs_in_vg_activated(struct volume_group *vg)
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_active(lv) == 1);
if (lv->status & VISIBLE_LV)
count += (_lv_active(lv) == 1);
}
return count;
@@ -540,7 +542,8 @@ int lvs_in_vg_opened(struct volume_group *vg)
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_open_count(lv) > 0);
if (lv->status & VISIBLE_LV)
count += (_lv_open_count(lv) > 0);
}
return count;

View File

@@ -21,7 +21,11 @@
#include "lvm-string.h"
#include "fs.h"
#include "defaults.h"
#include "segtypes.h"
#include "display.h"
#include "toolcontext.h"
#include "targets.h"
#include "config.h"
#include <libdevmapper.h>
#include <limits.h>
@@ -62,13 +66,8 @@ enum {
SUSPENDED = 4,
NOPROPAGATE = 5,
TOPLEVEL = 6,
REMOVE = 7
};
enum {
MIRR_DISABLED,
MIRR_RUNNING,
MIRR_COMPLETED
REMOVE = 7,
RESUME_IMMEDIATE = 8
};
typedef enum {
@@ -112,14 +111,14 @@ struct dl_list {
};
static const char *stripe_filler = NULL;
static uint32_t mirror_region_size = 0;
struct dev_manager {
struct pool *mem;
struct config_tree *cft;
struct cmd_context *cmd;
const char *stripe_filler;
uint32_t mirror_region_size;
void *target_state;
uint32_t pvmove_mirror_count;
char *vg_name;
@@ -336,7 +335,7 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
static int _info(const char *name, const char *uuid, int mknodes,
struct dm_info *info, struct pool *mem, char **uuid_out)
{
if (!mknodes && uuid && *uuid &&
if (!mknodes && uuid && *uuid &&
_info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists)
return 1;
@@ -427,18 +426,16 @@ static int _percent_run(struct dev_manager *dm, const char *name,
uint64_t start, length;
char *type = NULL;
char *params = NULL;
float percent2;
struct list *segh = &lv->segments;
struct lv_segment *seg = NULL;
struct segment_type *segtype;
uint64_t numerator, denominator;
uint64_t total_numerator = 0, total_denominator = 0;
*percent = -1;
if (!(dmt = _setup_task(name, uuid, event_nr,
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS)))
{
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS))) {
stack;
return 0;
}
@@ -471,40 +468,19 @@ static int _percent_run(struct dev_manager *dm, const char *name,
if (!type || !params || strcmp(type, target_type))
continue;
/* Mirror? */
if (!strcmp(type, "mirror")) {
log_debug("Mirror status: %s", params);
if (sscanf(params, "%*d %*x:%*x %*x:%*x %" PRIu64
"/%" PRIu64, &numerator,
&denominator) != 2) {
log_error("Failure parsing mirror status: %s",
params);
goto out;
}
total_numerator += numerator;
total_denominator += denominator;
if (seg && (seg->status & PVMOVE))
seg->extents_moved = dm->mirror_region_size *
numerator / lv->vg->extent_size;
if (!(segtype = get_segtype_from_string(dm->cmd, type)))
continue;
if (segtype->ops->target_percent &&
!segtype->ops->target_percent(&dm->target_state, dm->mem,
dm->cmd->cft, seg, params,
&total_numerator,
&total_denominator,
percent)) {
stack;
goto out;
}
if (strcmp(type, "snapshot"))
continue;
/* Snapshot */
if (index(params, '/')) {
if (sscanf(params, "%" PRIu64 "/%" PRIu64,
&numerator, &denominator) == 2) {
total_numerator += numerator;
total_denominator += denominator;
}
continue;
} else if (sscanf(params, "%f", &percent2) == 1) {
*percent += percent2;
*percent /= 2;
}
} while (next);
if (lv && (segh = list_next(&lv->segments, segh))) {
@@ -515,7 +491,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
if (total_denominator)
*percent = (float) total_numerator *100 / total_denominator;
else
else if (*percent < 0)
*percent = 100;
log_debug("LV percent: %f", *percent);
@@ -574,6 +550,55 @@ static int _rename(struct dev_layer *dl, char *newname)
return r;
}
static int _suspend_or_resume(const char *name, action_t suspend)
{
int r;
struct dm_task *dmt;
int sus = (suspend == SUSPEND) ? 1 : 0;
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name);
if (!(dmt = _setup_task(name, NULL, 0, task))) {
stack;
return 0;
}
if (!(r = dm_task_run(dmt)))
log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
name);
dm_task_destroy(dmt);
return r;
}
static int _suspend(struct dev_layer *dl)
{
if (!dl->info.exists || dl->info.suspended)
return 1;
if (!_suspend_or_resume(dl->name, SUSPEND)) {
stack;
return 0;
}
dl->info.suspended = 1;
return 1;
}
static int _resume(struct dev_layer *dl)
{
if (!dl->info.exists || !dl->info.suspended)
return 1;
if (!_suspend_or_resume(dl->name, RESUME)) {
stack;
return 0;
}
dl->info.suspended = 0;
return 1;
}
static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
{
int r = 1;
@@ -633,9 +658,9 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
log_error("Couldn't load device '%s'.", dl->name);
if ((dl->lv->minor >= 0 || dl->lv->major >= 0) &&
_get_flag(dl, VISIBLE))
log_error("Perhaps the persistent device number "
"%d:%d is already in use?",
dl->lv->major, dl->lv->minor);
log_error("Perhaps the persistent device number "
"%d:%d is already in use?",
dl->lv->major, dl->lv->minor);
}
if (!dm_task_get_info(dmt, &dl->info)) {
@@ -650,6 +675,13 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
goto out;
}
if (_get_flag(dl, RESUME_IMMEDIATE) && dl->info.suspended &&
!_resume(dl)) {
stack;
r = 0;
goto out;
}
log_very_verbose("Activated %s %s %03u:%03u", dl->name,
dl->dlid, dl->info.major, dl->info.minor);
@@ -696,55 +728,6 @@ static int _remove(struct dev_layer *dl)
return r;
}
static int _suspend_or_resume(const char *name, action_t suspend)
{
int r;
struct dm_task *dmt;
int sus = (suspend == SUSPEND) ? 1 : 0;
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name);
if (!(dmt = _setup_task(name, NULL, 0, task))) {
stack;
return 0;
}
if (!(r = dm_task_run(dmt)))
log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
name);
dm_task_destroy(dmt);
return r;
}
static int _suspend(struct dev_layer *dl)
{
if (!dl->info.exists || dl->info.suspended)
return 1;
if (!_suspend_or_resume(dl->name, SUSPEND)) {
stack;
return 0;
}
dl->info.suspended = 1;
return 1;
}
static int _resume(struct dev_layer *dl)
{
if (!dl->info.exists || !dl->info.suspended)
return 1;
if (!_suspend_or_resume(dl->name, RESUME)) {
stack;
return 0;
}
dl->info.suspended = 0;
return 1;
}
/*
* The functions that populate the table in a dm_task as part of
* a create/reload.
@@ -759,98 +742,26 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
size_t paramsize)
{
uint64_t esize = seg->lv->vg->extent_size;
uint32_t s, start_area = 0u, areas = seg->area_count;
int w = 0, tw = 0;
int w = 0;
const char *target = NULL;
const char *trailing_space;
int mirror_status;
struct dev_layer *dl;
char devbuf[10];
int r;
switch (seg->type) {
case SEG_SNAPSHOT:
if (!seg->segtype->ops->compose_target_line) {
log_error("_emit_target: Internal error: Can't handle "
"SEG_SNAPSHOT");
"segment type %s", seg->segtype->name);
return 0;
/* Target formats:
* linear [device offset]+
* striped #stripes stripe_size [device offset]+
* mirror log_type #log_params [log_params]*
* #mirrors [device offset]+
*/
case SEG_STRIPED:
if (areas == 1)
target = "linear";
else if (areas > 1) {
target = "striped";
if ((tw = lvm_snprintf(params, paramsize, "%u %u ",
areas, seg->stripe_size)) < 0)
goto error;
w = tw;
} else {
log_error("_emit_target: Internal error: SEG_STRIPED "
"with no stripes");
return 0;
}
break;
case SEG_MIRRORED:
mirror_status = MIRR_RUNNING;
if (seg->status & PVMOVE) {
if (seg->extents_moved == seg->area_len) {
mirror_status = MIRR_COMPLETED;
start_area = 1;
} else if (dm->pvmove_mirror_count++) {
mirror_status = MIRR_DISABLED;
areas = 1;
}
}
if (mirror_status != MIRR_RUNNING) {
target = "linear";
break;
}
target = "mirror";
if ((tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
dm->mirror_region_size, areas)) < 0)
goto error;
w = tw;
break;
}
for (s = start_area; s < areas; s++, w += tw) {
trailing_space = (areas - s - 1) ? " " : "";
if ((seg->area[s].type == AREA_PV &&
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
tw = lvm_snprintf(params + w, paramsize - w,
"%s 0%s", dm->stripe_filler,
trailing_space);
else if (seg->area[s].type == AREA_PV)
tw = lvm_snprintf(params + w, paramsize - w,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].u.pv.pv->dev),
(seg->area[s].u.pv.pv->pe_start +
(esize * seg->area[s].u.pv.pe)),
trailing_space);
else {
if (!(dl = hash_lookup(dm->layers,
seg->area[s].u.lv.lv->lvid.s))) {
log_error("device layer %s missing from hash",
seg->area[s].u.lv.lv->lvid.s);
return 0;
}
if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major, dl->info.minor)) {
log_error("Failed to format device number as dm target (%u,%u)",
dl->info.major, dl->info.minor);
return 0;
}
tw = lvm_snprintf(params + w, paramsize - w,
"%s %" PRIu64 "%s", devbuf,
esize * seg->area[s].u.lv.le,
trailing_space);
}
if (tw < 0)
goto error;
if ((r = seg->segtype->ops->compose_target_line(dm, dm->mem,
dm->cmd->cft,
&dm->target_state, seg,
params, paramsize,
&target, &w,
&dm->
pvmove_mirror_count)) <=
0) {
stack;
return r;
}
log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
@@ -863,11 +774,62 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
}
return 1;
}
error:
log_debug("Insufficient space in params[%" PRIsize_t "] for target "
"parameters.", paramsize);
return -1;
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos, int start_area,
int areas)
{
uint32_t s;
int tw = 0;
const char *trailing_space;
uint64_t esize = seg->lv->vg->extent_size;
struct dev_layer *dl;
char devbuf[10];
for (s = start_area; s < areas; s++, *pos += tw) {
trailing_space = (areas - s - 1) ? " " : "";
if ((seg->area[s].type == AREA_PV &&
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s 0%s", dm->stripe_filler,
trailing_space);
else if (seg->area[s].type == AREA_PV)
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].u.pv.pv->dev),
(seg->area[s].u.pv.pv->pe_start +
(esize * seg->area[s].u.pv.pe)),
trailing_space);
else {
if (!(dl = hash_lookup(dm->layers,
seg->area[s].u.lv.lv->lvid.s))) {
log_error("device layer %s missing from hash",
seg->area[s].u.lv.lv->lvid.s);
return 0;
}
if (!dm_format_dev
(devbuf, sizeof(devbuf), dl->info.major,
dl->info.minor)) {
log_error
("Failed to format device number as dm target (%u,%u)",
dl->info.major, dl->info.minor);
return 0;
}
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s %" PRIu64 "%s", devbuf,
esize * seg->area[s].u.lv.le,
trailing_space);
}
if (tw < 0) {
stack;
return -1;
}
}
return 1;
}
static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
@@ -892,6 +854,9 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
if (ret >= 0)
return ret;
log_debug("Insufficient space in params[%" PRIsize_t
"] for target parameters.", paramsize);
paramsize *= 2;
} while (paramsize < MAX_TARGET_PARAMSIZE);
@@ -1023,8 +988,8 @@ static int _populate_snapshot(struct dev_manager *dm,
/*
* dev_manager implementation.
*/
struct dev_manager *dev_manager_create(const char *vg_name,
struct config_tree *cft)
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
const char *vg_name)
{
struct pool *mem;
struct dev_manager *dm;
@@ -1039,22 +1004,16 @@ struct dev_manager *dev_manager_create(const char *vg_name,
goto bad;
}
dm->cmd = cmd;
dm->mem = mem;
dm->cft = cft;
if (!stripe_filler) {
stripe_filler = find_config_str(cft->root,
stripe_filler = find_config_str(cmd->cft->root,
"activation/missing_stripe_filler",
DEFAULT_STRIPE_FILLER);
}
dm->stripe_filler = stripe_filler;
if (!mirror_region_size) {
mirror_region_size = 2 * find_config_int(cft->root,
"activation/mirror_region_size",
DEFAULT_MIRROR_REGION_SIZE);
}
dm->mirror_region_size = mirror_region_size;
if (!(dm->vg_name = pool_strdup(dm->mem, vg_name))) {
stack;
goto bad;
@@ -1070,6 +1029,8 @@ struct dev_manager *dev_manager_create(const char *vg_name,
list_init(&dm->remove_list);
list_init(&dm->suspend_list);
dm->target_state = NULL;
return dm;
bad:
@@ -1282,15 +1243,13 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
/* Add dependencies for any LVs that segments refer to */
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (seg->type != SEG_STRIPED && seg->type != SEG_MIRRORED)
continue;
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_LV)
continue;
if (!str_list_add(dm->mem, &dl->pre_create,
_build_dlid(dm->mem,
seg->area[s].u.lv.
lv->lvid.s, NULL))) {
seg->area[s].u.lv.lv->
lvid.s, NULL))) {
stack;
return 0;
}
@@ -1311,7 +1270,7 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
_clear_flag(dlr, VISIBLE);
_clear_flag(dlr, TOPLEVEL);
_set_flag(dlr, REMOVE);
/* add the dependency on the real device */
if (!str_list_add(dm->mem, &dl->pre_create,
pool_strdup(dm->mem, dlr->dlid))) {
@@ -1336,6 +1295,9 @@ static int _expand_origin_real(struct dev_manager *dm,
_clear_flag(dl, VISIBLE);
_clear_flag(dl, TOPLEVEL);
/* Size changes must take effect before tables using it are reloaded */
_set_flag(dl, RESUME_IMMEDIATE);
real_dlid = dl->dlid;
if (!(dl = _create_layer(dm, NULL, lv))) {
@@ -1688,7 +1650,6 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
return 1;
}
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
{
struct list *lvh;
@@ -1756,8 +1717,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
continue;
}
if (!str_list_add(dm->mem, &dep->pre_create,
dl->dlid)) {
if (!str_list_add(dm->mem, &dep->pre_create, dl->dlid)) {
stack;
return 0;
}
@@ -1773,8 +1733,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
continue;
}
if (!str_list_add(dm->mem, &dep->pre_suspend,
dl->dlid)) {
if (!str_list_add(dm->mem, &dep->pre_suspend, dl->dlid)) {
stack;
return 0;
}
@@ -2086,6 +2045,73 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
return 1;
}
static int _targets_present(struct dev_manager *dm, struct list *lvs)
{
struct logical_volume *lv;
struct list *lvh, *segh;
struct segment_type *segtype;
struct lv_segment *seg;
int snapshots = 0, mirrors = 0;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!snapshots)
if (lv_is_cow(lv) || lv_is_origin(lv))
snapshots = 1;
if (!mirrors)
if (lv->status & PVMOVE)
mirrors = 1;
if (lv->status & VIRTUAL) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (seg->segtype->ops->target_present &&
!seg->segtype->ops->target_present()) {
log_error("Can't expand LV: %s target "
"support missing "
"from kernel?",
seg->segtype->name);
return 0;
}
}
}
}
if (mirrors) {
if (!(segtype = get_segtype_from_string(dm->cmd, "mirror"))) {
log_error("Can't expand LV: Mirror support "
"missing from tools?");
return 0;
}
if (!segtype->ops->target_present ||
!segtype->ops->target_present()) {
log_error("Can't expand LV: Mirror support missing "
"from kernel?");
return 0;
}
}
if (snapshots) {
if (!(segtype = get_segtype_from_string(dm->cmd, "snapshot"))) {
log_error("Can't expand LV: Snapshot support "
"missing from tools?");
return 0;
}
if (!segtype->ops->target_present ||
!segtype->ops->target_present()) {
log_error("Can't expand LV: Snapshot support missing "
"from kernel?");
return 0;
}
}
return 1;
}
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
{
char *dlid;
@@ -2168,6 +2194,12 @@ static int _action(struct dev_manager *dm, struct logical_volume *lv,
}
}
if (!_targets_present(dm, &dm->active_list) ||
!_targets_present(dm, &dm->reload_list)) {
stack;
return 0;
}
if (!_execute(dm, lv->vg)) {
stack;
return 0;

View File

@@ -16,17 +16,16 @@
#ifndef _LVM_DEV_MANAGER_H
#define _LVM_DEV_MANAGER_H
#include "metadata.h"
#include "config.h"
struct logical_volume;
struct cmd_context;
struct dev_manager;
struct dm_info;
/*
* Constructor and destructor.
*/
struct dev_manager *dev_manager_create(const char *vg_name,
struct config_tree *cf);
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
const char *vg_name);
void dev_manager_destroy(struct dev_manager *dm);
void dev_manager_exit(void);

View File

@@ -181,7 +181,7 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
#ifdef HAVE_SELINUX
if (!set_selinux_context(lv_path)) {
log_sys_error("set_selinux_context", lv_path);
stack;
return 0;
}
#endif

25
lib/activate/targets.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TARGETS_H
#define _LVM_TARGETS_H
struct dev_manager;
struct lv_segment;
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos,
int start_area, int areas);
#endif

View File

@@ -20,7 +20,6 @@
#include "dev-cache.h"
#include "uuid.h"
#include "label.h"
#include "metadata.h"
#define ORPHAN ""
@@ -30,6 +29,10 @@
/* LVM specific per-volume info */
/* Eventual replacement for struct physical_volume perhaps? */
struct cmd_context;
struct format_type;
struct volume_group;
struct lvmcache_vginfo {
struct list list; /* Join these vginfos together */
struct list infos; /* List head for lvmcache_infos */

View File

@@ -33,6 +33,8 @@
#include "display.h"
#include "memlock.h"
#include "str_list.h"
#include "segtypes.h"
#include "lvmcache.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
@@ -42,6 +44,10 @@
#include "format1.h"
#endif
#ifdef POOL_INTERNAL
#include "format_pool.h"
#endif
#include <locale.h>
#include <sys/stat.h>
#include <sys/utsname.h>
@@ -116,8 +122,7 @@ static void _init_logging(struct cmd_context *cmd)
find_config_int(cmd->cft->root, "global/test", 0);
/* Settings for logging to file */
if (find_config_int(cmd->cft->root, "log/overwrite",
DEFAULT_OVERWRITE))
if (find_config_int(cmd->cft->root, "log/overwrite", DEFAULT_OVERWRITE))
append = 0;
log_file = find_config_str(cmd->cft->root, "log/file", 0);
@@ -198,51 +203,260 @@ static int _process_config(struct cmd_context *cmd)
return 1;
}
/* Find and read config file */
static int _init_config(struct cmd_context *cmd)
static int _set_tag(struct cmd_context *cmd, const char *tag)
{
struct stat info;
char config_file[PATH_MAX] = "";
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
if (!(cmd->cft = create_config_tree())) {
stack;
return 0;
}
/* No config file if LVM_SYSTEM_DIR is empty */
if (!*cmd->sys_dir)
return 1;
if (lvm_snprintf(config_file, sizeof(config_file),
"%s/lvm.conf", cmd->sys_dir) < 0) {
log_error("LVM_SYSTEM_DIR was too long");
destroy_config_tree(cmd->cft);
return 0;
}
/* Is there a config file? */
if (stat(config_file, &info) == -1) {
if (errno == ENOENT)
return 1;
log_sys_error("stat", config_file);
destroy_config_tree(cmd->cft);
return 0;
}
if (!read_config_file(cmd->cft, config_file)) {
log_error("Failed to load config file %s", config_file);
destroy_config_tree(cmd->cft);
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
log_error("_set_tag: str_list_add %s failed", tag);
return 0;
}
return 1;
}
static int _init_dev_cache(struct cmd_context *cmd)
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
int *passes)
{
struct config_node *cn;
struct config_value *cv;
*passes = 1;
for (cn = hn; cn; cn = cn->sib) {
if (!cn->v)
continue;
if (!strcmp(cn->key, "host_list")) {
*passes = 0;
if (cn->v->type == CFG_EMPTY_ARRAY)
continue;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid hostname string "
"for tag %s", cn->key);
return 0;
}
if (!strcmp(cv->v.str, cmd->hostname)) {
*passes = 1;
return 1;
}
}
}
if (!strcmp(cn->key, "host_filter")) {
log_error("host_filter not supported yet");
return 0;
}
}
return 1;
}
static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
{
const struct config_node *tn, *cn;
const char *tag;
int passes;
if (!(tn = find_config_node(cft->root, "tags")) || !tn->child)
return 1;
/* NB hosttags 0 when already 1 intentionally does not delete the tag */
if (!cmd->hosttags && find_config_int(cft->root, "tags/hosttags",
DEFAULT_HOSTTAGS)) {
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
if (!_set_tag(cmd, cmd->hostname)) {
stack;
return 0;
}
cmd->hosttags = 1;
}
for (cn = tn->child; cn; cn = cn->sib) {
if (cn->v)
continue;
tag = cn->key;
if (*tag == '@')
tag++;
if (!validate_name(tag)) {
log_error("Invalid tag in config file: %s", cn->key);
return 0;
}
if (cn->child) {
passes = 0;
if (!_check_host_filters(cmd, cn->child, &passes)) {
stack;
return 0;
}
if (!passes)
continue;
}
if (!_set_tag(cmd, tag)) {
stack;
return 0;
}
}
return 1;
}
static int _load_config_file(struct cmd_context *cmd, const char *tag)
{
char config_file[PATH_MAX] = "";
const char *filler = "";
struct stat info;
struct config_tree_list *cfl;
if (*tag)
filler = "_";
if (lvm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
cmd->sys_dir, filler, tag) < 0) {
log_error("LVM_SYSTEM_DIR or tag was too long");
return 0;
}
if (!(cfl = pool_alloc(cmd->libmem, sizeof(*cfl)))) {
log_error("config_tree_list allocation failed");
return 0;
}
if (!(cfl->cft = create_config_tree(config_file))) {
log_error("config_tree allocation failed");
return 0;
}
/* Is there a config file? */
if (stat(config_file, &info) == -1) {
if (errno == ENOENT) {
list_add(&cmd->config_files, &cfl->list);
goto out;
}
log_sys_error("stat", config_file);
destroy_config_tree(cfl->cft);
return 0;
}
log_very_verbose("Loading config file: %s", config_file);
if (!read_config_file(cfl->cft)) {
log_error("Failed to load config file %s", config_file);
destroy_config_tree(cfl->cft);
return 0;
}
list_add(&cmd->config_files, &cfl->list);
out:
if (*tag)
_init_tags(cmd, cfl->cft);
else
/* Use temporary copy of lvm.conf while loading other files */
cmd->cft = cfl->cft;
return 1;
}
/* Find and read first config file */
static int _init_lvm_conf(struct cmd_context *cmd)
{
/* No config file if LVM_SYSTEM_DIR is empty */
if (!*cmd->sys_dir) {
if (!(cmd->cft = create_config_tree(NULL))) {
log_error("Failed to create config tree");
return 0;
}
return 1;
}
if (!_load_config_file(cmd, "")) {
stack;
return 0;
}
return 1;
}
/* Read any additional config files */
static int _init_tag_configs(struct cmd_context *cmd)
{
struct str_list *sl;
/* Tag list may grow while inside this loop */
list_iterate_items(sl, &cmd->tags) {
if (!_load_config_file(cmd, sl->str)) {
stack;
return 0;
}
}
return 1;
}
static int _merge_config_files(struct cmd_context *cmd)
{
struct config_tree_list *cfl;
/* Replace temporary duplicate copy of lvm.conf */
if (cmd->cft->root) {
if (!(cmd->cft = create_config_tree(NULL))) {
log_error("Failed to create config tree");
return 0;
}
}
list_iterate_items(cfl, &cmd->config_files) {
/* Merge all config trees into cmd->cft using merge/tag rules */
if (!merge_config_tree(cmd, cmd->cft, cfl->cft)) {
stack;
return 0;
}
}
return 1;
}
static void _destroy_tags(struct cmd_context *cmd)
{
struct list *slh, *slht;
list_iterate_safe(slh, slht, &cmd->tags) {
list_del(slh);
}
}
int config_files_changed(struct cmd_context *cmd)
{
struct config_tree_list *cfl;
list_iterate_items(cfl, &cmd->config_files) {
if (config_file_changed(cfl->cft))
return 1;
}
return 0;
}
static void _destroy_tag_configs(struct cmd_context *cmd)
{
struct config_tree_list *cfl;
if (cmd->cft && cmd->cft->root) {
destroy_config_tree(cmd->cft);
cmd->cft = NULL;
}
list_iterate_items(cfl, &cmd->config_files) {
destroy_config_tree(cfl->cft);
}
list_init(&cmd->config_files);
}
static int _init_dev_cache(struct cmd_context *cmd)
{
const struct config_node *cn;
struct config_value *cv;
if (!dev_cache_init()) {
stack;
return 0;
@@ -281,7 +495,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
{
unsigned nr_filt = 0;
struct config_node *cn;
const struct config_node *cn;
struct dev_filter *filters[MAX_FILTERS];
memset(filters, 0, sizeof(filters));
@@ -351,8 +565,8 @@ static int _init_filters(struct cmd_context *cmd)
return 0;
}
dev_cache =
find_config_str(cmd->cft->root, "devices/cache", cache_file);
dev_cache = find_config_str(cmd->cft->root, "devices/cache",
cache_file);
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
log_error("Failed to create persistent device filter");
return 0;
@@ -384,7 +598,7 @@ static int _init_formats(struct cmd_context *cmd)
struct list *fmth;
#ifdef HAVE_LIBDL
struct config_node *cn;
const struct config_node *cn;
#endif
label_init();
@@ -396,6 +610,13 @@ static int _init_formats(struct cmd_context *cmd)
list_add(&cmd->formats, &fmt->list);
#endif
#ifdef POOL_INTERNAL
if (!(fmt = init_pool_format(cmd)))
return 0;
fmt->library = NULL;
list_add(&cmd->formats, &fmt->list);
#endif
#ifdef HAVE_LIBDL
/* Load any formats in shared libs */
if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) {
@@ -454,6 +675,97 @@ static int _init_formats(struct cmd_context *cmd)
return 0;
}
static int _init_segtypes(struct cmd_context *cmd)
{
struct segment_type *segtype;
#ifdef HAVE_LIBDL
const struct config_node *cn;
#endif
if (!(segtype = init_striped_segtype(cmd)))
return 0;
segtype->library = NULL;
list_add(&cmd->segtypes, &segtype->list);
if (!(segtype = init_zero_segtype(cmd)))
return 0;
segtype->library = NULL;
list_add(&cmd->segtypes, &segtype->list);
if (!(segtype = init_error_segtype(cmd)))
return 0;
segtype->library = NULL;
list_add(&cmd->segtypes, &segtype->list);
#ifdef SNAPSHOT_INTERNAL
if (!(segtype = init_snapshot_segtype(cmd)))
return 0;
segtype->library = NULL;
list_add(&cmd->segtypes, &segtype->list);
#endif
#ifdef MIRRORED_INTERNAL
if (!(segtype = init_mirrored_segtype(cmd)))
return 0;
segtype->library = NULL;
list_add(&cmd->segtypes, &segtype->list);
#endif
#ifdef HAVE_LIBDL
/* Load any formats in shared libs */
if ((cn = find_config_node(cmd->cft->root, "global/segment_libraries"))) {
struct config_value *cv;
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
void *lib;
struct list *sgtl, *tmp;
struct segment_type *segtype2;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"global/segment_libraries");
return 0;
}
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
"segment type"))) {
stack;
return 0;
}
if (!(init_segtype_fn = dlsym(lib, "init_segtype"))) {
log_error("Shared library %s does not contain "
"segment type functions", cv->v.str);
dlclose(lib);
return 0;
}
if (!(segtype = init_segtype_fn(cmd)))
return 0;
segtype->library = lib;
list_add(&cmd->segtypes, &segtype->list);
list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
segtype2 = list_item(sgtl, struct segment_type);
if (!strcmp(segtype2->name, segtype->name)) {
log_error("Duplicate segment type %s: "
"unloading shared library %s",
segtype->name, cv->v.str);
list_del(&segtype->list);
segtype->ops->destroy(segtype);
dlclose(lib);
break;
}
}
}
}
#endif
return 1;
}
static int _init_hostname(struct cmd_context *cmd)
{
struct utsname uts;
@@ -476,105 +788,6 @@ static int _init_hostname(struct cmd_context *cmd)
return 1;
}
static int _set_tag(struct cmd_context *cmd, const char *tag)
{
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
log_error("_init_tags: str_list_add %s failed", tag);
return 0;
}
return 1;
}
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
int *passes)
{
struct config_node *cn;
struct config_value *cv;
*passes = 1;
for (cn = hn; cn; cn = cn->sib) {
if (!cn->v)
continue;
if (!strcmp(cn->key, "host_list")) {
*passes = 0;
if (cn->v->type == CFG_EMPTY_ARRAY)
continue;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid hostname string "
"for tag %s", cn->key);
return 0;
}
if (!strcmp(cv->v.str, cmd->hostname)) {
*passes = 1;
return 1;
}
}
}
if (!strcmp(cn->key, "host_filter")) {
log_error("host_filter not supported yet");
return 0;
}
}
return 1;
}
static int _init_tags(struct cmd_context *cmd)
{
struct config_node *tn, *cn;
const char *tag;
int passes;
list_init(&cmd->tags);
if (!(tn = find_config_node(cmd->cft->root, "tags")) ||
!tn->child) {
log_very_verbose("No tags defined in config file");
return 1;
}
if (find_config_int(cmd->cft->root, "tags/hosttags",
DEFAULT_HOSTTAGS)) {
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
if (!_set_tag(cmd, cmd->hostname)) {
stack;
return 0;
}
}
for (cn = tn->child; cn; cn = cn->sib) {
if (cn->v)
continue;
tag = cn->key;
if (*tag == '@')
tag++;
if (!validate_name(tag)) {
log_error("Invalid tag in config file: %s", cn->key);
return 0;
}
if (cn->child) {
passes = 0;
if (!_check_host_filters(cmd, cn->child, &passes)) {
stack;
return 0;
}
if (!passes)
continue;
}
if (!_set_tag(cmd, tag)) {
stack;
return 0;
}
}
return 1;
}
/* Entry point */
struct cmd_context *create_toolcontext(struct arg *the_args)
{
@@ -599,7 +812,11 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
}
memset(cmd, 0, sizeof(*cmd));
cmd->args = the_args;
cmd->hosttags = 0;
list_init(&cmd->formats);
list_init(&cmd->segtypes);
list_init(&cmd->tags);
list_init(&cmd->config_files);
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
@@ -610,16 +827,28 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
goto error;
if (!_init_config(cmd))
goto error;
_init_logging(cmd);
if (!(cmd->libmem = pool_create(4 * 1024))) {
log_error("Library memory pool creation failed");
return 0;
}
if (!_init_lvm_conf(cmd))
goto error;
_init_logging(cmd);
if (!_init_hostname(cmd))
goto error;
if (!_init_tags(cmd, cmd->cft))
goto error;
if (!_init_tag_configs(cmd))
goto error;
if (!_merge_config_files(cmd))
goto error;
if (!_process_config(cmd))
goto error;
@@ -639,14 +868,12 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!_init_formats(cmd))
goto error;
if (!_init_hostname(cmd))
goto error;
if (!_init_tags(cmd))
if (!_init_segtypes(cmd))
goto error;
cmd->current_settings = cmd->default_settings;
cmd->config_valid = 1;
return cmd;
error:
@@ -654,16 +881,6 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
return NULL;
}
int refresh_toolcontext(struct cmd_context *cmd)
{
_init_logging(cmd);
_init_tags(cmd);
/* FIXME Reset filters and dev_cache */
return 1;
}
static void _destroy_formats(struct list *formats)
{
struct list *fmtl, *tmp;
@@ -682,6 +899,83 @@ static void _destroy_formats(struct list *formats)
}
}
static void _destroy_segtypes(struct list *segtypes)
{
struct list *sgtl, *tmp;
struct segment_type *segtype;
void *lib;
list_iterate_safe(sgtl, tmp, segtypes) {
segtype = list_item(sgtl, struct segment_type);
list_del(&segtype->list);
lib = segtype->library;
segtype->ops->destroy(segtype);
#ifdef HAVE_LIBDL
if (lib)
dlclose(lib);
#endif
}
}
int refresh_toolcontext(struct cmd_context *cmd)
{
log_verbose("Reloading config files");
if (cmd->config_valid) {
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
}
activation_exit();
lvmcache_destroy();
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(&cmd->formats);
if (cmd->filter) {
cmd->filter->destroy(cmd->filter);
cmd->filter = NULL;
}
dev_cache_exit();
_destroy_tags(cmd);
_destroy_tag_configs(cmd);
cmd->config_valid = 0;
cmd->hosttags = 0;
if (!_init_lvm_conf(cmd))
return 0;
_init_logging(cmd);
if (!_init_tags(cmd, cmd->cft))
return 0;
if (!_init_tag_configs(cmd))
return 0;
if (!_merge_config_files(cmd))
return 0;
if (!_process_config(cmd))
return 0;
if (!_init_dev_cache(cmd))
return 0;
if (!_init_filters(cmd))
return 0;
if (!_init_formats(cmd))
return 0;
if (!_init_segtypes(cmd))
return 0;
cmd->config_valid = 1;
return 1;
}
void destroy_toolcontext(struct cmd_context *cmd)
{
if (cmd->dump_filter)
@@ -690,11 +984,13 @@ void destroy_toolcontext(struct cmd_context *cmd)
activation_exit();
lvmcache_destroy();
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(&cmd->formats);
cmd->filter->destroy(cmd->filter);
pool_destroy(cmd->mem);
dev_cache_exit();
destroy_config_tree(cmd->cft);
_destroy_tags(cmd);
_destroy_tag_configs(cmd);
pool_destroy(cmd->libmem);
dbg_free(cmd);

View File

@@ -17,9 +17,7 @@
#define _LVM_TOOLCONTEXT_H
#include "dev-cache.h"
#include "config.h"
#include "pool.h"
#include "metadata.h"
#include <stdio.h>
#include <limits.h>
@@ -47,6 +45,8 @@ struct config_info {
mode_t umask;
};
struct config_tree;
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
struct cmd_context {
@@ -57,6 +57,7 @@ struct cmd_context {
struct format_type *fmt_backup; /* Format to use for backups */
struct list formats; /* Available formats */
struct list segtypes; /* Available segment types */
const char *hostname;
const char *kernel_vsn;
@@ -68,12 +69,15 @@ struct cmd_context {
struct dev_filter *filter;
int dump_filter; /* Dump filter when exiting? */
struct list config_files;
int config_valid;
struct config_tree *cft;
struct config_info default_settings;
struct config_info current_settings;
/* List of defined tags */
struct list tags;
int hosttags;
char sys_dir[PATH_MAX];
char dev_dir[PATH_MAX];
@@ -83,5 +87,6 @@ struct cmd_context {
struct cmd_context *create_toolcontext(struct arg *the_args);
void destroy_toolcontext(struct cmd_context *cmd);
int refresh_toolcontext(struct cmd_context *cmd);
int config_files_changed(struct cmd_context *cmd);
#endif

View File

@@ -18,6 +18,8 @@
#include "crc.h"
#include "pool.h"
#include "device.h"
#include "str_list.h"
#include "toolcontext.h"
#include <sys/stat.h>
#include <sys/mman.h>
@@ -56,6 +58,7 @@ struct cs {
struct pool *mem;
time_t timestamp;
char *filename;
int exists;
};
static void _get_token(struct parser *p, int tok_prev);
@@ -93,7 +96,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
/*
* public interface
*/
struct config_tree *create_config_tree(void)
struct config_tree *create_config_tree(const char *filename)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
@@ -103,7 +106,7 @@ struct config_tree *create_config_tree(void)
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
if (!(c = pool_zalloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
@@ -112,7 +115,9 @@ struct config_tree *create_config_tree(void)
c->mem = mem;
c->cft.root = (struct config_node *) NULL;
c->timestamp = 0;
c->filename = NULL;
c->exists = 0;
if (filename)
c->filename = pool_strdup(c->mem, filename);
return &c->cft;
}
@@ -204,29 +209,33 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
return r;
}
int read_config_file(struct config_tree *cft, const char *file)
int read_config_file(struct config_tree *cft)
{
struct cs *c = (struct cs *) cft;
struct stat info;
struct device *dev;
int r = 1;
if (stat(file, &info)) {
log_sys_error("stat", file);
if (stat(c->filename, &info)) {
log_sys_error("stat", c->filename);
c->exists = 0;
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("%s is not a regular file", file);
log_error("%s is not a regular file", c->filename);
c->exists = 0;
return 0;
}
c->exists = 1;
if (info.st_size == 0) {
log_verbose("%s is empty", file);
log_verbose("%s is empty", c->filename);
return 1;
}
if (!(dev = dev_create_file(file, NULL, NULL))) {
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
stack;
return 0;
}
@@ -242,7 +251,6 @@ int read_config_file(struct config_tree *cft, const char *file)
dev_close(dev);
c->timestamp = info.st_mtime;
c->filename = pool_strdup(c->mem, file);
return r;
}
@@ -255,74 +263,43 @@ time_t config_file_timestamp(struct config_tree *cft)
}
/*
* Returns 1 if config file reloaded
* Return 1 if config files ought to be reloaded
*/
int reload_config_file(struct config_tree **cft)
int config_file_changed(struct config_tree *cft)
{
struct config_tree *new_cft;
struct cs *c = (struct cs *) *cft;
struct cs *new_cs;
struct cs *c = (struct cs *) cft;
struct stat info;
struct device *dev;
int r;
if (!c->filename)
return 0;
if (stat(c->filename, &info) == -1) {
if (errno == ENOENT)
return 1;
/* Ignore a deleted config file: still use original data */
if (errno == ENOENT) {
if (!c->exists)
return 0;
log_very_verbose("Config file %s has disappeared!",
c->filename);
goto reload;
}
log_sys_error("stat", c->filename);
log_error("Failed to reload configuration file");
log_error("Failed to reload configuration files");
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("Configuration file %s is not a regular file",
c->filename);
return 0;
goto reload;
}
/* Unchanged? */
if (c->timestamp == info.st_mtime)
return 0;
log_verbose("Detected config file change: Reloading %s", c->filename);
if (info.st_size == 0) {
log_verbose("Config file reload: %s is empty", c->filename);
return 0;
}
if (!(new_cft = create_config_tree())) {
log_error("Allocation of new config_tree failed");
return 0;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
stack;
return 0;
}
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
r = read_config_fd(new_cft, dev, 0, (size_t) info.st_size,
0, 0, (checksum_fn_t) NULL, 0);
dev_close(dev);
if (r) {
new_cs = (struct cs *) new_cft;
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
new_cs->timestamp = info.st_mtime;
destroy_config_tree(*cft);
*cft = new_cft;
}
return r;
reload:
log_verbose("Detected config file change to %s", c->filename);
return 1;
}
static void _write_value(FILE *fp, struct config_value *v)
@@ -739,7 +716,8 @@ static char *_dup_tok(struct parser *p)
/*
* utility functions
*/
struct config_node *find_config_node(struct config_node *cn, const char *path)
struct config_node *find_config_node(const struct config_node *cn,
const char *path)
{
const char *e;
@@ -767,13 +745,13 @@ struct config_node *find_config_node(struct config_node *cn, const char *path)
path = e;
}
return cn;
return (struct config_node *) cn;
}
const char *find_config_str(struct config_node *cn,
const char *find_config_str(const struct config_node *cn,
const char *path, const char *fail)
{
struct config_node *n = find_config_node(cn, path);
const struct config_node *n = find_config_node(cn, path);
if (n && n->v->type == CFG_STRING) {
if (*n->v->v.str)
@@ -787,9 +765,9 @@ const char *find_config_str(struct config_node *cn,
return fail;
}
int find_config_int(struct config_node *cn, const char *path, int fail)
int find_config_int(const struct config_node *cn, const char *path, int fail)
{
struct config_node *n = find_config_node(cn, path);
const struct config_node *n = find_config_node(cn, path);
if (n && n->v->type == CFG_INT) {
log_very_verbose("Setting %s to %d", path, n->v->v.i);
@@ -801,9 +779,10 @@ int find_config_int(struct config_node *cn, const char *path, int fail)
return fail;
}
float find_config_float(struct config_node *cn, const char *path, float fail)
float find_config_float(const struct config_node *cn, const char *path,
float fail)
{
struct config_node *n = find_config_node(cn, path);
const struct config_node *n = find_config_node(cn, path);
if (n && n->v->type == CFG_FLOAT) {
log_very_verbose("Setting %s to %f", path, n->v->v.r);
@@ -843,9 +822,9 @@ static int _str_to_bool(const char *str, int fail)
return fail;
}
int find_config_bool(struct config_node *cn, const char *path, int fail)
int find_config_bool(const struct config_node *cn, const char *path, int fail)
{
struct config_node *n = find_config_node(cn, path);
const struct config_node *n = find_config_node(cn, path);
struct config_value *v;
if (!n)
@@ -864,10 +843,10 @@ int find_config_bool(struct config_node *cn, const char *path, int fail)
return fail;
}
int get_config_uint32(struct config_node *cn, const char *path,
int get_config_uint32(const struct config_node *cn, const char *path,
uint32_t *result)
{
struct config_node *n;
const struct config_node *n;
n = find_config_node(cn, path);
@@ -878,10 +857,10 @@ int get_config_uint32(struct config_node *cn, const char *path,
return 1;
}
int get_config_uint64(struct config_node *cn, const char *path,
int get_config_uint64(const struct config_node *cn, const char *path,
uint64_t *result)
{
struct config_node *n;
const struct config_node *n;
n = find_config_node(cn, path);
@@ -893,9 +872,10 @@ int get_config_uint64(struct config_node *cn, const char *path,
return 1;
}
int get_config_str(struct config_node *cn, const char *path, char **result)
int get_config_str(const struct config_node *cn, const char *path,
char **result)
{
struct config_node *n;
const struct config_node *n;
n = find_config_node(cn, path);
@@ -905,3 +885,115 @@ int get_config_str(struct config_node *cn, const char *path, char **result)
*result = n->v->v.str;
return 1;
}
/* Insert cn2 after cn1 */
static void _insert_config_node(struct config_node **cn1,
struct config_node *cn2)
{
if (!*cn1) {
*cn1 = cn2;
cn2->sib = NULL;
} else {
cn2->sib = (*cn1)->sib;
(*cn1)->sib = cn2;
}
}
/*
* Merge section cn2 into section cn1 (which has the same name)
* overwriting any existing cn1 nodes with matching names.
*/
static void _merge_section(struct config_node *cn1, struct config_node *cn2)
{
struct config_node *cn, *nextn, *oldn;
struct config_value *cv;
for (cn = cn2->child; cn; cn = nextn) {
nextn = cn->sib;
/* Skip "tags" */
if (!strcmp(cn->key, "tags"))
continue;
/* Subsection? */
if (!cn->v)
/* Ignore - we don't have any of these yet */
continue;
/* Not already present? */
if (!(oldn = find_config_node(cn1->child, cn->key))) {
_insert_config_node(&cn1->child, cn);
continue;
}
/* Merge certain value lists */
if ((!strcmp(cn1->key, "activation") &&
!strcmp(cn->key, "volume_list")) ||
(!strcmp(cn1->key, "devices") &&
(!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) {
cv = cn->v;
while (cv->next)
cv = cv->next;
cv->next = oldn->v;
}
/* Replace values */
oldn->v = cn->v;
}
}
static int _match_host_tags(struct list *tags, struct config_node *tn)
{
struct config_value *tv;
const char *str;
for (tv = tn->v; tv; tv = tv->next) {
if (tv->type != CFG_STRING)
continue;
str = tv->v.str;
if (*str == '@')
str++;
if (!*str)
continue;
if (str_list_match_item(tags, str))
return 1;
}
return 0;
}
/* Destructively merge a new config tree into an existing one */
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
struct config_tree *newdata)
{
struct config_node *root = cft->root;
struct config_node *cn, *nextn, *oldn, *tn, *cn2;
for (cn = newdata->root; cn; cn = nextn) {
nextn = cn->sib;
/* Ignore tags section */
if (!strcmp(cn->key, "tags"))
continue;
/* If there's a tags node, skip if host tags don't match */
if ((tn = find_config_node(cn->child, "tags"))) {
if (!_match_host_tags(&cmd->tags, tn))
continue;
}
if (!(oldn = find_config_node(root, cn->key))) {
_insert_config_node(&cft->root, cn);
/* Remove any "tags" nodes */
for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
if (!strcmp(cn2->key, "tags")) {
cn->child = cn2->sib;
continue;
}
if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
cn2->sib = cn2->sib->sib;
continue;
}
}
continue;
}
_merge_section(oldn, cn);
}
return 1;
}

View File

@@ -16,7 +16,8 @@
#ifndef _LVM_CONFIG_H
#define _LVM_CONFIG_H
#include "device.h"
struct device;
struct cmd_context;
enum {
CFG_STRING,
@@ -45,42 +46,51 @@ struct config_tree {
struct config_node *root;
};
struct config_tree *create_config_tree(void);
void destroy_config_tree(struct config_tree *cf);
struct config_tree_list {
struct list list;
struct config_tree *cft;
};
struct config_tree *create_config_tree(const char *filename);
void destroy_config_tree(struct config_tree *cft);
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
int read_config_fd(struct config_tree *cf, struct device *dev,
int read_config_fd(struct config_tree *cft, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum);
int read_config_file(struct config_tree *cf, const char *file);
int write_config_file(struct config_tree *cf, const char *file);
int reload_config_file(struct config_tree **cf);
time_t config_file_timestamp(struct config_tree *cf);
int read_config_file(struct config_tree *cft);
int write_config_file(struct config_tree *cft, const char *file);
time_t config_file_timestamp(struct config_tree *cft);
int config_file_changed(struct config_tree *cft);
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
struct config_tree *newdata);
struct config_node *find_config_node(struct config_node *cn,
struct config_node *find_config_node(const struct config_node *cn,
const char *path);
const char *find_config_str(struct config_node *cn, const char *path,
const char *find_config_str(const struct config_node *cn, const char *path,
const char *fail);
int find_config_int(struct config_node *cn, const char *path, int fail);
int find_config_int(const struct config_node *cn, const char *path, int fail);
float find_config_float(struct config_node *cn, const char *path, float fail);
float find_config_float(const struct config_node *cn, const char *path,
float fail);
/*
* Understands (0, ~0), (y, n), (yes, no), (on,
* off), (true, false).
*/
int find_config_bool(struct config_node *cn, const char *path, int fail);
int find_config_bool(const struct config_node *cn, const char *path, int fail);
int get_config_uint32(struct config_node *cn, const char *path,
int get_config_uint32(const struct config_node *cn, const char *path,
uint32_t *result);
int get_config_uint64(struct config_node *cn, const char *path,
int get_config_uint64(const struct config_node *cn, const char *path,
uint64_t *result);
int get_config_str(struct config_node *cn, const char *path, char **result);
int get_config_str(const struct config_node *cn, const char *path,
char **result);
#endif

View File

@@ -91,12 +91,12 @@
#define DEFAULT_REP_HEADINGS 1
#define DEFAULT_REP_SEPARATOR " "
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,move_percent"
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent"
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,move_percent,lv_uuid"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"

View File

@@ -18,6 +18,7 @@
#include "display.h"
#include "activate.h"
#include "toolcontext.h"
#include "segtypes.h"
#define SIZE_BUF 128
@@ -26,23 +27,13 @@ static struct {
const char *str;
} _policies[] = {
{
ALLOC_NEXT_FREE, "next free"}, {
ALLOC_CONTIGUOUS, "contiguous"}, {
ALLOC_DEFAULT, "next free (default)"}
};
static struct {
segment_type_t segtype;
const char *str;
} _segtypes[] = {
{
SEG_STRIPED, "striped"}, {
SEG_MIRRORED, "mirror"}, {
SEG_SNAPSHOT, "snapshot"}
ALLOC_NORMAL, "normal"}, {
ALLOC_ANYWHERE, "anywhere"}, {
ALLOC_INHERIT, "inherit"}
};
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
uint64_t units_to_bytes(const char *units, char *unit_type)
{
@@ -124,17 +115,6 @@ const char *get_alloc_string(alloc_policy_t alloc)
return NULL;
}
const char *get_segtype_string(segment_type_t segtype)
{
int i;
for (i = 0; i < _num_segtypes; i++)
if (_segtypes[i].segtype == segtype)
return _segtypes[i].str;
return "unknown";
}
alloc_policy_t get_alloc_from_string(const char *str)
{
int i;
@@ -143,26 +123,19 @@ alloc_policy_t get_alloc_from_string(const char *str)
if (!strcmp(_policies[i].str, str))
return _policies[i].alloc;
log_error("Unrecognised allocation policy - using default");
return ALLOC_DEFAULT;
}
segment_type_t get_segtype_from_string(const char *str)
{
int i;
for (i = 0; i < _num_segtypes; i++)
if (!strcmp(_segtypes[i].str, str))
return _segtypes[i].segtype;
log_error("Unrecognised segment type - using default (striped)");
return SEG_STRIPED;
/* Special case for old metadata */
if(!strcmp("next free", str))
return ALLOC_NORMAL;
log_error("Unrecognised allocation policy %s", str);
return ALLOC_INVALID;
}
/* Size supplied in sectors */
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
{
int s;
int suffix = 1;
int suffix = 1, precision;
uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
@@ -197,8 +170,9 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
if (s < 8) {
byte = cmd->current_settings.unit_factor;
size *= UINT64_C(1024);
size *= UINT64_C(512);
} else {
size /= 2;
suffix = 1;
if (cmd->current_settings.unit_type == 'H')
units = UINT64_C(1000);
@@ -210,8 +184,18 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
s++, byte /= units;
}
snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
suffix ? size_str[s][sl] : "");
/* FIXME Make precision configurable */
switch(toupper((int) cmd->current_settings.unit_type)) {
case 'B':
case 'S':
precision = 0;
break;
default:
precision = 2;
}
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
(double) size / byte, suffix ? size_str[s][sl] : "");
return size_buf;
}
@@ -264,18 +248,18 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
log_print("VG Name %s%s", pv->vg_name,
pv->status & EXPORTED_VG ? " (exported)" : "");
size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
size = display_size(cmd, (uint64_t) pv->size, SIZE_SHORT);
if (pv->pe_size && pv->pe_count) {
/******** FIXME display LVM on-disk data size
size2 = display_size(pv->size / 2, SIZE_SHORT);
size2 = display_size(pv->size, SIZE_SHORT);
********/
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
size, display_size(cmd,
(pv->size -
pv->pe_count * pv->pe_size) / 2,
SIZE_SHORT));
size,
display_size(cmd, (pv->size -
pv->pe_count * pv->pe_size),
SIZE_SHORT));
} else
log_print("PV Size %s", size);
@@ -386,8 +370,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
snap_active = lv_snapshot_percent(snap->cow,
&snap_percent);
if (!snap_active || snap_percent < 0 ||
snap_percent >= 100)
snap_active = 0;
snap_percent >= 100) snap_active = 0;
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
@@ -419,7 +402,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
log_print("LV Size %s",
display_size(cmd,
snap ? snap->origin->size / 2 : lv->size / 2,
snap ? snap->origin->size : lv->size,
SIZE_SHORT));
log_print("Current LE %u",
@@ -440,11 +423,11 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
snap_percent = 100;
log_print("Snapshot chunk size %s",
display_size(cmd, (uint64_t) snap->chunk_size / 2,
display_size(cmd, (uint64_t) snap->chunk_size,
SIZE_SHORT));
/*
size = display_size(lv->size / 2, SIZE_SHORT);
size = display_size(lv->size, SIZE_SHORT);
sscanf(size, "%f", &fsize);
fused = fsize * snap_percent / 100;
*/
@@ -478,7 +461,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
{
switch (seg->area[s].type) {
case AREA_PV:
@@ -506,52 +489,18 @@ static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
int lvdisplay_segments(struct logical_volume *lv)
{
uint32_t s;
struct list *segh;
struct lv_segment *seg;
log_print("--- Segments ---");
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
list_iterate_items(seg, &lv->segments) {
log_print("Logical extent %u to %u:",
seg->le, seg->le + seg->len - 1);
if (seg->type == SEG_STRIPED && seg->area_count == 1)
log_print(" Type\t\tlinear");
else
log_print(" Type\t\t%s",
get_segtype_string(seg->type));
log_print(" Type\t\t%s", seg->segtype->ops->name(seg));
switch (seg->type) {
case SEG_STRIPED:
if (seg->area_count == 1)
_display_stripe(seg, 0, " ");
else {
log_print(" Stripes\t\t%u", seg->area_count);
log_print(" Stripe size\t\t%u KB",
seg->stripe_size / 2);
for (s = 0; s < seg->area_count; s++) {
log_print(" Stripe %d:", s);
_display_stripe(seg, s, " ");
}
}
log_print(" ");
break;
case SEG_SNAPSHOT:
break;
case SEG_MIRRORED:
log_print(" Mirrors\t\t%u", seg->area_count);
log_print(" Mirror size\t\t%u", seg->area_len);
log_print(" Mirror original:");
_display_stripe(seg, 0, " ");
log_print(" Mirror destination:");
_display_stripe(seg, 1, " ");
log_print(" ");
break;
}
if (seg->segtype->ops->display)
seg->segtype->ops->display(seg);
}
log_print(" ");
@@ -605,7 +554,7 @@ void vgdisplay_full(struct volume_group *vg)
log_print("Open LV %u", lvs_in_vg_opened(vg));
/****** FIXME Max LV Size
log_print ( "MAX LV Size %s",
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
( s1 = display_size ( LVM_LV_SIZE_MAX(vg), SIZE_SHORT)));
free ( s1);
*********/
log_print("Max PV %u", vg->max_pv);
@@ -614,32 +563,25 @@ void vgdisplay_full(struct volume_group *vg)
log_print("VG Size %s",
display_size(vg->cmd,
(uint64_t) vg->extent_count * (vg->extent_size /
2), SIZE_SHORT));
(uint64_t) vg->extent_count * vg->extent_size,
SIZE_SHORT));
log_print("PE Size %s",
display_size(vg->cmd, (uint64_t) vg->extent_size / 2,
display_size(vg->cmd, (uint64_t) vg->extent_size,
SIZE_SHORT));
log_print("Total PE %u", vg->extent_count);
log_print("Alloc PE / Size %u / %s",
vg->extent_count - vg->free_count, display_size(vg->cmd,
((uint64_t)
vg->
extent_count
-
vg->
free_count) *
(vg->
extent_size /
2),
SIZE_SHORT));
vg->extent_count - vg->free_count,
display_size(vg->cmd,
((uint64_t) vg->extent_count - vg->free_count) *
vg->extent_size, SIZE_SHORT));
log_print("Free PE / Size %u / %s", vg->free_count,
display_size(vg->cmd,
(uint64_t) vg->free_count * (vg->extent_size /
2), SIZE_SHORT));
(uint64_t) vg->free_count * vg->extent_size,
SIZE_SHORT));
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
stack;
@@ -708,15 +650,15 @@ void vgdisplay_short(struct volume_group *vg)
{
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
display_size(vg->cmd, (uint64_t) vg->extent_count *
vg->extent_size / 2, SIZE_SHORT),
display_size(vg->cmd,
(uint64_t) vg->extent_count * vg->extent_size,
SIZE_SHORT),
display_size(vg->cmd,
((uint64_t) vg->extent_count -
vg->free_count) * vg->extent_size / 2,
SIZE_SHORT), display_size(vg->cmd,
(uint64_t) vg->
free_count *
vg->extent_size / 2,
SIZE_SHORT));
vg->free_count) * vg->extent_size,
SIZE_SHORT),
display_size(vg->cmd,
(uint64_t) vg->free_count * vg->extent_size,
SIZE_SHORT));
return;
}

View File

@@ -27,6 +27,7 @@ uint64_t units_to_bytes(const char *units, char *unit_type);
/* Specify size in KB */
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
char *display_uuid(char *uuidstr);
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre);
void pvdisplay_colons(struct physical_volume *pv);
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
@@ -50,10 +51,4 @@ void vgdisplay_short(struct volume_group *vg);
const char *get_alloc_string(alloc_policy_t alloc);
alloc_policy_t get_alloc_from_string(const char *str);
/*
* Segment type display conversion routines.
*/
segment_type_t get_segtype_from_string(const char *str);
const char *get_segtype_string(segment_type_t segtype);
#endif

101
lib/error/errseg.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "list.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "display.h"
#include "text_export.h"
#include "text_import.h"
#include "config.h"
#include "str_list.h"
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
static const char *_name(const struct lv_segment *seg)
{
return seg->segtype->name;
}
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
{
seg1->len += seg2->len;
seg1->area_len += seg2->area_len;
return 1;
}
#ifdef DEVMAPPER_SUPPORT
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
struct config_tree *cft, void **target_state,
struct lv_segment *seg, char *params,
size_t paramsize, const char **target, int *pos,
uint32_t *pvmove_mirror_count)
{
/* error */
*target = "error";
*params = '\0';
return 1;
}
static int _target_present(void)
{
static int checked = 0;
static int present = 0;
if (!checked)
present = target_present("error");
checked = 1;
return present;
}
#endif
static void _destroy(const struct segment_type *segtype)
{
dbg_free((void *) segtype);
}
static struct segtype_handler _error_ops = {
name:_name,
merge_segments:_merge_segments,
#ifdef DEVMAPPER_SUPPORT
compose_target_line:_compose_target_line,
target_present:_target_present,
#endif
destroy:_destroy,
};
struct segment_type *init_error_segtype(struct cmd_context *cmd)
{
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
if (!segtype) {
stack;
return NULL;
}
segtype->cmd = cmd;
segtype->ops = &_error_ops;
segtype->name = "error";
segtype->private = NULL;
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
return segtype;
}

View File

@@ -48,7 +48,7 @@ static void _destroy(struct dev_filter *f)
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
{
struct dev_filter **filters_copy, *cf;
struct dev_filter **filters_copy, *cft;
if (!filters) {
stack;
@@ -63,15 +63,15 @@ struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
memcpy(filters_copy, filters, sizeof(*filters) * n);
filters_copy[n] = NULL;
if (!(cf = dbg_malloc(sizeof(*cf)))) {
if (!(cft = dbg_malloc(sizeof(*cft)))) {
log_error("compsoite filters allocation failed");
dbg_free(filters_copy);
return NULL;
}
cf->passes_filter = _and_p;
cf->destroy = _destroy;
cf->private = filters_copy;
cft->passes_filter = _and_p;
cft->destroy = _destroy;
cft->private = filters_copy;
return cf;
return cft;
}

View File

@@ -63,7 +63,7 @@ int persistent_filter_wipe(struct dev_filter *f)
static int _read_array(struct pfilter *pf, struct config_tree *cft,
const char *path, void *data)
{
struct config_node *cn;
const struct config_node *cn;
struct config_value *cv;
if (!(cn = find_config_node(cft->root, path))) {
@@ -99,12 +99,12 @@ int persistent_filter_load(struct dev_filter *f)
int r = 0;
struct config_tree *cft;
if (!(cft = create_config_tree())) {
if (!(cft = create_config_tree(pf->file))) {
stack;
return 0;
}
if (!read_config_file(cft, pf->file)) {
if (!read_config_file(cft)) {
stack;
goto out;
}

View File

@@ -54,6 +54,7 @@ static const device_info_t device_info[] = {
{"ataraid", 16}, /* ATA Raid */
{"drbd", 16}, /* Distributed Replicated Block Device */
{"power2", 16}, /* EMC Powerpath */
{"i2o_block", 16}, /* i2o Block Disk */
{NULL, 0}
};
@@ -82,7 +83,7 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
return 1;
}
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
{
char line[80];
char proc_devices[PATH_MAX];
@@ -199,7 +200,7 @@ static int *_scan_proc_dev(const char *proc, struct config_node *cn)
}
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn)
const struct config_node *cn)
{
struct dev_filter *f;

View File

@@ -29,7 +29,7 @@
#endif
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn);
const struct config_node *cn);
void lvm_type_filter_destroy(struct dev_filter *f);

View File

@@ -117,6 +117,7 @@ static void _xlate_extents(struct pe_disk *extents, uint32_t count)
static int _munge_formats(struct pv_disk *pvd)
{
uint32_t pe_start;
int b, e;
switch (pvd->version) {
case 1:
@@ -134,17 +135,54 @@ static int _munge_formats(struct pv_disk *pvd)
return 0;
}
/* UUID too long? */
if (pvd->pv_uuid[ID_LEN]) {
/* Retain ID_LEN chars from end */
for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) {
if (!pvd->pv_uuid[e]) {
e--;
break;
}
}
for (b = 0; b < ID_LEN; b++) {
pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN];
/* FIXME Remove all invalid chars */
if (pvd->pv_uuid[b] == '/')
pvd->pv_uuid[b] = '#';
}
memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN);
}
/* If UUID is missing, create one */
if (pvd->pv_uuid[0] == '\0')
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
return 1;
}
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
/*
* If exported, remove "PV_EXP" from end of VG name
*/
static void _munge_exported_vg(struct pv_disk *pvd)
{
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
}
int l;
size_t s;
/* Return if PV not in a VG */
if ((!*pvd->vg_name))
return;
/* FIXME also check vgd->status & VG_EXPORTED? */
l = strlen(pvd->vg_name);
s = sizeof(EXPORTED_TAG);
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
pvd->vg_name[l - s + 1] = '\0';
pvd->pv_status |= VG_EXPORTED;
}
}
int munge_pvd(struct device *dev, struct pv_disk *pvd)
{
_xlate_pvd(pvd);
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
@@ -159,13 +197,23 @@ static int _read_pvd(struct device *dev, struct pv_disk *pvd)
return 0;
}
/* If UUID is missing, create one */
if (pvd->pv_uuid[0] == '\0')
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
/* If VG is exported, set VG name back to the real name */
_munge_exported_vg(pvd);
return 1;
}
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
}
return munge_pvd(dev, pvd);
}
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
{
if (!dev_read(dev, pos, sizeof(*disk), disk))
@@ -185,6 +233,9 @@ static int _read_vgd(struct disk_list *data)
_xlate_vgd(vgd);
if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV))
fail;
/* If UUID is missing, create one */
if (vgd->vg_uuid[0] == '\0')
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
@@ -269,26 +320,6 @@ static int _read_extents(struct disk_list *data)
return 1;
}
/*
* If exported, remove "PV_EXP" from end of VG name
*/
void munge_exported_vg(struct pv_disk *pvd)
{
int l;
size_t s;
/* Return if PV not in a VG */
if ((!*pvd->vg_name))
return;
l = strlen(pvd->vg_name);
s = sizeof(EXPORTED_TAG);
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
pvd->vg_name[l - s + 1] = '\0';
pvd->pv_status |= VG_EXPORTED;
}
}
static struct disk_list *__read_disk(const struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name)
@@ -312,9 +343,6 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
goto bad;
}
/* If VG is exported, set VG name back to the real name */
munge_exported_vg(&dl->pvd);
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
dl->pvd.vg_name, NULL)))
stack;

View File

@@ -216,7 +216,7 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg);
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
int import_extents(struct pool *mem, struct volume_group *vg,
int import_extents(struct cmd_context *cmd, struct volume_group *vg,
struct list *pvds);
int export_extents(struct disk_list *dl, uint32_t lv_num,
struct logical_volume *lv, struct physical_volume *pv);
@@ -237,7 +237,7 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg);
void export_numbers(struct list *pvds, struct volume_group *vg);
void export_pv_act(struct list *pvds);
void munge_exported_vg(struct pv_disk *pvd);
int munge_pvd(struct device *dev, struct pv_disk *pvd);
/* blech */
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,

View File

@@ -164,7 +164,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
if (!import_lvs(mem, vg, pvs))
goto bad;
if (!import_extents(mem, vg, pvs))
if (!import_extents(fid->fmt->cmd, vg, pvs))
goto bad;
if (!import_snapshots(mem, vg, pvs))
@@ -345,7 +345,7 @@ static int _pv_setup(const struct format_type *fmt,
pv->size--;
if (pv->size > MAX_PV_SIZE) {
log_error("Physical volumes cannot be bigger than %s",
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE / 2,
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE,
SIZE_SHORT));
return 0;
}
@@ -386,7 +386,7 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
}
if (lv->size > max_size) {
log_error("logical volumes cannot be larger than %s",
display_size(fid->fmt->cmd, max_size / 2,
display_size(fid->fmt->cmd, max_size,
SIZE_SHORT));
return 0;
}
@@ -468,21 +468,18 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
log_error("Extent size must be between %s and %s",
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE
/ 2,
SIZE_SHORT), display_size(fid->fmt->cmd,
(uint64_t)
MAX_PE_SIZE
/ 2,
SIZE_SHORT));
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE,
SIZE_SHORT),
display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE,
SIZE_SHORT));
return 0;
}
if (vg->extent_size % MIN_PE_SIZE) {
log_error("Extent size must be multiple of %s",
display_size(fid->fmt->cmd,
(uint64_t) MIN_PE_SIZE / 2, SIZE_SHORT));
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE,
SIZE_SHORT));
return 0;
}

View File

@@ -25,6 +25,7 @@
#include "lvm-string.h"
#include "filter.h"
#include "toolcontext.h"
#include "segtypes.h"
#include <time.h>
@@ -236,6 +237,7 @@ int import_vg(struct pool *mem,
vg->free_count = vgd->pe_total - vgd->pe_allocated;
vg->max_lv = vgd->lv_max;
vg->max_pv = vgd->pv_max;
vg->alloc = ALLOC_NORMAL;
if (partial)
vg->status |= PARTIAL_VG;
@@ -315,7 +317,7 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
if (lvd->lv_allocation & LV_CONTIGUOUS)
lv->alloc = ALLOC_CONTIGUOUS;
else
lv->alloc = ALLOC_NEXT_FREE;
lv->alloc = ALLOC_NORMAL;
lv->read_ahead = lvd->lv_read_ahead;
lv->size = lvd->lv_size;
@@ -380,9 +382,10 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
if (seg->type != SEG_STRIPED) {
log_error("Non-striped segment type in LV %s: "
"unsupported by format1", lv->name);
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
log_error("Segment type %s in LV %s: "
"unsupported by format1",
seg->segtype->name, lv->name);
return 0;
}
if (seg->area[s].type != AREA_PV) {

View File

@@ -19,6 +19,8 @@
#include "pool.h"
#include "disk-rep.h"
#include "lv_alloc.h"
#include "display.h"
#include "segtypes.h"
/*
* After much thought I have decided it is easier,
@@ -201,21 +203,24 @@ static int _check_maps_are_complete(struct hash_table *maps)
return 1;
}
static int _read_linear(struct pool *mem, struct lv_map *lvm)
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t le = 0;
struct lv_segment *seg;
while (le < lvm->lv->le_count) {
seg = alloc_lv_segment(mem, 1);
seg = alloc_lv_segment(cmd->mem, 1);
seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
seg->le = le;
seg->len = 0;
seg->area_len = 0;
seg->stripe_size = 0;
seg->area_count = 1;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = lvm->map[le].pv;
@@ -251,13 +256,12 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
(seg->area[st].u.pv.pv &&
lvm->map[le + st * len].pe !=
seg->area[st].u.pv.pe + seg->len))
return 0;
seg->area[st].u.pv.pe + seg->len)) return 0;
return 1;
}
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t st, le = 0, len;
struct lv_segment *seg;
@@ -273,15 +277,17 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
len = lvm->lv->le_count / lvm->stripes;
while (le < len) {
if (!(seg = alloc_lv_segment(mem, lvm->stripes))) {
if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
stack;
return 0;
}
seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
seg->stripe_size = lvm->stripe_size;
seg->area_count = lvm->stripes;
seg->le = seg->area_count * le;
seg->len = 1;
seg->area_len = 1;
@@ -312,20 +318,20 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
return 1;
}
static int _build_segments(struct pool *mem, struct lv_map *lvm)
static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm)
{
return (lvm->stripes > 1 ? _read_stripes(mem, lvm) :
_read_linear(mem, lvm));
return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) :
_read_linear(cmd, lvm));
}
static int _build_all_segments(struct pool *mem, struct hash_table *maps)
static int _build_all_segments(struct cmd_context *cmd, struct hash_table *maps)
{
struct hash_node *n;
struct lv_map *lvm;
for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) {
lvm = (struct lv_map *) hash_get_data(maps, n);
if (!_build_segments(mem, lvm)) {
if (!_build_segments(cmd, lvm)) {
stack;
return 0;
}
@@ -334,7 +340,8 @@ static int _build_all_segments(struct pool *mem, struct hash_table *maps)
return 1;
}
int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds)
int import_extents(struct cmd_context *cmd, struct volume_group *vg,
struct list *pvds)
{
int r = 0;
struct pool *scratch = pool_create(10 * 1024);
@@ -360,7 +367,7 @@ int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds)
goto out;
}
if (!_build_all_segments(mem, maps)) {
if (!_build_all_segments(cmd, maps)) {
log_err("Couldn't build extent segments.");
goto out;
}

View File

@@ -60,7 +60,8 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
struct pv_disk *pvd = (struct pv_disk *) buf;
struct lvmcache_info *info;
munge_exported_vg(pvd);
munge_pvd(dev, pvd);
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
stack;
return 0;

View File

@@ -0,0 +1 @@
init_format

View File

@@ -0,0 +1,37 @@
#
# Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of the LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES =\
disk_rep.c \
format_pool.c \
import_export.c \
pool_label.c
LIB_SHARED = liblvm2formatpool.so
include ../../make.tmpl
.PHONY: install
install: liblvm2formatpool.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2formatpool.so.$(LIB_VERSION)
$(LN_S) -f liblvm2formatpool.so.$(LIB_VERSION) \
$(libdir)/liblvm2formatpool.so

385
lib/format_pool/disk_rep.c Normal file
View File

@@ -0,0 +1,385 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "label.h"
#include "metadata.h"
#include "lvmcache.h"
#include "filter.h"
#include "list.h"
#include "xlate.h"
#include "disk_rep.h"
/* FIXME: memcpy might not be portable */
#define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
#define CPOUT_8(x, y, z) {memcpy((y), (x), (z));}
#define CPIN_16(x, y) {(x) = xlate16_be((y));}
#define CPOUT_16(x, y) {(y) = xlate16_be((x));}
#define CPIN_32(x, y) {(x) = xlate32_be((y));}
#define CPOUT_32(x, y) {(y) = xlate32_be((x));}
#define CPIN_64(x, y) {(x) = xlate64_be((y));}
#define CPOUT_64(x, y) {(y) = xlate64_be((x));}
static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
struct pool *mem, struct pool_list *pl,
const char *vg_name)
{
char buf[512];
/* FIXME: Need to check the cache here first */
if (!dev_read(dev, UINT64_C(0), 512, buf)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
}
if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL)) {
stack;
return 0;
}
return 1;
}
static void _add_pl_to_list(struct list *head, struct pool_list *data)
{
struct list *pvdh;
struct pool_list *pl;
list_iterate(pvdh, head) {
pl = list_item(pvdh, struct pool_list);
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
char uuid[ID_LEN + 7];
id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
if (MAJOR(data->dev->dev) != md_major()) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s", uuid,
dev_name(data->dev));
return;
}
log_very_verbose("Duplicate PV %s - using md %s",
uuid, dev_name(data->dev));
list_del(pvdh);
break;
}
}
list_add(head, &data->list);
}
int read_pool_label(struct pool_list *pl, struct labeller *l,
struct device *dev, char *buf, struct label **label)
{
struct lvmcache_info *info;
struct id pvid;
struct id vgid;
char uuid[ID_LEN + 7];
struct pool_disk *pd = &pl->pd;
pool_label_in(pd, buf);
get_pool_pv_uuid(&pvid, pd);
id_write_format(&pvid, uuid, ID_LEN + 7);
log_debug("Calculated uuid %s for %s", uuid, dev_name(dev));
get_pool_vg_uuid(&vgid, pd);
id_write_format(&vgid, uuid, ID_LEN + 7);
log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
(char *) &vgid))) {
stack;
return 0;
}
if (label)
*label = info->label;
info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT;
list_init(&info->mdas);
info->status &= ~CACHE_INVALID;
pl->dev = dev;
pl->pv = NULL;
memcpy(&pl->pv_uuid, &pvid, sizeof(pvid));
return 1;
}
/**
* pool_label_out - copies a pool_label_t into a char buffer
* @pl: ptr to a pool_label_t struct
* @buf: ptr to raw space where label info will be copied
*
* This function is important because it takes care of all of
* the endian issues when copying to disk. This way, when
* machines of different architectures are used, they will
* be able to interpret ondisk labels correctly. Always use
* this function before writing to disk.
*/
void pool_label_out(struct pool_disk *pl, char *buf)
{
struct pool_disk *bufpl = (struct pool_disk *) buf;
CPOUT_64(pl->pl_magic, bufpl->pl_magic);
CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id);
CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
CPOUT_32(pl->pl_version, bufpl->pl_version);
CPOUT_32(pl->pl_subpools, bufpl->pl_subpools);
CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id);
CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type);
CPOUT_64(pl->pl_blocks, bufpl->pl_blocks);
CPOUT_32(pl->pl_striping, bufpl->pl_striping);
CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
CPOUT_32(pl->pl_minor, bufpl->pl_minor);
CPOUT_32(pl->pl_padding, bufpl->pl_padding);
CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184);
}
/**
* pool_label_in - copies a char buffer into a pool_label_t
* @pl: ptr to a pool_label_t struct
* @buf: ptr to raw space where label info is copied from
*
* This function is important because it takes care of all of
* the endian issues when information from disk is about to be
* used. This way, when machines of different architectures
* are used, they will be able to interpret ondisk labels
* correctly. Always use this function before using labels that
* were read from disk.
*/
void pool_label_in(struct pool_disk *pl, char *buf)
{
struct pool_disk *bufpl = (struct pool_disk *) buf;
CPIN_64(pl->pl_magic, bufpl->pl_magic);
CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id);
CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
CPIN_32(pl->pl_version, bufpl->pl_version);
CPIN_32(pl->pl_subpools, bufpl->pl_subpools);
CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id);
CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type);
CPIN_64(pl->pl_blocks, bufpl->pl_blocks);
CPIN_32(pl->pl_striping, bufpl->pl_striping);
CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
CPIN_32(pl->pl_minor, bufpl->pl_minor);
CPIN_32(pl->pl_padding, bufpl->pl_padding);
CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184);
}
static char _calc_char(unsigned int id)
{
/*
* [0-9A-Za-z!#] - 64 printable chars (6-bits)
*/
if (id < 10)
return id + 48;
if (id < 36)
return (id - 10) + 65;
if (id < 62)
return (id - 36) + 97;
if (id == 62)
return '!';
if (id == 63)
return '#';
return '%';
}
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid)
{
int i;
unsigned shifter = 0x003F;
assert(ID_LEN == 32);
memset(uuid, 0, ID_LEN);
strcat(uuid, "POOL0000000000");
/* We grab the entire 64 bits (+2 that get shifted in) */
for (i = 13; i < 24; i++) {
uuid[i] = _calc_char(((unsigned) poolid) & shifter);
poolid = poolid >> 6;
}
/* We grab the entire 32 bits (+4 that get shifted in) */
for (i = 24; i < 30; i++) {
uuid[i] = _calc_char((unsigned) (spid & shifter));
spid = spid >> 6;
}
/*
* Since we can only have 128 devices, we only worry about the
* last 12 bits
*/
for (i = 30; i < 32; i++) {
uuid[i] = _calc_char((unsigned) (devid & shifter));
devid = devid >> 6;
}
}
static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
struct lvmcache_vginfo *vginfo, struct list *head,
uint32_t *devcount)
{
struct list *vgih = NULL;
struct device *dev;
struct pool_list *pl = NULL;
struct pool *tmpmem = NULL;
uint32_t sp_count = 0;
uint32_t *sp_devs = NULL;
int i;
/* FIXME: maybe should return a different error in memory
* allocation failure */
if (!(tmpmem = pool_create(512))) {
stack;
return 0;
}
list_iterate(vgih, &vginfo->infos) {
dev = list_item(vgih, struct lvmcache_info)->dev;
if (dev &&
!(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname)))
break;
/*
* We need to keep track of the total expected number
* of devices per subpool
*/
if (!sp_count) {
sp_count = pl->pd.pl_subpools;
if (!(sp_devs =
pool_zalloc(tmpmem,
sizeof(uint32_t) * sp_count))) {
log_error("Unable to allocate %d 32-bit uints",
sp_count);
pool_destroy(tmpmem);
return 0;
}
}
/*
* watch out for a pool label with a different subpool
* count than the original - give up if it does
*/
if (sp_count != pl->pd.pl_subpools)
break;
_add_pl_to_list(head, pl);
if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0)
sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs;
}
*devcount = 0;
for (i = 0; i < sp_count; i++) {
*devcount += sp_devs[i];
}
pool_destroy(tmpmem);
if (pl && *pl->pd.pl_pool_name)
return 1;
return 0;
}
int read_pool_pds(const struct format_type *fmt, const char *vg_name,
struct pool *mem, struct list *pdhead)
{
struct lvmcache_vginfo *vginfo;
uint32_t totaldevs;
int full_scan = -1;
do {
/*
* If the cache scanning doesn't work, this will never work
*/
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
vginfo->infos.n) {
if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
/*
* If we found all the devices we were
* expecting, return success
*/
if (list_size(pdhead) == totaldevs)
return 1;
/*
* accept partial pool if we've done a full
* rescan of the cache
*/
if (full_scan > 0)
return 1;
}
}
/* Failed */
list_init(pdhead);
full_scan++;
if (full_scan > 1) {
log_debug("No devices for vg %s found in cache",
vg_name);
return 0;
}
lvmcache_label_scan(fmt->cmd, full_scan);
} while (1);
}
struct pool_list *read_pool_disk(const struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name)
{
struct pool_list *pl;
if (!dev_open(dev)) {
stack;
return NULL;
}
if (!(pl = pool_zalloc(mem, sizeof(*pl)))) {
log_error("Unable to allocate pool list structure");
return 0;
}
if (!__read_pool_disk(fmt, dev, mem, pl, vg_name)) {
stack;
return NULL;
}
if (!dev_close(dev))
stack;
return pl;
}

178
lib/format_pool/disk_rep.h Normal file
View File

@@ -0,0 +1,178 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DISK_REP_FORMAT_POOL_H
#define DISK_REP_FORMAT_POOL_H
#include "label.h"
#include "metadata.h"
#include "pool.h"
/* From NSP.cf */
#define NSPMajorVersion 4
#define NSPMinorVersion 1
#define NSPUpdateLevel 3
/* From pool_std.h */
#define POOL_NAME_SIZE (256)
#define POOL_MAGIC 0x011670
#define POOL_MAJOR (121)
#define POOL_MAX_DEVICES 128
/* When checking for version matching, the first two numbers **
** are important for metadata formats, a.k.a pool labels. **
** All the numbers are important when checking if the user **
** space tools match up with the kernel module............. */
#define POOL_VERSION (NSPMajorVersion << 16 | \
NSPMinorVersion << 8 | \
NSPUpdateLevel)
/* Pool label is at the head of every pool disk partition */
#define SIZEOF_POOL_LABEL (8192)
/* in sectors */
#define POOL_PE_SIZE (SIZEOF_POOL_LABEL >> SECTOR_SHIFT)
#define POOL_PE_START (SIZEOF_POOL_LABEL >> SECTOR_SHIFT)
/* Helper fxns */
#define get_pool_vg_uuid(id, pd) do { get_pool_uuid((char *)(id), \
(pd)->pl_pool_id, 0, 0); \
} while(0)
#define get_pool_pv_uuid(id, pd) do { get_pool_uuid((char *)(id), \
(pd)->pl_pool_id, \
(pd)->pl_sp_id, \
(pd)->pl_sp_devid); \
} while(0)
#define get_pool_lv_uuid(id, pd) do { get_pool_uuid((char *)&(id)[0], \
(pd)->pl_pool_id, 0, 0); \
get_pool_uuid((char*)&(id)[1], \
(pd)->pl_pool_id, 0, 0); \
} while(0)
struct pool_disk;
struct pool_list;
struct user_subpool;
struct user_device;
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
/* Generic Labels */
#define SPTYPE_DATA (0x00000000)
/* GFS specific labels */
#define SPTYPE_GFS_DATA (0x68011670)
#define SPTYPE_GFS_JOURNAL (0x69011670)
struct sptype_name {
const char *name;
uint32_t label;
};
static const struct sptype_name sptype_names[] = {
{"data", SPTYPE_DATA},
{"gfs_data", SPTYPE_GFS_DATA},
{"gfs_journal", SPTYPE_GFS_JOURNAL},
{"", 0x0} /* This must be the last flag. */
};
struct pool_disk {
uint64_t pl_magic; /* Pool magic number */
uint64_t pl_pool_id; /* Unique pool identifier */
char pl_pool_name[POOL_NAME_SIZE]; /* Name of pool */
uint32_t pl_version; /* Pool version */
uint32_t pl_subpools; /* Number of subpools in this pool */
uint32_t pl_sp_id; /* Subpool number within pool */
uint32_t pl_sp_devs; /* Number of data partitions in this subpool */
uint32_t pl_sp_devid; /* Partition number within subpool */
uint32_t pl_sp_type; /* Partition type */
uint64_t pl_blocks; /* Number of blocks in this partition */
uint32_t pl_striping; /* Striping size within subpool */
/*
* If the number of DMEP devices is zero, then the next field **
* ** (pl_sp_dmepid) becomes the subpool ID for redirection. In **
* ** other words, if this subpool does not have the capability **
* ** to do DMEP, then it must specify which subpool will do it **
* ** in it's place
*/
/*
* While the next 3 field are no longer used, they must stay to keep **
* ** backward compatibility...........................................
*/
uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */
uint32_t pl_sp_dmepid; /* Dmep device number within subpool */
uint32_t pl_sp_weight; /* if dmep dev, pref to using it */
uint32_t pl_minor; /* the pool minor number */
uint32_t pl_padding; /* reminder - think about alignment */
/*
* Even though we're zeroing out 8k at the front of the disk before
* writing the label, putting this in
*/
char pl_reserve[184]; /* bump the structure size out to 512 bytes */
};
struct pool_list {
struct list list;
struct pool_disk pd;
struct physical_volume *pv;
struct id pv_uuid;
struct device *dev;
};
struct user_subpool {
uint32_t initialized;
uint32_t id;
uint32_t striping;
uint32_t num_devs;
uint32_t type;
uint32_t dummy;
struct user_device *devs;
};
struct user_device {
uint32_t initialized;
uint32_t sp_id;
uint32_t devid;
uint32_t dummy;
uint64_t blocks;
struct physical_volume *pv;
};
int read_pool_label(struct pool_list *pl, struct labeller *l,
struct device *dev, char *buf, struct label **label);
void pool_label_out(struct pool_disk *pl, char *buf);
void pool_label_in(struct pool_disk *pl, char *buf);
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid);
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls);
int import_pool_lvs(struct volume_group *vg, struct pool *mem,
struct list *pls);
int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
struct list *pvs, struct pool *mem, struct list *pls);
int import_pool_pv(const struct format_type *fmt, struct pool *mem,
struct volume_group *vg, struct physical_volume *pv,
struct pool_list *pl);
int import_pool_segments(struct list *lvs, struct pool *mem,
struct user_subpool *usp, int sp_count);
int read_pool_pds(const struct format_type *fmt, const char *vgname,
struct pool *mem, struct list *head);
struct pool_list *read_pool_disk(const struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name);
#endif /* DISK_REP_POOL_FORMAT_H */

View File

@@ -0,0 +1,361 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "label.h"
#include "metadata.h"
#include "hash.h"
#include "limits.h"
#include "list.h"
#include "display.h"
#include "toolcontext.h"
#include "lvmcache.h"
#include "disk_rep.h"
#include "format_pool.h"
#include "pool_label.h"
#define FMT_POOL_NAME "pool"
/* Must be called after pvs are imported */
static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
int *sps)
{
struct list *plhs;
struct pool_list *pl;
struct user_subpool *usp = NULL, *cur_sp = NULL;
struct user_device *cur_dev = NULL;
/*
* FIXME: Need to do some checks here - I'm tempted to add a
* user_pool structure and build the entire thing to check against.
*/
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
*sps = pl->pd.pl_subpools;
if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
log_error("Unable to allocate %d subpool structures",
*sps);
return 0;
}
if (cur_sp != &usp[pl->pd.pl_sp_id]) {
cur_sp = &usp[pl->pd.pl_sp_id];
cur_sp->id = pl->pd.pl_sp_id;
cur_sp->striping = pl->pd.pl_striping;
cur_sp->num_devs = pl->pd.pl_sp_devs;
cur_sp->type = pl->pd.pl_sp_type;
cur_sp->initialized = 1;
}
if (!cur_sp->devs &&
(!(cur_sp->devs =
pool_zalloc(mem,
sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) {
log_error("Unable to allocate %d pool_device "
"structures", pl->pd.pl_sp_devs);
return 0;
}
cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
cur_dev->sp_id = cur_sp->id;
cur_dev->devid = pl->pd.pl_sp_id;
cur_dev->blocks = pl->pd.pl_blocks;
cur_dev->pv = pl->pv;
cur_dev->initialized = 1;
}
return usp;
}
static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count)
{
int i, j;
for (i = 0; i < sp_count; i++) {
if (!usp[i].initialized) {
log_error("Missing subpool %d in pool %s", i, vgname);
return 0;
}
for (j = 0; j < usp[i].num_devs; j++) {
if (!usp[i].devs[j].initialized) {
log_error("Missing device %d for subpool %d"
" in pool %s", j, i, vgname);
return 0;
}
}
}
return 1;
}
static struct volume_group *_build_vg_from_pds(struct format_instance
*fid, struct pool *mem,
struct list *pds)
{
struct pool *smem = fid->fmt->cmd->mem;
struct volume_group *vg = NULL;
struct user_subpool *usp = NULL;
int sp_count;
if (!(vg = pool_zalloc(smem, sizeof(*vg)))) {
log_error("Unable to allocate volume group structure");
return NULL;
}
vg->cmd = fid->fmt->cmd;
vg->fid = fid;
vg->name = NULL;
vg->status = 0;
vg->extent_count = 0;
vg->pv_count = 0;
vg->lv_count = 0;
vg->snapshot_count = 0;
vg->seqno = 1;
vg->system_id = NULL;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
if (!import_pool_vg(vg, smem, pds)) {
stack;
return NULL;
}
if (!import_pool_pvs(fid->fmt, vg, &vg->pvs, smem, pds)) {
stack;
return NULL;
}
if (!import_pool_lvs(vg, smem, pds)) {
stack;
return NULL;
}
/*
* I need an intermediate subpool structure that contains all the
* relevant info for this. Then i can iterate through the subpool
* structures for checking, and create the segments
*/
if (!(usp = _build_usp(pds, mem, &sp_count))) {
stack;
return NULL;
}
/*
* check the subpool structures - we can't handle partial VGs in
* the pool format, so this will error out if we're missing PVs
*/
if (!_check_usp(vg->name, usp, sp_count)) {
stack;
return NULL;
}
if (!import_pool_segments(&vg->lvs, smem, usp, sp_count)) {
stack;
return NULL;
}
return vg;
}
static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024);
struct list pds;
struct volume_group *vg = NULL;
list_init(&pds);
/* We can safely ignore the mda passed in */
if (!mem) {
stack;
return NULL;
}
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
/* Read all the pvs in the vg */
if (!read_pool_pds(fid->fmt, vg_name, mem, &pds)) {
stack;
goto out;
}
/* Do the rest of the vg stuff */
if (!(vg = _build_vg_from_pds(fid, mem, &pds))) {
stack;
goto out;
}
out:
pool_destroy(mem);
return vg;
}
static int _pv_setup(const struct format_type *fmt,
uint64_t pe_start, uint32_t extent_count,
uint32_t extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas,
struct physical_volume *pv, struct volume_group *vg)
{
return 1;
}
static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct pool_list *pl;
struct device *dev;
int r = 0;
log_very_verbose("Reading physical volume data %s from disk", pv_name);
if (!mem) {
stack;
return 0;
}
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
stack;
goto out;
}
/*
* I need to read the disk and populate a pv structure here
* I'll probably need to abstract some of this later for the
* vg_read code
*/
if (!(pl = read_pool_disk(fmt, dev, mem, NULL))) {
stack;
goto out;
}
if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl)) {
stack;
goto out;
}
pv->fmt = fmt;
r = 1;
out:
pool_destroy(mem);
return r;
}
/* *INDENT-OFF* */
static struct metadata_area_ops _metadata_format_pool_ops = {
vg_read:_vg_read,
};
/* *INDENT-ON* */
static struct format_instance *_create_instance(const struct format_type *fmt,
const char *vgname,
void *private)
{
struct format_instance *fid;
struct metadata_area *mda;
if (!(fid = pool_zalloc(fmt->cmd->mem, sizeof(*fid)))) {
log_error("Unable to allocate format instance structure for "
"pool format");
return NULL;
}
fid->fmt = fmt;
list_init(&fid->metadata_areas);
/* Define a NULL metadata area */
if (!(mda = pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) {
log_error("Unable to allocate metadata area structure "
"for pool format");
pool_free(fmt->cmd->mem, fid);
return NULL;
}
mda->ops = &_metadata_format_pool_ops;
mda->metadata_locn = NULL;
list_add(&fid->metadata_areas, &mda->list);
return fid;
}
static void _destroy_instance(struct format_instance *fid)
{
return;
}
static void _destroy(const struct format_type *fmt)
{
dbg_free((void *) fmt);
}
/* *INDENT-OFF* */
static struct format_handler _format_pool_ops = {
pv_read:_pv_read,
pv_setup:_pv_setup,
create_instance:_create_instance,
destroy_instance:_destroy_instance,
destroy:_destroy,
};
/* *INDENT-ON */
#ifdef POOL_INTERNAL
struct format_type *init_pool_format(struct cmd_context *cmd)
#else /* Shared */
struct format_type *init_format(struct cmd_context *cmd);
struct format_type *init_format(struct cmd_context *cmd)
#endif
{
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
if (!fmt) {
log_error("Unable to allocate format type structure for pool "
"format");
return NULL;
}
fmt->cmd = cmd;
fmt->ops = &_format_pool_ops;
fmt->name = FMT_POOL_NAME;
fmt->alias = NULL;
fmt->features = 0;
fmt->private = NULL;
if (!(fmt->labeller = pool_labeller_create(fmt))) {
log_error("Couldn't create pool label handler.");
return NULL;
}
if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) {
log_error("Couldn't register pool label handler.");
return NULL;
}
return fmt;
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_FORMAT_POOL_H
#define _LVM_FORMAT_POOL_H
#include "metadata.h"
#ifdef POOL_INTERNAL
struct format_type *init_pool_format(struct cmd_context *cmd);
#endif
#endif

View File

@@ -0,0 +1,309 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "label.h"
#include "metadata.h"
#include "lvmcache.h"
#include "disk_rep.h"
#include "lv_alloc.h"
#include "str_list.h"
#include "display.h"
#include "segtypes.h"
/* This file contains only imports at the moment... */
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
{
struct list *plhs;
struct pool_list *pl;
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
vg->extent_count +=
((pl->pd.pl_blocks) / POOL_PE_SIZE);
vg->pv_count++;
if (vg->name)
continue;
vg->name = pool_strdup(mem, pl->pd.pl_pool_name);
get_pool_vg_uuid(&vg->id, &pl->pd);
vg->extent_size = POOL_PE_SIZE;
vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED;
vg->free_count = 0;
vg->max_lv = 1;
vg->max_pv = POOL_MAX_DEVICES;
vg->alloc = ALLOC_NORMAL;
vg->lv_count = 0;
}
return 1;
}
int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
{
struct pool_list *pl;
struct list *plhs;
struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl));
struct logical_volume *lv;
if (!lvl) {
log_error("Unable to allocate lv list structure");
return 0;
}
if (!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
log_error("Unable to allocate logical volume structure");
return 0;
}
lv = lvl->lv;
lv->status = 0;
lv->vg = vg;
lv->alloc = ALLOC_NORMAL;
lv->size = 0;
lv->name = NULL;
lv->le_count = 0;
lv->read_ahead = 0;
list_init(&lv->segments);
list_init(&lv->tags);
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
lv->size += pl->pd.pl_blocks;
if (lv->name)
continue;
if (!(lv->name = pool_strdup(mem, pl->pd.pl_pool_name))) {
stack;
return 0;
}
get_pool_lv_uuid(lv->lvid.id, &pl->pd);
log_debug("Calculated lv uuid for lv %s: %s", lv->name,
lv->lvid.s);
lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE;
lv->major = POOL_MAJOR;
/* for pool a minor of 0 is dynamic */
if (pl->pd.pl_minor) {
lv->status |= FIXED_MINOR;
lv->minor = pl->pd.pl_minor;
} else {
lv->minor = -1;
}
list_init(&lv->segments);
list_init(&lv->tags);
}
lv->le_count = lv->size / POOL_PE_SIZE;
lvl->lv = lv;
list_add(&vg->lvs, &lvl->list);
vg->lv_count++;
return 1;
}
int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
struct list *pvs, struct pool *mem, struct list *pls)
{
struct pv_list *pvl;
struct pool_list *pl;
struct list *plhs;
list_iterate(plhs, pls) {
pl = list_item(plhs, struct pool_list);
if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
log_error("Unable to allocate pv list structure");
return 0;
}
if (!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
log_error("Unable to allocate pv structure");
return 0;
}
if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) {
return 0;
}
pl->pv = pvl->pv;
pvl->mdas = NULL;
pvl->alloc_areas = NULL;
list_add(pvs, &pvl->list);
}
return 1;
}
int import_pool_pv(const struct format_type *fmt, struct pool *mem,
struct volume_group *vg, struct physical_volume *pv,
struct pool_list *pl)
{
struct pool_disk *pd = &pl->pd;
memset(pv, 0, sizeof(*pv));
get_pool_pv_uuid(&pv->id, pd);
pv->fmt = fmt;
pv->dev = pl->dev;
if (!(pv->vg_name = pool_strdup(mem, pd->pl_pool_name))) {
log_error("Unable to duplicate vg_name string");
return 0;
}
pv->status = 0;
pv->size = pd->pl_blocks;
pv->pe_size = POOL_PE_SIZE;
pv->pe_start = POOL_PE_START;
pv->pe_count = pv->size / POOL_PE_SIZE;
pv->pe_alloc_count = pv->pe_count;
list_init(&pv->tags);
return 1;
}
static const char *_cvt_sptype(uint32_t sptype)
{
int i;
for (i = 0; sptype_names[i].name[0]; i++) {
if (sptype == sptype_names[i].label) {
break;
}
}
log_debug("Found sptype %X and converted it to %s",
sptype, sptype_names[i].name);
return sptype_names[i].name;
}
static int _add_stripe_seg(struct pool *mem,
struct user_subpool *usp, struct logical_volume *lv,
uint32_t *le_cur)
{
struct lv_segment *seg;
int j;
if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
log_error("Unable to allocate striped lv_segment structure");
return 0;
}
if(usp->striping & (usp->striping - 1)) {
log_error("Stripe size must be a power of 2");
return 0;
}
seg->stripe_size = usp->striping;
seg->status |= 0;
seg->le += *le_cur;
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
for (j = 0; j < usp->num_devs; j++) {
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
stack;
return 0;
}
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
seg->len += seg->area_len;
*le_cur += seg->area_len;
seg->lv = lv;
seg->area[j].type = AREA_PV;
seg->area[j].u.pv.pv = usp->devs[j].pv;
seg->area[j].u.pv.pe = 0;
}
list_add(&lv->segments, &seg->list);
return 1;
}
static int _add_linear_seg(struct pool *mem,
struct user_subpool *usp, struct logical_volume *lv,
uint32_t *le_cur)
{
struct lv_segment *seg;
int j;
for (j = 0; j < usp->num_devs; j++) {
/* linear segments only have 1 data area */
if (!(seg = alloc_lv_segment(mem, 1))) {
log_error("Unable to allocate linear lv_segment "
"structure");
return 0;
}
seg->stripe_size = usp->striping;
seg->le += *le_cur;
seg->chunk_size = POOL_PE_SIZE;
seg->status |= 0;
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
stack;
return 0;
}
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
seg->lv = lv;
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
seg->len = seg->area_len;
*le_cur += seg->len;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = usp->devs[j].pv;
seg->area[0].u.pv.pe = 0;
list_add(&lv->segments, &seg->list);
}
return 1;
}
int import_pool_segments(struct list *lvs, struct pool *mem,
struct user_subpool *usp, int subpools)
{
struct list *lvhs;
struct lv_list *lvl;
struct logical_volume *lv;
uint32_t le_cur = 0;
int i;
list_iterate(lvhs, lvs) {
lvl = list_item(lvhs, struct lv_list);
lv = lvl->lv;
for (i = 0; i < subpools; i++) {
if (usp[i].striping) {
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
stack;
return 0;
}
} else {
if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) {
stack;
return 0;
}
}
}
}
return 1;
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "label.h"
#include "metadata.h"
#include "xlate.h"
#include "disk_rep.h"
#include "pool_label.h"
#include <sys/stat.h>
#include <fcntl.h>
static void _not_supported(const char *op)
{
log_error("The '%s' operation is not supported for the pool labeller.",
op);
}
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
{
struct pool_disk pd;
/*
* POOL label must always be in first sector
*/
if (sector)
return 0;
pool_label_in(&pd, buf);
/* can ignore 8 rightmost bits for ondisk format check */
if ((pd.pl_magic == POOL_MAGIC) &&
(pd.pl_version >> 8 == POOL_VERSION >> 8))
return 1;
return 0;
}
static int _write(struct label *label, char *buf)
{
_not_supported("write");
return 0;
}
static int _read(struct labeller *l, struct device *dev, char *buf,
struct label **label)
{
struct pool_list pl;
return read_pool_label(&pl, l, dev, buf, label);
}
static int _initialise_label(struct labeller *l, struct label *label)
{
strcpy(label->type, "POOL");
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
return;
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _pool_ops = {
can_handle:_can_handle,
write:_write,
read:_read,
verify:_can_handle,
initialise_label:_initialise_label,
destroy_label:_destroy_label,
destroy:_destroy
};
struct labeller *pool_labeller_create(struct format_type *fmt)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_error("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_pool_ops;
l->private = (const void *) fmt;
return l;
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_POOL_LABEL_H
#define _LVM_POOL_LABEL_H
#include "metadata.h"
struct labeller *pool_labeller_create(struct format_type *fmt);
#endif

View File

@@ -380,4 +380,3 @@ int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname)
return 1;
}

View File

@@ -20,6 +20,8 @@
#include "pool.h"
#include "display.h"
#include "lvm-string.h"
#include "segtypes.h"
#include "text_export.h"
#include <stdarg.h>
#include <time.h>
@@ -74,14 +76,6 @@ static void _init(void)
/*
* Formatting functions.
*/
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
static int _out_hint(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
static int _out(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
#define MAX_INDENT 5
static void _inc_indent(struct formatter *f)
@@ -206,7 +200,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
* Appends a comment giving a size in more easily
* readable form (eg, 4M instead of 8096).
*/
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
{
char buffer[64];
va_list ap;
@@ -226,7 +220,7 @@ static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
* Appends a comment indicating that the line is
* only a hint.
*/
static int _out_hint(struct formatter *f, const char *fmt, ...)
int out_hint(struct formatter *f, const char *fmt, ...)
{
va_list ap;
int r;
@@ -241,7 +235,7 @@ static int _out_hint(struct formatter *f, const char *fmt, ...)
/*
* The normal output function.
*/
static int _out(struct formatter *f, const char *fmt, ...)
int out_text(struct formatter *f, const char *fmt, ...)
{
va_list ap;
int r;
@@ -253,8 +247,6 @@ static int _out(struct formatter *f, const char *fmt, ...)
return r;
}
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
static int _print_header(struct formatter *f,
struct volume_group *vg, const char *desc)
{
@@ -262,17 +254,17 @@ static int _print_header(struct formatter *f,
t = time(NULL);
_outf(f, "# Generated by LVM2: %s", ctime(&t));
_outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
_outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
outf(f, "# Generated by LVM2: %s", ctime(&t));
outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
f->nl(f);
_outf(f, "description = \"%s\"", desc);
outf(f, "description = \"%s\"", desc);
f->nl(f);
_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
_utsname.sysname, _utsname.nodename, _utsname.release,
_utsname.version, _utsname.machine);
_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
_utsname.sysname, _utsname.nodename, _utsname.release,
_utsname.version, _utsname.machine);
outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
return 1;
}
@@ -286,34 +278,41 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
return 0;
}
_outf(f, "id = \"%s\"", buffer);
outf(f, "id = \"%s\"", buffer);
_outf(f, "seqno = %u", vg->seqno);
outf(f, "seqno = %u", vg->seqno);
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "status = %s", buffer);
outf(f, "status = %s", buffer);
if (!list_empty(&vg->tags)) {
if (!print_tags(&vg->tags, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "tags = %s", buffer);
outf(f, "tags = %s", buffer);
}
if (vg->system_id && *vg->system_id)
_outf(f, "system_id = \"%s\"", vg->system_id);
outf(f, "system_id = \"%s\"", vg->system_id);
if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
vg->extent_size)) {
if (!out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
vg->extent_size)) {
stack;
return 0;
}
_outf(f, "max_lv = %u", vg->max_lv);
_outf(f, "max_pv = %u", vg->max_pv);
outf(f, "max_lv = %u", vg->max_lv);
outf(f, "max_pv = %u", vg->max_pv);
/* Default policy is NORMAL; INHERIT is meaningless */
if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
f->nl(f);
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(vg->alloc));
}
return 1;
}
@@ -336,7 +335,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
char buffer[4096];
const char *name;
_outf(f, "physical_volumes {");
outf(f, "physical_volumes {");
_inc_indent(f);
list_iterate(pvh, &vg->pvs) {
@@ -348,7 +347,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
}
f->nl(f);
_outf(f, "%s {", name);
outf(f, "%s {", name);
_inc_indent(f);
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
@@ -356,8 +355,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
return 0;
}
_outf(f, "id = \"%s\"", buffer);
if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
outf(f, "id = \"%s\"", buffer);
if (!out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
stack;
return 0;
}
@@ -367,119 +366,106 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
stack;
return 0;
}
_outf(f, "status = %s", buffer);
outf(f, "status = %s", buffer);
if (!list_empty(&pv->tags)) {
if (!print_tags(&pv->tags, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "tags = %s", buffer);
outf(f, "tags = %s", buffer);
}
_outf(f, "pe_start = %" PRIu64, pv->pe_start);
if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
"pe_count = %u", pv->pe_count)) {
outf(f, "pe_start = %" PRIu64, pv->pe_start);
if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
"pe_count = %u", pv->pe_count)) {
stack;
return 0;
}
_dec_indent(f);
_outf(f, "}");
outf(f, "}");
}
_dec_indent(f);
_outf(f, "}");
outf(f, "}");
return 1;
}
static int _print_segment(struct formatter *f, struct volume_group *vg,
int count, struct lv_segment *seg)
{
unsigned int s;
const char *name;
const char *type;
char buffer[4096];
_outf(f, "segment%u {", count);
outf(f, "segment%u {", count);
_inc_indent(f);
_outf(f, "start_extent = %u", seg->le);
if (!_out_size(f, (uint64_t) seg->len * vg->extent_size,
"extent_count = %u", seg->len)) {
outf(f, "start_extent = %u", seg->le);
if (!out_size(f, (uint64_t) seg->len * vg->extent_size,
"extent_count = %u", seg->len)) {
stack;
return 0;
}
f->nl(f);
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
outf(f, "type = \"%s\"", seg->segtype->name);
if (!list_empty(&seg->tags)) {
if (!print_tags(&seg->tags, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "tags = %s", buffer);
outf(f, "tags = %s", buffer);
}
switch (seg->type) {
case SEG_SNAPSHOT:
_outf(f, "chunk_size = %u", seg->chunk_size);
_outf(f, "origin = \"%s\"", seg->origin->name);
_outf(f, "cow_store = \"%s\"", seg->cow->name);
break;
case SEG_MIRRORED:
case SEG_STRIPED:
type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe";
_outf(f, "%s_count = %u%s", type, seg->area_count,
(seg->area_count == 1) ? "\t# linear" : "");
if ((seg->type == SEG_MIRRORED) && (seg->status & PVMOVE))
_out_size(f, (uint64_t) seg->extents_moved,
"extents_moved = %u", seg->extents_moved);
if ((seg->type == SEG_STRIPED) && (seg->area_count > 1))
_out_size(f, (uint64_t) seg->stripe_size,
"stripe_size = %u", seg->stripe_size);
f->nl(f);
_outf(f, "%ss = [", type);
_inc_indent(f);
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_PV:
if (!(name = _get_pv_name(f, seg->
area[s].u.pv.pv))) {
stack;
return 0;
}
_outf(f, "\"%s\", %u%s", name,
seg->area[s].u.pv.pe,
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_LV:
_outf(f, "\"%s\", %u%s",
seg->area[s].u.lv.lv->name,
seg->area[s].u.lv.le,
(s == seg->area_count - 1) ? "" : ",");
}
}
_dec_indent(f);
_outf(f, "]");
break;
if (seg->segtype->ops->text_export &&
!seg->segtype->ops->text_export(seg, f)) {
stack;
return 0;
}
_dec_indent(f);
_outf(f, "}");
outf(f, "}");
return 1;
}
int out_areas(struct formatter *f, const struct lv_segment *seg,
const char *type)
{
const char *name;
unsigned int s;
f->nl(f);
outf(f, "%ss = [", type);
_inc_indent(f);
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_PV:
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
stack;
return 0;
}
outf(f, "\"%s\", %u%s", name,
seg->area[s].u.pv.pe,
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_LV:
outf(f, "\"%s\", %u%s",
seg->area[s].u.lv.lv->name,
seg->area[s].u.lv.le,
(s == seg->area_count - 1) ? "" : ",");
}
}
_dec_indent(f);
outf(f, "]");
return 1;
}
static int _count_segments(struct logical_volume *lv)
{
int r = 0;
@@ -499,7 +485,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
f->nl(f);
_outf(f, "snapshot%u {", count);
outf(f, "snapshot%u {", count);
_inc_indent(f);
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
@@ -507,25 +493,39 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
return 0;
}
_outf(f, "id = \"%s\"", buffer);
if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
buffer, sizeof(buffer))) {
outf(f, "id = \"%s\"", buffer);
seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "status = %s", buffer);
_outf(f, "segment_count = 1");
outf(f, "status = %s", buffer);
outf(f, "segment_count = 1");
f->nl(f);
seg.type = SEG_SNAPSHOT;
if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
"snapshot"))) {
stack;
return 0;
}
seg.le = 0;
seg.len = snap->origin->le_count;
seg.origin = snap->origin;
seg.cow = snap->cow;
seg.chunk_size = snap->chunk_size;
/* FIXME Dummy values */
list_init(&seg.list);
seg.lv = snap->cow;
seg.stripe_size = 0;
seg.area_count = 0;
seg.area_len = 0;
seg.extents_copied = 0;
/* Can't tag a snapshot independently of its origin */
list_init(&seg.tags);
@@ -535,7 +535,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
}
_dec_indent(f);
_outf(f, "}");
outf(f, "}");
return 1;
}
@@ -572,14 +572,14 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
if (list_empty(&vg->lvs))
return 1;
_outf(f, "logical_volumes {");
outf(f, "logical_volumes {");
_inc_indent(f);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
f->nl(f);
_outf(f, "%s {", lv->name);
outf(f, "%s {", lv->name);
_inc_indent(f);
/* FIXME: Write full lvid */
@@ -588,32 +588,33 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
return 0;
}
_outf(f, "id = \"%s\"", buffer);
outf(f, "id = \"%s\"", buffer);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "status = %s", buffer);
outf(f, "status = %s", buffer);
if (!list_empty(&lv->tags)) {
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "tags = %s", buffer);
outf(f, "tags = %s", buffer);
}
if (lv->alloc != ALLOC_DEFAULT)
_outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));
if (lv->alloc != ALLOC_INHERIT)
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));
if (lv->read_ahead)
_outf(f, "read_ahead = %u", lv->read_ahead);
outf(f, "read_ahead = %u", lv->read_ahead);
if (lv->major >= 0)
_outf(f, "major = %d", lv->major);
outf(f, "major = %d", lv->major);
if (lv->minor >= 0)
_outf(f, "minor = %d", lv->minor);
_outf(f, "segment_count = %u", _count_segments(lv));
outf(f, "minor = %d", lv->minor);
outf(f, "segment_count = %u", _count_segments(lv));
f->nl(f);
seg_count = 1;
@@ -625,7 +626,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
}
_dec_indent(f);
_outf(f, "}");
outf(f, "}");
}
if (!_print_snapshots(f, vg)) {
@@ -634,7 +635,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
}
_dec_indent(f);
_outf(f, "}");
outf(f, "}");
return 1;
}
@@ -707,7 +708,7 @@ static int _text_vg_export(struct formatter *f,
if (f->header && !_print_header(f, vg, desc))
fail;
if (!_out(f, "%s {", vg->name))
if (!out_text(f, "%s {", vg->name))
fail;
_inc_indent(f);
@@ -724,7 +725,7 @@ static int _text_vg_export(struct formatter *f,
fail;
_dec_indent(f);
if (!_out(f, "}"))
if (!out_text(f, "}"))
fail;
if (!f->header && !_print_header(f, vg, desc))
@@ -804,4 +805,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
return r;
}
#undef _outf
#undef outf

View File

@@ -52,6 +52,8 @@ static struct flag _lv_flags[] = {
{VISIBLE_LV, "VISIBLE"},
{PVMOVE, "PVMOVE"},
{LOCKED, "LOCKED"},
{MIRRORED, NULL},
{VIRTUAL, NULL},
{0, NULL}
};
@@ -92,18 +94,21 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
for (f = 0; flags[f].mask; f++) {
if (status & flags[f].mask) {
status &= ~flags[f].mask;
/* Internal-only flag? */
if (!flags[f].description)
continue;
if (!first) {
if (!emit_to_buffer(&buffer, &size, ", "))
return 0;
} else
first = 0;
if (!emit_to_buffer(&buffer, &size, "\"%s\"",
flags[f].description))
flags[f].description))
return 0;
status &= ~flags[f].mask;
}
}

View File

@@ -30,6 +30,7 @@
#include "xlate.h"
#include "label.h"
#include "memlock.h"
#include "lvmcache.h"
#include <unistd.h>
#include <sys/file.h>
@@ -80,7 +81,7 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
uint64_t max_size = UINT_MAX;
if (lv->size > max_size) {
char *dummy = display_size(max_size / 2, SIZE_SHORT);
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
dbg_free(dummy);
return 0;
@@ -928,8 +929,7 @@ static int _mda_setup(const struct format_type *fmt,
/* FIXME If creating new mdas, wipe them! */
if (mda_size1) {
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
mda_size1))
return 0;
mda_size1)) return 0;
if (!dev_zero((struct device *) pv->dev, start1,
(size_t) (mda_size1 >
@@ -976,8 +976,7 @@ static int _mda_setup(const struct format_type *fmt,
if (mda_size2) {
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
mda_size2))
return 0;
mda_size2)) return 0;
if (!dev_zero(pv->dev, start2,
(size_t) (mda_size1 >
wipe_size ? wipe_size : mda_size1))) {
@@ -1066,8 +1065,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
}
}
if (!add_da
(fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT,
UINT64_C(0))) {
(fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0))) {
stack;
return 0;
}
@@ -1139,8 +1137,7 @@ static int _add_raw(struct list *raw_list, struct device_area *dev_area)
rl = list_item(rlh, struct raw_list);
/* FIXME Check size/overlap consistency too */
if (rl->dev_area.dev == dev_area->dev &&
rl->dev_area.start == dev_area->start)
return 1;
rl->dev_area.start == dev_area->start) return 1;
}
if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
@@ -1334,11 +1331,10 @@ static int _pv_setup(const struct format_type *fmt,
list_item(mdash,
struct metadata_area);
if (mda2->ops !=
&_metadata_text_raw_ops)
continue;
&_metadata_text_raw_ops) continue;
mdac2 =
(struct mda_context *) mda2->
metadata_locn;
(struct mda_context *)
mda2->metadata_locn;
if (!memcmp
(&mdac2->area, &mdac->area,
sizeof(mdac->area))) {
@@ -1356,8 +1352,7 @@ static int _pv_setup(const struct format_type *fmt,
}
if (!(mdac_new = pool_alloc(fmt->cmd->mem,
sizeof(*mdac_new))))
{
sizeof(*mdac_new)))) {
stack;
return 0;
}
@@ -1486,8 +1481,7 @@ static struct format_instance *_create_text_instance(const struct format_type
}
if (!(mdac_new = pool_alloc(fmt->cmd->mem,
sizeof(*mdac_new))))
{
sizeof(*mdac_new)))) {
stack;
return NULL;
}
@@ -1649,7 +1643,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
fmt->alias = FMT_TEXT_ALIAS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
log_error("Failed to allocate dir_list");

View File

@@ -49,12 +49,12 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
*desc = NULL;
*when = 0;
if (!(cft = create_config_tree())) {
if (!(cft = create_config_tree(file))) {
stack;
goto out;
}
if ((!dev && !read_config_file(cft, file)) ||
if ((!dev && !read_config_file(cft)) ||
(dev && !read_config_fd(cft, dev, offset, size,
offset2, size2, checksum_fn, checksum))) {
log_error("Couldn't read volume group metadata.");

View File

@@ -22,6 +22,8 @@
#include "toolcontext.h"
#include "lvmcache.h"
#include "lv_alloc.h"
#include "segtypes.h"
#include "text_import.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn,
@@ -234,17 +236,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *sn,
struct hash_table *pv_hash)
{
unsigned int s;
uint32_t area_count = 0;
uint32_t area_count = 0u;
struct lv_segment *seg;
struct config_node *cn;
struct config_value *cv;
const char *seg_name = sn->key;
uint32_t start_extent, extent_count;
uint32_t chunk_size, extents_moved = 0u, seg_status = 0u;
const char *org_name, *cow_name;
struct logical_volume *org, *cow, *lv1;
segment_type_t segtype;
struct segment_type *segtype;
const char *segtype_str;
if (!(sn = sn->child)) {
log_error("Empty segment section.");
@@ -263,40 +261,26 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
return 0;
}
segtype = SEG_STRIPED; /* Default */
segtype_str = "striped";
if ((cn = find_config_node(sn, "type"))) {
cv = cn->v;
if (!cv || !cv->v.str) {
log_error("Segment type must be a string.");
return 0;
}
segtype = get_segtype_from_string(cv->v.str);
segtype_str = cv->v.str;
}
if (segtype == SEG_STRIPED) {
if (!_read_int32(sn, "stripe_count", &area_count)) {
log_error("Couldn't read 'stripe_count' for "
"segment '%s'.", sn->key);
return 0;
}
if (!(segtype = get_segtype_from_string(vg->cmd, segtype_str))) {
stack;
return 0;
}
if (segtype == SEG_MIRRORED) {
if (!_read_int32(sn, "mirror_count", &area_count)) {
log_error("Couldn't read 'mirror_count' for "
"segment '%s'.", sn->key);
return 0;
}
if (find_config_node(sn, "extents_moved")) {
if (_read_uint32(sn, "extents_moved", &extents_moved))
seg_status |= PVMOVE;
else {
log_error("Couldn't read 'extents_moved' for "
"segment '%s'.", sn->key);
return 0;
}
}
if (segtype->ops->text_import_area_count &&
!segtype->ops->text_import_area_count(sn, &area_count)) {
stack;
return 0;
}
if (!(seg = alloc_lv_segment(mem, area_count))) {
@@ -308,9 +292,15 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
seg->le = start_extent;
seg->len = extent_count;
seg->area_len = extent_count;
seg->type = segtype;
seg->status = seg_status;
seg->extents_moved = extents_moved;
seg->status = 0u;
seg->segtype = segtype;
seg->extents_copied = 0u;
if (seg->segtype->ops->text_import &&
!seg->segtype->ops->text_import(seg, sn, pv_hash)) {
stack;
return 0;
}
/* Optional tags */
if ((cn = find_config_node(sn, "tags")) &&
@@ -320,145 +310,89 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
return 0;
}
switch (segtype) {
case SEG_SNAPSHOT:
lv->status |= SNAPSHOT;
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_error("Couldn't read chunk size for snapshot.");
return 0;
}
log_suppress(1);
if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
log_suppress(0);
log_error("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", NULL))) {
log_suppress(0);
log_error("Snapshot origin not specified.");
return 0;
}
log_suppress(0);
if (!(cow = find_lv(vg, cow_name))) {
log_error("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_error("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
stack;
return 0;
}
break;
case SEG_STRIPED:
if ((area_count != 1) &&
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
log_error("Couldn't read stripe_size for segment '%s'.",
sn->key);
return 0;
}
if (!(cn = find_config_node(sn, "stripes"))) {
log_error("Couldn't find stripes array for segment "
"'%s'.", sn->key);
return 0;
}
seg->area_len /= area_count;
case SEG_MIRRORED:
seg->area_count = area_count;
if (!seg->area_count) {
log_error("Zero areas not allowed for segment '%s'",
sn->key);
return 0;
}
if ((seg->type == SEG_MIRRORED) &&
!(cn = find_config_node(sn, "mirrors"))) {
log_error("Couldn't find mirrors array for segment "
"'%s'.", sn->key);
return 0;
}
for (cv = cn->v, s = 0; cv && s < seg->area_count;
s++, cv = cv->next) {
/* first we read the pv */
const char *bad = "Badly formed areas array for "
"segment '%s'.";
struct physical_volume *pv;
if (cv->type != CFG_STRING) {
log_error(bad, sn->key);
return 0;
}
if (!cv->next) {
log_error(bad, sn->key);
return 0;
}
if (cv->next->type != CFG_INT) {
log_error(bad, sn->key);
return 0;
}
/* FIXME Cope if LV not yet read in */
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
seg->area[s].type = AREA_PV;
seg->area[s].u.pv.pv = pv;
seg->area[s].u.pv.pe = cv->next->v.i;
/*
* Adjust extent counts in the pv and vg.
*/
pv->pe_alloc_count += seg->area_len;
vg->free_count -= seg->area_len;
} else if ((lv1 = find_lv(vg, cv->v.str))) {
seg->area[s].type = AREA_LV;
seg->area[s].u.lv.lv = lv1;
seg->area[s].u.lv.le = cv->next->v.i;
} else {
log_error("Couldn't find volume '%s' "
"for segment '%s'.",
cv->v.str ? cv->v.str : "NULL",
seg_name);
return 0;
}
cv = cv->next;
}
/*
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->area_count)) {
log_error("Incorrect number of areas in area array "
"for segment '%s'.", seg_name);
return 0;
}
}
/*
* Insert into correct part of segment list.
*/
_insert_segment(lv, seg);
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
lv->status |= MIRRORED;
if (seg->segtype->flags & SEG_VIRTUAL)
lv->status |= VIRTUAL;
return 1;
}
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
const struct config_node *cn, struct hash_table *pv_hash)
{
unsigned int s;
struct config_value *cv;
struct logical_volume *lv1;
const char *seg_name = sn->key;
if (!seg->area_count) {
log_error("Zero areas not allowed for segment '%s'", sn->key);
return 0;
}
for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
/* first we read the pv */
const char *bad = "Badly formed areas array for "
"segment '%s'.";
struct physical_volume *pv;
if (cv->type != CFG_STRING) {
log_error(bad, sn->key);
return 0;
}
if (!cv->next) {
log_error(bad, sn->key);
return 0;
}
if (cv->next->type != CFG_INT) {
log_error(bad, sn->key);
return 0;
}
/* FIXME Cope if LV not yet read in */
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
seg->area[s].type = AREA_PV;
seg->area[s].u.pv.pv = pv;
seg->area[s].u.pv.pe = cv->next->v.i;
/*
* Adjust extent counts in the pv and vg.
*/
pv->pe_alloc_count += seg->area_len;
seg->lv->vg->free_count -= seg->area_len;
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
seg->area[s].type = AREA_LV;
seg->area[s].u.lv.lv = lv1;
seg->area[s].u.lv.le = cv->next->v.i;
} else {
log_error("Couldn't find volume '%s' "
"for segment '%s'.",
cv->v.str ? cv->v.str : "NULL", seg_name);
return 0;
}
cv = cv->next;
}
/*
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->area_count)) {
log_error("Incorrect number of areas in area array "
"for segment '%s'.", seg_name);
return 0;
}
return 1;
}
@@ -555,7 +489,7 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
return 0;
}
lv->alloc = ALLOC_DEFAULT;
lv->alloc = ALLOC_INHERIT;
if ((cn = find_config_node(lvn, "allocation_policy"))) {
struct config_value *cv = cn->v;
if (!cv || !cv->v.str) {
@@ -564,6 +498,10 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
}
lv->alloc = get_alloc_from_string(cv->v.str);
if (lv->alloc == ALLOC_INVALID) {
stack;
return 0;
}
}
/* read_ahead defaults to 0 */
@@ -765,6 +703,21 @@ static struct volume_group *_read_vg(struct format_instance *fid,
goto bad;
}
vg->alloc = ALLOC_NORMAL;
if ((cn = find_config_node(vgn, "allocation_policy"))) {
struct config_value *cv = cn->v;
if (!cv || !cv->v.str) {
log_error("allocation_policy must be a string.");
return 0;
}
vg->alloc = get_alloc_from_string(cv->v.str);
if (vg->alloc == ALLOC_INVALID) {
stack;
return 0;
}
}
/*
* The pv hash memoises the pv section names -> pv
* structures.

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TEXT_EXPORT_H
#define _LVM_TEXT_EXPORT_H
#define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0)
struct formatter;
struct lv_segment;
int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
int out_hint(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
int out_text(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
int out_areas(struct formatter *f, const struct lv_segment *seg,
const char *type);
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TEXT_IMPORT_H
#define _LVM_TEXT_IMPORT_H
struct lv_segment;
struct config_node;
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
const struct config_node *cn, struct hash_table *pv_hash);
#endif

View File

@@ -18,6 +18,7 @@
#include "layout.h"
#include "label.h"
#include "xlate.h"
#include "lvmcache.h"
#include <sys/stat.h>
#include <fcntl.h>

View File

@@ -19,6 +19,7 @@
#include "crc.h"
#include "xlate.h"
#include "lvmcache.h"
#include "metadata.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -78,6 +79,8 @@ void label_exit(void)
li->l->ops->destroy(li->l);
_free_li(li);
}
list_init(&_labellers);
}
int label_register_handler(const char *name, struct labeller *handler)

View File

@@ -16,7 +16,6 @@
#ifndef _LVM_LABEL_H
#define _LVM_LABEL_H
#include "lvmcache.h"
#include "uuid.h"
#include "device.h"
@@ -25,6 +24,8 @@
#define LABEL_SCAN_SECTORS 4L
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
struct labeller;
/* On disk - 32 bytes */
struct label_header {
uint8_t id[8]; /* LABELONE */

View File

@@ -19,6 +19,7 @@
#include "sharedlib.h"
static void *_locking_lib = NULL;
static void (*_reset_fn) (void) = NULL;
static void (*_end_fn) (void) = NULL;
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
int flags) = NULL;
@@ -45,6 +46,13 @@ static void _fin_external_locking(void)
_init_fn = NULL;
_end_fn = NULL;
_lock_fn = NULL;
_reset_fn = NULL;
}
static void _reset_external_locking(void)
{
if (_reset_fn)
_reset_fn();
}
int init_external_locking(struct locking_type *locking, struct config_tree *cft)
@@ -58,6 +66,7 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
locking->lock_resource = _lock_resource;
locking->fin_locking = _fin_external_locking;
locking->reset_locking = _reset_external_locking;
locking->flags = 0;
libname = find_config_str(cft->root, "global/locking_library",
@@ -71,6 +80,7 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
/* Get the functions we need */
if (!(_init_fn = dlsym(_locking_lib, "locking_init")) ||
!(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
!(_reset_fn = dlsym(_locking_lib, "reset_locking")) ||
!(_end_fn = dlsym(_locking_lib, "locking_end"))) {
log_error("Shared library %s does not contain locking "
"functions", libname);

View File

@@ -232,9 +232,14 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
if (!lv_resume_if_active(cmd, resource))
return 0;
break;
case LCK_NULL:
log_debug("Locking LV %s (NL)", resource);
if (!lv_deactivate(cmd, resource))
return 0;
break;
case LCK_READ:
log_debug("Locking LV %s (R)", resource);
if (!lv_activate(cmd, resource))
if (!lv_activate_with_filter(cmd, resource))
return 0;
break;
case LCK_WRITE:
@@ -244,7 +249,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
break;
case LCK_EXCL:
log_debug("Locking LV %s (EX)", resource);
if (!lv_deactivate(cmd, resource))
if (!lv_activate_with_filter(cmd, resource))
return 0;
break;
default:

View File

@@ -252,32 +252,54 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
}
/* Unlock list of LVs */
int unlock_lvs(struct cmd_context *cmd, struct list *lvs)
int resume_lvs(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
}
return 1;
}
/* Lock a list of LVs */
int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags)
int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!lock_vol(cmd, lv->lvid.s, flags)) {
if (!suspend_lv(cmd, lv->lvid.s)) {
log_error("Failed to suspend %s", lv->name);
list_uniterate(lvh, lvs, lvh) {
lv = list_item(lvh, struct lv_list)->lv;
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
}
return 0;
}
}
return 1;
}
/* Lock a list of LVs */
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs)
{
struct list *lvh;
struct logical_volume *lv;
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!activate_lv_excl(cmd, lv->lvid.s)) {
log_error("Failed to activate %s", lv->name);
list_uniterate(lvh, lvs, lvh) {
lv = list_item(lvh, struct lv_list)->lv;
activate_lv(cmd, lv->lvid.s);
}
return 0;

View File

@@ -13,7 +13,6 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "metadata.h"
#include "uuid.h"
#include "config.h"
@@ -72,16 +71,23 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define LCK_VG_WRITE (LCK_VG | LCK_WRITE | LCK_HOLD)
#define LCK_VG_UNLOCK (LCK_VG | LCK_UNLOCK)
#define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE)
#define LCK_LV_EXCLUSIVE (LCK_LV | LCK_EXCL | LCK_NONBLOCK)
#define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE | LCK_NONBLOCK)
#define LCK_LV_RESUME (LCK_LV | LCK_UNLOCK | LCK_NONBLOCK)
#define LCK_LV_UNLOCK (LCK_LV | LCK_UNLOCK)
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ)
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_EXCL)
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ | LCK_NONBLOCK)
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_NULL | LCK_NONBLOCK)
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
/* Process list of LVs */
int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags);
int unlock_lvs(struct cmd_context *cmd, struct list *lvs);
#define resume_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_RESUME)
#define suspend_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_SUSPEND | LCK_HOLD)
#define deactivate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_DEACTIVATE)
#define activate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD)
#define activate_lv_excl(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_EXCLUSIVE | LCK_HOLD)
/* Process list of LVs */
int suspend_lvs(struct cmd_context *cmd, struct list *lvs);
int resume_lvs(struct cmd_context *cmd, struct list *lvs);
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs);

View File

@@ -53,14 +53,16 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
break;
case LCK_LV:
switch (flags & LCK_TYPE_MASK) {
case LCK_NULL:
return lv_deactivate(cmd, resource);
case LCK_UNLOCK:
return lv_resume_if_active(cmd, resource);
case LCK_READ:
return lv_activate(cmd, resource);
return lv_activate_with_filter(cmd, resource);
case LCK_WRITE:
return lv_suspend_if_active(cmd, resource);
case LCK_EXCL:
return lv_deactivate(cmd, resource);
return lv_activate_with_filter(cmd, resource);
default:
break;
}

View File

@@ -20,6 +20,8 @@
#include "lvm-string.h"
#include "toolcontext.h"
#include "lv_alloc.h"
#include "display.h"
#include "segtypes.h"
/*
* These functions adjust the pe counts in pv's
@@ -69,6 +71,7 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
return NULL;
}
seg->area_count = num_areas;
list_init(&seg->tags);
return seg;
@@ -76,6 +79,7 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
uint32_t stripe_size,
struct segment_type *segtype,
struct pv_area **areas, uint32_t *ix)
{
uint32_t count, area_len, smallest;
@@ -83,7 +87,9 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
struct lv_segment *seg;
int striped = 0;
striped = 1;
/* Striped or mirrored? */
if (segtype->flags & SEG_AREAS_STRIPED)
striped = 1;
count = lv->le_count - *ix;
area_len = count / (striped ? area_count : 1);
@@ -98,13 +104,12 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
}
seg->lv = lv;
seg->type = SEG_STRIPED;
seg->segtype = segtype;
seg->le = *ix;
seg->len = area_len * (striped ? area_count : 1);
seg->area_len = area_len;
seg->area_count = area_count;
seg->stripe_size = stripe_size;
seg->extents_moved = 0u;
seg->extents_copied = 0u;
for (s = 0; s < area_count; s++) {
struct pv_area *pva = areas[s];
@@ -116,6 +121,10 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
list_add(&lv->segments, &seg->list);
*ix += seg->len;
if (!striped)
lv->status |= MIRRORED;
return 1;
}
@@ -135,7 +144,8 @@ static int _comp_area(const void *l, const void *r)
static int _alloc_parallel(struct logical_volume *lv,
struct list *pvms, uint32_t allocated,
uint32_t stripes, uint32_t stripe_size)
uint32_t stripes, uint32_t stripe_size,
uint32_t mirrors, struct segment_type *segtype)
{
int r = 0;
struct list *pvmh;
@@ -145,7 +155,15 @@ static int _alloc_parallel(struct logical_volume *lv,
size_t len;
uint32_t area_count;
area_count = stripes;
if (stripes > 1 && mirrors > 1) {
log_error("striped mirrors are not supported yet");
return 0;
}
if (stripes > 1)
area_count = stripes;
else
area_count = mirrors;
list_iterate(pvmh, pvms)
pv_count++;
@@ -179,8 +197,8 @@ static int _alloc_parallel(struct logical_volume *lv,
/* sort the areas so we allocate from the biggest */
qsort(areas, ix, sizeof(*areas), _comp_area);
if (!_alloc_parallel_area(lv, area_count, stripe_size, areas,
&allocated)) {
if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype,
areas, &allocated)) {
stack;
goto out;
}
@@ -215,12 +233,14 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
}
seg->lv = lv;
seg->type = SEG_STRIPED;
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
stack;
return 0;
}
seg->le = *ix;
seg->len = count;
seg->area_len = count;
seg->stripe_size = 0;
seg->area_count = 1;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = map->pvl->pv;
seg->area[0].u.pv.pe = pva->start;
@@ -234,6 +254,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
struct pv_map *map, struct pv_area *pva,
struct segment_type *segtype,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
@@ -251,14 +272,13 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
}
seg->lv = lv;
seg->type = SEG_MIRRORED;
seg->status = 0u;
seg->segtype = segtype;
seg->le = *ix;
seg->status = 0u;
seg->len = count;
seg->area_len = count;
seg->stripe_size = 0;
seg->area_count = 2;
seg->extents_moved = 0u;
seg->extents_copied = 0u;
/* FIXME Remove AREA_PV restriction here? */
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = mirrored_pv;
@@ -321,6 +341,7 @@ static int _alloc_contiguous(struct logical_volume *lv,
/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
static int _alloc_mirrored(struct logical_volume *lv,
struct list *pvms, uint32_t allocated,
struct segment_type *segtype,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
@@ -343,7 +364,7 @@ static int _alloc_mirrored(struct logical_volume *lv,
continue;
}
if (!_alloc_mirrored_area(lv, &allocated, pvm, pva,
if (!_alloc_mirrored_area(lv, &allocated, pvm, pva, segtype,
mirrored_pv, mirrored_pe)) {
stack;
return 0;
@@ -395,12 +416,37 @@ static int _alloc_next_free(struct logical_volume *lv,
return 1;
}
static int _alloc_virtual(struct logical_volume *lv,
uint32_t allocated, struct segment_type *segtype)
{
struct lv_segment *seg;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) {
log_err("Couldn't allocate new zero segment.");
return 0;
}
seg->lv = lv;
seg->segtype = segtype;
seg->status = 0u;
seg->le = allocated;
seg->len = lv->le_count - allocated;
seg->area_len = seg->len;
seg->stripe_size = 0;
seg->extents_copied = 0u;
list_add(&lv->segments, &seg->list);
lv->status |= VIRTUAL;
return 1;
}
/*
* Chooses a correct allocation policy.
*/
static int _allocate(struct volume_group *vg, struct logical_volume *lv,
struct list *allocatable_pvs, uint32_t allocated,
uint32_t stripes, uint32_t stripe_size,
alloc_policy_t alloc, struct segment_type *segtype,
uint32_t stripes, uint32_t stripe_size, uint32_t mirrors,
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
uint32_t status)
{
@@ -409,32 +455,40 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
struct list *pvms, *old_tail = lv->segments.p, *segh;
struct lv_segment *seg;
if (segtype->flags & SEG_VIRTUAL)
return _alloc_virtual(lv, allocated, segtype);
if (!(scratch = pool_create(1024))) {
stack;
return 0;
}
if (alloc == ALLOC_INHERIT)
alloc = vg->alloc;
/*
* Build the sets of available areas on the pv's.
*/
if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs)))
goto out;
if (stripes > 1)
r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size);
if (stripes > 1 || mirrors > 1)
r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size,
mirrors, segtype);
else if (mirrored_pv)
r = _alloc_mirrored(lv, pvms, allocated, mirrored_pv,
r = _alloc_mirrored(lv, pvms, allocated, segtype, mirrored_pv,
mirrored_pe);
else if (lv->alloc == ALLOC_CONTIGUOUS)
else if (alloc == ALLOC_CONTIGUOUS)
r = _alloc_contiguous(lv, pvms, allocated);
else if (lv->alloc == ALLOC_NEXT_FREE || lv->alloc == ALLOC_DEFAULT)
else if (alloc == ALLOC_NORMAL || alloc == ALLOC_ANYWHERE)
r = _alloc_next_free(lv, pvms, allocated);
else {
log_error("Unknown allocation policy: "
"unable to setup logical volume.");
log_error("Unrecognised allocation policy: "
"unable to set up logical volume.");
goto out;
}
@@ -554,57 +608,42 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
return lv;
}
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,
struct volume_group *vg,
struct list *allocatable_pvs)
int lv_extend(struct format_instance *fid,
struct logical_volume *lv,
struct segment_type *segtype,
uint32_t stripes, uint32_t stripe_size,
uint32_t mirrors, uint32_t extents,
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
uint32_t status, struct list *allocatable_pvs,
alloc_policy_t alloc)
{
struct logical_volume *lv;
uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size;
if (!extents) {
log_error("Unable to create logical volume %s with no extents",
name);
return NULL;
}
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (vg->free_count < extents) {
log_error("Insufficient free extents (%u) in volume group %s: "
"%u required", vg->free_count, vg->name, extents);
return NULL;
}
if (stripes > list_size(allocatable_pvs)) {
log_error("Number of stripes (%u) must not exceed "
"number of physical volumes (%d)", stripes,
list_size(allocatable_pvs));
return NULL;
}
if (!(lv = lv_create_empty(fi, name, "lvol%d", status, alloc, vg))) {
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, alloc,
segtype, stripes, stripe_size, mirrors, mirrored_pv,
mirrored_pe, status)) {
lv->le_count = old_le_count;
lv->size = old_size;
stack;
return NULL;
return 0;
}
lv->size = (uint64_t) extents *vg->extent_size;
lv->le_count = extents;
if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
log_err("Couldn't merge segments after extending "
"logical volume.");
return 0;
}
if (!_allocate(vg, lv, allocatable_pvs, 0u, stripes, stripe_size,
NULL, 0u, 0u)) {
if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
stack;
return NULL;
return 0;
}
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
return NULL;
}
return lv;
return 1;
}
int lv_reduce(struct format_instance *fi,
@@ -628,7 +667,7 @@ int lv_reduce(struct format_instance *fi,
/* reduce this segment */
_put_extents(seg);
seg->len -= count;
striped = (seg->type == SEG_STRIPED);
striped = seg->segtype->flags & SEG_AREAS_STRIPED;
/* Caller must ensure exact divisibility */
if (striped && (count % seg->area_count)) {
log_error("Segment extent reduction %" PRIu32
@@ -655,68 +694,6 @@ int lv_reduce(struct format_instance *fi,
return 1;
}
int lv_extend(struct format_instance *fi,
struct logical_volume *lv,
uint32_t stripes, uint32_t stripe_size,
uint32_t extents, struct list *allocatable_pvs)
{
uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size;
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count,
stripes, stripe_size, NULL, 0u, 0u)) {
lv->le_count = old_le_count;
lv->size = old_size;
stack;
return 0;
}
if (!lv_merge_segments(lv)) {
log_err("Couldn't merge segments after extending "
"logical volume.");
return 0;
}
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
return 0;
}
return 1;
}
int lv_extend_mirror(struct format_instance *fid,
struct logical_volume *lv,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe,
uint32_t extents, struct list *allocatable_pvs,
uint32_t status)
{
uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size;
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count,
1, extents, mirrored_pv, mirrored_pe, status)) {
lv->le_count = old_le_count;
lv->size = old_size;
stack;
return 0;
}
if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
stack;
return 0;
}
return 1;
}
int lv_remove(struct volume_group *vg, struct logical_volume *lv)
{
struct list *segh;

View File

@@ -18,60 +18,20 @@
#include "toolcontext.h"
#include "lv_alloc.h"
#include "str_list.h"
/*
* Test whether two segments could be merged by the current merging code
*/
static int _segments_compatible(struct lv_segment *first,
struct lv_segment *second)
{
uint32_t width;
unsigned s;
/* FIXME Relax the seg type restriction */
if (!first || !second ||
(first->type != SEG_STRIPED) || (second->type != first->type) ||
(first->area_count != second->area_count) ||
(first->stripe_size != second->stripe_size))
return 0;
for (s = 0; s < first->area_count; s++) {
/* FIXME Relax this to first area type != second area type */
/* plus the additional AREA_LV checks needed */
if ((first->area[s].type != AREA_PV) ||
(second->area[s].type != AREA_PV))
return 0;
width = first->area_len;
if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
(first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
return 0;
}
if (!str_list_lists_equal(&first->tags, &second->tags))
return 0;
return 1;
}
#include "segtypes.h"
/*
* Attempt to merge two adjacent segments.
* Currently only supports SEG_STRIPED on AREA_PV.
* Currently only supports striped segments on AREA_PV.
* Returns success if successful, in which case 'first'
* gets adjusted to contain both areas.
*/
static int _merge(struct lv_segment *first, struct lv_segment *second)
{
if (!first || !second || first->segtype != second->segtype ||
!first->segtype->ops->merge_segments) return 0;
if (!_segments_compatible(first, second))
return 0;
first->len += second->len;
first->area_len += second->area_len;
return 1;
return first->segtype->ops->merge_segments(first, second);
}
int lv_merge_segments(struct logical_volume *lv)
@@ -126,15 +86,14 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
uint32_t s;
uint32_t offset = le - seg->le;
if (seg->type == SEG_SNAPSHOT) {
log_error("Unable to split the snapshot segment at LE %" PRIu32
" in LV %s", le, lv->name);
if (!(seg->segtype->flags & SEG_CAN_SPLIT)) {
log_error("Unable to split the %s segment at LE %" PRIu32
" in LV %s", seg->segtype->name, le, lv->name);
return 0;
}
/* Clone the existing segment */
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem,
seg->area_count))) {
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) {
log_error("Couldn't allocate new LV segment.");
return 0;
}
@@ -148,7 +107,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
}
/* In case of a striped segment, the offset has to be / stripes */
if (seg->type == SEG_STRIPED)
if (seg->segtype->flags & SEG_AREAS_STRIPED)
offset /= seg->area_count;
/* Adjust the PV mapping */
@@ -205,4 +164,3 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le)
return 1;
}

View File

@@ -162,7 +162,8 @@ const char *strip_dir(const char *vg_name, const char *dev_dir)
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
uint32_t extent_size, uint32_t max_pv,
uint32_t max_lv, int pv_count, char **pv_names)
uint32_t max_lv, alloc_policy_t alloc,
int pv_count, char **pv_names)
{
struct volume_group *vg;
struct pool *mem = cmd->mem;
@@ -211,6 +212,8 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
vg->max_lv = max_lv;
vg->max_pv = max_pv;
vg->alloc = alloc;
vg->pv_count = 0;
list_init(&vg->pvs);
@@ -418,6 +421,24 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
return NULL;
}
struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
const char *pv_name)
{
struct physical_volume *pv;
if (!(pv = pv_read(cmd, pv_name, NULL, NULL))) {
log_error("Physical volume %s not found", pv_name);
return NULL;
}
if (!pv->vg_name[0]) {
log_error("Physical volume %s not in a volume group", pv_name);
return NULL;
}
return pv;
}
/* Find segment at a given logical extent in an LV */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
{

View File

@@ -53,6 +53,8 @@
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
#define PVMOVE 0x00002000 /* VG LV SEG */
#define LOCKED 0x00004000 /* LV */
#define MIRRORED 0x00008000 /* LV - internal use only */
#define VIRTUAL 0x00010000 /* LV - internal use only */
#define LVM_READ 0x00000100 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */
@@ -66,18 +68,14 @@
#define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
typedef enum {
ALLOC_DEFAULT,
ALLOC_NEXT_FREE,
ALLOC_CONTIGUOUS
} alloc_policy_t;
typedef enum {
SEG_STRIPED,
SEG_SNAPSHOT,
SEG_MIRRORED
} segment_type_t;
ALLOC_INVALID,
ALLOC_INHERIT,
ALLOC_CONTIGUOUS,
ALLOC_NORMAL,
ALLOC_ANYWHERE
} alloc_policy_t;
typedef enum {
AREA_PV,
@@ -171,6 +169,7 @@ struct volume_group {
char *system_id;
uint32_t status;
alloc_policy_t alloc;
uint32_t extent_size;
uint32_t extent_count;
@@ -194,11 +193,12 @@ struct volume_group {
struct list tags;
};
struct segment_type;
struct lv_segment {
struct list list;
struct logical_volume *lv;
segment_type_t type;
struct segment_type *segtype;
uint32_t le;
uint32_t len;
@@ -211,7 +211,7 @@ struct lv_segment {
struct logical_volume *origin;
struct logical_volume *cow;
uint32_t chunk_size;
uint32_t extents_moved;
uint32_t extents_copied;
struct list tags;
@@ -392,27 +392,15 @@ struct physical_volume *pv_create(const struct format_type *fmt,
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, uint32_t max_pv,
uint32_t max_lv, int pv_count, char **pv_names);
uint32_t max_lv, alloc_policy_t alloc,
int pv_count, char **pv_names);
int vg_remove(struct volume_group *vg);
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
const char *new_name);
int vg_extend(struct format_instance *fi, struct volume_group *vg,
int pv_count, char **pv_names);
/*
* Create a new LV within a given volume group.
*
*/
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,
struct volume_group *vg,
struct list *allocatable_pvs);
/* Manipulate LVs */
struct logical_volume *lv_create_empty(struct format_instance *fi,
const char *name,
const char *name_format,
@@ -420,22 +408,17 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
alloc_policy_t alloc,
struct volume_group *vg);
/* Manipulate LVs */
int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents);
int lv_extend(struct format_instance *fi,
int lv_extend(struct format_instance *fid,
struct logical_volume *lv,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents, struct list *allocatable_pvs);
int lv_extend_mirror(struct format_instance *fid,
struct logical_volume *lv,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe,
uint32_t extents, struct list *allocatable_pvs,
uint32_t status);
struct segment_type *segtype,
uint32_t stripes, uint32_t stripe_size,
uint32_t mirrors, uint32_t extents,
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
uint32_t status, struct list *allocatable_pvs,
alloc_policy_t alloc);
/* lv must be part of vg->lvs */
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
@@ -466,6 +449,8 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
/* FIXME Merge these functions with ones above */
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name);
struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
const char *pv_name);
/* Find LV segment containing given LE */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
@@ -522,11 +507,14 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
int remove_pvmove_mirrors(struct volume_group *vg,
struct logical_volume *lv_mirr);
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
struct device *dev);
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv);
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
*lv_mirr);
float pvmove_percent(struct logical_volume *lv_mirr);
struct device *dev, uint32_t lv_type);
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
struct volume_group *vg,
const char *name,
uint32_t lv_type);
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv);
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr);
float copy_percent(struct logical_volume *lv_mirr);
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv);

View File

@@ -16,6 +16,9 @@
#include "lib.h"
#include "metadata.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "display.h"
#include "activate.h"
/*
* Replace any LV segments on given PV with temporary mirror.
@@ -33,7 +36,21 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
struct lv_list *lvl;
int lv_used = 0;
uint32_t s, start_le, extent_count = 0u;
struct segment_type *segtype;
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "mirror"))) {
stack;
return 0;
}
if (activation() && segtype->ops->target_present &&
!segtype->ops->target_present()) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", segtype->name);
return 0;
}
/* Work through all segments on the supplied PV */
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
@@ -41,6 +58,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
seg->area[s].u.pv.pv->dev != pv->dev)
continue;
/* First time, add LV to list of LVs affected */
if (!lv_used) {
if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
log_error("lv_list alloc failed");
@@ -52,11 +70,12 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
}
start_le = lv_mirr->le_count;
if (!lv_extend_mirror(lv->vg->fid, lv_mirr,
seg->area[s].u.pv.pv,
seg->area[s].u.pv.pe,
seg->area_len, allocatable_pvs,
PVMOVE)) {
if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
seg->area_len, 0u, seg->area_len,
seg->area[s].u.pv.pv,
seg->area[s].u.pv.pe,
PVMOVE, allocatable_pvs,
lv->alloc)) {
log_error("Allocation for temporary "
"pvmove LV failed");
return 0;
@@ -77,6 +96,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
return 1;
}
/* Remove a temporary mirror */
int remove_pvmove_mirrors(struct volume_group *vg,
struct logical_volume *lv_mirr)
{
@@ -85,11 +105,13 @@ int remove_pvmove_mirrors(struct volume_group *vg,
struct lv_segment *seg, *mir_seg;
uint32_t s, c;
/* Loop through all LVs except the temporary mirror */
list_iterate(lvh, &vg->lvs) {
lv1 = list_item(lvh, struct lv_list)->lv;
if (lv1 == lv_mirr)
continue;
/* Find all segments that point at the temporary mirror */
list_iterate(segh, &lv1->segments) {
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
@@ -97,14 +119,19 @@ int remove_pvmove_mirrors(struct volume_group *vg,
seg->area[s].u.lv.lv != lv_mirr)
continue;
/* Find the mirror segment pointed at */
if (!(mir_seg = find_seg_by_le(lv_mirr,
seg->area[s].u.
lv.le))) {
seg->area[s].
u.lv.le))) {
/* FIXME Error message */
log_error("No segment found with LE");
return 0;
}
if (mir_seg->type != SEG_MIRRORED ||
/* Check the segment params are compatible */
/* FIXME Improve error mesg & remove restrcn */
if ((!(mir_seg->segtype->flags
& SEG_AREAS_MIRRORED)) ||
!(mir_seg->status & PVMOVE) ||
mir_seg->le != seg->area[s].u.lv.le ||
mir_seg->area_count != 2 ||
@@ -113,7 +140,11 @@ int remove_pvmove_mirrors(struct volume_group *vg,
return 0;
}
if (mir_seg->extents_moved == mir_seg->area_len)
/* Replace original segment with newly-mirrored
* area (or original if reverting)
*/
if (mir_seg->extents_copied ==
mir_seg->area_len)
c = 1;
else
c = 0;
@@ -122,9 +153,17 @@ int remove_pvmove_mirrors(struct volume_group *vg,
seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
mir_seg->type = SEG_STRIPED;
/* Replace mirror with old area */
if (!
(mir_seg->segtype =
get_segtype_from_string(vg->cmd,
"striped"))) {
log_error("Missing striped segtype");
return 0;
}
mir_seg->area_count = 1;
/* FIXME Assumes only one pvmove at a time! */
lv1->status &= ~LOCKED;
}
}
@@ -133,25 +172,24 @@ int remove_pvmove_mirrors(struct volume_group *vg,
return 1;
}
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
*lv_mirr)
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
{
struct list *segh;
struct lv_segment *seg;
list_iterate(segh, &lv_mirr->segments) {
seg = list_item(segh, struct lv_segment);
if (seg->type != SEG_MIRRORED)
if (!(seg->segtype->flags & SEG_AREAS_MIRRORED))
continue;
if (seg->area[0].type != AREA_PV)
continue;
return seg->area[0].u.pv.pv;
return dev_name(seg->area[0].u.pv.pv->dev);
}
return NULL;
}
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
{
struct list *segh;
struct lv_segment *seg;
@@ -162,7 +200,7 @@ struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_LV)
continue;
return get_pvmove_pv_from_lv_mirr(seg->area[s].u.lv.lv);
return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv);
}
}
@@ -170,7 +208,8 @@ struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
}
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
struct device *dev)
struct device *dev,
uint32_t lv_type)
{
struct list *lvh, *segh;
struct logical_volume *lv;
@@ -180,9 +219,10 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!(lv->status & PVMOVE))
if (!(lv->status & lv_type))
continue;
/* Check segment origins point to pvname */
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (seg->area[0].type != AREA_PV)
@@ -196,6 +236,21 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
return NULL;
}
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
struct volume_group *vg,
const char *name,
uint32_t lv_type)
{
struct physical_volume *pv;
if (!(pv = find_pv_by_name(cmd, name))) {
stack;
return NULL;
}
return find_pvmove_lv(vg, pv->dev, lv_type);
}
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv)
{
@@ -218,6 +273,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
if (lv1 == lv)
continue;
/* Find whether any segment points at the supplied LV */
list_iterate(segh, &lv1->segments) {
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
@@ -240,7 +296,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
return lvs;
}
float pvmove_percent(struct logical_volume *lv_mirr)
float copy_percent(struct logical_volume *lv_mirr)
{
uint32_t numerator = 0u, denominator = 0u;
struct list *segh;
@@ -248,11 +304,13 @@ float pvmove_percent(struct logical_volume *lv_mirr)
list_iterate(segh, &lv_mirr->segments) {
seg = list_item(segh, struct lv_segment);
if (!(seg->status & PVMOVE))
continue;
numerator += seg->extents_moved;
denominator += seg->area_len;
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
numerator += seg->extents_copied;
else
numerator += seg->area_len;
}
return denominator ? (float) numerator *100 / denominator : 100.0;

32
lib/metadata/segtypes.c Normal file
View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "toolcontext.h"
#include "segtypes.h"
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
const char *str)
{
struct segment_type *segtype;
list_iterate_items(segtype, &cmd->segtypes) {
if (!strcmp(segtype->name, str))
return segtype;
}
log_error("Unrecognised segment type %s", str);
return NULL;
}

88
lib/metadata/segtypes.h Normal file
View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _SEGTYPES_H
#define _SEGTYPES_H
struct segtype_handler;
struct cmd_context;
struct config_tree;
struct lv_segment;
struct formatter;
struct config_node;
struct hash_table;
struct dev_manager;
/* Feature flags */
#define SEG_CAN_SPLIT 0x00000001
#define SEG_AREAS_STRIPED 0x00000002
#define SEG_AREAS_MIRRORED 0x00000004
#define SEG_SNAPSHOT 0x00000008
#define SEG_FORMAT1_SUPPORT 0x00000010
#define SEG_VIRTUAL 0x00000020
struct segment_type {
struct list list;
struct cmd_context *cmd;
uint32_t flags;
struct segtype_handler *ops;
const char *name;
void *library;
void *private;
};
struct segtype_handler {
const char *(*name) (const struct lv_segment * seg);
void (*display) (const struct lv_segment * seg);
int (*text_export) (const struct lv_segment * seg,
struct formatter * f);
int (*text_import_area_count) (struct config_node * sn,
uint32_t *area_count);
int (*text_import) (struct lv_segment * seg,
const struct config_node * sn,
struct hash_table * pv_hash);
int (*merge_segments) (struct lv_segment * seg1,
struct lv_segment * seg2);
int (*compose_target_line) (struct dev_manager * dm, struct pool * mem,
struct config_tree * cft,
void **target_state,
struct lv_segment * seg, char *params,
size_t paramsize, const char **target,
int *pos, uint32_t *pvmove_mirror_count);
int (*target_percent) (void **target_state, struct pool * mem,
struct config_tree * cft,
struct lv_segment * seg, char *params,
uint64_t *total_numerator,
uint64_t *total_denominator, float *percent);
int (*target_present) (void);
void (*destroy) (const struct segment_type * segtype);
};
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
const char *str);
struct segment_type *init_striped_segtype(struct cmd_context *cmd);
struct segment_type *init_zero_segtype(struct cmd_context *cmd);
struct segment_type *init_error_segtype(struct cmd_context *cmd);
#ifdef SNAPSHOT_INTERNAL
struct segment_type *init_snapshot_segtype(struct cmd_context *cmd);
#endif
#ifdef MIRRORED_INTERNAL
struct segment_type *init_mirrored_segtype(struct cmd_context *cmd);
#endif
#endif

View File

@@ -0,0 +1 @@
init_segtype

31
lib/mirror/Makefile.in Normal file
View File

@@ -0,0 +1,31 @@
#
# Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of the LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES = mirrored.c
LIB_SHARED = liblvm2mirror.so
include ../../make.tmpl
.PHONY: install
install: liblvm2mirror.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2mirror.so.$(LIB_VERSION)
$(LN_S) -f liblvm2mirror.so.$(LIB_VERSION) $(libdir)/liblvm2mirror.so

251
lib/mirror/mirrored.c Normal file
View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "list.h"
#include "toolcontext.h"
#include "metadata.h"
#include "segtypes.h"
#include "display.h"
#include "text_export.h"
#include "text_import.h"
#include "config.h"
#include "defaults.h"
#include "lvm-string.h"
#include "targets.h"
#include "activate.h"
enum {
MIRR_DISABLED,
MIRR_RUNNING,
MIRR_COMPLETED
};
struct mirror_state {
uint32_t region_size;
};
static const char *_name(const struct lv_segment *seg)
{
return seg->segtype->name;
}
static void _display(const struct lv_segment *seg)
{
log_print(" Mirrors\t\t%u", seg->area_count);
log_print(" Mirror size\t\t%u", seg->area_len);
log_print(" Mirror original:");
display_stripe(seg, 0, " ");
log_print(" Mirror destination:");
display_stripe(seg, 1, " ");
log_print(" ");
}
static int _text_import_area_count(struct config_node *sn, uint32_t *area_count)
{
if (!get_config_uint32(sn, "mirror_count", area_count)) {
log_error("Couldn't read 'mirror_count' for "
"segment '%s'.", sn->key);
return 0;
}
return 1;
}
static int _text_import(struct lv_segment *seg, const struct config_node *sn,
struct hash_table *pv_hash)
{
const struct config_node *cn;
if (find_config_node(sn, "extents_moved")) {
if (get_config_uint32(sn, "extents_moved",
&seg->extents_copied))
seg->status |= PVMOVE;
else {
log_error("Couldn't read 'extents_moved' for "
"segment '%s'.", sn->key);
return 0;
}
}
if (!(cn = find_config_node(sn, "mirrors"))) {
log_error("Couldn't find mirrors array for segment "
"'%s'.", sn->key);
return 0;
}
return text_import_areas(seg, sn, cn, pv_hash);
}
static int _text_export(const struct lv_segment *seg, struct formatter *f)
{
outf(f, "mirror_count = %u", seg->area_count);
if (seg->status & PVMOVE)
out_size(f, (uint64_t) seg->extents_copied,
"extents_moved = %u", seg->extents_copied);
return out_areas(f, seg, "mirror");
}
#ifdef DEVMAPPER_SUPPORT
static struct mirror_state *_init_target(struct pool *mem,
struct config_tree *cft)
{
struct mirror_state *mirr_state;
if (!(mirr_state = pool_alloc(mem, sizeof(*mirr_state)))) {
log_error("struct mirr_state allocation failed");
return NULL;
}
mirr_state->region_size = 2 *
find_config_int(cft->root,
"activation/mirror_region_size",
DEFAULT_MIRROR_REGION_SIZE);
return mirr_state;
}
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
struct config_tree *cft, void **target_state,
struct lv_segment *seg, char *params,
size_t paramsize, const char **target, int *pos,
uint32_t *pvmove_mirror_count)
{
struct mirror_state *mirr_state;
int mirror_status = MIRR_RUNNING;
int areas = seg->area_count;
int start_area = 0u;
if (!*target_state)
*target_state = _init_target(mem, cft);
mirr_state = *target_state;
/* mirror log_type #log_params [log_params]*
* #mirrors [device offset]+
*/
if (seg->status & PVMOVE) {
if (seg->extents_copied == seg->area_len) {
mirror_status = MIRR_COMPLETED;
start_area = 1;
} else if (*pvmove_mirror_count++) {
mirror_status = MIRR_DISABLED;
areas = 1;
}
}
if (mirror_status != MIRR_RUNNING) {
*target = "linear";
} else {
*target = "mirror";
if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ",
mirr_state->region_size, areas)) < 0) {
stack;
return -1;
}
}
return compose_areas_line(dm, seg, params, paramsize, pos, start_area,
areas);
}
static int _target_percent(void **target_state, struct pool *mem,
struct config_tree *cft, struct lv_segment *seg,
char *params, uint64_t *total_numerator,
uint64_t *total_denominator, float *percent)
{
struct mirror_state *mirr_state;
uint64_t numerator, denominator;
if (!*target_state)
*target_state = _init_target(mem, cft);
mirr_state = *target_state;
log_debug("Mirror status: %s", params);
if (sscanf(params, "%*d %*x:%*x %*x:%*x %" PRIu64
"/%" PRIu64, &numerator, &denominator) != 2) {
log_error("Failure parsing mirror status: %s", params);
return 0;
}
*total_numerator += numerator;
*total_denominator += denominator;
if (seg)
seg->extents_copied = mirr_state->region_size *
numerator / seg->lv->vg->extent_size;
return 1;
}
static int _target_present(void)
{
static int checked = 0;
static int present = 0;
if (!checked)
present = target_present("mirror");
checked = 1;
return present;
}
#endif
static void _destroy(const struct segment_type *segtype)
{
dbg_free((void *) segtype);
}
static struct segtype_handler _mirrored_ops = {
name:_name,
display:_display,
text_import_area_count:_text_import_area_count,
text_import:_text_import,
text_export:_text_export,
#ifdef DEVMAPPER_SUPPORT
compose_target_line:_compose_target_line,
target_percent:_target_percent,
target_present:_target_present,
#endif
destroy:_destroy,
};
#ifdef MIRRORED_INTERNAL
struct segment_type *init_mirrored_segtype(struct cmd_context *cmd)
#else /* Shared */
struct segment_type *init_segtype(struct cmd_context *cmd);
struct segment_type *init_segtype(struct cmd_context *cmd)
#endif
{
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
if (!segtype) {
stack;
return NULL;
}
segtype->cmd = cmd;
segtype->ops = &_mirrored_ops;
segtype->name = "mirror";
segtype->private = NULL;
segtype->flags = SEG_AREAS_MIRRORED;
return segtype;
}

View File

@@ -24,7 +24,7 @@ int set_selinux_context(const char *path)
log_very_verbose("Setting SELinux context for %s", path);
if (is_selinux_enabled() <= 0)
return 0;
return 1;
if (matchpathcon(path, 0, &scontext) < 0) {
log_sys_error("matchpathcon", path);

View File

@@ -27,7 +27,7 @@ FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
FIELD(LVS, lv, NUM, "Move%", lvid, 6, movepercent, "move_percent")
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
@@ -45,7 +45,7 @@ FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
FIELD(VGS, vg, STR, "Attr", status, 4, vgstatus, "vg_attr")
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
@@ -67,4 +67,5 @@ FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize")
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
/* *INDENT-ON* */

View File

@@ -21,6 +21,7 @@
#include "lvm-string.h"
#include "display.h"
#include "activate.h"
#include "segtypes.h"
/*
* For macro use
@@ -97,6 +98,20 @@ struct row {
struct field *(*sort_fields)[]; /* Fields in sort order */
};
static char _alloc_policy_char(alloc_policy_t alloc)
{
switch (alloc) {
case ALLOC_CONTIGUOUS:
return 'c';
case ALLOC_NORMAL:
return 'n';
case ALLOC_ANYWHERE:
return 'a';
default:
return 'i';
}
}
/*
* Data-munging functions to prepare each data type for display and sorting
*/
@@ -123,6 +138,68 @@ static int _dev_name_disp(struct report_handle *rh, struct field *field,
return _string_disp(rh, field, &name);
}
static int _devices_disp(struct report_handle *rh, struct field *field,
const void *data)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
unsigned int s;
const char *name;
uint32_t extent;
char extent_str[32];
if (!pool_begin_object(rh->mem, 256)) {
log_error("pool_begin_object failed");
return 0;
}
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_LV:
name = seg->area[s].u.lv.lv->name;
extent = seg->area[s].u.lv.le;
break;
case AREA_PV:
name = dev_name(seg->area[s].u.pv.pv->dev);
extent = seg->area[s].u.pv.pe;
break;
default:
name = "unknown";
extent = 0;
}
if (!pool_grow_object(rh->mem, name, strlen(name))) {
log_error("pool_grow_object failed");
return 0;
}
if (lvm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
")", extent) < 0) {
log_error("Extent number lvm_snprintf failed");
return 0;
}
if (!pool_grow_object(rh->mem, extent_str, strlen(extent_str))) {
log_error("pool_grow_object failed");
return 0;
}
if ((s != seg->area_count - 1) &&
!pool_grow_object(rh->mem, ",", 1)) {
log_error("pool_grow_object failed");
return 0;
}
}
if (!pool_grow_object(rh->mem, "\0", 1)) {
log_error("pool_grow_object failed");
return 0;
}
field->report_string = pool_end_object(rh->mem);
field->sort_value = (const void *) field->report_string;
return 1;
}
static int _tags_disp(struct report_handle *rh, struct field *field,
const void *data)
{
@@ -198,6 +275,10 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
if (lv->status & PVMOVE)
repstr[0] = 'p';
else if (lv->status & MIRRORED)
repstr[0] = 'm';
else if (lv->status & VIRTUAL)
repstr[0] = 'v';
else if (lv_is_origin(lv))
repstr[0] = 'o';
else if (find_cow(lv))
@@ -212,10 +293,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
else
repstr[1] = 'r';
if (lv->alloc == ALLOC_CONTIGUOUS)
repstr[2] = 'c';
else
repstr[2] = 'n';
repstr[2] = _alloc_policy_char(lv->alloc);
if (lv->status & LOCKED)
repstr[2] = toupper(repstr[2]);
@@ -287,34 +365,36 @@ static int _pvstatus_disp(struct report_handle *rh, struct field *field,
static int _vgstatus_disp(struct report_handle *rh, struct field *field,
const void *data)
{
const uint32_t status = *(const uint32_t *) data;
const struct volume_group *vg = (const struct volume_group *) data;
char *repstr;
if (!(repstr = pool_zalloc(rh->mem, 5))) {
if (!(repstr = pool_zalloc(rh->mem, 6))) {
log_error("pool_alloc failed");
return 0;
}
if (status & LVM_WRITE)
if (vg->status & LVM_WRITE)
repstr[0] = 'w';
else
repstr[0] = 'r';
if (status & RESIZEABLE_VG)
if (vg->status & RESIZEABLE_VG)
repstr[1] = 'z';
else
repstr[1] = '-';
if (status & EXPORTED_VG)
if (vg->status & EXPORTED_VG)
repstr[2] = 'x';
else
repstr[2] = '-';
if (status & PARTIAL_VG)
if (vg->status & PARTIAL_VG)
repstr[3] = 'p';
else
repstr[3] = '-';
repstr[4] = _alloc_policy_char(vg->alloc);
field->report_string = repstr;
field->sort_value = (const void *) field->report_string;
@@ -329,7 +409,7 @@ static int _segtype_disp(struct report_handle *rh, struct field *field,
if (seg->area_count == 1)
field->report_string = "linear";
else
field->report_string = get_segtype_string(seg->type);
field->report_string = seg->segtype->ops->name(seg);
field->sort_value = (const void *) field->report_string;
return 1;
@@ -379,7 +459,7 @@ static int _size32_disp(struct report_handle *rh, struct field *field,
const char *disp;
uint64_t *sortval;
if (!*(disp = display_size(rh->cmd, (uint64_t) size / 2, SIZE_UNIT))) {
if (!*(disp = display_size(rh->cmd, (uint64_t) size, SIZE_UNIT))) {
stack;
return 0;
}
@@ -407,7 +487,7 @@ static int _size64_disp(struct report_handle *rh, struct field *field,
const char *disp;
uint64_t *sortval;
if (!*(disp = display_size(rh->cmd, size / 2, SIZE_UNIT))) {
if (!*(disp = display_size(rh->cmd, size, SIZE_UNIT))) {
stack;
return 0;
}
@@ -654,11 +734,11 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
return 1;
}
static int _movepercent_disp(struct report_handle *rh, struct field *field,
static int _copypercent_disp(struct report_handle *rh, struct field *field,
const void *data)
{
struct logical_volume *lv = (struct logical_volume *) data;
float move_percent;
float percent;
uint64_t *sortval;
char *repstr;
@@ -667,27 +747,27 @@ static int _movepercent_disp(struct report_handle *rh, struct field *field,
return 0;
}
if (!(lv->status & PVMOVE) ||
!lv_mirror_percent(lv, 0, &move_percent, NULL)) {
if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
!lv_mirror_percent(lv, 0, &percent, NULL)) {
field->report_string = "";
*sortval = UINT64_C(0);
field->sort_value = sortval;
return 1;
}
move_percent = pvmove_percent(lv);
percent = copy_percent(lv);
if (!(repstr = pool_zalloc(rh->mem, 8))) {
log_error("pool_alloc failed");
return 0;
}
if (lvm_snprintf(repstr, 7, "%.2f", move_percent) < 0) {
log_error("move percentage too large");
if (lvm_snprintf(repstr, 7, "%.2f", percent) < 0) {
log_error("copy percentage too large");
return 0;
}
*sortval = move_percent * UINT64_C(1000);
*sortval = percent * UINT64_C(1000);
field->sort_value = sortval;
field->report_string = repstr;
@@ -1060,32 +1140,58 @@ static int _report_headings(void *handle)
struct report_handle *rh = handle;
struct list *fh;
struct field_properties *fp;
const char *heading;
char buf[1024];
if (rh->flags & RH_HEADINGS_PRINTED)
return 1;
rh->flags |= RH_HEADINGS_PRINTED;
if (!(rh->flags & RH_HEADINGS))
goto out;
return 1;
if (!pool_begin_object(rh->mem, 128)) {
log_error("pool_begin_object failed for headings");
return 0;
}
/* First heading line */
list_iterate(fh, &rh->field_props) {
fp = list_item(fh, struct field_properties);
if (fp->flags & FLD_HIDDEN)
continue;
if (rh->flags & RH_ALIGNED)
printf("%-*.*s", fp->width, fp->width,
_fields[fp->field_num].heading);
else
printf("%s", _fields[fp->field_num].heading);
if (!list_end(&rh->field_props, fh))
printf("%s", rh->separator);
}
printf("\n");
out:
rh->flags |= RH_HEADINGS_PRINTED;
heading = _fields[fp->field_num].heading;
if (rh->flags & RH_ALIGNED) {
if (lvm_snprintf(buf, sizeof(buf), "%-*.*s",
fp->width, fp->width, heading) < 0) {
log_error("snprintf heading failed");
pool_end_object(rh->mem);
return 0;
}
if (!pool_grow_object(rh->mem, buf, fp->width))
goto bad;
} else if (!pool_grow_object(rh->mem, heading, strlen(heading)))
goto bad;
if (!list_end(&rh->field_props, fh))
if (!pool_grow_object(rh->mem, rh->separator,
strlen(rh->separator)))
goto bad;
}
if (!pool_grow_object(rh->mem, "\0", 1)) {
log_error("pool_grow_object failed");
goto bad;
}
log_print("%s", (char *) pool_end_object(rh->mem));
return 1;
bad:
log_error("Failed to generate report headings for printing");
return 0;
}
/*
@@ -1170,6 +1276,9 @@ int report_output(void *handle)
struct list *fh, *rowh, *ftmp, *rtmp;
struct row *row = NULL;
struct field *field;
const char *repstr;
char buf[4096];
int width;
if (list_empty(&rh->rows))
return 1;
@@ -1184,26 +1293,53 @@ int report_output(void *handle)
/* Print and clear buffer */
list_iterate_safe(rowh, rtmp, &rh->rows) {
if (!pool_begin_object(rh->mem, 512)) {
log_error("pool_begin_object failed for row");
return 0;
}
row = list_item(rowh, struct row);
list_iterate_safe(fh, ftmp, &row->fields) {
field = list_item(fh, struct field);
if (field->props->flags & FLD_HIDDEN)
continue;
if (!(rh->flags & RH_ALIGNED))
printf("%s", field->report_string);
else if (field->props->flags & FLD_ALIGN_LEFT)
printf("%-*.*s", field->props->width,
field->props->width,
field->report_string);
else if (field->props->flags & FLD_ALIGN_RIGHT)
printf("%*.*s", field->props->width,
field->props->width,
field->report_string);
repstr = field->report_string;
width = field->props->width;
if (!(rh->flags & RH_ALIGNED)) {
if (!pool_grow_object(rh->mem, repstr,
strlen(repstr)))
goto bad;
} else if (field->props->flags & FLD_ALIGN_LEFT) {
if (lvm_snprintf(buf, sizeof(buf), "%-*.*s",
width, width, repstr) < 0) {
log_error("snprintf repstr failed");
pool_end_object(rh->mem);
return 0;
}
if (!pool_grow_object(rh->mem, buf, width))
goto bad;
} else if (field->props->flags & FLD_ALIGN_RIGHT) {
if (lvm_snprintf(buf, sizeof(buf), "%*.*s",
width, width, repstr) < 0) {
log_error("snprintf repstr failed");
pool_end_object(rh->mem);
return 0;
}
if (!pool_grow_object(rh->mem, buf, width))
goto bad;
}
if (!list_end(&row->fields, fh))
printf("%s", rh->separator);
if (!pool_grow_object(rh->mem, rh->separator,
strlen(rh->separator)))
goto bad;
list_del(&field->list);
}
printf("\n");
if (!pool_grow_object(rh->mem, "\0", 1)) {
log_error("pool_grow_object failed for row");
return 0;
}
log_print("%s", (char *) pool_end_object(rh->mem));
list_del(&row->list);
}
@@ -1211,4 +1347,8 @@ int report_output(void *handle)
pool_free(rh->mem, row);
return 1;
bad:
log_error("Failed to generate row for printing");
return 0;
}

View File

@@ -0,0 +1 @@
init_segtype

32
lib/snapshot/Makefile.in Normal file
View File

@@ -0,0 +1,32 @@
#
# Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of the LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES = snapshot.c
LIB_SHARED = liblvm2snapshot.so
include ../../make.tmpl
.PHONY: install
install: liblvm2snapshot.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2snapshot.so.$(LIB_VERSION)
$(LN_S) -f liblvm2snapshot.so.$(LIB_VERSION) \
$(libdir)/liblvm2snapshot.so

165
lib/snapshot/snapshot.c Normal file
View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "list.h"
#include "toolcontext.h"
#include "metadata.h"
#include "segtypes.h"
#include "text_export.h"
#include "config.h"
#include "activate.h"
static const char *_name(const struct lv_segment *seg)
{
return seg->segtype->name;
}
static int _text_import(struct lv_segment *seg, const struct config_node *sn,
struct hash_table *pv_hash)
{
uint32_t chunk_size;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
seg->lv->status |= SNAPSHOT;
if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
log_error("Couldn't read chunk size for snapshot.");
return 0;
}
log_suppress(1);
if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
log_suppress(0);
log_error("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", NULL))) {
log_suppress(0);
log_error("Snapshot origin not specified.");
return 0;
}
log_suppress(0);
if (!(cow = find_lv(seg->lv->vg, cow_name))) {
log_error("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(seg->lv->vg, org_name))) {
log_error("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], chunk_size)) {
stack;
return 0;
}
return 1;
}
static int _text_export(const struct lv_segment *seg, struct formatter *f)
{
outf(f, "chunk_size = %u", seg->chunk_size);
outf(f, "origin = \"%s\"", seg->origin->name);
outf(f, "cow_store = \"%s\"", seg->cow->name);
return 1;
}
#ifdef DEVMAPPER_SUPPORT
static int _target_percent(void **target_state, struct pool *mem,
struct config_tree *cft, struct lv_segment *seg,
char *params, uint64_t *total_numerator,
uint64_t *total_denominator, float *percent)
{
float percent2;
uint64_t numerator, denominator;
if (index(params, '/')) {
if (sscanf(params, "%" PRIu64 "/%" PRIu64,
&numerator, &denominator) == 2) {
*total_numerator += numerator;
*total_denominator += denominator;
}
} else if (sscanf(params, "%f", &percent2) == 1) {
*percent += percent2;
*percent /= 2;
}
return 1;
}
static int _target_present(void)
{
static int checked = 0;
static int present = 0;
if (!checked)
present = target_present("snapshot") &&
target_present("snapshot-origin");
checked = 1;
return present;
}
#endif
static void _destroy(const struct segment_type *segtype)
{
dbg_free((void *) segtype);
}
static struct segtype_handler _snapshot_ops = {
name:_name,
text_import:_text_import,
text_export:_text_export,
#ifdef DEVMAPPER_SUPPORT
target_percent:_target_percent,
target_present:_target_present,
#endif
destroy:_destroy,
};
#ifdef SNAPSHOT_INTERNAL
struct segment_type *init_snapshot_segtype(struct cmd_context *cmd)
#else /* Shared */
struct segment_type *init_segtype(struct cmd_context *cmd);
struct segment_type *init_segtype(struct cmd_context *cmd)
#endif
{
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
if (!segtype) {
stack;
return NULL;
}
segtype->cmd = cmd;
segtype->ops = &_snapshot_ops;
segtype->name = "snapshot";
segtype->private = NULL;
segtype->flags = SEG_SNAPSHOT;
return segtype;
}

221
lib/striped/striped.c Normal file
View File

@@ -0,0 +1,221 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "list.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "display.h"
#include "text_export.h"
#include "text_import.h"
#include "config.h"
#include "str_list.h"
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
static const char *_name(const struct lv_segment *seg)
{
return (seg->area_count == 1) ? "linear" : seg->segtype->name;
}
static void _display(const struct lv_segment *seg)
{
uint32_t s;
if (seg->area_count == 1)
display_stripe(seg, 0, " ");
else {
log_print(" Stripes\t\t%u", seg->area_count);
log_print(" Stripe size\t\t%u KB", seg->stripe_size / 2);
for (s = 0; s < seg->area_count; s++) {
log_print(" Stripe %d:", s);
display_stripe(seg, s, " ");
}
}
log_print(" ");
}
static int _text_import_area_count(struct config_node *sn, uint32_t *area_count)
{
if (!get_config_uint32(sn, "stripe_count", area_count)) {
log_error("Couldn't read 'stripe_count' for "
"segment '%s'.", sn->key);
return 0;
}
return 1;
}
static int _text_import(struct lv_segment *seg, const struct config_node *sn,
struct hash_table *pv_hash)
{
struct config_node *cn;
if ((seg->area_count != 1) &&
!get_config_uint32(sn, "stripe_size", &seg->stripe_size)) {
log_error("Couldn't read stripe_size for segment '%s'.",
sn->key);
return 0;
}
if (!(cn = find_config_node(sn, "stripes"))) {
log_error("Couldn't find stripes array for segment "
"'%s'.", sn->key);
return 0;
}
seg->area_len /= seg->area_count;
return text_import_areas(seg, sn, cn, pv_hash);
}
static int _text_export(const struct lv_segment *seg, struct formatter *f)
{
outf(f, "stripe_count = %u%s", seg->area_count,
(seg->area_count == 1) ? "\t# linear" : "");
if (seg->area_count > 1)
out_size(f, (uint64_t) seg->stripe_size,
"stripe_size = %u", seg->stripe_size);
return out_areas(f, seg, "stripe");
}
/*
* Test whether two segments could be merged by the current merging code
*/
static int _segments_compatible(struct lv_segment *first,
struct lv_segment *second)
{
uint32_t width;
unsigned s;
if ((first->area_count != second->area_count) ||
(first->stripe_size != second->stripe_size)) return 0;
for (s = 0; s < first->area_count; s++) {
/* FIXME Relax this to first area type != second area type */
/* plus the additional AREA_LV checks needed */
if ((first->area[s].type != AREA_PV) ||
(second->area[s].type != AREA_PV)) return 0;
width = first->area_len;
if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
(first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
return 0;
}
if (!str_list_lists_equal(&first->tags, &second->tags))
return 0;
return 1;
}
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
{
if (!_segments_compatible(seg1, seg2))
return 0;
seg1->len += seg2->len;
seg1->area_len += seg2->area_len;
return 1;
}
#ifdef DEVMAPPER_SUPPORT
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
struct config_tree *cft, void **target_state,
struct lv_segment *seg, char *params,
size_t paramsize, const char **target, int *pos,
uint32_t *pvmove_mirror_count)
{
/* linear [device offset]+
* striped #stripes stripe_size [device offset]+ */
if (seg->area_count == 1)
*target = "linear";
else if (seg->area_count > 1) {
*target = "striped";
if ((*pos = lvm_snprintf(params, paramsize, "%u %u ",
seg->area_count,
seg->stripe_size)) < 0) {
stack;
return -1;
}
} else {
log_error("Internal error: striped target with no stripes");
return 0;
}
return compose_areas_line(dm, seg, params, paramsize, pos, 0u,
seg->area_count);
}
static int _target_present(void)
{
static int checked = 0;
static int present = 0;
if (!checked)
present = target_present("linear") && target_present("striped");
checked = 1;
return present;
}
#endif
static void _destroy(const struct segment_type *segtype)
{
dbg_free((void *) segtype);
}
static struct segtype_handler _striped_ops = {
name:_name,
display:_display,
text_import_area_count:_text_import_area_count,
text_import:_text_import,
text_export:_text_export,
merge_segments:_merge_segments,
#ifdef DEVMAPPER_SUPPORT
compose_target_line:_compose_target_line,
target_present:_target_present,
#endif
destroy:_destroy,
};
struct segment_type *init_striped_segtype(struct cmd_context *cmd)
{
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
if (!segtype) {
stack;
return NULL;
}
segtype->cmd = cmd;
segtype->ops = &_striped_ops;
segtype->name = "striped";
segtype->private = NULL;
segtype->flags =
SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
return segtype;
}

101
lib/zero/zero.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "pool.h"
#include "list.h"
#include "toolcontext.h"
#include "segtypes.h"
#include "display.h"
#include "text_export.h"
#include "text_import.h"
#include "config.h"
#include "str_list.h"
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
static const char *_name(const struct lv_segment *seg)
{
return seg->segtype->name;
}
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
{
seg1->len += seg2->len;
seg1->area_len += seg2->area_len;
return 1;
}
#ifdef DEVMAPPER_SUPPORT
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
struct config_tree *cft, void **target_state,
struct lv_segment *seg, char *params,
size_t paramsize, const char **target, int *pos,
uint32_t *pvmove_mirror_count)
{
/* zero */
*target = "zero";
*params = '\0';
return 1;
}
static int _target_present(void)
{
static int checked = 0;
static int present = 0;
if (!checked)
present = target_present("zero");
checked = 1;
return present;
}
#endif
static void _destroy(const struct segment_type *segtype)
{
dbg_free((void *) segtype);
}
static struct segtype_handler _zero_ops = {
name:_name,
merge_segments:_merge_segments,
#ifdef DEVMAPPER_SUPPORT
compose_target_line:_compose_target_line,
target_present:_target_present,
#endif
destroy:_destroy,
};
struct segment_type *init_zero_segtype(struct cmd_context *cmd)
{
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
if (!segtype) {
stack;
return NULL;
}
segtype->cmd = cmd;
segtype->ops = &_zero_ops;
segtype->name = "zero";
segtype->private = NULL;
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
return segtype;
}

View File

@@ -17,6 +17,8 @@ dm_task_set_newname
dm_task_set_event_nr
dm_task_set_major
dm_task_set_minor
dm_task_set_sector
dm_task_set_message
dm_task_add_target
dm_get_next_target
dm_task_run

View File

@@ -115,6 +115,7 @@ static struct cmd_data _cmd_data_v1[] = {
{ "clear", 0, {4, 0, 0} },
{ "mknodes", 0, {4, 0, 0} },
{ "versions", 0, {4, 1, 0} },
{ "message", 0, {4, 2, 0} },
};
/* *INDENT-ON* */

View File

@@ -93,6 +93,9 @@ static struct cmd_data _cmd_data_v4[] = {
#ifdef DM_LIST_VERSIONS
{"versions", DM_LIST_VERSIONS, {4, 1, 0}},
#endif
#ifdef DM_TARGET_MSG
{"message", DM_TARGET_MSG, {4, 2, 0}},
#endif
};
/* *INDENT-ON* */
@@ -146,6 +149,9 @@ void dm_task_destroy(struct dm_task *dmt)
if (dmt->newname)
free(dmt->newname);
if (dmt->message)
free(dmt->message);
if (dmt->dmi.v4)
free(dmt->dmi.v4);
@@ -190,8 +196,9 @@ static int _unmarshal_status_v1(struct dm_task *dmt, struct dm_ioctl_v1 *dmi)
if (!dm_task_add_target(dmt, spec->sector_start,
(uint64_t) spec->length,
spec->target_type,
outptr + sizeof(*spec)))
outptr + sizeof(*spec))) {
return 0;
}
outptr = outbuf + spec->next;
}
@@ -652,8 +659,9 @@ static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
if (!dm_task_add_target(dmt, spec->sector_start,
spec->length,
spec->target_type,
outptr + sizeof(*spec)))
outptr + sizeof(*spec))) {
return 0;
}
outptr = outbuf + spec->next;
}
@@ -775,6 +783,23 @@ int dm_task_set_newname(struct dm_task *dmt, const char *newname)
return 1;
}
int dm_task_set_message(struct dm_task *dmt, const char *message)
{
if (!(dmt->message = strdup(message))) {
log_error("dm_task_set_message: strdup(%s) failed", message);
return 0;
}
return 1;
}
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
{
dmt->sector = sector;
return 1;
}
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr)
{
dmt->event_nr = event_nr;
@@ -861,6 +886,7 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
struct dm_ioctl *dmi;
struct target *t;
struct dm_target_msg *tmsg;
size_t len = sizeof(struct dm_ioctl);
void *b, *e;
int count = 0;
@@ -871,14 +897,32 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
count++;
}
if (count && (dmt->sector || dmt->message)) {
log_error("targets and message are incompatible");
return NULL;
}
if (count && dmt->newname) {
log_error("targets and newname are incompatible");
return NULL;
}
if (dmt->newname && (dmt->sector || dmt->message)) {
log_error("message and newname are incompatible");
return NULL;
}
if (dmt->sector && !dmt->message) {
log_error("message is required with sector");
return NULL;
}
if (dmt->newname)
len += strlen(dmt->newname) + 1;
if (dmt->message)
len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
/*
* Give len a minimum size so that we have space to store
* dependencies or status information.
@@ -933,6 +977,12 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
if (dmt->newname)
strcpy(b, dmt->newname);
if (dmt->message) {
tmsg = (struct dm_target_msg *) b;
tmsg->sector = dmt->sector;
strcpy(tmsg->message, dmt->message);
}
return dmi;
bad:
@@ -1118,8 +1168,9 @@ int dm_task_run(struct dm_task *dmt)
dmi->flags |= DM_STATUS_TABLE_FLAG;
dmi->flags |= DM_EXISTS_FLAG; /* FIXME */
log_debug("dm %s %s %s %s", _cmd_data_v4[dmt->type].name, dmi->name,
dmi->uuid, dmt->newname ? dmt->newname : "");
log_debug("dm %s %s %s %s%.0llu %s", _cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? dmt->newname : "",
dmt->sector, dmt->message ? dmt->message : "");
if (ioctl(_control_fd, command, dmi) < 0) {
if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
(dmt->type == DM_DEVICE_MKNODES))) {

View File

@@ -45,6 +45,8 @@ struct dm_task {
struct dm_ioctl_v1 *v1;
} dmi;
char *newname;
char *message;
uint64_t sector;
char *uuid;
};

View File

@@ -68,7 +68,9 @@ enum {
DM_DEVICE_MKNODES,
DM_DEVICE_LIST_VERSIONS
DM_DEVICE_LIST_VERSIONS,
DM_DEVICE_TARGET_MSG
};
struct dm_task;
@@ -130,6 +132,8 @@ int dm_task_set_newname(struct dm_task *dmt, const char *newname);
int dm_task_set_minor(struct dm_task *dmt, int minor);
int dm_task_set_major(struct dm_task *dmt, int major);
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
int dm_task_set_message(struct dm_task *dmt, const char *message);
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
/*
* Use these to prepare for a create or reload.

View File

@@ -0,0 +1,6 @@
all:
echo "Nothing to do for make all"
manpage:
pod2man --center="create LVM2 initrd" --name='lvm2create_initrd' --section=8 -r 'lvm2create_initrd' ./lvm2create_initrd.pod > lvm2create_initrd.8

View File

@@ -0,0 +1,40 @@
http://poochiereds.net/svn/lvm2/
This is the lvm2create_initrd script written by Miguel Cabeca, with some small
modifications by myself.
Here are some other requirements and tips for using it:
1) this script uses busybox on the initrd image, hence busybox needs to be
installed when you create your initrd.
2) Make sure /etc/lvm/lvm.conf is set up correctly before running this. In
particular, if you're using LVM on RAID, make sure that you have a filter that
excludes the RAID component devices (this may not be necessary with the latest
patch by Luca Berra, but it doesn't hurt).
3) This initrd image does not support modules. If you need to plug in any
kernel modules during the initrd phase, then you'll need to hand-modify the
image.
4) The generated initrd image supports an 'lvm2rescue' mode as well. If you add
the parameter 'lvmrescue' on the kernel command line, it will run a shell at
the end of the initrd 'init' script. This can be helpful when trying to fix a
corrupt root volume or root LVM2 volume group.
5) No userspace md tools are installed, so if you're using LVM on RAID, then
you'll probably want to mark your RAID partitions as type 'fd' so that the
kernel will start them automagically (or hand-modify the image).
6) I'm not sure if devfs will work with this or not. udev, however does work,
and is recommended. Because the dm-* devices use dynamically allocated major
and minor numbers, kernel upgrades and the like can renumber your devices. To
fix this, you need to run a 'vgscan --mknodes' prior to fscking and mounting
your rootfs. Doing this with a static /dev creates a problem though -- you
will be modifying the root filesystem before it has been fsck'ed. udev gets
around this by mounting a ramdisk over /dev, but you'll probably need to add
a startup script that creates devices in /dev. The lvm2udev script in this
directory is an example of such a beast.
--
Jeffrey Layton <jtlayton@poochiereds.net>

View File

@@ -0,0 +1,476 @@
#!/bin/bash
#
# lvm2create_initrd
#
# Miguel Cabeca
# cabeca (at) ist (dot) utl (dot) pt
#
# Inspiration to write this script came from various sources
#
# Original LVM lvmcreate_initrd: ftp://ftp.sistina.com/pub/LVM/1.0/
# Kernel initrd.txt: http://www.kernel.org/
# EVMS INSTALL.initrd & linuxrc: http://evms.sourceforge.net/
# Jeffrey Layton's lvm2create_initrd: http://poochiereds.net/svn/lvm2create_initrd/
# Christophe Saout's initrd & linuxrc: http://www.saout.de/misc/
#
# This script was only tested with kernel 2.6 with everything required to boot
# the root filesystem built-in (not as modules). Ex: SCSI or IDE, RAID, device mapper
# It does not support devfs as it is deprecated in the 2.6 kernel series
#
# It needs lvm2 tools, busybox, pivot_root, MAKEDEV
#
# It has been tested on Debian sid (unstable) only
#
# Changelog
# 26/02/2004 Initial release -- Miguel Cabeca
# 27/02/2004 Removed the BUSYBOXSYMLINKS var. The links are now determined at runtime.
# some changes in init script to call a shell if something goes wrong. -- Miguel Cabeca
# 19/04/2004 Several small changes. Pass args to init so single user mode works. Add some
# PATH entries to /sbin/init shell script so chroot works without /usr mounted. Remove
# mkdir /initrd so we don't cause problems if root filesystem is corrupted. -- Jeff Layton
# 15/05/2004 initial support for modules, create lvm.conf from lvm dumpconfig, other cleanups -- Jeff Layton
#
# Copyright Miguel Cabeca, Jeffrey Layton, 2004
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
TMPMNT=/tmp/mnt.$$
DEVRAM=/tmp/initrd.$$
# set defaults
BINFILES=${BINFILES:-"/lib/lvm-200/lvm /bin/bash /bin/busybox /sbin/pivot_root"}
BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"}
BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"}
MAKEDEV=${MAKEDEV:-"debian"}
# Uncomment this if you want to disable automatic size detection
#INITRDSIZE=4096
PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
usage () {
echo "Create an initial ramdisk image for LVM2 root filesystem"
echo "$cmd: [-h] [-v] [-c lvm.conf] [-m modulelist] [-e extrafiles] -r [raiddevs] [-R mdadm.conf] [-M style] [kernel version]"
echo " -h|--help print this usage message"
echo " -v|--verbose verbose progress messages"
echo " -c|--lvmconf path to lvm.conf (/etc/lvm/lvm.conf)"
echo " -m|--modules modules to copy to initrd image"
echo " -e|--extra extra files to add to initrd"
echo " -r|--raid raid devices to start in initrd"
echo " -R|--raidconf location of mdadm.conf file to include"
echo " -M|--makedev set MAKEDEV type (debian or redhat)"
}
verbose () {
[ "$VERBOSE" ] && echo "`echo $cmd | tr '[a-z0-9/_]' ' '` -- $1" || true
}
cleanup () {
[ "`mount | grep $DEVRAM`" ] && verbose "unmounting $DEVRAM" && umount $DEVRAM
[ -f $DEVRAM ] && verbose "removing $DEVRAM" && rm $DEVRAM
[ -d $TMPMNT ] && verbose "removing $TMPMNT" && rmdir $TMPMNT
verbose "exit with code $1"
exit $1
}
trap "
verbose 'Caught interrupt'
echo 'Bye bye...'
cleanup 1
" 1 2 3 15
create_init () {
cat << 'INIT' > $TMPMNT/sbin/init
#!/bin/bash
# include in the path some dirs from the real root filesystem
# for chroot, blockdev
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/lib/lvm-200:/initrd/bin:/initrd/sbin"
PRE="initrd:"
do_shell(){
/bin/echo
/bin/echo "*** Entering LVM2 rescue shell. Exit shell to continue booting. ***"
/bin/echo
/bin/bash
}
echo "$PRE Remounting / read/write"
mount -t ext2 -o remount,rw /dev/ram0 /
# We need /proc for device mapper
echo "$PRE Mounting /proc"
mount -t proc none /proc
# plug in modules listed in /etc/modules
if [ -f /etc/modules ]; then
echo -n "$PRE plugging in kernel modules:"
cat /etc/modules |
while read module; do
echo -n " $module"
modprobe $module
done
echo '.'
fi
# start raid devices if raid_autostart file exists
if [ -f /etc/raid_autostart ]; then
if [ ! -f /etc/mdadm/mdadm.conf ]; then
mdoptions='--super-minor=dev'
fi
cat /etc/raid_autostart|
while read dev; do
echo "Starting RAID device $dev"
/sbin/mdadm --assemble $dev $mdoptions
done
fi
# Create the /dev/mapper/control device for the ioctl
# interface using the major and minor numbers that have been allocated
# dynamically.
echo -n "$PRE Finding device mapper major and minor numbers "
MAJOR=$(sed -n 's/^ *\([0-9]\+\) \+misc$/\1/p' /proc/devices)
MINOR=$(sed -n 's/^ *\([0-9]\+\) \+device-mapper$/\1/p' /proc/misc)
if test -n "$MAJOR" -a -n "$MINOR" ; then
mkdir -p -m 755 /dev/mapper
mknod -m 600 /dev/mapper/control c $MAJOR $MINOR
fi
echo "($MAJOR,$MINOR)"
# Device-Mapper dynamically allocates all device numbers. This means it is possible
# that the root volume specified to LILO or Grub may have a different number when the
# initrd runs than when the system was last running. In order to make sure the
# correct volume is mounted as root, the init script must determine what the
# desired root volume name is by getting the LVM2 root volume name from the kernel command line. In order for
# this to work correctly, "lvm2root=/dev/Volume_Group_Name/Root_Volume_Name" needs to be passed
# to the kernel command line (where Root_Volume_Name is replaced by your actual
# root volume's name.
for arg in `cat /proc/cmdline`; do
echo $arg | grep '^lvm2root=' > /dev/null
if [ $? -eq 0 ]; then
rootvol=${arg#lvm2root=}
break
fi
done
echo "$PRE Activating LVM2 volumes"
# run a shell if we're passed lvm2rescue on commandline
grep lvm2rescue /proc/cmdline 1>/dev/null 2>&1
if [ $? -eq 0 ]; then
lvm vgchange --ignorelockingfailure -P -a y
do_shell
else
lvm vgchange --ignorelockingfailure -a y
fi
echo "$PRE Mounting root filesystem $rootvol ro"
mkdir /rootvol
if ! mount -t auto -o ro $rootvol /rootvol; then
echo "\t*FAILED*";
do_shell
fi
echo "$PRE Umounting /proc"
umount /proc
echo "$PRE Changing roots"
cd /rootvol
if ! pivot_root . initrd ; then
echo "\t*FAILED*"
do_shell
fi
echo "$PRE Proceeding with boot..."
exec chroot . /bin/sh -c "umount /initrd; blockdev --flushbufs /dev/ram0 ; exec /sbin/init $*" < dev/console > dev/console 2>&1
INIT
chmod 555 $TMPMNT/sbin/init
}
# create lvm.conf file from dumpconfig. Just use filter options
create_lvmconf () {
echo 'devices {' > $TMPMNT/etc/lvm/lvm.conf
lvm dumpconfig | grep 'filter=' >> $TMPMNT/etc/lvm/lvm.conf
echo '}' >> $TMPMNT/etc/lvm/lvm.conf
}
#
# Main
#
cmd=`basename $0`
VERSION=`uname -r`
while [ $# -gt 0 ]; do
case $1 in
-h|--help) usage; exit 0;;
-v|--verbose) VERBOSE="y";;
-c|--lvmconf) LVMCONF=$2; shift;;
-m|--modules) MODULES=$2; shift;;
-e|--extra) EXTRAFILES=$2; shift;;
-r|--raid) RAID=$2; shift;;
-R|--raidconf) RAIDCONF=$2; shift;;
-M|--makedev) MAKEDEV=$2; shift;;
[2-9].[0-9]*.[0-9]*) VERSION=$1;;
*) echo "$cmd -- invalid option '$1'"; usage; exit 0;;
esac
shift
done
INITRD=${INITRD:-"/boot/initrd-lvm2-$VERSION.gz"}
echo "$cmd -- make LVM initial ram disk $INITRD"
echo ""
if [ -n "$RAID" ]; then
BINFILES="$BINFILES /sbin/mdadm"
RAIDCONF=${RAIDCONF:-"/etc/mdadm/mdadm.conf"}
if [ -r $RAIDCONF ]; then
EXTRAFILES="$EXTRAFILES $RAIDCONF"
else
echo "$cmd -- WARNING: No $RAIDCONF! Your RAID device minor numbers must match their superblock values!"
fi
fi
# add modprobe if we declared any modules
if [ -n "$MODULES" ]; then
BINFILES="$BINFILES /sbin/modprobe /sbin/insmod /sbin/rmmod"
fi
for a in $BINFILES $EXTRAFILES; do
if [ ! -r "$a" ] ; then
echo "$cmd -- ERROR: you need $a"
exit 1;
fi;
done
# Figure out which shared libraries we actually need in our initrd
echo "$cmd -- finding required shared libraries"
verbose "BINFILES: `echo $BINFILES`"
LIBFILES=`ldd $BINFILES 2>/dev/null | awk '{if (/=>/) { print $3 }}' | sort -u`
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR figuring out needed shared libraries"
exit 1
fi
verbose "Shared libraries needed: `echo $LIBFILES`"
INITRDFILES="$BINFILES $LIBFILES $MODULES $EXTRAFILES"
# tack on stuff for modules if we declared any and the files exist
if [ -n "$MODULES" ]; then
if [ -f "/etc/modprobe.conf" ]; then
INITRDFILES="$INITRDFILES /etc/modprobe.conf"
fi
if [ -f "/lib/modules/modprobe.conf" ]; then
INITRDFILES="$INITRDFILES /lib/modules/modprobe.conf"
fi
fi
# Calculate the the size of the ramdisk image.
# Don't forget that inodes take up space too, as does the filesystem metadata.
echo "$cmd -- calculating initrd filesystem parameters"
if [ -z "$INITRDSIZE" ]; then
echo "$cmd -- calculating loopback file size"
verbose "finding size"
INITRDSIZE="`du -Lck $INITRDFILES | tail -1 | cut -f 1`"
verbose "minimum: $INITRDSIZE kB for files + inodes + filesystem metadata"
INITRDSIZE=`expr $INITRDSIZE + 512` # enough for ext2 fs + a bit
fi
echo "$cmd -- making loopback file ($INITRDSIZE kB)"
verbose "using $DEVRAM as a temporary loopback file"
dd if=/dev/zero of=$DEVRAM count=$INITRDSIZE bs=1024 > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR creating loopback file"
cleanup 1
fi
echo "$cmd -- making ram disk filesystem"
verbose "mke2fs -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE"
[ "$VERBOSE" ] && OPT_Q="" || OPT_Q="-q"
mke2fs $OPT_Q -F -m0 -L LVM-$VERSION $DEVRAM $INITRDSIZE
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR making ram disk filesystem"
echo "$cmd -- ERROR you need to use mke2fs >= 1.14 or increase INITRDSIZE"
cleanup 1
fi
verbose "creating mountpoint $TMPMNT"
mkdir $TMPMNT
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR making $TMPMNT"
cleanup 1
fi
echo "$cmd -- mounting ram disk filesystem"
verbose "mount -o loop $DEVRAM $TMPMNT"
mount -oloop $DEVRAM $TMPMNT
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR mounting $DEVRAM on $TMPMNT"
cleanup 1
fi
verbose "creating basic set of directories in $TMPMNT"
(cd $TMPMNT; mkdir bin dev etc lib proc sbin var)
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR creating directories in $TMPMNT"
cleanup 1
fi
# Add some /dev files. We have to handle different types of MAKEDEV invocations
# here, so this is rather messy.
RETCODE=0
echo "$cmd -- adding required /dev files"
verbose "BASICDEVICES: `echo $BASICDEVICES`"
verbose "BLOCKDEVICES: `echo $BLOCKDEVICES`"
[ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q=""
case "$MAKEDEV" in
debian)
(cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
RETCODE=$?
;;
redhat)
(cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2)
RETCODE=$?
;;
*)
echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style."
RETCODE=1
;;
esac
if [ $RETCODE -ne 0 ]; then
echo "$cmd -- ERROR adding /dev files"
cleanup 1
fi
# copy necessary files to ram disk
echo "$cmd -- copying initrd files to ram disk"
[ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q="--quiet"
verbose "find \$INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT"
find $INITRDFILES | cpio -pdmL $OPT_Q $TMPMNT
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR cpio to ram disk"
cleanup 1
fi
echo "$cmd -- creating symlinks to busybox"
shopt -s extglob
[ "$VERBOSE" ] && OPT_Q="-v" || OPT_Q=""
BUSYBOXSYMLINKS=`busybox 2>&1| awk '/^Currently defined functions:$/ {i++;next} i'|tr ',\t\n' ' '`
for link in ${BUSYBOXSYMLINKS//@(linuxrc|init|busybox)}; do
ln -s $OPT_Q busybox $TMPMNT/bin/$link;
done
shopt -u extglob
echo "$cmd -- creating new $TMPMNT/sbin/init"
create_init
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR creating init"
cleanup
exit 1
fi
# copy LVMCONF into place or create a stripped down one from lvm dumpconfig
mkdir -p $TMPMNT/etc/lvm
if [ -n "$LVMCONF" ]; then
echo "$cmd -- copying $LVMCONF to $TMPMNT/etc/lvm/lvm.conf"
if [ -f "$LVMCONF" ]; then
cp $LVMCONF $TMPMNT/etc/lvm/lvm.conf
else
echo "$cmd -- ERROR: $LVMCONF does not exist!"
cleanup
exit 1
fi
else
echo "$cmd -- creating new $TMPMNT/etc/lvm/lvm.conf"
create_lvmconf
fi
if [ -n "$RAID" ]; then
RAIDLIST="$TMPMNT/etc/raid_autostart"
echo "$cmd -- creating $RAIDLIST file."
for device in $RAID; do
echo $device >> $RAIDLIST
done
fi
# create modules.dep and /etc/modules files if needed
if [ -n "$MODULES" ]; then
echo "$cmd -- creating $MODDIR/modules.dep file and $TMPMNT/etc/modules"
depmod -b $TMPMNT $VERSION
for module in $MODULES; do
basename $module | sed 's/\.k\{0,1\}o$//' >> $TMPMNT/etc/modules
done
fi
verbose "removing $TMPMNT/lost+found"
rmdir $TMPMNT/lost+found
echo "$cmd -- ummounting ram disk"
umount $DEVRAM
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR umounting $DEVRAM"
cleanup 1
fi
echo "$cmd -- creating compressed initrd $INITRD"
verbose "dd if=$DEVRAM bs=1k count=$INITRDSIZE | gzip -9"
dd if=$DEVRAM bs=1k count=$INITRDSIZE 2>/dev/null | gzip -9 > $INITRD
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR creating $INITRD"
cleanup 1
fi
cat << FINALTXT
--------------------------------------------------------
Your initrd is ready in $INITRD
Don't forget to set root=/dev/ram0 in kernel parameters
Don't forget to set lvm2root=/dev/VG/LV in kernel parameters, where LV is your root volume
If you use lilo try adding/modifying an entry similar to this one in lilo.conf:
image=/boot/vmlinuz-lvm2-$VERSION
label="ramdisk_LVM"
initrd=/boot/initrd-lvm2-$VERSION.gz
append="root=/dev/ram0 lvm2root=/dev/system/root <other parameters>"
If using grub try adding/modifying an entry similar to this one in menu.lst
title ramdisk LVM
kernel /boot/vmlinuz-lvm2-$VERSION root=/dev/ram0 lvm2root=/dev/system/root <other parameters>
initrd /boot/initrd-lvm2-$VERSION.gz
You can also pass lvm2rescue to the kernel to get a shell
--------------------------------------------------------
FINALTXT
cleanup 0

View File

@@ -0,0 +1,281 @@
.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sh \" Subsection heading
.br
.if t .Sp
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. | will give a
.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
.\" expand to `' in nroff, nothing in troff, for use with C<>.
.tr \(*W-|\(bv\*(Tr
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
'br\}
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. nr % 0
. rr F
.\}
.\"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.hy 0
.if n .na
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "lvm2create_initrd 8"
.TH lvm2create_initrd 8 "2004-06-05" "lvm2create_initrd" "create LVM2 initrd"
.SH "NAME"
lvm2create_initrd \- create initrd image for booting to root\e\-on\e\-LVM2
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
\&\fBlvm2create_initrd\fR [ \fB\-h|\-\-help\fR ] [ \fB\-v|\-\-verbose\fR ] [ \fB\-c|\-\-lvmconf\fR \fI/path/to/lvm.conf\fR ] [ \fB\-m|\-\-modules\fR "\fImodule1 module2 ...\fR" ] [ \fB\-e|\-\-extra\fR "\fIfile1 file2 ...\fR" ] [ \fB\-r|\-\-raid\fR "\fI/dev/md1 /dev/md2 ...\fR" ]
[ \fB\-R|\-\-raidconf\fR \fI/path/to/mdadm.conf\fR ] [ \fB\-M|\-\-makedev\fR \fIstyle\fR ]
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
lvm2create_initrd creates an initial ramdisk (initrd) image suitable for booting to system that has an \s-1LVM2\s0 volume as its root filesystem.
.PP
To boot to such a setup, you'll
either need a bootloader that understands \s-1LVM2\s0 volumes, or you'll need a
filesystem on a regular volume to act as a boot partition (typically mounted
on /boot).
.PP
The resulting initrd image is fairly full\-featured. It can harbor and load
kernel modules, start \s-1MD\s0 devices, and boot to a shell to perform rescue
operations.
.Sh "Booting to your initrd Image:"
.IX Subsection "Booting to your initrd Image:"
The filesystem image created is an ext2fs filesystem, hence your kernel must have
ext2fs built into it statically in order to boot to the image.
.PP
Once you create your initrd image, you must pass the correct options to the kernel when
you boot using it. Your kernel command line should look something like this:
.PP
\&\fBroot=/dev/ram0 lvm2root=/dev/rootvg/root [ lvm2rescue ]\fR
.PP
of course there may be other options.
.IP "\fBroot=/dev/ram0\fR" 4
.IX Item "root=/dev/ram0"
This option is required. It tells the kernel that the root filesystem should initially
be set to the ramdisk (/dev/ram0).
.IP "\fBlvm2root=/dev/rootvg/root\fR" 4
.IX Item "lvm2root=/dev/rootvg/root"
This option is also required. It tells the initrd image which \s-1LVM2\s0 device the root filesystem is located on.
.IP "\fBlvm2rescue\fR" 4
.IX Item "lvm2rescue"
Causes the initrd image to run a shell prior to mounting the root filesystem. This is
helpful in disaster situations where your initrd image is accessable, but there is
a problem with the root filesystem (corrupted image, incorrect device setup, etc.). This
option is (of course) optional.
.SH "OPTIONS"
.IX Header "OPTIONS"
Most of parameters that can be set via command-line options can also be set
via environment variables. Options specified on the command-line always take
precedence.
.IP "\fB\-h|\-\-help\fR" 4
.IX Item "-h|--help"
Display short help text and exit. If used, other options are ignored.
.IP "\fB\-v|\-\-verbose\fR" 4
.IX Item "-v|--verbose"
Turn on extra verbosity for debugging, etc.
.IP "\fB\-c|\-\-lvmconf\fR \fI/path/to/lvm.conf\fR" 4
.IX Item "-c|--lvmconf /path/to/lvm.conf"
Specify an lvm.conf file to include in the image. This is useful if you have
special device filters or other options you wish to use during the initrd
stage. If this option is not
included, then a lvm.conf file is created that contains only the current
device filter from an \fBlvm dumpconfig\fR. This can also be set via the \fB$LVMCONF\fR
environment variable.
.ie n .IP "\fB\-m|\-\-modules\fR ""\fI/path/to/module1.ko /path/to/module2.ko ...\fR""" 4
.el .IP "\fB\-m|\-\-modules\fR ``\fI/path/to/module1.ko /path/to/module2.ko ...\fR''" 4
.IX Item "-m|--modules ""/path/to/module1.ko /path/to/module2.ko ..."""
Specify modules to include and plug in during the initrd phase. This option
takes a quoted, space-separated list of modules. Full pathnames are required.
These modules are loaded into the kernel early in the initrd phase of the boot
process. The current modprobe.conf file is also copied to the initrd image
as well. This can also be specified via the \fB$MODULES\fR environment variable.
.ie n .IP "\fB\-e|\-\-extra\fR ""\fI/path/to/file1 /path/to/file2 ...\fR""" 4
.el .IP "\fB\-e|\-\-extra\fR ``\fI/path/to/file1 /path/to/file2 ...\fR''" 4
.IX Item "-e|--extra ""/path/to/file1 /path/to/file2 ..."""
Extra files that should be included in the initrd image. These files will be
copied to the same location in the initrd image that they are in the current
filesystem. Again full pathnames are required. This can also be specified via
the \fB$EXTRAFILES\fR environment variable.
.ie n .IP "\fB\-r|\-\-raid\fR ""\fI/dev/md1 /dev/md2...\fR""" 4
.el .IP "\fB\-r|\-\-raid\fR ``\fI/dev/md1 /dev/md2...\fR''" 4
.IX Item "-r|--raid ""/dev/md1 /dev/md2..."""
\&\s-1RAID\s0 devices to be started prior to scanning for \s-1LVM2\s0 volume groups. If this
option is used then then \fBmdadm\fR program must be installed. This can also be
specified via the \fB$RAID\fR environment variable.
.ie n .IP "\fB\-R|\-\-raidconf\fR ""\fI/path/to/mdadm.conf\fR""" 4
.el .IP "\fB\-R|\-\-raidconf\fR ``\fI/path/to/mdadm.conf\fR''" 4
.IX Item "-R|--raidconf ""/path/to/mdadm.conf"""
Location of a mdadm.conf file to include. If this is not specified, then no
files are included, and any devices specified with the \fB\-r\fR option above
must have minor numbers that match their superblock values. This can also be
specified via the \fB$RAIDCONF\fR environment variable.
.IP "\fB\-M|\-\-makedev\fR \fIstyle\fR" 4
.IX Item "-M|--makedev style"
Set \s-1MAKEDEV\s0 invocation style. The script currently supports 2 styles of
\&\s-1MAKEDEV\s0 programs \fIdebian\fR and \fIredhat\fR. The default is \fIdebian\fR. Set
to \fIredhat\fR if using the RedHat/Fedora binary \s-1MAKEDEV\s0 program. Please send
a bug report to maintainer if your distrib doesn't work with any of the
current options.
.SH "ENVIRONMENT VARIABLES"
.IX Header "ENVIRONMENT VARIABLES"
Most of the options to this script can be set via environment variables. In
situations where both are set, then the command-line options take precedence.
.IP "\fB$LVMCONF\fR" 4
.IX Item "$LVMCONF"
Same as \-c option.
.IP "\fB$MODULES\fR" 4
.IX Item "$MODULES"
Same as \-m option.
.IP "\fB$EXTRAFILES\fR" 4
.IX Item "$EXTRAFILES"
Same as \-e option.
.IP "\fB$RAID\fR" 4
.IX Item "$RAID"
Same as \-r option.
.IP "\fB$RAIDCONF\fR" 4
.IX Item "$RAIDCONF"
Same as \-R option.
.IP "\fB$MAKEDEV\fR" 4
.IX Item "$MAKEDEV"
Same as \-M option.
.IP "\fB$BASICDEVICES\fR" 4
.IX Item "$BASICDEVICES"
Overrides the default value of \f(CW$BASICDEVICES\fR in the script (which is \*(L"std consoleonly fd\*(R"). These values are passed to the \fB\s-1MAKEDEV\s0\fR program to create device
entries in the initrd image.
.IP "\fB$BLOCKDEVICES\fR" 4
.IX Item "$BLOCKDEVICES"
Overrides the default value of \f(CW$BLOCKDEVICES\fR in the script (which is \*(L"md hda hdb hdc hdd sda sdb sdc sdd\*(R"). This value is passed to the \fB\s-1MAKEDEV\s0\fR program to
create device entries in the initrd image.
.IP "\fB$BINFILES\fR" 4
.IX Item "$BINFILES"
Overrides the default value of \f(CW$BINFILES\fR (which is \*(L"/lib/lvm\-200/lvm /bin/bash /bin/busybox /sbin/pivot_root\*(R"). The difference between using this and adding
a file to the \f(CW$EXTRAFILES\fR list above is that libraries that these depend upon are also included. You can still use \f(CW$EXTRAFILES\fR to achieve the same effect, but
you must resolve library dependencies youself.
.IP "\fB$INITRDSIZE\fR" 4
.IX Item "$INITRDSIZE"
Force a particular size for your initrd image. The default is to total up the size of
the included files and to add 512K as a buffer.
.SH "BUGS"
.IX Header "BUGS"
I don't like having to specify a \-M option to set the \s-1MAKEDEV\s0 style, but I know
of no way to reliably detect what type of \s-1MAKEDEV\s0 is being used. We'll probably
have to add other \s-1MAKEDEV\s0 styles in the future as this script is tested on
other distributions.
.SH "AUTHORS"
.IX Header "AUTHORS"
The script was originally written by Miguel Cabeca, with significant
improvements by Jeffrey Layton. Comments, bug reports and patches should be
sent to Jeffrey Layton at \fBjtlayton@poochiereds.net\fR.
.SH "SEE ALSO"
.IX Header "SEE ALSO"
\&\fB\s-1MAKEDEV\s0\fR(8), \fBmdadm\fR(8), \fBbusybox\fR(8), \fBlvm.conf\fR(5)

View File

@@ -0,0 +1,187 @@
=head1 NAME
lvm2create_initrd - create initrd image for booting to root\-on\-LVM2
=head1 SYNOPSIS
B<lvm2create_initrd> [ B<-h|--help> ] [ B<-v|--verbose> ] [ B<-c|--lvmconf> I</path/to/lvm.conf> ] [ B<-m|--modules> "I<module1 module2 ...>" ] [ B<-e|--extra> "I<file1 file2 ...>" ] [ B<-r|--raid> "I</dev/md1 /dev/md2 ...>" ]
[ B<-R|--raidconf> I</path/to/mdadm.conf> ] [ B<-M|--makedev> I<style> ]
=head1 DESCRIPTION
lvm2create_initrd creates an initial ramdisk (initrd) image suitable for booting to system that has an LVM2 volume as its root filesystem.
To boot to such a setup, you'll
either need a bootloader that understands LVM2 volumes, or you'll need a
filesystem on a regular volume to act as a boot partition (typically mounted
on /boot).
The resulting initrd image is fairly full-featured. It can harbor and load
kernel modules, start MD devices, and boot to a shell to perform rescue
operations.
=head2 Booting to your initrd Image:
The filesystem image created is an ext2fs filesystem, hence your kernel must have
ext2fs built into it statically in order to boot to the image.
Once you create your initrd image, you must pass the correct options to the kernel when
you boot using it. Your kernel command line should look something like this:
B<root=/dev/ram0 lvm2root=/dev/rootvg/root [ lvm2rescue ]>
of course there may be other options.
=over
=item B<root=/dev/ram0>
This option is required. It tells the kernel that the root filesystem should initially
be set to the ramdisk (/dev/ram0).
=item B<lvm2root=/dev/rootvg/root>
This option is also required. It tells the initrd image which LVM2 device the root filesystem is located on.
=item B<lvm2rescue>
Causes the initrd image to run a shell prior to mounting the root filesystem. This is
helpful in disaster situations where your initrd image is accessable, but there is
a problem with the root filesystem (corrupted image, incorrect device setup, etc.). This
option is (of course) optional.
=back
=head1 OPTIONS
Most of parameters that can be set via command-line options can also be set
via environment variables. Options specified on the command-line always take
precedence.
=over
=item B<-h|--help>
Display short help text and exit. If used, other options are ignored.
=item B<-v|--verbose>
Turn on extra verbosity for debugging, etc.
=item B<-c|--lvmconf> I</path/to/lvm.conf>
Specify an lvm.conf file to include in the image. This is useful if you have
special device filters or other options you wish to use during the initrd
stage. If this option is not
included, then a lvm.conf file is created that contains only the current
device filter from an B<lvm dumpconfig>. This can also be set via the B<$LVMCONF>
environment variable.
=item B<-m|--modules> "I</path/to/module1.ko /path/to/module2.ko ...>"
Specify modules to include and plug in during the initrd phase. This option
takes a quoted, space-separated list of modules. Full pathnames are required.
These modules are loaded into the kernel early in the initrd phase of the boot
process. The current modprobe.conf file is also copied to the initrd image
as well. This can also be specified via the B<$MODULES> environment variable.
=item B<-e|--extra> "I</path/to/file1 /path/to/file2 ...>"
Extra files that should be included in the initrd image. These files will be
copied to the same location in the initrd image that they are in the current
filesystem. Again full pathnames are required. This can also be specified via
the B<$EXTRAFILES> environment variable.
=item B<-r|--raid> "I</dev/md1 /dev/md2...>"
RAID devices to be started prior to scanning for LVM2 volume groups. If this
option is used then then B<mdadm> program must be installed. This can also be
specified via the B<$RAID> environment variable.
=item B<-R|--raidconf> "I</path/to/mdadm.conf>"
Location of a mdadm.conf file to include. If this is not specified, then no
files are included, and any devices specified with the B<-r> option above
must have minor numbers that match their superblock values. This can also be
specified via the B<$RAIDCONF> environment variable.
=item B<-M|--makedev> I<style>
Set MAKEDEV invocation style. The script currently supports 2 styles of
MAKEDEV programs I<debian> and I<redhat>. The default is I<debian>. Set
to I<redhat> if using the RedHat/Fedora binary MAKEDEV program. Please send
a bug report to maintainer if your distrib doesn't work with any of the
current options.
=back
=head1 ENVIRONMENT VARIABLES
Most of the options to this script can be set via environment variables. In
situations where both are set, then the command-line options take precedence.
=over
=item B<$LVMCONF>
Same as -c option.
=item B<$MODULES>
Same as -m option.
=item B<$EXTRAFILES>
Same as -e option.
=item B<$RAID>
Same as -r option.
=item B<$RAIDCONF>
Same as -R option.
=item B<$MAKEDEV>
Same as -M option.
=item B<$BASICDEVICES>
Overrides the default value of $BASICDEVICES in the script (which is "std consoleonly fd"). These values are passed to the B<MAKEDEV> program to create device
entries in the initrd image.
=item B<$BLOCKDEVICES>
Overrides the default value of $BLOCKDEVICES in the script (which is "md hda hdb hdc hdd sda sdb sdc sdd"). This value is passed to the B<MAKEDEV> program to
create device entries in the initrd image.
=item B<$BINFILES>
Overrides the default value of $BINFILES (which is "/lib/lvm-200/lvm /bin/bash /bin/busybox /sbin/pivot_root"). The difference between using this and adding
a file to the $EXTRAFILES list above is that libraries that these depend upon are also included. You can still use $EXTRAFILES to achieve the same effect, but
you must resolve library dependencies youself.
=item B<$INITRDSIZE>
Force a particular size for your initrd image. The default is to total up the size of
the included files and to add 512K as a buffer.
=back
=head1 BUGS
I don't like having to specify a -M option to set the MAKEDEV style, but I know
of no way to reliably detect what type of MAKEDEV is being used. We'll probably
have to add other MAKEDEV styles in the future as this script is tested on
other distributions.
=head1 AUTHORS
The script was originally written by Miguel Cabeca, with significant
improvements by Jeffrey Layton. Comments, bug reports and patches should be
sent to Jeffrey Layton at S<B<jtlayton@poochiereds.net>>.
=head1 SEE ALSO
B<MAKEDEV>(8), B<mdadm>(8), B<busybox>(8), B<lvm.conf>(5)

View File

@@ -0,0 +1,33 @@
#!/bin/sh
# $Id$
# simple startup script to create lvm2 devices if /dev is a mountpoint, there
# are active dm- devices, and an executable /sbin/vgscan.
# this script is licensed under GPLv2.
# See http://www.gnu.org/licenses/gpl.html
case $1 in
start)
# is /dev a mountpoint?
mountpoint -q /dev
DEVMNTPOINT=$?
# check to see if there are active dm entries under /sys
ls /sys/block/dm-*/dev 1>/dev/null 2>&1
ACTIVEDMDEVS=$?
# mknodes if conditions are right
if [ $DEVMNTPOINT -eq 0 -a $ACTIVEDMDEVS -eq 0 -a -x /sbin/vgscan ]; then
/sbin/vgscan --mknodes --ignorelockingfailure
fi
;;
stop)
exit 0
;;
*)
echo "usage:"
echo " $0 start|stop"
;;
esac

View File

@@ -31,6 +31,7 @@ SOURCES =\
lvrename.c \
lvresize.c \
lvscan.c \
polldaemon.c \
pvchange.c \
pvcreate.c \
pvdisplay.c \

View File

@@ -41,6 +41,8 @@ arg(deltag_ARG, '\0', "deltag", tag_arg)
arg(refresh_ARG, '\0', "refresh", NULL)
arg(mknodes_ARG, '\0', "mknodes", NULL)
arg(minor_ARG, '\0', "minor", minor_arg)
arg(type_ARG, '\0', "type", segtype_arg)
arg(alloc_ARG, '\0', "alloc", alloc_arg)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -49,7 +51,7 @@ arg(allocation_ARG, '\0', "allocation", yes_no_arg)
/*
* ... and now the short args.
*/
arg(available_ARG, 'a', "available", yes_no_arg)
arg(available_ARG, 'a', "available", yes_no_excl_arg)
arg(all_ARG, 'a', "all", NULL)
arg(autobackup_ARG, 'A', "autobackup", yes_no_arg)
arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL)

View File

@@ -52,6 +52,7 @@ xx(lvchange,
"\t[-A|--autobackup y|n]\n"
"\t[-a|--available y|n]\n"
"\t[--addtag Tag]\n"
"\t[--alloc AllocationType]\n"
"\t[-C|--contiguous y|n]\n"
"\t[-d|--debug]\n"
"\t[--deltag Tag]\n"
@@ -68,7 +69,7 @@ xx(lvchange,
"\t[--version]" "\n"
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
ignorelockingfailure_ARG, major_ARG, minor_ARG, partial_ARG, permission_ARG,
persistent_ARG, readahead_ARG, refresh_ARG, addtag_ARG, deltag_ARG,
test_ARG)
@@ -78,6 +79,7 @@ xx(lvcreate,
"lvcreate " "\n"
"\t[-A|--autobackup {y|n}]\n"
"\t[--addtag Tag]\n"
"\t[--alloc AllocationType]\n"
"\t[-C|--contiguous {y|n}]\n"
"\t[-d|--debug]\n"
"\t[-h|-?|--help]\n"
@@ -89,6 +91,7 @@ xx(lvcreate,
"\t[-p|--permission {r|rw}]\n"
"\t[-r|--readahead ReadAheadSectors]\n"
"\t[-t|--test]\n"
"\t[--type VolumeType]\n"
"\t[-v|--verbose]\n"
"\t[-Z|--zero {y|n}]\n"
"\t[--version]\n"
@@ -98,6 +101,7 @@ xx(lvcreate,
"\t[-c|--chunksize]\n"
"\t[-A|--autobackup {y|n}]\n"
"\t[--addtag Tag]\n"
"\t[--alloc AllocationType]\n"
"\t[-C|--contiguous {y|n}]\n"
"\t[-d|--debug]\n"
"\t[-h|-?|--help]\n"
@@ -113,10 +117,10 @@ xx(lvcreate,
"\t[--version]\n"
"\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
autobackup_ARG, chunksize_ARG, contiguous_ARG, extents_ARG, major_ARG,
minor_ARG, name_ARG, permission_ARG, persistent_ARG, readahead_ARG, size_ARG,
snapshot_ARG, stripes_ARG, stripesize_ARG, addtag_ARG, test_ARG,
zero_ARG)
addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
extents_ARG, major_ARG, minor_ARG, name_ARG, permission_ARG,
persistent_ARG, readahead_ARG, size_ARG, snapshot_ARG, stripes_ARG,
stripesize_ARG, test_ARG, type_ARG, zero_ARG)
xx(lvdisplay,
"Display information about a logical volume",
@@ -159,18 +163,20 @@ xx(lvextend,
"Add space to a logical volume",
"lvextend\n"
"\t[-A|--autobackup y|n]\n"
"\t[--alloc AllocationType]\n"
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+]LogicalExtentsNumber |\n"
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-t|--test]\n"
"\t[--type VolumeType]\n"
"\t[-v|--verbose]\n"
"\t[--version]" "\n"
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
autobackup_ARG, extents_ARG, size_ARG, stripes_ARG,
stripesize_ARG, test_ARG)
alloc_ARG, autobackup_ARG, extents_ARG, size_ARG, stripes_ARG,
stripesize_ARG, test_ARG, type_ARG)
xx(lvmchange,
"With the device mapper, this is obsolete and does nothing.",
@@ -264,18 +270,20 @@ xx(lvresize,
"Resize a logical volume",
"lvresize\n"
"\t[-A|--autobackup y|n]\n"
"\t[--alloc AllocationType]\n"
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+|-]LogicalExtentsNumber |\n"
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-t|--test]\n"
"\t[--type VolumeType]\n"
"\t[-v|--verbose]\n"
"\t[--version]" "\n"
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
autobackup_ARG, extents_ARG, size_ARG, stripes_ARG, stripesize_ARG,
test_ARG)
alloc_ARG, autobackup_ARG, extents_ARG, size_ARG, stripes_ARG,
stripesize_ARG, test_ARG, type_ARG)
xx(lvs,
"Display information about logical volumes",
@@ -533,6 +541,7 @@ xx(vgchange,
"Change volume group attributes",
"vgchange" "\n"
"\t[-A|--autobackup {y|n}] " "\n"
"\t[--alloc AllocationType] " "\n"
"\t[-P|--partial] " "\n"
"\t[-d|--debug] " "\n"
"\t[-h|--help] " "\n"
@@ -548,9 +557,9 @@ xx(vgchange,
"\t --deltag Tag}\n"
"\t[VolumeGroupName...]\n",
allocation_ARG, autobackup_ARG, available_ARG, ignorelockingfailure_ARG,
logicalvolume_ARG, partial_ARG, resizeable_ARG, resizable_ARG, deltag_ARG,
addtag_ARG, test_ARG, uuid_ARG)
addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
deltag_ARG, ignorelockingfailure_ARG, logicalvolume_ARG, partial_ARG,
resizeable_ARG, resizable_ARG, test_ARG, uuid_ARG)
xx(vgck,
"Check the consistency of volume group(s)",
@@ -583,6 +592,7 @@ xx(vgcreate,
"vgcreate" "\n"
"\t[-A|--autobackup {y|n}] " "\n"
"\t[--addtag Tag] " "\n"
"\t[--alloc AllocationType] " "\n"
"\t[-d|--debug]" "\n"
"\t[-h|--help]" "\n"
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
@@ -594,8 +604,8 @@ xx(vgcreate,
"\t[--version] " "\n"
"\tVolumeGroupName PhysicalVolume [PhysicalVolume...]\n",
autobackup_ARG, maxlogicalvolumes_ARG, maxphysicalvolumes_ARG,
metadatatype_ARG, physicalextentsize_ARG, addtag_ARG, test_ARG)
addtag_ARG, alloc_ARG, autobackup_ARG, maxlogicalvolumes_ARG,
maxphysicalvolumes_ARG, metadatatype_ARG, physicalextentsize_ARG, test_ARG)
xx(vgdisplay,
"Display volume group information",

View File

@@ -248,6 +248,51 @@ static int _rename(int argc, char **argv, void *data)
return r;
}
static int _message(int argc, char **argv, void *data)
{
int r = 0, sz = 1, i;
struct dm_task *dmt;
char *str;
if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
return 0;
if (!dm_task_set_name(dmt, argv[1]))
goto out;
if (!dm_task_set_sector(dmt, atoll(argv[2])))
goto out;
argc -= 3;
argv += 3;
for (i = 0; i < argc; i++)
sz += strlen(argv[i]) + 1;
str = malloc(sz);
for (i = 0; i < argc; i++) {
if (i)
strcat(str, " ");
strcat(str, argv[i]);
}
if (!dm_task_set_message(dmt, str))
goto out;
free(str);
if (!dm_task_run(dmt))
goto out;
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
static int _version(int argc, char **argv, void *data)
{
int r = 0;
@@ -264,8 +309,9 @@ static int _version(int argc, char **argv, void *data)
goto out;
if (!dm_task_get_driver_version(dmt, (char *) &version,
sizeof(version)))
sizeof(version))) {
goto out;
}
printf("Driver version: %s\n", version);
@@ -623,6 +669,7 @@ static struct command _commands[] = {
{"clear", "<dev_name>", 1, 1, _clear},
{"reload", "<dev_name> [<table_file>]", 1, 2, _reload},
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
{"message", "<dev_name> <sector> <message>", 3, -1, _message},
{"ls", "", 0, 0, _ls},
{"info", "[<dev_name>]", 0, 1, _info},
{"deps", "[<dev_name>]", 0, 1, _deps},
@@ -744,7 +791,8 @@ int main(int argc, char **argv)
exit(1);
}
if (argc < c->min_args + 1 || argc > c->max_args + 1) {
if (argc < c->min_args + 1 ||
(c->max_args >= 0 && argc > c->max_args + 1)) {
fprintf(stderr, "Incorrect number of arguments\n");
_usage(stderr);
exit(1);

View File

@@ -52,19 +52,19 @@ static int lvchange_permission(struct cmd_context *cmd,
backup(lv->vg);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
if (!suspend_lv(cmd, lv->lvid.s)) {
log_error("Failed to lock %s", lv->name);
vg_revert(lv->vg);
return 0;
}
if (!vg_commit(lv->vg)) {
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
return 0;
}
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!unlock_lv(cmd, lv->lvid.s)) {
if (!resume_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
@@ -75,26 +75,33 @@ static int lvchange_permission(struct cmd_context *cmd,
static int lvchange_availability(struct cmd_context *cmd,
struct logical_volume *lv)
{
int activate = 0;
struct physical_volume *pv;
int activate;
const char *pvname;
if (strcmp(arg_str_value(cmd, available_ARG, "n"), "n"))
activate = 1;
activate = arg_uint_value(cmd, available_ARG, 0);
if (activate) {
/* FIXME Tighter locking if lv_is_origin() */
log_verbose("Activating logical volume \"%s\"", lv->name);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE))
if (lv_is_origin(lv) || (activate == 2)) {
if (!activate_lv_excl(cmd, lv->lvid.s)) {
stack;
return 0;
}
} else if (!activate_lv(cmd, lv->lvid.s)) {
stack;
return 0;
if ((lv->status & LOCKED) && (pv = get_pvmove_pv_from_lv(lv))) {
}
if ((lv->status & LOCKED) && (pvname = get_pvmove_pvname_from_lv(lv))) {
log_verbose("Spawning background pvmove process for %s",
dev_name(pv->dev));
pvmove_poll(cmd, dev_name(pv->dev), 1);
pvname);
pvmove_poll(cmd, pvname, 1);
}
} else {
log_verbose("Deactivating logical volume \"%s\"", lv->name);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE))
if (!deactivate_lv(cmd, lv->lvid.s)) {
stack;
return 0;
}
}
return 1;
@@ -103,52 +110,36 @@ static int lvchange_availability(struct cmd_context *cmd,
static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
{
log_verbose("Refreshing logical volume \"%s\" (if active)", lv->name);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD) ||
!unlock_lv(cmd, lv->lvid.s))
if (!suspend_lv(cmd, lv->lvid.s) || !resume_lv(cmd, lv->lvid.s))
return 0;
return 1;
}
static int lvchange_contiguous(struct cmd_context *cmd,
struct logical_volume *lv)
static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
{
int want_contiguous = 0;
alloc_policy_t alloc;
if (strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"))
want_contiguous = 1;
want_contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
alloc = want_contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc);
if (want_contiguous && lv->alloc == ALLOC_CONTIGUOUS) {
if (alloc == lv->alloc) {
log_error("Allocation policy of logical volume \"%s\" is "
"already contiguous", lv->name);
"already %s", lv->name, get_alloc_string(alloc));
return 0;
}
if (!want_contiguous && lv->alloc != ALLOC_CONTIGUOUS) {
log_error
("Allocation policy of logical volume \"%s\" is already"
" not contiguous", lv->name);
return 0;
}
lv->alloc = alloc;
/******** FIXME lv_check_contiguous?
if (want_contiguous)
&& (ret = lv_check_contiguous(vg, lv_index + 1)) == FALSE) {
log_error("No contiguous logical volume \"%s\"", lv->name);
return 0;
*********/
/* FIXME If contiguous, check existing extents already are */
if (want_contiguous) {
lv->alloc = ALLOC_CONTIGUOUS;
log_verbose("Setting contiguous allocation policy for \"%s\"",
lv->name);
} else {
lv->alloc = ALLOC_DEFAULT;
log_verbose("Reverting to default allocation policy for \"%s\"",
lv->name);
}
log_verbose("Setting contiguous allocation policy for \"%s\" to %s",
lv->name, get_alloc_string(alloc));
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!vg_write(lv->vg)) {
stack;
return 0;
@@ -163,7 +154,6 @@ static int lvchange_contiguous(struct cmd_context *cmd,
}
return 1;
}
static int lvchange_readahead(struct cmd_context *cmd,
@@ -199,19 +189,19 @@ static int lvchange_readahead(struct cmd_context *cmd,
backup(lv->vg);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
if (!suspend_lv(cmd, lv->lvid.s)) {
log_error("Failed to lock %s", lv->name);
vg_revert(lv->vg);
return 0;
}
if (!vg_commit(lv->vg)) {
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
return 0;
}
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!unlock_lv(cmd, lv->lvid.s)) {
if (!resume_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
@@ -223,6 +213,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
struct logical_volume *lv)
{
struct lvinfo info;
int active = 0;
if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "n")) {
if (!(lv->status & FIXED_MINOR)) {
@@ -247,17 +238,16 @@ static int lvchange_persistent(struct cmd_context *cmd,
if (lv_info(lv, &info) && info.exists &&
!arg_count(cmd, force_ARG)) {
if (yes_no_prompt("Logical volume %s will be "
"deactivated first. "
"Continue? [y/n]: ",
lv->name) == 'n') {
"deactivated temporarily. "
"Continue? [y/n]: ", lv->name) == 'n') {
log_print("%s device number not changed.",
lv->name);
return 0;
}
active = 1;
}
log_print("Ensuring %s is inactive. "
"(Reactivate using lvchange -ay.)", lv->name);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
log_verbose("Ensuring %s is inactive.", lv->name);
if (!deactivate_lv(cmd, lv->lvid.s)) {
log_error("%s: deactivation failed", lv->name);
return 0;
}
@@ -266,6 +256,14 @@ static int lvchange_persistent(struct cmd_context *cmd,
lv->major = arg_int_value(cmd, major_ARG, lv->major);
log_verbose("Setting persistent device number to (%d, %d) "
"for \"%s\"", lv->major, lv->minor, lv->name);
if (active) {
log_verbose("Re-activating logical volume \"%s\"",
lv->name);
if (!activate_lv(cmd, lv->lvid.s)) {
log_error("%s: reactivation failed", lv->name);
return 0;
}
}
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
@@ -276,19 +274,19 @@ static int lvchange_persistent(struct cmd_context *cmd,
backup(lv->vg);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
if (!suspend_lv(cmd, lv->lvid.s)) {
log_error("Failed to lock %s", lv->name);
vg_revert(lv->vg);
return 0;
}
if (!vg_commit(lv->vg)) {
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
return 0;
}
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!unlock_lv(cmd, lv->lvid.s)) {
if (!resume_lv(cmd, lv->lvid.s)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
@@ -350,7 +348,8 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!(lv->vg->status & LVM_WRITE) &&
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
arg_count(cmd, alloc_ARG))) {
log_error("Only -a permitted with read-only volume "
"group \"%s\"", lv->vg->name);
return EINVALID_CMD_LINE;
@@ -358,7 +357,8 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
if (lv_is_origin(lv) &&
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
arg_count(cmd, alloc_ARG))) {
log_error("Can't change logical volume \"%s\" under snapshot",
lv->name);
return ECMD_FAILED;
@@ -386,11 +386,11 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
}
/* allocation policy change */
if (arg_count(cmd, contiguous_ARG)) {
if (arg_count(cmd, contiguous_ARG) || arg_count(cmd, alloc_ARG)) {
if (!archived && !archive(lv->vg))
return ECMD_FAILED;
archived = 1;
doit += lvchange_contiguous(cmd, lv);
doit += lvchange_alloc(cmd, lv);
}
/* read ahead sector change */
@@ -446,9 +446,10 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
&& !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)
&& !arg_count(cmd, persistent_ARG) && !arg_count(cmd, addtag_ARG)
&& !arg_count(cmd, deltag_ARG) && !arg_count(cmd, refresh_ARG)) {
&& !arg_count(cmd, deltag_ARG) && !arg_count(cmd, refresh_ARG)
&& !arg_count(cmd, alloc_ARG)) {
log_error("One or more of -a, -C, -j, -m, -M, -p, -r, "
"--refresh, --addtag or --deltag required");
"--refresh, --alloc, --addtag or --deltag required");
return EINVALID_CMD_LINE;
}
@@ -456,7 +457,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
arg_count(cmd, addtag_ARG) || arg_count(cmd, deltag_ARG) ||
arg_count(cmd, refresh_ARG))) {
arg_count(cmd, refresh_ARG) || arg_count(cmd, alloc_ARG))) {
log_error("Only -a permitted with --ignorelockingfailure");
return EINVALID_CMD_LINE;
}
@@ -477,6 +478,11 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, contiguous_ARG) && arg_count(cmd, alloc_ARG)) {
log_error("Only one of --alloc and --contiguous permitted");
return EINVALID_CMD_LINE;
}
return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
&lvchange_single);
}

View File

@@ -21,7 +21,6 @@ struct lvcreate_params {
/* flags */
int snapshot;
int zero;
int contiguous;
int major;
int minor;
@@ -33,12 +32,17 @@ struct lvcreate_params {
uint32_t stripe_size;
uint32_t chunk_size;
uint32_t mirrors;
struct segment_type *segtype;
/* size */
uint32_t extents;
uint64_t size;
uint32_t permission;
uint32_t read_ahead;
alloc_policy_t alloc;
int pv_count;
char **pvs;
@@ -53,9 +57,7 @@ static int _read_name_params(struct lvcreate_params *lp,
if (arg_count(cmd, name_ARG))
lp->lv_name = arg_value(cmd, name_ARG);
if (arg_count(cmd, snapshot_ARG)) {
lp->snapshot = 1;
if (lp->snapshot) {
if (!argc) {
log_err("Please specify a logical volume to act as "
"the snapshot origin.");
@@ -139,20 +141,8 @@ static int _read_name_params(struct lvcreate_params *lp,
static int _read_size_params(struct lvcreate_params *lp,
struct cmd_context *cmd, int *pargc, char ***pargv)
{
/*
* There are two mutually exclusive ways of specifying
* the size ...
*/
if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) {
log_error("Invalid combination of arguments");
return 0;
}
/*
* ... you must use one of them.
*/
if (arg_count(cmd, size_ARG) + arg_count(cmd, extents_ARG) == 0) {
log_error("Please indicate size using option -l or -L");
if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
log_error("Please specify either size or extents (not both)");
return 0;
}
@@ -182,14 +172,6 @@ static int _read_stripe_params(struct lvcreate_params *lp,
{
int argc = *pargc;
lp->stripes = 1;
if (arg_count(cmd, stripes_ARG)) {
lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
if (lp->stripes == 1)
log_print("Redundant stripes argument: default is 1");
}
if (arg_count(cmd, stripesize_ARG)) {
if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
log_error("Negative stripesize is invalid");
@@ -235,14 +217,27 @@ 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)
{
int contiguous;
memset(lp, 0, sizeof(*lp));
/*
* Check selected options are compatible and set defaults
* Check selected options are compatible and determine segtype
*/
if (arg_count(cmd, snapshot_ARG)) {
lp->segtype = (struct segment_type *)
arg_ptr_value(cmd, type_ARG,
get_segtype_from_string(cmd, "striped"));
lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
if (arg_count(cmd, stripes_ARG) && lp->stripes == 1)
log_print("Redundant stripes argument: default is 1");
if (arg_count(cmd, snapshot_ARG) || (lp->segtype->flags & SEG_SNAPSHOT))
lp->snapshot = 1;
if (lp->snapshot) {
if (arg_count(cmd, zero_ARG)) {
log_error("-s and -Z are incompatible");
log_error("-Z is incompatible with snapshots");
return 0;
}
if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
@@ -251,11 +246,23 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
}
lp->chunk_size = 2 * arg_uint_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");
if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot"))) {
stack;
return 0;
}
} else {
if (arg_count(cmd, chunksize_ARG)) {
log_error("-c is only available with snapshots");
return 0;
}
}
if (activation() && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present()) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", lp->segtype->name);
return 0;
}
if (!_read_name_params(lp, cmd, &argc, &argv) ||
@@ -269,9 +276,18 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
lp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
/*
* Contiguous ?
* Alloc policy
*/
lp->contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc);
if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
log_error("Conflicting contiguous and alloc arguments");
return 0;
}
/*
* Read ahead.
@@ -365,16 +381,12 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
uint32_t size_rest;
uint32_t status = 0;
uint64_t tmp_size;
alloc_policy_t alloc = ALLOC_DEFAULT;
struct volume_group *vg;
struct logical_volume *lv, *org = NULL;
struct list *pvh;
const char *tag;
int consistent = 1;
if (lp->contiguous)
alloc = ALLOC_CONTIGUOUS;
status |= lp->permission | VISIBLE_LV;
/* does VG exist? */
@@ -428,7 +440,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
tmp_size += vg->extent_size - tmp_size %
vg->extent_size;
log_print("Rounding up size to full physical extent %s",
display_size(cmd, tmp_size / 2, SIZE_SHORT));
display_size(cmd, tmp_size, SIZE_SHORT));
}
lp->extents = tmp_size / vg->extent_size;
@@ -466,9 +478,37 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
status |= LVM_WRITE;
}
if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc, lp->stripes,
lp->stripe_size, lp->extents, vg, pvh)))
if (!lp->extents) {
log_error("Unable to create logical volume %s with no extents",
lp->lv_name);
return 0;
}
if (!(lp->segtype->flags & SEG_VIRTUAL) &&
vg->free_count < lp->extents) {
log_error("Insufficient free extents (%u) in volume group %s: "
"%u required", vg->free_count, vg->name, lp->extents);
return 0;
}
if (lp->stripes > list_size(pvh)) {
log_error("Number of stripes (%u) must not exceed "
"number of physical volumes (%d)", lp->stripes,
list_size(pvh));
return 0;
}
if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d",
status, lp->alloc, vg))) {
stack;
return 0;
}
if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes, lp->stripe_size,
lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) {
stack;
return 0;
}
if (lp->read_ahead) {
log_verbose("Setting read ahead sectors");
@@ -518,7 +558,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE)) {
if (!activate_lv(cmd, lv->lvid.s)) {
if (lp->snapshot)
/* FIXME Remove the failed lv we just added */
log_error("Aborting. Failed to activate snapshot "
@@ -544,14 +584,14 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
/* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE))
lv->status &= ~LVM_WRITE;
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
log_err("Couldn't unlock snapshot.");
if (!deactivate_lv(cmd, lv->lvid.s)) {
log_err("Couldn't deactivate new snapshot.");
return 0;
}
/* FIXME write/commit/backup sequence issue */
if (!lock_vol(cmd, org->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
log_error("Failed to lock origin %s", org->name);
if (!suspend_lv(cmd, org->lvid.s)) {
log_error("Failed to suspend origin %s", org->name);
return 0;
}
@@ -564,7 +604,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
if (!vg_write(vg) || !vg_commit(vg))
return 0;
if (!unlock_lv(cmd, org->lvid.s)) {
if (!resume_lv(cmd, org->lvid.s)) {
log_error("Problem reactivating origin %s", org->name);
return 0;
}

View File

@@ -1,6 +1,7 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
@@ -84,6 +85,31 @@ int yes_no_arg(struct cmd_context *cmd, struct arg *a)
return 1;
}
int yes_no_excl_arg(struct cmd_context *cmd, struct arg *a)
{
a->sign = SIGN_NONE;
if (!strcmp(a->value, "e")) {
a->i_value = 2;
a->ui_value = 2;
}
else if (!strcmp(a->value, "y")) {
a->i_value = 1;
a->ui_value = 1;
}
else if (!strcmp(a->value, "n")) {
a->i_value = 0;
a->ui_value = 0;
}
else
return 0;
return 1;
}
int metadatatype_arg(struct cmd_context *cmd, struct arg *a)
{
struct format_type *fmt;
@@ -286,6 +312,29 @@ int permission_arg(struct cmd_context *cmd, struct arg *a)
return 1;
}
int alloc_arg(struct cmd_context *cmd, struct arg *a)
{
alloc_policy_t alloc;
a->sign = SIGN_NONE;
alloc = get_alloc_from_string(a->value);
if (alloc == ALLOC_INVALID)
return 0;
a->ui_value = (uint32_t) alloc;
return 1;
}
int segtype_arg(struct cmd_context *cmd, struct arg *a)
{
if (!(a->ptr = (void *) get_segtype_from_string(cmd, a->value)))
return 0;
return 1;
}
char yes_no_prompt(const char *prompt, ...)
{
int c = 0;
@@ -375,8 +424,8 @@ static void _register_commands()
{
#define xx(a, b, c...) _register_command(# a, a, b, ## c, \
driverloaded_ARG, \
debug_ARG, help_ARG, help2_ARG, \
version_ARG, verbose_ARG, \
debug_ARG, help_ARG, help2_ARG, \
version_ARG, verbose_ARG, \
quiet_ARG, -1);
#include "commands.h"
#undef xx
@@ -758,7 +807,7 @@ static int _run_command(struct cmd_context *cmd, int argc, char **argv)
set_cmd_name(cmd->command->name);
if (reload_config_file(&cmd->cft)) {
if (!cmd->config_valid || config_files_changed(cmd)) {
/* Reinitialise various settings inc. logging, filters */
if (!refresh_toolcontext(cmd)) {
log_error("Updated config file invalid. Aborting.");
@@ -1054,7 +1103,7 @@ static char *_list_args(const char *text, int state)
char c;
if (!(c = (the_args +
com->valid_args[match_no++])->short_arg))
continue;
continue;
sprintf(s, "-%c", c);
if (!strncmp(text, s, len))

View File

@@ -64,7 +64,7 @@ static void _print(struct cmd_context *cmd, const struct device *dev,
uint64_t size, const char *what)
{
log_print("%-*s [%15s] %s", max_len, dev_name(dev),
display_size(cmd, size / 2, SIZE_SHORT), what ? : "");
display_size(cmd, size, SIZE_SHORT), what ? : "");
}
static int _check_device(struct cmd_context *cmd, struct device *dev)

View File

@@ -62,7 +62,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!archive(vg))
return ECMD_FAILED;
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
if (!deactivate_lv(cmd, lv->lvid.s)) {
log_error("Unable to deactivate logical volume \"%s\"",
lv->name);
return ECMD_FAILED;

View File

@@ -160,19 +160,18 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
backup(lv->vg);
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD |
LCK_NONBLOCK)) {
if (!suspend_lv(cmd, lv->lvid.s)) {
stack;
goto error;
}
if (!vg_commit(vg)) {
stack;
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
goto error;
}
unlock_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv->lvid.s);
unlock_vg(cmd, vg_name);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
@@ -15,117 +15,138 @@
#include "tools.h"
int lvresize(struct cmd_context *cmd, int argc, char **argv)
{
struct volume_group *vg;
struct logical_volume *lv;
struct snapshot *snap;
struct lvinfo info;
uint32_t extents = 0;
uint32_t size = 0;
uint32_t stripes = 0, ssize = 0, stripesize_extents = 0;
uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
uint32_t extents_used = 0;
uint32_t size_rest;
sign_t sign = SIGN_NONE;
char *lv_name;
struct lvresize_params {
const char *vg_name;
char *st, *lock_lvid;
const char *cmd_name;
struct list *pvh;
struct lv_list *lvl;
int opt = 0;
int consistent = 1;
struct lv_segment *seg;
uint32_t seg_extents;
uint32_t sz, str;
const char *lv_name;
uint32_t stripes;
uint32_t stripe_size;
struct segment_type *segtype;
/* size */
uint32_t extents;
uint64_t size;
sign_t sign;
enum {
LV_ANY = 0,
LV_REDUCE = 1,
LV_EXTEND = 2
} resize = LV_ANY;
} resize;
int argc;
char **argv;
};
static int _read_params(struct cmd_context *cmd, int argc, char **argv,
struct lvresize_params *lp)
{
const char *cmd_name;
char *st;
lp->sign = SIGN_NONE;
lp->resize = LV_ANY;
cmd_name = command_name(cmd);
if (!strcmp(cmd_name, "lvreduce"))
resize = LV_REDUCE;
lp->resize = LV_REDUCE;
if (!strcmp(cmd_name, "lvextend"))
resize = LV_EXTEND;
lp->resize = LV_EXTEND;
if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
log_error("Please specify either size or extents (not both)");
return EINVALID_CMD_LINE;
return 0;
}
if (arg_count(cmd, extents_ARG)) {
extents = arg_uint_value(cmd, extents_ARG, 0);
sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
lp->extents = arg_uint_value(cmd, extents_ARG, 0);
lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
}
/* Size returned in kilobyte units; held in sectors */
if (arg_count(cmd, size_ARG)) {
size = arg_uint_value(cmd, size_ARG, 0);
sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
}
if (resize == LV_EXTEND && sign == SIGN_MINUS) {
if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
log_error("Negative argument not permitted - use lvreduce");
return EINVALID_CMD_LINE;
return 0;
}
if (resize == LV_REDUCE && sign == SIGN_PLUS) {
if (lp->resize == LV_REDUCE && lp->sign == SIGN_PLUS) {
log_error("Positive sign not permitted - use lvextend");
return EINVALID_CMD_LINE;
return 0;
}
if (!argc) {
log_error("Please provide the logical volume name");
return EINVALID_CMD_LINE;
return 0;
}
lv_name = argv[0];
lp->lv_name = argv[0];
argv++;
argc--;
if (!(vg_name = extract_vgname(cmd, lv_name))) {
if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
log_error("Please provide a volume group name");
return EINVALID_CMD_LINE;
return 0;
}
if ((st = strrchr(lv_name, '/')))
lv_name = st + 1;
if ((st = strrchr(lp->lv_name, '/')))
lp->lv_name = st + 1;
/* does VG exist? */
log_verbose("Finding volume group %s", vg_name);
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", vg_name);
lp->argc = argc;
lp->argv = argv;
return 1;
}
static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
{
struct volume_group *vg;
struct logical_volume *lv;
struct snapshot *snap;
struct lvinfo info;
uint32_t stripesize_extents = 0;
uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
uint32_t extents_used = 0;
uint32_t size_rest;
alloc_policy_t alloc;
char *lock_lvid;
struct lv_list *lvl;
int consistent = 1;
struct lv_segment *seg;
uint32_t seg_extents;
uint32_t sz, str;
struct list *pvh = NULL;
if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
log_error("Volume group %s doesn't exist", lp->vg_name);
return ECMD_FAILED;
}
if (!(vg = vg_read(cmd, vg_name, &consistent))) {
log_error("Volume group %s doesn't exist", vg_name);
goto error;
}
if (vg->status & EXPORTED_VG) {
log_error("Volume group %s is exported", vg->name);
goto error;
return ECMD_FAILED;
}
if (!(vg->status & LVM_WRITE)) {
log_error("Volume group %s is read-only", vg_name);
goto error;
log_error("Volume group %s is read-only", lp->vg_name);
return ECMD_FAILED;
}
/* does LV exist? */
if (!(lvl = find_lv_in_vg(vg, lv_name))) {
if (!(lvl = find_lv_in_vg(vg, lp->lv_name))) {
log_error("Logical volume %s not found in volume group %s",
lv_name, vg_name);
goto error;
lp->lv_name, lp->vg_name);
return ECMD_FAILED;
}
if (arg_count(cmd, stripes_ARG)) {
if (vg->fid->fmt->features & FMT_SEGMENTS)
stripes = arg_uint_value(cmd, stripes_ARG, 1);
lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
else
log_print("Varied striping not supported. Ignoring.");
}
@@ -133,10 +154,11 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
if (arg_count(cmd, stripesize_ARG)) {
if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
log_error("Stripesize may not be negative.");
goto error;
return ECMD_FAILED;
}
if (vg->fid->fmt->features & FMT_SEGMENTS)
ssize = 2 * arg_uint_value(cmd, stripesize_ARG, 0);
lp->stripe_size = 2 * arg_uint_value(cmd,
stripesize_ARG, 0);
else
log_print("Varied stripesize not supported. Ignoring.");
}
@@ -145,179 +167,192 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
if (lv->status & LOCKED) {
log_error("Can't resize locked LV %s", lv->name);
goto error;
return ECMD_FAILED;
}
if (size) {
/* No of 512-byte sectors */
extents = size * 2;
alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc);
if (extents % vg->extent_size) {
if (sign == SIGN_MINUS)
extents -= extents % vg->extent_size;
if (lp->size) {
if (lp->size % vg->extent_size) {
if (lp->sign == SIGN_MINUS)
lp->size -= lp->size % vg->extent_size;
else
extents += vg->extent_size -
(extents % vg->extent_size);
lp->size += vg->extent_size -
(lp->size % vg->extent_size);
log_print("Rounding up size to full physical extent %s",
display_size(cmd, (uint64_t) extents / 2,
display_size(cmd, (uint64_t) lp->size,
SIZE_SHORT));
}
extents /= vg->extent_size;
lp->extents = lp->size / vg->extent_size;
}
if (sign == SIGN_PLUS)
extents += lv->le_count;
if (lp->sign == SIGN_PLUS)
lp->extents += lv->le_count;
if (sign == SIGN_MINUS) {
if (extents >= lv->le_count) {
if (lp->sign == SIGN_MINUS) {
if (lp->extents >= lv->le_count) {
log_error("Unable to reduce %s below 1 extent",
lv_name);
goto error_cmdline;
lp->lv_name);
return EINVALID_CMD_LINE;
}
extents = lv->le_count - extents;
lp->extents = lv->le_count - lp->extents;
}
if (!extents) {
if (!lp->extents) {
log_error("New size of 0 not permitted");
goto error_cmdline;
return EINVALID_CMD_LINE;
}
if (extents == lv->le_count) {
if (lp->extents == lv->le_count) {
log_error("New size (%d extents) matches existing size "
"(%d extents)", extents, lv->le_count);
goto error_cmdline;
"(%d extents)", lp->extents, lv->le_count);
return EINVALID_CMD_LINE;
}
seg_size = extents - lv->le_count;
seg_size = lp->extents - lv->le_count;
/* Use segment type of last segment */
list_iterate_items(seg, &lv->segments) {
lp->segtype = seg->segtype;
}
/* FIXME Support LVs with mixed segment types */
if (lp->segtype != (struct segment_type *) arg_ptr_value(cmd, type_ARG,
lp->segtype)) {
log_error("VolumeType does not match (%s)", lp->segtype->name);
return EINVALID_CMD_LINE;
}
/* If extending, find stripes, stripesize & size of last segment */
if (extents > lv->le_count && !(stripes == 1 || (stripes > 1 && ssize))) {
if ((lp->extents > lv->le_count) &&
!(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
list_iterate_items(seg, &lv->segments) {
if (seg->type != SEG_STRIPED)
if (!(seg->segtype->flags & SEG_AREAS_STRIPED))
continue;
sz = seg->stripe_size;
str = seg->area_count;
if ((seg_stripesize && seg_stripesize != sz
&& !ssize) ||
(seg_stripes && seg_stripes != str && !stripes)) {
&& !lp->stripe_size) ||
(seg_stripes && seg_stripes != str && !lp->stripes)) {
log_error("Please specify number of "
"stripes (-i) and stripesize (-I)");
goto error_cmdline;
return EINVALID_CMD_LINE;
}
seg_stripesize = sz;
seg_stripes = str;
}
if (!stripes)
stripes = seg_stripes;
if (!lp->stripes)
lp->stripes = seg_stripes;
if (!ssize && stripes > 1) {
if (!lp->stripe_size && lp->stripes > 1) {
if (seg_stripesize) {
log_print("Using stripesize of last segment "
"%dKB", seg_stripesize / 2);
ssize = seg_stripesize;
lp->stripe_size = seg_stripesize;
} else {
ssize = find_config_int(cmd->cft->root,
lp->stripe_size =
find_config_int(cmd->cft->root,
"metadata/stripesize",
DEFAULT_STRIPESIZE) * 2;
log_print("Using default stripesize %dKB",
ssize / 2);
lp->stripe_size / 2);
}
}
}
/* If reducing, find stripes, stripesize & size of last segment */
if (extents < lv->le_count) {
if (lp->extents < lv->le_count) {
extents_used = 0;
if (stripes || ssize)
if (lp->stripes || lp->stripe_size)
log_error("Ignoring stripes and stripesize arguments "
"when reducing");
list_iterate_items(seg, &lv->segments) {
seg_extents = seg->len;
if (seg->type == SEG_STRIPED) {
if (seg->segtype->flags & SEG_AREAS_STRIPED) {
seg_stripesize = seg->stripe_size;
seg_stripes = seg->area_count;
}
if (extents <= extents_used + seg_extents)
if (lp->extents <= extents_used + seg_extents)
break;
extents_used += seg_extents;
}
seg_size = extents - extents_used;
ssize = seg_stripesize;
stripes = seg_stripes;
seg_size = lp->extents - extents_used;
lp->stripe_size = seg_stripesize;
lp->stripes = seg_stripes;
}
if (stripes > 1 && !ssize) {
if (lp->stripes > 1 && !lp->stripe_size) {
log_error("Stripesize for striped segment should not be 0!");
goto error_cmdline;
return EINVALID_CMD_LINE;
}
if ((stripes > 1)) {
if (!(stripesize_extents = ssize / vg->extent_size))
if ((lp->stripes > 1)) {
if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
stripesize_extents = 1;
if ((size_rest = seg_size % (stripes * stripesize_extents))) {
if ((size_rest = seg_size % (lp->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;
lp->extents, lp->extents - size_rest);
lp->extents = lp->extents - size_rest;
}
}
if (extents == lv->le_count) {
if (lp->extents == lv->le_count) {
log_error("New size (%d extents) matches existing size "
"(%d extents)", extents, lv->le_count);
goto error_cmdline;
"(%d extents)", lp->extents, lv->le_count);
return EINVALID_CMD_LINE;
}
if (extents < lv->le_count) {
if (resize == LV_EXTEND) {
if (lp->extents < lv->le_count) {
if (lp->resize == LV_EXTEND) {
log_error("New size given (%d extents) not larger "
"than existing size (%d extents)",
extents, lv->le_count);
goto error_cmdline;
lp->extents, lv->le_count);
return EINVALID_CMD_LINE;
} else
resize = LV_REDUCE;
lp->resize = LV_REDUCE;
}
if (extents > lv->le_count) {
if (resize == LV_REDUCE) {
if (lp->extents > lv->le_count) {
if (lp->resize == LV_REDUCE) {
log_error("New size given (%d extents) not less than "
"existing size (%d extents)", extents,
"existing size (%d extents)", lp->extents,
lv->le_count);
goto error_cmdline;
return EINVALID_CMD_LINE;
} else
resize = LV_EXTEND;
lp->resize = LV_EXTEND;
}
if (resize == LV_REDUCE) {
if (argc)
if (lp->resize == LV_REDUCE) {
if (lp->argc)
log_print("Ignoring PVs on command line when reducing");
memset(&info, 0, sizeof(info));
if (!lv_info(lv, &info) && driver_version(NULL, 0)) {
log_error("lv_info failed: aborting");
goto error;
return ECMD_FAILED;
}
if (info.exists) {
log_print("WARNING: Reducing active%s logical volume "
"to %s", info.open_count ? " and open" : "",
display_size(cmd, (uint64_t)
extents * (vg->extent_size / 2),
display_size(cmd, (uint64_t) lp->extents *
vg->extent_size,
SIZE_SHORT));
log_print("THIS MAY DESTROY YOUR DATA "
@@ -326,44 +361,52 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
if (!arg_count(cmd, force_ARG)) {
if (yes_no_prompt("Do you really want to reduce %s?"
" [y/n]: ", lv_name) == 'n') {
" [y/n]: ", lp->lv_name) == 'n') {
log_print("Logical volume %s NOT reduced",
lv_name);
goto error;
lp->lv_name);
return ECMD_FAILED;
}
}
if (!archive(vg))
goto error;
if (!lv_reduce(vg->fid, lv, lv->le_count - extents))
goto error;
}
if (resize == LV_EXTEND) {
if (!(pvh = argc ? create_pv_list(cmd->mem, vg, argc - opt,
argv + opt) : &vg->pvs)) {
if (!archive(vg)) {
stack;
goto error;
return ECMD_FAILED;
}
if (!archive(vg))
goto error;
if (!lv_reduce(vg->fid, lv, lv->le_count - lp->extents))
return ECMD_FAILED;
}
log_print("Extending logical volume %s to %s", lv_name,
if (lp->resize == LV_EXTEND) {
if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc,
lp->argv) : &vg->pvs)) {
stack;
return ECMD_FAILED;
}
if (!archive(vg)) {
stack;
return ECMD_FAILED;
}
log_print("Extending logical volume %s to %s", lp->lv_name,
display_size(cmd, (uint64_t)
extents * (vg->extent_size / 2),
lp->extents * vg->extent_size,
SIZE_SHORT));
if (!lv_extend(vg->fid, lv, stripes, ssize,
extents - lv->le_count, pvh))
goto error;
if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes,
lp->stripe_size, 0u,
lp->extents - lv->le_count,
NULL, 0u, 0u, pvh, alloc)) {
stack;
return ECMD_FAILED;
}
}
/* store vg on disk(s) */
if (!vg_write(vg)) {
stack;
goto error;
return ECMD_FAILED;
}
backup(vg);
@@ -374,34 +417,48 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
else
lock_lvid = lv->lvid.s;
if (!lock_vol(cmd, lock_lvid, LCK_LV_SUSPEND | LCK_HOLD)) {
log_error("Can't get lock for %s", lv_name);
if (!suspend_lv(cmd, lock_lvid)) {
log_error("Failed to suspend %s", lp->lv_name);
vg_revert(vg);
goto error;
return ECMD_FAILED;
}
if (!vg_commit(vg)) {
stack;
unlock_lv(cmd, lock_lvid);
goto error;
resume_lv(cmd, lock_lvid);
return ECMD_FAILED;
}
if (!unlock_lv(cmd, lock_lvid)) {
log_error("Problem reactivating %s", lv_name);
goto error;
if (!resume_lv(cmd, lock_lvid)) {
log_error("Problem reactivating %s", lp->lv_name);
return ECMD_FAILED;
}
unlock_vg(cmd, vg_name);
log_print("Logical volume %s successfully resized", lv_name);
log_print("Logical volume %s successfully resized", lp->lv_name);
return ECMD_PROCESSED;
error:
unlock_vg(cmd, vg_name);
return ECMD_FAILED;
error_cmdline:
unlock_vg(cmd, vg_name);
return EINVALID_CMD_LINE;
}
int lvresize(struct cmd_context *cmd, int argc, char **argv)
{
struct lvresize_params lp;
int r;
memset(&lp, 0, sizeof(lp));
if (!_read_params(cmd, argc, argv, &lp))
return EINVALID_CMD_LINE;
log_verbose("Finding volume group %s", lp.vg_name);
if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", lp.vg_name);
return ECMD_FAILED;
}
if (!(r = _lvresize(cmd, &lp)))
stack;
unlock_vg(cmd, lp.vg_name);
return r;
}

View File

@@ -39,7 +39,7 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
log_print("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
cmd->dev_dir, lv->vg->name, lv->name,
display_size(cmd, lv->size / 2, SIZE_SHORT),
display_size(cmd, lv->size, SIZE_SHORT),
get_alloc_string(lv->alloc));
lv_total++;

264
tools/polldaemon.c Normal file
View File

@@ -0,0 +1,264 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tools.h"
#include "polldaemon.h"
#include <signal.h>
#include <sys/wait.h>
static void _sigchld_handler(int sig)
{
while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ;
}
static int _become_daemon(struct cmd_context *cmd)
{
pid_t pid;
struct sigaction act = {
{_sigchld_handler},
.sa_flags = SA_NOCLDSTOP,
};
log_verbose("Forking background process");
sigaction(SIGCHLD, &act, NULL);
if ((pid = fork()) == -1) {
log_error("fork failed: %s", strerror(errno));
return 1;
}
/* Parent */
if (pid > 0)
return 0;
/* Child */
if (setsid() == -1)
log_error("Background process failed to setsid: %s",
strerror(errno));
init_verbose(VERBOSE_BASE_LEVEL);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
strncpy(*cmd->argv, "(lvm2copyd)", strlen(*cmd->argv));
reset_locking();
dev_close_all();
return 1;
}
static int _check_mirror_status(struct cmd_context *cmd,
struct volume_group *vg,
struct logical_volume *lv_mirr,
const char *name, struct daemon_parms *parms,
int *finished)
{
struct list *lvs_changed;
float segment_percent = 0.0, overall_percent = 0.0;
uint32_t event_nr = 0;
/* By default, caller should not retry */
*finished = 1;
if (parms->aborting) {
if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
log_error("Failed to generate list of copied LVs: "
"can't abort.");
return 0;
}
parms->poll_fns->finish_copy(cmd, vg, lv_mirr, lvs_changed);
return 0;
}
if (!lv_mirror_percent(lv_mirr, !parms->interval, &segment_percent,
&event_nr)) {
log_error("ABORTING: Mirror percentage check failed.");
return 0;
}
overall_percent = copy_percent(lv_mirr);
if (parms->progress_display)
log_print("%s: Moved: %.1f%%", name, overall_percent);
else
log_verbose("%s: Moved: %.1f%%", name, overall_percent);
if (segment_percent < 100.0) {
/* The only case the caller *should* try again later */
*finished = 0;
return 1;
}
if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
log_error("ABORTING: Failed to generate list of copied LVs");
return 0;
}
/* Finished? Or progress to next segment? */
if (overall_percent >= 100.0) {
if (!parms->poll_fns->finish_copy(cmd, vg, lv_mirr,
lvs_changed))
return 0;
} else {
if (!parms->poll_fns->update_metadata(cmd, vg, lv_mirr,
lvs_changed, 0)) {
log_error("ABORTING: Segment progression failed.");
parms->poll_fns->finish_copy(cmd, vg, lv_mirr,
lvs_changed);
return 0;
}
*finished = 0; /* Another segment */
}
return 1;
}
static int _wait_for_single_mirror(struct cmd_context *cmd, const char *name,
struct daemon_parms *parms)
{
struct volume_group *vg;
struct logical_volume *lv_mirr;
int finished = 0;
/* Poll for mirror completion */
while (!finished) {
/* FIXME Also needed in vg/lvchange -ay? */
/* FIXME Use alarm for regular intervals instead */
if (parms->interval && !parms->aborting)
sleep(parms->interval);
/* Locks the (possibly renamed) VG again */
if (!(vg = parms->poll_fns->get_copy_vg(cmd, name))) {
log_error("ABORTING: Can't reread VG for %s", name);
/* What more could we do here? */
return 0;
}
if (!(lv_mirr = parms->poll_fns->get_copy_lv(cmd, vg, name,
parms->lv_type))) {
log_error("ABORTING: Can't find mirror LV in %s for %s",
vg->name, name);
unlock_vg(cmd, vg->name);
return 0;
}
if (!_check_mirror_status(cmd, vg, lv_mirr, name, parms,
&finished)) {
unlock_vg(cmd, vg->name);
return 0;
}
unlock_vg(cmd, vg->name);
}
return 1;
}
static int _poll_vg(struct cmd_context *cmd, const char *vgname,
struct volume_group *vg, int consistent, void *handle)
{
struct daemon_parms *parms = (struct daemon_parms *) handle;
struct lv_list *lvl;
struct logical_volume *lv_mirr;
const char *name;
int finished;
if (!vg) {
log_error("Couldn't read volume group %s", vgname);
return ECMD_FAILED;
}
if (!consistent) {
log_error("Volume Group %s inconsistent - skipping", vgname);
/* FIXME Should we silently recover it here or not? */
return ECMD_FAILED;
}
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return ECMD_FAILED;
}
list_iterate_items(lvl, &vg->lvs) {
lv_mirr = lvl->lv;
if (!(lv_mirr->status & parms->lv_type))
continue;
if (!(name = parms->poll_fns->get_copy_name_from_lv(lv_mirr)))
continue;
/* FIXME Need to do the activation from _set_up_pvmove here
* if it's not running and we're not aborting */
if (_check_mirror_status(cmd, vg, lv_mirr, name,
parms, &finished) && !finished)
parms->outstanding_count++;
}
return ECMD_PROCESSED;
}
static void _poll_for_all_vgs(struct cmd_context *cmd,
struct daemon_parms *parms)
{
while (1) {
parms->outstanding_count = 0;
process_each_vg(cmd, 0, NULL, LCK_VG_WRITE, 1, parms, _poll_vg);
if (!parms->outstanding_count)
break;
sleep(parms->interval);
}
}
int poll_daemon(struct cmd_context *cmd, const char *name, unsigned background,
uint32_t lv_type, struct poll_functions *poll_fns)
{
struct daemon_parms parms;
parms.aborting = arg_count(cmd, abort_ARG) ? 1 : 0;
parms.background = background;
parms.interval = arg_uint_value(cmd, interval_ARG, DEFAULT_INTERVAL);
parms.progress_display = 1;
parms.lv_type = lv_type;
parms.poll_fns = poll_fns;
if (parms.interval && !parms.aborting)
log_verbose("Checking progress every %u seconds",
parms.interval);
if (!parms.interval) {
parms.progress_display = 0;
/* FIXME Disabled multiple-copy wait_event */
if (!name)
parms.interval = DEFAULT_INTERVAL;
}
if (parms.background) {
if (!_become_daemon(cmd))
return ECMD_PROCESSED; /* Parent */
parms.progress_display = 0;
/* FIXME Use wait_event (i.e. interval = 0) and */
/* fork one daemon per copy? */
}
if (name) {
if (!_wait_for_single_mirror(cmd, name, &parms))
return ECMD_FAILED;
} else
_poll_for_all_vgs(cmd, &parms);
return ECMD_PROCESSED;
}

52
tools/polldaemon.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TOOL_POLLDAEMON_H
#define _LVM_TOOL_POLLDAEMON_H
#include "metadata.h"
struct poll_functions {
const char *(*get_copy_name_from_lv) (struct logical_volume * lv_mirr);
struct volume_group *(*get_copy_vg) (struct cmd_context * cmd,
const char *name);
struct logical_volume *(*get_copy_lv) (struct cmd_context * cmd,
struct volume_group * vg,
const char *name,
uint32_t lv_type);
int (*update_metadata) (struct cmd_context * cmd,
struct volume_group * vg,
struct logical_volume * lv_mirr,
struct list * lvs_changed, int first_time);
int (*finish_copy) (struct cmd_context * cmd,
struct volume_group * vg,
struct logical_volume * lv_mirr,
struct list * lvs_changed);
};
struct daemon_parms {
unsigned interval;
unsigned aborting;
unsigned background;
unsigned outstanding_count;
unsigned progress_display;
uint32_t lv_type;
struct poll_functions *poll_fns;
};
int poll_daemon(struct cmd_context *cmd, const char *name, unsigned background,
uint32_t lv_type, struct poll_functions *poll_fns);
#endif

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