1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-12-24 16:23:50 +03:00

Compare commits

...

47 Commits

Author SHA1 Message Date
Alasdair Kergon
32d9126094 . 2006-10-12 17:42:40 +00:00
Alasdair Kergon
db43314e50 missing mesg 2006-10-12 17:41:21 +00:00
Alasdair Kergon
68d2baeb65 pre-release 2006-10-12 17:37:42 +00:00
Alasdair Kergon
1fd5f562d3 noflush code fixes: missing debug log; non-standard variable name 2006-10-12 17:29:05 +00:00
Alasdair Kergon
48e02f2086 remove unused variable 2006-10-12 17:18:40 +00:00
Alasdair Kergon
eab7b2b581 fix dmsetup usage display (missing \n and --noflush wrong place) 2006-10-12 17:09:09 +00:00
Alasdair Kergon
45abade7fc Add suspend noflush support.
Add basic dmsetup loop support.
2006-10-12 15:42:25 +00:00
Alasdair Kergon
5372fc4b43 Test message to lvm-devel list. 2006-10-10 17:20:40 +00:00
Patrick Caulfield
4e2f240c98 Add clvmd call to return the cluster name. 2006-10-09 14:11:57 +00:00
Alasdair Kergon
bb3605518d add cling allocation policy 2006-10-08 12:01:13 +00:00
Alasdair Kergon
3ef6d37f27 . 2006-10-07 23:42:03 +00:00
Alasdair Kergon
88e9f2f7f4 check_contiguous to use for_each_pv 2006-10-07 23:40:36 +00:00
Alasdair Kergon
704a447df9 More work towards pv->size always holding the same value in internal metadata.
Store it in external text metadata as dev_size, and estimate it if not
present when metadata is read back in.
2006-10-07 23:17:17 +00:00
Alasdair Kergon
a5fcb26a33 rely on pv_setup functions to fix up pe_count 2006-10-07 23:06:18 +00:00
Alasdair Kergon
2491a61481 Accept regionsize with lvconvert. 2006-10-07 23:04:36 +00:00
Alasdair Kergon
91831d51ed more refactoring 2006-10-07 16:00:28 +00:00
Alasdair Kergon
174f0c19f7 Extend _for_each_pv() to allow termination without error. 2006-10-07 12:41:06 +00:00
Alasdair Kergon
de6fadfb4f abstract _is_contiguous() 2006-10-07 11:34:53 +00:00
Alasdair Kergon
f946db3e00 move _for_each_pv() 2006-10-07 11:23:22 +00:00
Alasdair Kergon
8d05e5bc31 Remove duplicated pv arg from _check_contiguous(). 2006-10-07 11:00:09 +00:00
Alasdair Kergon
cfb46820e4 Accept regionsize with lvconvert 2006-10-07 10:47:05 +00:00
Alasdair Kergon
081f1cbcc2 Correct regionsize default on lvcreate man page (MB). 2006-10-07 10:43:40 +00:00
Alasdair Kergon
7bc6da326f Add report columns with underscore before field names ending 'size'. 2006-10-07 10:42:27 +00:00
Patrick Caulfield
cd95a0df7b Use strncpy rather than strcpy 2006-10-06 10:06:37 +00:00
Patrick Caulfield
82fa497c16 Fix clvmd bug that could cause it to die when a node with a long name crashed. 2006-10-06 10:06:10 +00:00
Alasdair Kergon
44fd345206 Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
(This area of the code needs a lot more work.)
2006-10-05 22:02:52 +00:00
Alasdair Kergon
088e1c9db4 Fix _for_each_pv() for mirror with core log. 2006-10-05 21:24:48 +00:00
Alasdair Kergon
d4f16e666e Add lvm_dump.sh script to create a tarball of debugging info from a system. 2006-10-05 18:42:33 +00:00
Patrick Caulfield
8233cfd371 Vastly improve the errors returned to the user from clvmd.
It now captures the error messages that are generated and returns them
in the reply packet rather than just telling the user to check syslog.
2006-10-05 13:55:50 +00:00
Alasdair Kergon
ff05e2e30d Remove unused #defines from filter-md.c. 2006-10-04 16:03:17 +00:00
Patrick Caulfield
a8ea7dd3fb Make clvmd restart init script wait until clvmd has died before starting it. 2006-10-04 08:42:14 +00:00
Patrick Caulfield
96f70a5303 Update man page for clvmd -R 2006-10-04 08:28:17 +00:00
Patrick Caulfield
f1604c3e69 Add -R switch to clvmd.
This option will instruct all the clvmd daemons in the cluster to reload their device cache
2006-10-04 08:22:16 +00:00
Alasdair Kergon
c42c8c5192 Test. Future commit messages should now also go to the dm-devel list
(450 subscribers) for discussion as well as the read-only dm-cvs list
(just 15 subscribers).
2006-10-03 21:51:28 +00:00
Alasdair Kergon
5facb53a41 exclude targets that are always built-in 2006-10-03 18:02:06 +00:00
Alasdair Kergon
d039ce89af Add LV column to reports listing kernel modules needed for activation. 2006-10-03 17:55:20 +00:00
Alasdair Kergon
bc7605103f Show available fields if report given invalid field. (e.g. lvs -o list) 2006-10-02 16:46:27 +00:00
Alasdair Kergon
d305d655d4 Fix compiler warnings in percent arg. [pjc] 2006-10-02 16:15:03 +00:00
Alasdair Kergon
4ef1220b16 Add timestamp functions with --disable-realtime configure option. [AJ] 2006-09-30 20:02:02 +00:00
Alasdair Kergon
a4fef143cd Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
e.g. lvcreate -l 100%FREE to create an LV using all available space.
     lvextend -l 50%LV to increase an LV by 50% of its existing size.
     lvcreate -l 20%VG to create an LV using 20% of the total VG size.
2006-09-26 09:35:43 +00:00
Alasdair Kergon
74ecb724a9 Fix two potential NULL pointer derefs in error cases in vg_read(). 2006-09-21 20:25:54 +00:00
Alasdair Kergon
af235897ab Separate --enable-cluster from locking lib options in lvmconf.sh. 2006-09-20 17:36:47 +00:00
Alasdair Kergon
5ec4e458b5 Supply missing comma. [via Debian] 2006-09-19 20:20:40 +00:00
Alasdair Kergon
2dae63ce21 post-release 2006-09-19 19:36:59 +00:00
Alasdair Kergon
be748fe33b pre-release 2006-09-19 19:15:10 +00:00
Alasdair Kergon
7408340b6a Fix lvconvert mirror change case detection logic.
Fix mirror log detachment so it correctly becomes a standalone LV.
2006-09-19 19:13:41 +00:00
Alasdair Kergon
29eb92446e post-release 2006-09-19 17:50:58 +00:00
62 changed files with 1816 additions and 188 deletions

View File

@@ -1 +1 @@
2.02.10-cvs (2006-08-17)
2.02.11-cvs (2006-09-19)

View File

@@ -1,5 +1,35 @@
Version 2.02.10 -
==================================
Version 2.02.11 -
=====================================
Add clvmd function to return the cluster name. not used by LVM yet.
Add cling allocation policy.
Change _check_contiguous() to use _for_each_pv().
Extend _for_each_pv() to allow termination without error.
Abstract _is_contiguous().
Remove duplicated pv arg from _check_contiguous().
Accept regionsize with lvconvert.
Add report columns with underscore before field names ending 'size'.
Correct regionsize default on lvcreate man page (MB).
Fix clvmd bug that could cause it to die when a node with a long name crashed.
Add device size to text metadata.
Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
Fix _for_each_pv() for mirror with core log.
Add lvm_dump.sh script to create a tarball of debugging info from a system.
Capture error messages in clvmd and pass them back to the user.
Remove unused #defines from filter-md.c.
Make clvmd restart init script wait until clvmd has died before starting it.
Add -R to clvmd which tells running clvmds to reload their device cache.
Add LV column to reports listing kernel modules needed for activation.
Show available fields if report given invalid field. (e.g. lvs -o list)
Add timestamp functions with --disable-realtime configure option.
Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
Fix two potential NULL pointer derefs in error cases in vg_read().
Separate --enable-cluster from locking lib options in lvmconf.sh.
Add a missing comma in lvcreate man page.
Version 2.02.10 - 19th September 2006
=====================================
Fix lvconvert mirror change case detection logic.
Fix mirror log detachment so it correctly becomes a standalone LV.
Extend _check_contiguous() to detect single-area LVs.
Include mirror log (untested) in _for_each_pv() processing.
Use MIRROR_LOG_SIZE constant.

View File

@@ -1,3 +1,9 @@
Version 1.02.11 - 12 Oct 2006
==============================
Add suspend noflush support.
Add basic dmsetup loop support.
Switch dmsetup to use dm_malloc and dm_free.
Version 1.02.10 - 19 Sep 2006
=============================
Add dm_snprintf(), dm_split_words() and dm_split_lvm_name() to libdevmapper.

108
configure vendored
View File

@@ -310,7 +310,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 build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD 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 build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -853,6 +853,7 @@ Optional Features:
statically. Default is dynamic linking
--enable-readline Enable readline support
--disable-selinux Disable selinux support
--disable-realtime Disable realtime clock support
--enable-debug Enable debugging
--disable-devmapper Disable device-mapper interaction
--disable-o_direct Disable O_DIRECT
@@ -1459,6 +1460,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=yes
SELINUX=yes
REALTIME=yes
CLUSTER=internal
FSADM=no ;;
darwin*)
@@ -1473,6 +1475,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=no
SELINUX=no
REALTIME=no
CLUSTER=none
FSADM=no ;;
esac
@@ -7431,6 +7434,17 @@ fi;
echo "$as_me:$LINENO: result: $SELINUX" >&5
echo "${ECHO_T}$SELINUX" >&6
################################################################################
echo "$as_me:$LINENO: checking whether to enable realtime support" >&5
echo $ECHO_N "checking whether to enable realtime support... $ECHO_C" >&6
# Check whether --enable-realtime or --disable-realtime was given.
if test "${enable_realtime+set}" = set; then
enableval="$enable_realtime"
REALTIME=$enableval
fi;
echo "$as_me:$LINENO: result: $REALTIME" >&5
echo "${ECHO_T}$REALTIME" >&6
################################################################################
echo "$as_me:$LINENO: checking whether to build cluster LVM daemon" >&5
echo $ECHO_N "checking whether to build cluster LVM daemon... $ECHO_C" >&6
@@ -8420,6 +8434,96 @@ echo "$as_me: WARNING: Disabling selinux" >&2;}
fi
fi
################################################################################
if test x$REALTIME = xyes; then
echo "$as_me:$LINENO: checking for clock_gettime function" >&5
echo $ECHO_N "checking for clock_gettime function... $ECHO_C" >&6
echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char clock_gettime ();
int
main ()
{
clock_gettime ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_lib_rt_clock_gettime=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_rt_clock_gettime=no
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
echo "${ECHO_T}$ac_cv_lib_rt_clock_gettime" >&6
if test $ac_cv_lib_rt_clock_gettime = yes; then
HAVE_REALTIME=yes
else
HAVE_REALTIME=no
fi
echo "$as_me:$LINENO: result: $HAVE_REALTIME" >&5
echo "${ECHO_T}$HAVE_REALTIME" >&6
if test x$HAVE_REALTIME = xyes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_REALTIME 1
_ACEOF
LIBS="-lrt $LIBS"
else
{ echo "$as_me:$LINENO: WARNING: Disabling realtime clock" >&5
echo "$as_me: WARNING: Disabling realtime clock" >&2;}
fi
fi
################################################################################
for ac_header in getopt.h
@@ -11095,6 +11199,7 @@ fi
################################################################################
@@ -11789,6 +11894,7 @@ s,@DEBUG@,$DEBUG,;t t
s,@DEVMAPPER@,$DEVMAPPER,;t t
s,@HAVE_LIBDL@,$HAVE_LIBDL,;t t
s,@HAVE_SELINUX@,$HAVE_SELINUX,;t t
s,@HAVE_REALTIME@,$HAVE_REALTIME,;t t
s,@CMDLIB@,$CMDLIB,;t t
s,@LOCALEDIR@,$LOCALEDIR,;t t
s,@CONFDIR@,$CONFDIR,;t t

View File

@@ -42,6 +42,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=yes
SELINUX=yes
REALTIME=yes
CLUSTER=internal
FSADM=no ;;
darwin*)
@@ -56,6 +57,7 @@ case "$host_os" in
DEVMAPPER=yes
ODIRECT=no
SELINUX=no
REALTIME=no
CLUSTER=none
FSADM=no ;;
esac
@@ -282,6 +284,13 @@ AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
SELINUX=$enableval)
AC_MSG_RESULT($SELINUX)
################################################################################
dnl -- Disable realtime clock support
AC_MSG_CHECKING(whether to enable realtime support)
AC_ARG_ENABLE(realtime, [ --disable-realtime Disable realtime clock support],
REALTIME=$enableval)
AC_MSG_RESULT($REALTIME)
################################################################################
dnl -- Build cluster LVM daemon
AC_MSG_CHECKING(whether to build cluster LVM daemon)
@@ -449,6 +458,21 @@ if test x$SELINUX = xyes; then
fi
fi
################################################################################
dnl -- Check for realtime clock support
if test x$REALTIME = xyes; then
AC_MSG_CHECKING(for clock_gettime function)
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
AC_MSG_RESULT($HAVE_REALTIME)
if test x$HAVE_REALTIME = xyes; then
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
LIBS="-lrt $LIBS"
else
AC_MSG_WARN(Disabling realtime clock)
fi
fi
################################################################################
dnl -- Check for getopt
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 to if getopt_long is available.]))
@@ -578,6 +602,7 @@ AC_SUBST(DEBUG)
AC_SUBST(DEVMAPPER)
AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_SELINUX)
AC_SUBST(HAVE_REALTIME)
AC_SUBST(CMDLIB)
AC_SUBST(MSGFMT)
AC_SUBST(LOCALEDIR)

View File

@@ -19,6 +19,7 @@ SOURCES = \
clvmd-command.c \
clvmd.c \
lvm-functions.c \
refresh_clvmd.c \
system-lv.c
ifeq ("@CLVMD@", "gulm")

View File

@@ -63,4 +63,8 @@ static const char CLVMD_SOCKNAME[] = "\0clvmd";
#define CLVMD_CMD_LOCK_LV 50
#define CLVMD_CMD_LOCK_VG 51
/* Misc functions */
#define CLVMD_CMD_REFRESH 40
#define CLVMD_CMD_GET_CLUSTERNAME 41
#endif

View File

@@ -172,7 +172,7 @@ static int _cluster_do_node_callback(struct local_client *client,
this currently just means that a node has stopped listening on our port */
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
{
char namebuf[MAX_CLUSTER_NAME_LEN];
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
switch (reason) {
case CMAN_REASON_PORTCLOSED:
@@ -471,6 +471,18 @@ static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
}
static int _get_cluster_name(char *buf, int buflen)
{
cman_cluster_t cluster_info;
int status;
status = cman_get_cluster(c_handle, &cluster_info);
if (!status) {
strncpy(buf, cluster_info.ci_name, buflen);
}
return status;
}
static struct cluster_ops _cluster_cman_ops = {
.cluster_init_completed = _cluster_init_completed,
.cluster_send_message = _cluster_send_message,
@@ -484,6 +496,7 @@ static struct cluster_ops _cluster_cman_ops = {
.get_our_csid = _get_our_csid,
.add_up_node = _add_up_node,
.cluster_closedown = _cluster_closedown,
.get_cluster_name = _get_cluster_name,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};

View File

@@ -75,6 +75,8 @@
#include "clvmd.h"
#include "libdlm.h"
extern struct cluster_ops *clops;
/* This is where all the real work happens:
NOTE: client will be NULL when this is executed on a remote node */
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
@@ -117,11 +119,21 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
if (status == EIO) {
*retlen =
1 + snprintf(*buf, buflen,
"Internal lvm error, check syslog");
get_last_lvm_error());
return EIO;
}
break;
case CLVMD_CMD_REFRESH:
do_refresh_cache();
break;
case CLVMD_CMD_GET_CLUSTERNAME:
status = clops->get_cluster_name(*buf, buflen);
if (!status)
*retlen = strlen(*buf);
break;
default:
/* Won't get here because command is validated in pre_command */
break;
@@ -222,6 +234,10 @@ int do_pre_command(struct local_client *client)
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
break;
case CLVMD_CMD_REFRESH:
case CLVMD_CMD_GET_CLUSTERNAME:
break;
default:
log_error("Unknown command %d received\n", header->cmd);
status = EINVAL;

View File

@@ -43,6 +43,8 @@ struct cluster_ops {
void (*reread_config) (void);
void (*cluster_closedown) (void);
int (*get_cluster_name)(char *buf, int buflen);
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
int (*sync_unlock) (const char *resource, int lockid);

View File

@@ -973,6 +973,12 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
return gulm_cluster_send_message(buf, msglen, csid, errtext);
}
static int _get_cluster_name(char *buf, int buflen)
{
strncpy(buf, cluster_name, buflen);
return 0;
}
static struct cluster_ops _cluster_gulm_ops = {
.cluster_init_completed = NULL,
.cluster_send_message = _cluster_send_message,
@@ -987,6 +993,7 @@ static struct cluster_ops _cluster_gulm_ops = {
.add_up_node = gulm_add_up_node,
.reread_config = _reread_config,
.cluster_closedown = _cluster_closedown,
.get_cluster_name = _get_cluster_name,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};

View File

@@ -42,6 +42,7 @@
#include "clvm.h"
#include "version.h"
#include "clvmd.h"
#include "refresh_clvmd.h"
#include "libdlm.h"
#include "system-lv.h"
#include "list.h"
@@ -66,7 +67,7 @@ static struct local_client local_client_head;
static unsigned short global_xid = 0; /* Last transaction ID issued */
static struct cluster_ops *clops = NULL;
struct cluster_ops *clops = NULL;
static char our_csid[MAX_CSID_LEN];
static unsigned max_csid_len;
@@ -143,6 +144,7 @@ static void usage(char *prog, FILE *file)
fprintf(file, " -V Show version of clvmd\n");
fprintf(file, " -h Show this help information\n");
fprintf(file, " -d Don't fork, run in the foreground\n");
fprintf(file, " -R Tell all running clvmds in the cluster to reload their device cache\n");
fprintf(file, " -t<secs> Command timeout (default 60 seconds)\n");
fprintf(file, "\n");
}
@@ -173,7 +175,7 @@ int main(int argc, char *argv[])
/* Deal with command-line arguments */
opterr = 0;
optind = 0;
while ((opt = getopt(argc, argv, "?vVhdt:")) != EOF) {
while ((opt = getopt(argc, argv, "?vVhdt:R")) != EOF) {
switch (opt) {
case 'h':
usage(argv[0], stdout);
@@ -183,6 +185,9 @@ int main(int argc, char *argv[])
usage(argv[0], stderr);
exit(0);
case 'R':
return refresh_clvmd();
case 'd':
debug++;
break;
@@ -1684,6 +1689,7 @@ static void *lvm_thread_fn(void *arg)
}
pthread_mutex_unlock(&lvm_thread_mutex);
}
return NULL;
}
/* Pass down some work to the LVM thread */

View File

@@ -50,12 +50,18 @@
static struct cmd_context *cmd = NULL;
static struct dm_hash_table *lv_hash = NULL;
static pthread_mutex_t lv_hash_lock;
static char last_error[1024];
struct lv_info {
int lock_id;
int lock_mode;
};
char *get_last_lvm_error()
{
return last_error;
}
/* Return the mode a lock is currently held at (or -1 if not held) */
static int get_current_lock(char *resource)
{
@@ -201,8 +207,17 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
/* Try to get the lock if it's a clustered volume group */
if (lock_flags & LCK_CLUSTER_VG) {
status = hold_lock(resource, mode, LKF_NOQUEUE);
if (status)
if (status) {
/* Return an LVM-sensible error for this.
* Forcing EIO makes the upper level return this text
* rather than the strerror text for EAGAIN.
*/
if (errno == EAGAIN) {
sprintf(last_error, "Volume is busy on another node");
errno = EIO;
}
return errno;
}
}
/* If it's suspended then resume it */
@@ -416,6 +431,13 @@ int do_check_lvm1(char *vgname)
return status == 1 ? 0 : EBUSY;
}
int do_refresh_cache()
{
DEBUGLOG("Refreshing context\n");
log_notice("Refreshing context");
return refresh_toolcontext(cmd)==1?0:-1;
}
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
that might be hanging around if we died for any reason
@@ -505,6 +527,20 @@ static void *get_initial_state()
return NULL;
}
static void lvm2_log_fn(int level, const char *file, int line,
const char *message)
{
/*
* Ignore non-error messages, but store the latest one for returning
* to the user.
*/
if (level != _LOG_ERR && level != _LOG_FATAL)
return;
strncpy(last_error, message, sizeof(last_error));
last_error[sizeof(last_error)-1] = '\0';
}
/* This checks some basic cluster-LVM configuration stuff */
static void check_config()
{
@@ -557,5 +593,8 @@ int init_lvm(int using_gulm)
get_initial_state();
/* Trap log messages so we can pass them back to the user */
init_log_fn(lvm2_log_fn);
return 1;
}

View File

@@ -25,11 +25,13 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
char *resource);
extern int do_check_lvm1(char *vgname);
extern int do_refresh_cache(void);
extern int init_lvm(int using_gulm);
extern void init_lvhash(void);
extern int hold_unlock(char *resource);
extern int hold_lock(char *resource, int mode, int flags);
extern void unlock_all(void);
extern char *get_last_lvm_error(void);
#endif

View File

@@ -0,0 +1,334 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2006 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
*/
/*
* Tell all clvmds in a cluster to refresh their toolcontext
*
*/
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <libdevmapper.h>
#include <stdint.h>
#include <stdio.h>
#include "clvm.h"
#include "refresh_clvmd.h"
typedef struct lvm_response {
char node[255];
char *response;
int status;
int len;
} lvm_response_t;
/*
* This gets stuck at the start of memory we allocate so we
* can sanity-check it at deallocation time
*/
#define LVM_SIGNATURE 0x434C564D
static int _clvmd_sock = -1;
/* Open connection to the Cluster Manager daemon */
static int _open_local_sock(void)
{
int local_socket;
struct sockaddr_un sockaddr;
/* Open local socket */
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
return -1;
}
memset(&sockaddr, 0, sizeof(sockaddr));
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
sockaddr.sun_family = AF_UNIX;
if (connect(local_socket,(struct sockaddr *) &sockaddr,
sizeof(sockaddr))) {
int saved_errno = errno;
fprintf(stderr, "connect() failed on local socket: %s\n",
strerror(errno));
if (close(local_socket))
return -1;
errno = saved_errno;
return -1;
}
return local_socket;
}
/* Send a request and return the status */
static int _send_request(char *inbuf, int inlen, char **retbuf)
{
char outbuf[PIPE_BUF];
struct clvm_header *outheader = (struct clvm_header *) outbuf;
int len;
int off;
int buflen;
int err;
/* Send it to CLVMD */
rewrite:
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
if (err == -1 && errno == EINTR)
goto rewrite;
fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
return 0;
}
/* Get the response */
reread:
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
if (errno == EINTR)
goto reread;
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
return 0;
}
if (len == 0) {
fprintf(stderr, "EOF reading CLVMD");
errno = ENOTCONN;
return 0;
}
/* Allocate buffer */
buflen = len + outheader->arglen;
*retbuf = dm_malloc(buflen);
if (!*retbuf) {
errno = ENOMEM;
return 0;
}
/* Copy the header */
memcpy(*retbuf, outbuf, len);
outheader = (struct clvm_header *) *retbuf;
/* Read the returned values */
off = 1; /* we've already read the first byte */
while (off <= outheader->arglen && len > 0) {
len = read(_clvmd_sock, outheader->args + off,
buflen - off - offsetof(struct clvm_header, args));
if (len > 0)
off += len;
}
/* Was it an error ? */
if (outheader->status != 0) {
errno = outheader->status;
/* Only return an error here if there are no node-specific
errors present in the message that might have more detail */
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
return 0;
}
}
return 1;
}
/* Build the structure header and parse-out wildcard node names */
static void _build_header(struct clvm_header *head, int cmd, const char *node,
int len)
{
head->cmd = cmd;
head->status = 0;
head->flags = 0;
head->clientid = 0;
head->arglen = len;
if (node) {
/*
* Allow a couple of special node names:
* "*" for all nodes,
* "." for the local node only
*/
if (strcmp(node, "*") == 0) {
head->node[0] = '\0';
} else if (strcmp(node, ".") == 0) {
head->node[0] = '\0';
head->flags = CLVMD_FLAG_LOCAL;
} else
strcpy(head->node, node);
} else
head->node[0] = '\0';
}
/*
* Send a message to a(or all) node(s) in the cluster and wait for replies
*/
static int _cluster_request(char cmd, const char *node, void *data, int len,
lvm_response_t ** response, int *num)
{
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
int *outptr;
char *inptr;
char *retbuf = NULL;
int status;
int i;
int num_responses = 0;
struct clvm_header *head = (struct clvm_header *) outbuf;
lvm_response_t *rarray;
*num = 0;
if (_clvmd_sock == -1)
_clvmd_sock = _open_local_sock();
if (_clvmd_sock == -1)
return 0;
_build_header(head, cmd, node, len);
memcpy(head->node + strlen(head->node) + 1, data, len);
status = _send_request(outbuf, sizeof(struct clvm_header) +
strlen(head->node) + len, &retbuf);
if (!status)
goto out;
/* Count the number of responses we got */
head = (struct clvm_header *) retbuf;
inptr = head->args;
while (inptr[0]) {
num_responses++;
inptr += strlen(inptr) + 1;
inptr += sizeof(int);
inptr += strlen(inptr) + 1;
}
/*
* Allocate response array.
* With an extra pair of INTs on the front to sanity
* check the pointer when we are given it back to free
*/
outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
sizeof(int) * 2);
if (!outptr) {
errno = ENOMEM;
status = 0;
goto out;
}
*response = (lvm_response_t *) (outptr + 2);
outptr[0] = LVM_SIGNATURE;
outptr[1] = num_responses;
rarray = *response;
/* Unpack the response into an lvm_response_t array */
inptr = head->args;
i = 0;
while (inptr[0]) {
strcpy(rarray[i].node, inptr);
inptr += strlen(inptr) + 1;
memcpy(&rarray[i].status, inptr, sizeof(int));
inptr += sizeof(int);
rarray[i].response = dm_malloc(strlen(inptr) + 1);
if (rarray[i].response == NULL) {
/* Free up everything else and return error */
int j;
for (j = 0; j < i; j++)
dm_free(rarray[i].response);
free(outptr);
errno = ENOMEM;
status = -1;
goto out;
}
strcpy(rarray[i].response, inptr);
rarray[i].len = strlen(inptr);
inptr += strlen(inptr) + 1;
i++;
}
*num = num_responses;
*response = rarray;
out:
if (retbuf)
dm_free(retbuf);
return status;
}
/* Free reply array */
static int _cluster_free_request(lvm_response_t * response)
{
int *ptr = (int *) response - 2;
int i;
int num;
/* Check it's ours to free */
if (response == NULL || *ptr != LVM_SIGNATURE) {
errno = EINVAL;
return 0;
}
num = ptr[1];
for (i = 0; i < num; i++) {
dm_free(response[i].response);
}
dm_free(ptr);
return 1;
}
int refresh_clvmd()
{
int num_responses;
char args[1]; // No args really.
lvm_response_t *response;
int saved_errno;
int status;
int i;
status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses);
/* If any nodes were down then display them and return an error */
for (i = 0; i < num_responses; i++) {
if (response[i].status == EHOSTDOWN) {
fprintf(stderr, "clvmd not running on node %s",
response[i].node);
status = 0;
errno = response[i].status;
} else if (response[i].status) {
fprintf(stderr, "Error resetting node %s: %s",
response[i].node,
response[i].response[0] ?
response[i].response :
strerror(response[i].status));
status = 0;
errno = response[i].status;
}
}
saved_errno = errno;
_cluster_free_request(response);
errno = saved_errno;
return status;
}

View File

@@ -0,0 +1,2 @@
int refresh_clvmd(void);

View File

@@ -79,6 +79,7 @@ SOURCES =\
misc/lvm-file.c \
misc/lvm-string.c \
misc/lvm-wrappers.c \
misc/timestamp.c \
mm/memlock.c \
regex/matcher.c \
regex/parse_rx.c \

View File

@@ -51,6 +51,66 @@ int lvm1_present(struct cmd_context *cmd)
return 0;
}
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct list *modules)
{
unsigned int s;
struct lv_segment *seg2, *snap_seg;
struct list *snh;
if (seg->segtype->ops->modules_needed &&
!seg->segtype->ops->modules_needed(mem, seg, modules)) {
log_error("module string allocation failed");
return 0;
}
if (lv_is_origin(seg->lv))
list_iterate(snh, &seg->lv->snapshot_segs)
if (!list_lv_modules(mem,
list_struct_base(snh,
struct lv_segment,
origin_list)->cow,
modules))
return_0;
if (lv_is_cow(seg->lv)) {
snap_seg = find_cow(seg->lv);
if (snap_seg->segtype->ops->modules_needed &&
!snap_seg->segtype->ops->modules_needed(mem, snap_seg,
modules)) {
log_error("snap_seg module string allocation failed");
return 0;
}
}
for (s = 0; s < seg->area_count; s++) {
switch (seg_type(seg, s)) {
case AREA_LV:
seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s));
if (seg2 && !list_segment_modules(mem, seg2, modules))
return_0;
break;
case AREA_PV:
case AREA_UNASSIGNED:
;
}
}
return 1;
}
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
struct list *modules)
{
struct lv_segment *seg;
list_iterate_items(seg, &lv->segments)
if (!list_segment_modules(mem, seg, modules))
return_0;
return 1;
}
#ifndef DEVMAPPER_SUPPORT
void set_activation(int act)
{

View File

@@ -39,6 +39,10 @@ int lvm1_present(struct cmd_context *cmd);
int target_present(const char *target_name, int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct list *modules);
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
struct list *modules);
void activation_release(void);
void activation_exit(void);

View File

@@ -30,6 +30,7 @@ static struct {
} _policies[] = {
{
ALLOC_CONTIGUOUS, "contiguous"}, {
ALLOC_CLING, "cling"}, {
ALLOC_NORMAL, "normal"}, {
ALLOC_ANYWHERE, "anywhere"}, {
ALLOC_INHERIT, "inherit"}

View File

@@ -23,6 +23,7 @@
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
#include "str_list.h"
static const char *_errseg_name(const struct lv_segment *seg)
{
@@ -64,6 +65,18 @@ static int _errseg_target_present(void)
}
#endif
static int _errseg_modules_needed(struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules)
{
if (!str_list_add(mem, modules, "error")) {
log_error("error module string list allocation failed");
return 0;
}
return 1;
}
static void _errseg_destroy(const struct segment_type *segtype)
{
dm_free((void *)segtype);
@@ -76,6 +89,7 @@ static struct segtype_handler _error_ops = {
.add_target_line = _errseg_add_target_line,
.target_present = _errseg_target_present,
#endif
.modules_needed = _errseg_modules_needed,
.destroy = _errseg_destroy,
};

View File

@@ -18,14 +18,6 @@
#ifdef linux
/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
#define MD_SB_MAGIC 0xa92b4efc
#define MD_RESERVED_BYTES (64 * 1024)
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
- MD_RESERVED_SECTORS)
static int _ignore_md(struct dev_filter *f, struct device *dev)
{
int ret;

View File

@@ -409,6 +409,11 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
outf(f, "tags = %s", buffer);
}
if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size)) {
stack;
return 0;
}
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)) {

View File

@@ -1007,11 +1007,8 @@ static int _mda_setup(const struct format_type *fmt,
uint64_t wipe_size = 8 << SECTOR_SHIFT;
size_t pagesize = lvm_getpagesize();
if (!pvmetadatacopies) {
/* Space available for PEs */
pv->size -= pe_align();
if (!pvmetadatacopies)
return 1;
}
alignment = pe_align() << SECTOR_SHIFT;
disk_size = pv->size << SECTOR_SHIFT;
@@ -1027,9 +1024,6 @@ static int _mda_setup(const struct format_type *fmt,
/* Requested metadatasize */
mda_size1 = pvmetadatasize << SECTOR_SHIFT;
/* Space available for PEs (before any mdas created) */
pv->size -= LABEL_SCAN_SECTORS;
/* Place mda straight after label area at start of disk */
start1 = LABEL_SCAN_SIZE;
@@ -1037,11 +1031,8 @@ static int _mda_setup(const struct format_type *fmt,
if ((!pe_start && !pe_end) ||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
mda_adjustment = start1 % pagesize;
if (mda_adjustment) {
if (mda_adjustment)
start1 += (pagesize - mda_adjustment);
pv->size -= ((pagesize - mda_adjustment) >>
SECTOR_SHIFT);
}
}
/* Ensure it's not going to be bigger than the disk! */
@@ -1071,7 +1062,8 @@ 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_set((struct device *) pv->dev, start1,
(size_t) (mda_size1 >
@@ -1080,7 +1072,6 @@ static int _mda_setup(const struct format_type *fmt,
return 0;
}
pv->size -= mda_size1 >> SECTOR_SHIFT;
if (pvmetadatacopies == 1)
return 1;
} else
@@ -1125,7 +1116,6 @@ static int _mda_setup(const struct format_type *fmt,
log_error("Failed to wipe new metadata area");
return 0;
}
pv->size -= mda_size2 >> SECTOR_SHIFT;
} else
return 0;
@@ -1416,8 +1406,8 @@ static int _text_pv_setup(const struct format_type *fmt,
struct lvmcache_info *info;
int found;
uint64_t pe_end = 0;
/* FIXME if vg, adjust start/end of pe area to avoid mdas! */
unsigned mda_count = 0;
uint64_t mda_size2 = 0;
/* FIXME Cope with pvchange */
/* FIXME Merge code with _text_create_text_instance */
@@ -1428,11 +1418,16 @@ static int _text_pv_setup(const struct format_type *fmt,
if ((info = info_from_pvid(pv->dev->pvid))) {
pvmdas = &info->mdas;
list_iterate_items(mda, pvmdas) {
mda_count++;
mdac =
(struct mda_context *) mda->metadata_locn;
/* FIXME Check it isn't already in use */
/* Reduce usable device size */
if (mda_count > 1)
mda_size2 = mdac->area.size >> SECTOR_SHIFT;
/* Ensure it isn't already on list */
found = 0;
list_iterate_items(mda2, mdas) {
@@ -1470,6 +1465,17 @@ static int _text_pv_setup(const struct format_type *fmt,
}
}
/* FIXME Cope with genuine pe_count 0 */
/* If missing, estimate pv->size from file-based metadata */
if (!pv->size && pv->pe_count)
pv->size = pv->pe_count * (uint64_t) vg->extent_size +
pv->pe_start + mda_size2;
/* Recalculate number of extents that will fit */
if (!pv->pe_count)
pv->pe_count = (pv->size - pv->pe_start - mda_size2) / vg->extent_size;
/* Unlike LVM1, we don't store this outside a VG */
/* FIXME Default from config file? vgextend cmdline flag? */
pv->status |= ALLOCATABLE_PV;

View File

@@ -179,6 +179,9 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
return 0;
}
/* Late addition */
_read_int64(pvn, "dev_size", &pv->size);
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
log_error("Couldn't read extent size for volume group.");
return 0;
@@ -206,7 +209,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
vg->free_count += pv->pe_count;
pv->pe_size = vg->extent_size;
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;

View File

@@ -398,6 +398,7 @@ struct alloced_area {
* Details of an allocation attempt
*/
struct alloc_handle {
struct cmd_context *cmd;
struct dm_pool *mem;
alloc_policy_t alloc; /* Overall policy */
@@ -417,7 +418,8 @@ struct alloc_handle {
/*
* Preparation for a specific allocation attempt
*/
static struct alloc_handle *_alloc_init(struct dm_pool *mem,
static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
struct dm_pool *mem,
const struct segment_type *segtype,
alloc_policy_t alloc,
uint32_t mirrors,
@@ -464,6 +466,8 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
if (segtype_is_virtual(segtype))
return ah;
ah->cmd = cmd;
if (!(ah->mem = dm_pool_create("allocation", 1024))) {
log_error("allocation pool creation failed");
return NULL;
@@ -666,6 +670,82 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
return 1;
}
/*
* Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
* If any constituent area contains more than one segment, max_seg_len is
* reduced to cover only the first.
* fn should return 0 on error, 1 to continue scanning or >1 to terminate without error.
* In the last case, this function passes on the return code.
*/
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t le, uint32_t len, uint32_t *max_seg_len,
uint32_t first_area, uint32_t max_areas,
int top_level_area_index,
int only_single_area_segments,
int (*fn)(struct cmd_context *cmd,
struct pv_segment *peg, uint32_t s,
void *data),
void *data)
{
struct lv_segment *seg;
uint32_t s;
uint32_t remaining_seg_len, area_len, area_multiple;
int r = 1;
if (!(seg = find_seg_by_le(lv, le))) {
log_error("Failed to find segment for %s extent %" PRIu32,
lv->name, le);
return 0;
}
/* Remaining logical length of segment */
remaining_seg_len = seg->len - (le - seg->le);
if (remaining_seg_len > len)
remaining_seg_len = len;
if (max_seg_len && *max_seg_len > remaining_seg_len)
*max_seg_len = remaining_seg_len;
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
area_len = remaining_seg_len / area_multiple ? : 1;
for (s = first_area;
s < seg->area_count && (!max_areas || s <= max_areas);
s++) {
if (seg_type(seg, s) == AREA_LV) {
if (!(r = _for_each_pv(cmd, seg_lv(seg, s),
seg_le(seg, s) +
(le - seg->le) / area_multiple,
area_len, max_seg_len,
only_single_area_segments ? 0 : 0,
only_single_area_segments ? 1 : 0,
top_level_area_index != -1 ? top_level_area_index : s,
only_single_area_segments, fn,
data)))
stack;
} else if (seg_type(seg, s) == AREA_PV)
if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? top_level_area_index : s, data)))
stack;
if (r != 1)
return r;
}
/* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */
if (!only_single_area_segments && seg_is_mirrored(seg) && seg->log_lv) {
if (!(r = _for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
NULL, 0, 0, 0, only_single_area_segments,
fn, data)))
stack;
if (r != 1)
return r;
}
/* FIXME Add snapshot cow LVs etc. */
return 1;
}
static int _comp_area(const void *l, const void *r)
{
const struct pv_area *lhs = *((const struct pv_area **) l);
@@ -680,40 +760,114 @@ static int _comp_area(const void *l, const void *r)
return 0;
}
/*
* Search for pvseg that matches condition
*/
struct pv_match {
int (*condition)(struct pv_segment *pvseg, struct pv_area *pva);
struct pv_area **areas;
struct pv_area *pva;
uint32_t areas_size;
int s; /* Area index of match */
};
/*
* Is PV area on the same PV?
*/
static int _is_same_pv(struct pv_segment *pvseg, struct pv_area *pva)
{
if (pvseg->pv != pva->map->pv)
return 0;
return 1;
}
/*
* Is PV area contiguous to PV segment?
*/
static int _is_contiguous(struct pv_segment *pvseg, struct pv_area *pva)
{
if (pvseg->pv != pva->map->pv)
return 0;
if (pvseg->pe + pvseg->len != pva->start)
return 0;
return 1;
}
static int _is_condition(struct cmd_context *cmd,
struct pv_segment *pvseg, uint32_t s,
void *data)
{
struct pv_match *pvmatch = data;
if (!pvmatch->condition(pvseg, pvmatch->pva))
return 1; /* Continue */
if (s >= pvmatch->areas_size)
return 1;
pvmatch->areas[s] = pvmatch->pva;
return 2; /* Finished */
}
/*
* Is pva on same PV as any existing areas?
*/
static int _check_cling(struct cmd_context *cmd,
struct lv_segment *prev_lvseg, struct pv_area *pva,
struct pv_area **areas, uint32_t areas_size)
{
struct pv_match pvmatch;
int r;
pvmatch.condition = _is_same_pv;
pvmatch.areas = areas;
pvmatch.areas_size = areas_size;
pvmatch.pva = pva;
/* FIXME Cope with stacks by flattening */
if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
0, 0, -1, 1,
_is_condition, &pvmatch)))
stack;
if (r != 2)
return 0;
return 1;
}
/*
* Is pva contiguous to any existing areas or on the same PV?
*/
static int _check_contiguous(struct lv_segment *prev_lvseg,
struct physical_volume *pv, struct pv_area *pva,
static int _check_contiguous(struct cmd_context *cmd,
struct lv_segment *prev_lvseg, struct pv_area *pva,
struct pv_area **areas, uint32_t areas_size)
{
struct pv_segment *prev_pvseg;
struct lv_segment *lastseg;
uint32_t s;
struct pv_match pvmatch;
int r;
for (s = 0; s < prev_lvseg->area_count && s < areas_size; s++) {
if (seg_type(prev_lvseg, s) == AREA_LV) {
lastseg = list_item(list_last(&seg_lv(prev_lvseg, s)->segments), struct lv_segment);
/* FIXME For more areas supply flattened prev_lvseg to ensure consistency */
if (lastseg->area_count == 1 &&
_check_contiguous(lastseg, pv, pva, &areas[s], 1))
return 1;
continue;
}
pvmatch.condition = _is_contiguous;
pvmatch.areas = areas;
pvmatch.areas_size = areas_size;
pvmatch.pva = pva;
if (!(prev_pvseg = seg_pvseg(prev_lvseg, s)))
continue; /* FIXME Broken */
/* FIXME Cope with stacks by flattening */
if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
0, 0, -1, 1,
_is_condition, &pvmatch)))
stack;
if ((prev_pvseg->pv != pv))
continue;
if (r != 2)
return 0;
if (prev_pvseg->pe + prev_pvseg->len == pva->start) {
areas[s] = pva;
return 1;
}
}
return 0;
return 1;
}
/*
@@ -729,9 +883,9 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
struct pv_area *pva;
struct pv_list *pvl;
unsigned already_found_one = 0;
unsigned contiguous = 0, contiguous_count = 0;
unsigned contiguous = 0, cling = 0, preferred_count = 0;
unsigned ix;
unsigned ix_offset = 0; /* Offset for non-contiguous allocations */
unsigned ix_offset = 0; /* Offset for non-preferred allocations */
uint32_t max_parallel; /* Maximum extents to allocate */
uint32_t next_le;
struct seg_pvs *spvs;
@@ -741,9 +895,14 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
/* FIXME Select log PV appropriately if there isn't one yet */
/* Are there any preceding segments we must follow on from? */
if ((alloc == ALLOC_CONTIGUOUS) && prev_lvseg) {
contiguous = 1;
if (prev_lvseg) {
ix_offset = prev_lvseg->area_count;
if ((alloc == ALLOC_CONTIGUOUS))
contiguous = 1;
else if ((alloc == ALLOC_CLING))
cling = 1;
else
ix_offset = 0;
}
/* FIXME This algorithm needs a lot of cleaning up! */
@@ -752,6 +911,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
/* ix holds the number of areas found on other PVs */
do {
ix = 0;
preferred_count = 0;
parallel_pvs = NULL;
max_parallel = needed;
@@ -801,16 +961,27 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
list_iterate_items(pva, &pvm->areas) {
if (contiguous) {
if (prev_lvseg &&
_check_contiguous(prev_lvseg,
pvm->pv,
_check_contiguous(ah->cmd,
prev_lvseg,
pva, areas,
areas_size)) {
contiguous_count++;
preferred_count++;
goto next_pv;
}
continue;
}
if (cling) {
if (prev_lvseg &&
_check_cling(ah->cmd,
prev_lvseg,
pva, areas,
areas_size)) {
preferred_count++;
}
goto next_pv;
}
/* Is it big enough on its own? */
if (pva->count * ah->area_multiple <
max_parallel - *allocated &&
@@ -834,7 +1005,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
break;
}
if (contiguous && (contiguous_count < ix_offset))
if ((contiguous || cling) && (preferred_count < ix_offset))
break;
/* Only allocate log_area the first time around */
@@ -943,6 +1114,18 @@ static int _allocate(struct alloc_handle *ah,
(!can_split && (allocated != old_allocated)))
goto finished;
old_allocated = allocated;
if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
areas_size, can_split,
prev_lvseg, &allocated, new_extents)) {
stack;
goto out;
}
if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
(!can_split && (allocated != old_allocated)))
goto finished;
old_allocated = allocated;
if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
areas_size, can_split,
@@ -1038,7 +1221,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
if (alloc == ALLOC_INHERIT)
alloc = vg->alloc;
if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
stripes, log_count, mirrored_pv,
mirrored_pe, parallel_areas))) {
stack;
@@ -1382,59 +1565,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
return lv;
}
/*
* Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
* If any constituent area contains more than one segment, max_seg_len is
* reduced to cover only the first.
*/
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t le, uint32_t len, uint32_t *max_seg_len,
int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, void *data),
void *data)
{
struct lv_segment *seg;
uint32_t s;
uint32_t remaining_seg_len, area_len, area_multiple;
if (!(seg = find_seg_by_le(lv, le))) {
log_error("Failed to find segment for %s extent %" PRIu32,
lv->name, le);
return 0;
}
/* Remaining logical length of segment */
remaining_seg_len = seg->len - (le - seg->le);
if (remaining_seg_len > len)
remaining_seg_len = len;
if (max_seg_len && *max_seg_len > remaining_seg_len)
*max_seg_len = remaining_seg_len;
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
area_len = remaining_seg_len / area_multiple ? : 1;
for (s = 0; s < seg->area_count; s++)
if (seg_type(seg, s) == AREA_LV) {
if (!_for_each_pv(cmd, seg_lv(seg, s),
seg_le(seg, s) + (le - seg->le) / area_multiple,
area_len, max_seg_len, fn, data))
return_0;
} else if ((seg_type(seg, s) == AREA_PV) &&
!fn(cmd, seg_pvseg(seg, s), data))
return_0;
if (seg_is_mirrored(seg) &&
!_for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
NULL, fn, data))
return_0;
/* FIXME Add snapshot cow LVs etc. */
return 1;
}
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, void *data)
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg,
uint32_t s __attribute((unused)), void *data)
{
struct seg_pvs *spvs = (struct seg_pvs *) data;
struct pv_list *pvl;
@@ -1488,7 +1620,8 @@ struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
/* Find next segment end */
/* FIXME Unnecessary nesting! */
if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len, _add_pvs, (void *) spvs)) {
if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len,
0, 0, -1, 0, _add_pvs, (void *) spvs)) {
stack;
return NULL;
}

View File

@@ -89,11 +89,8 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
pv->pe_start = pe_align();
/*
* The next two fields should be corrected
* by fid->pv_setup.
* pe_count must always be calculated by pv_setup
*/
pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
pv->pe_alloc_count = 0;
if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
@@ -734,6 +731,8 @@ int vg_validate(struct volume_group *vg)
char uuid[64];
int r = 1;
/* FIXME Also check there's no data/metadata overlap */
list_iterate_items(pvl, &vg->pvs) {
list_iterate_items(pvl2, &vg->pvs) {
if (pvl == pvl2)
@@ -1044,7 +1043,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if (correct_vg) {
if (list_size(&correct_vg->pvs) != list_size(pvids)) {
log_debug("Cached VG %s had incorrect PV list",
vg->name);
vgname);
if (memlock())
inconsistent = 1;
@@ -1053,7 +1052,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
} else list_iterate_items(pvl, &correct_vg->pvs) {
if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
log_debug("Cached VG %s had incorrect PV list",
vg->name);
vgname);
correct_vg = NULL;
break;
}

View File

@@ -82,6 +82,7 @@ typedef enum {
ALLOC_INVALID = 0,
ALLOC_INHERIT,
ALLOC_CONTIGUOUS,
ALLOC_CLING,
ALLOC_NORMAL,
ALLOC_ANYWHERE
} alloc_policy_t;

View File

@@ -161,9 +161,11 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
remove_log = 1;
}
if (remove_log) {
if (remove_log && mirrored_seg->log_lv) {
log_lv = mirrored_seg->log_lv;
mirrored_seg->log_lv = NULL;
log_lv->status &= ~MIRROR_LOG;
log_lv->status |= VISIBLE_LV;
}
/*

View File

@@ -77,6 +77,9 @@ struct segtype_handler {
uint64_t *total_numerator,
uint64_t *total_denominator, float *percent);
int (*target_present) (void);
int (*modules_needed) (struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules);
void (*destroy) (const struct segment_type * segtype);
int (*target_register_events) (struct lv_segment *seg, int events);
int (*target_unregister_events) (struct lv_segment *seg, int events);

View File

@@ -26,6 +26,7 @@
#include "targets.h"
#include "activate.h"
#include "sharedlib.h"
#include "str_list.h"
#ifdef DMEVENTD
# include <libdevmapper-event.h>
@@ -447,6 +448,28 @@ static int _target_unregister_events(struct lv_segment *seg,
#endif /* DMEVENTD */
#endif /* DEVMAPPER_SUPPORT */
static int _mirrored_modules_needed(struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules)
{
if (seg->log_lv &&
!list_segment_modules(mem, first_seg(seg->log_lv), modules))
return_0;
if ((seg->lv->vg->status & CLUSTERED) &&
!str_list_add(mem, modules, "clog")) {
log_error("cluster log string list allocation failed");
return 0;
}
if (!str_list_add(mem, modules, "mirror")) {
log_error("mirror string list allocation failed");
return 0;
}
return 1;
}
static void _mirrored_destroy(const struct segment_type *segtype)
{
dm_free((void *) segtype);
@@ -467,6 +490,7 @@ static struct segtype_handler _mirrored_ops = {
.target_unregister_events = _target_unregister_events,
#endif
#endif
.modules_needed = _mirrored_modules_needed,
.destroy = _mirrored_destroy,
};

View File

@@ -174,6 +174,9 @@
/* Define to 1 if you have the <selinux/selinux.h> header file. */
#undef HAVE_SELINUX_SELINUX_H
/* define to 1 to include support for realtime clock */
#undef HAVE_REALTIME
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE

130
lib/misc/timestamp.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2006 Rackable Systems 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
*/
/*
* Abstract out the time methods used so they can be adjusted later -
* the results of these routines should stay in-core. This implementation
* requires librt.
*/
#include "lib.h"
#include <stdlib.h>
#include "timestamp.h"
/*
* The realtime section uses clock_gettime with the CLOCK_MONOTONIC
* parameter to prevent issues with time warps
*/
#ifdef HAVE_REALTIME
#include <time.h>
#include <bits/time.h>
struct timestamp {
struct timespec t;
};
struct timestamp *get_timestamp(void)
{
struct timestamp *ts = NULL;
if (!(ts = dm_malloc(sizeof(*ts))))
return_NULL;
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
log_sys_error("clock_gettime", "get_timestamp");
return NULL;
}
return ts;
}
/* cmp_timestamp: Compare two timestamps
*
* Return: -1 if t1 is less than t2
* 0 if t1 is equal to t2
* 1 if t1 is greater than t2
*/
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
{
if(t1->t.tv_sec < t2->t.tv_sec)
return -1;
if(t1->t.tv_sec > t2->t.tv_sec)
return 1;
if(t1->t.tv_nsec < t2->t.tv_nsec)
return -1;
if(t1->t.tv_nsec > t2->t.tv_nsec)
return 1;
return 0;
}
#else /* ! HAVE_REALTIME */
/*
* The !realtime section just uses gettimeofday and is therefore subject
* to ntp-type time warps - not sure if should allow that.
*/
#include <sys/time.h>
struct timestamp {
struct timeval t;
};
struct timestamp *get_timestamp(void)
{
struct timestamp *ts = NULL;
if (!(ts = dm_malloc(sizeof(*ts))))
return_NULL;
if (gettimeofday(&ts->t, NULL)) {
log_sys_error("gettimeofday", "get_timestamp");
return NULL;
}
return ts;
}
/* cmp_timestamp: Compare two timestamps
*
* Return: -1 if t1 is less than t2
* 0 if t1 is equal to t2
* 1 if t1 is greater than t2
*/
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
{
if(t1->t.tv_sec < t2->t.tv_sec)
return -1;
if(t1->t.tv_sec > t2->t.tv_sec)
return 1;
if(t1->t.tv_usec < t2->t.tv_usec)
return -1;
if(t1->t.tv_usec > t2->t.tv_usec)
return 1;
return 0;
}
#endif /* HAVE_REALTIME */
void destroy_timestamp(struct timestamp *t)
{
if (t)
dm_free(t);
}

33
lib/misc/timestamp.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2006 Rackable Systems 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_TIMESTAMP_H
#define _LVM_TIMESTAMP_H
struct timestamp;
struct timestamp *get_timestamp(void);
/* cmp_timestamp: Compare two timestamps
*
* Return: -1 if t1 is less than t2
* 0 if t1 is equal to t2
* 1 if t1 is greater than t2
*/
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2);
void destroy_timestamp(struct timestamp *t);
#endif /* _LVM_TIMESTAMP_H */

View File

@@ -33,6 +33,7 @@ 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")
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
@@ -68,8 +69,11 @@ FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
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")

View File

@@ -21,6 +21,7 @@
#include "display.h"
#include "activate.h"
#include "segtype.h"
#include "str_list.h"
/*
* For macro use
@@ -103,6 +104,8 @@ static char _alloc_policy_char(alloc_policy_t alloc)
switch (alloc) {
case ALLOC_CONTIGUOUS:
return 'c';
case ALLOC_CLING:
return 'C';
case ALLOC_NORMAL:
return 'n';
case ALLOC_ANYWHERE:
@@ -200,6 +203,7 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
return 1;
}
static int _tags_disp(struct report_handle *rh, struct field *field,
const void *data)
{
@@ -230,6 +234,23 @@ static int _tags_disp(struct report_handle *rh, struct field *field,
return 1;
}
static int _modules_disp(struct report_handle *rh, struct field *field,
const void *data)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
struct list *modules;
if (!(modules = str_list_create(rh->mem))) {
log_error("modules str_list allocation failed");
return 0;
}
if (!list_lv_modules(rh->mem, lv, modules))
return_0;
return _tags_disp(rh, field, modules);
}
static int _vgfmt_disp(struct report_handle *rh, struct field *field,
const void *data)
{
@@ -948,6 +969,44 @@ static struct {
const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
static void _display_fields(void)
{
uint32_t f;
const char *type, *last_type = "";
for (f = 0; f < _num_fields; f++) {
switch (_fields[f].type) {
case PVS:
type = "Physical Volume";
break;
case LVS:
type = "Logical Volume";
break;
case VGS:
type = "Volume Group";
break;
case SEGS:
type = "Logical Volume Segment";
break;
case PVSEGS:
type = "Physical Volume Segment";
break;
default:
type = " ";
}
if (type != last_type) {
if (*last_type)
log_print(" ");
log_print("%s Fields", type);
}
log_print("- %s", _fields[f].id);
last_type = type;
}
}
/*
* Initialise report handle
*/
@@ -1080,6 +1139,8 @@ static int _parse_options(struct report_handle *rh, const char *format)
while (*we && *we != ',')
we++;
if (!_field_match(rh, ws, (size_t) (we - ws))) {
_display_fields();
log_print(" ");
log_error("Unrecognised field: %.*s", (int) (we - ws),
ws);
return 0;

View File

@@ -20,6 +20,7 @@
#include "text_export.h"
#include "config.h"
#include "activate.h"
#include "str_list.h"
static const char *_snap_name(const struct lv_segment *seg)
{
@@ -126,6 +127,18 @@ static int _snap_target_present(void)
}
#endif
static int _snap_modules_needed(struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules)
{
if (!str_list_add(mem, modules, "snapshot")) {
log_error("snapshot string list allocation failed");
return 0;
}
return 1;
}
static void _snap_destroy(const struct segment_type *segtype)
{
dm_free((void *)segtype);
@@ -139,6 +152,7 @@ static struct segtype_handler _snapshot_ops = {
.target_percent = _snap_target_percent,
.target_present = _snap_target_present,
#endif
.modules_needed = _snap_modules_needed,
.destroy = _snap_destroy,
};

View File

@@ -63,6 +63,18 @@ static int _zero_target_present(void)
}
#endif
static int _zero_modules_needed(struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules)
{
if (!str_list_add(mem, modules, "zero")) {
log_error("zero module string list allocation failed");
return 0;
}
return 1;
}
static void _zero_destroy(const struct segment_type *segtype)
{
dm_free((void *) segtype);
@@ -75,6 +87,7 @@ static struct segtype_handler _zero_ops = {
.add_target_line = _zero_add_target_line,
.target_present = _zero_target_present,
#endif
.modules_needed = _zero_modules_needed,
.destroy = _zero_destroy,
};

View File

@@ -28,6 +28,7 @@ dm_task_set_gid
dm_task_set_mode
dm_task_suppress_identical_reload
dm_task_add_target
dm_task_no_flush
dm_task_no_open_count
dm_task_skip_lockfs
dm_task_update_nodes

View File

@@ -1026,6 +1026,13 @@ int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char
return 1;
}
int dm_task_no_flush(struct dm_task *dmt)
{
dmt->no_flush = 1;
return 1;
}
int dm_task_no_open_count(struct dm_task *dmt)
{
dmt->no_open_count = 1;
@@ -1270,6 +1277,8 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
if (dmt->type == DM_DEVICE_SUSPEND)
dmi->flags |= DM_SUSPEND_FLAG;
if (dmt->no_flush)
dmi->flags |= DM_NOFLUSH_FLAG;
if (dmt->read_only)
dmi->flags |= DM_READONLY_FLAG;
if (dmt->skip_lockfs)
@@ -1543,7 +1552,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmi->flags |= DM_SKIP_BDGET_FLAG;
log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
"%s%c%s %.0llu %s [%u]",
"%s%c%c%s %.0llu %s [%u]",
_cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? " " : "",
dmt->newname ? dmt->newname : "",
@@ -1554,6 +1563,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmt->major > 0 && dmt->minor == 0 ? "0" : "",
dmt->major > 0 ? ") " : "",
dmt->no_open_count ? 'N' : 'O',
dmt->no_flush ? 'N' : 'F',
dmt->skip_lockfs ? "S " : "",
dmt->sector, dmt->message ? dmt->message : "",
dmi->data_size);

View File

@@ -52,6 +52,7 @@ struct dm_task {
char *message;
char *geometry;
uint64_t sector;
int no_flush;
int no_open_count;
int skip_lockfs;
int suppress_identical_reload;

View File

@@ -151,6 +151,7 @@ int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start);
int dm_task_set_message(struct dm_task *dmt, const char *message);
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
int dm_task_no_flush(struct dm_task *dmt);
int dm_task_no_open_count(struct dm_task *dmt);
int dm_task_skip_lockfs(struct dm_task *dmt);
int dm_task_suppress_identical_reload(struct dm_task *dmt);

View File

@@ -4,6 +4,7 @@ clvmd \- cluster LVM daemon
.SH SYNOPSIS
.B clvmd
[\-d] [\-h]
[\-R]
[\-t <timeout>]
[\-V]
.SH DESCRIPTION
@@ -22,6 +23,11 @@ be so small that commands with many disk updates to do will fail, so you
may need to increase this on systems with very large disk farms.
The default is 30 seconds.
.TP
.I \-R
Tells all the running clvmd in the cluster to reload their device cache and
re-read the lvm configuration file. This command should be run whenever the
devices on a cluster system are changed.
.TP
.I \-V
Display the version of the cluster LVM daemon.
.SH SEE ALSO

View File

@@ -13,7 +13,7 @@ dmsetup \- low level logical volume management
.I [-f|--force]
.br
.B dmsetup suspend
.I [--nolockfs] device_name
.I [--nolockfs] [--noflush] device_name
.br
.B dmsetup resume
.I device_name
@@ -213,7 +213,7 @@ Outputs status information for each of the device's targets.
With --target, only information relating to the specified target type
is displayed.
.IP \fBsuspend
.I [--nolockfs]
.I [--nolockfs] [--noflush]
.I device_name
.br
Suspends a device. Any I/O that has already been mapped by the device
@@ -221,6 +221,9 @@ but has not yet completed will be flushed. Any further I/O to that
device will be postponed for as long as the device is suspended.
If there's a filesystem on the device which supports the operation,
an attempt will be made to sync it first unless --nolockfs is specified.
Some targets such as recent (October 2006) versions of multipath may support
the --noflush option. This lets outstanding I/O that has not yet reached the
device to remain unflushed.
.IP \fBtable
.I [--target target_type]
.I [device_name]

View File

@@ -3,7 +3,7 @@
lvconvert \- convert a logical volume between linear and mirror
.SH SYNOPSIS
.B lvconvert
[\-m/\-\-mirrors Mirrors [\-\-corelog]]
[\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]]
[\-A/\-\-alloc AllocationPolicy]
[\-h/\-?/\-\-help]
[\-v/\-\-verbose]
@@ -28,6 +28,10 @@ mirror from using a disk-based (persistent) log to
an in-memory log. You may only specify this option
when the \-\-mirror argument is the same degree of
the mirror you are changing.
.TP
.I \-R, \-\-regionsize MirrorLogRegionSize
A mirror is divided into regions of this size (in MB), and the mirror log
uses this granularity to track which regions are in sync.
.SH Examples
"lvconvert -m1 vg00/lvol1"
.br

View File

@@ -8,13 +8,13 @@ lvcreate \- create a logical volume in an existing volume group
[\-A/\-\-autobackup y/n] [\-C/\-\-contiguous y/n] [\-d/\-\-debug]
[\-h/\-?/\-\-help]
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
{\-l/\-\-extents LogicalExtentsNumber |
{\-l/\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
\-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
[\-M/\-\-persistent y/n] [\-\-minor minor]
[\-m/\-\-mirrors Mirrors [\-\-nosync] [\-\-corelog]]
[\-m/\-\-mirrors Mirrors [\-\-nosync] [\-\-corelog]
[\-R/\-\-regionsize MirrorLogRegionSize]]
[\-n/\-\-name LogicalVolumeName]
[\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
[-R|--regionsize MirrorLogRegionSize]
[\-t/\-\-test]
[\-v/\-\-verbose] [\-Z/\-\-zero y/n]
VolumeGroupName [PhysicalVolumePath...]
@@ -22,7 +22,7 @@ VolumeGroupName [PhysicalVolumePath...]
.br
.B lvcreate
{\-l/\-\-extents LogicalExtentsNumber |
{\-l/\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
\-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
[\-c/\-\-chunksize ChunkSize]
\-s/\-\-snapshot \-n/\-\-name SnapshotLogicalVolumeName OriginalLogicalVolumePath
@@ -63,9 +63,12 @@ StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format.
For metadata in LVM2 format, the stripe size may be a larger
power of 2 but must not exceed the physical extent size.
.TP
.I \-l, \-\-extents LogicalExtentsNumber
.I \-l, \-\-extents LogicalExtentsNumber[%{VG|FREE}]
Gives the number of logical extents to allocate for the new
logical volume.
This can also be expressed as a percentage of the total space
in the Volume Group with the suffix %VG or of the remaining free space
with the suffix %FREE.
.TP
.I \-L, \-\-size LogicalVolumeSize[kKmMgGtT]
Gives the size to allocate for the new logical volume.
@@ -112,8 +115,8 @@ Default is read and write.
Set read ahead sector count of this logical volume to a value between 2 and 120.
Ignored by device-mapper.
.TP
.I \-R \-\-regionsize MirrorLogRegionSize
A mirror is divided into regions of this size (in KB), and the mirror log
.I \-R, \-\-regionsize MirrorLogRegionSize
A mirror is divided into regions of this size (in MB), and the mirror log
uses this granularity to track which regions are in sync.
.TP
.I \-s, \-\-snapshot

View File

@@ -6,7 +6,7 @@ lvextend \- extend the size of a logical volume
[\-\-alloc AllocationPolicy]
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
{\-l/\-\-extents [+]LogicalExtentsNumber |
{\-l/\-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}] |
\-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
[\-t/\-\-test]
[\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
@@ -21,10 +21,14 @@ volume use
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.I \-l, \-\-extents [+]LogicalExtentsNumber
.I \-l, \-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}]
Extend or set the logical volume size in units of logical extents.
With the + sign the value is added to the actual size
of the logical volume and without it, the value is taken as an absolute one.
The number can also be expressed as a percentage of the total space
in the Volume Group with the suffix %VG or relative to the existing
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
free space in the Volume Group with the suffix %FREE.
.TP
.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtT]
Extend or set the logical volume size in units in units of megabytes.

View File

@@ -136,7 +136,7 @@ Characters allowed in tags are: A-Z a-z 0-9 _ + . -
Delete the tag \fBtag\fP from a PV, VG or LV, if it's present.
.TP
\fB--alloc AllocationPolicy\fP
The allocation policy to use: \fBcontiguous\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
The allocation policy to use: \fBcontiguous\fP, \fBcling\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
When a command needs to allocate physical extents from the volume group,
the allocation policy controls how they are chosen.
Each volume group and logical volume has an allocation policy.
@@ -146,15 +146,18 @@ physical volume. The default for a logical volume is \fBinherit\fP
which applies the same policy as for the volume group. These policies can
be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden
on the command line of any command that performs allocation.
The \fBcontiguous\fP policy requires that new extents are adjacent to
existing extents. If there are sufficient free extents to satisfy
The \fBcontiguous\fP policy requires that new extents be placed adjacent
to existing extents.
The \fBcling\fP policy places new extents on the same physical
volume as existing extents in the same stripe of the Logical Volume.
If there are sufficient free extents to satisfy
an allocation request but \fBnormal\fP doesn't use them,
\fBanywhere\fP will - even if that reduces performance by
placing two stripes on the same physical volume.
.IP
N.B. The policies described above are not implemented fully yet.
In particular, \fBcontiguous\fP does not place new extents adjacent to existing
extents and \fBanywhere\fP is not implemented at all.
In particular, contiguous free space cannot be broken up to
satisfy allocation attempts.
.SH ENVIRONMENT VARIABLES
.TP
\fBLVM_SYSTEM_DIR\fP

View File

@@ -4,7 +4,8 @@ lvreduce \- reduce the size of a logical volume
.SH SYNOPSIS
.B lvreduce
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
[\-h/\-?/\-\-help] {\-l/\-\-extents [\-]LogicalExtentsNumber |
[\-h/\-?/\-\-help]
{\-l/\-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}] |
\-L/\-\-size [\-]LogicalVolumeSize[kKmMgGtT]}
[\-t/\-\-test]
[\-v/\-\-verbose] LogicalVolume[Path]
@@ -35,11 +36,15 @@ See \fBlvm\fP for common options.
.I \-f, \-\-force
Force size reduction without any question.
.TP
.I \-l, \-\-extents [\-]LogicalExtentsNumber
.I \-l, \-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}]
Reduce or set the logical volume size in units of logical extents.
With the - sign the value will be subtracted from
the logical volume's actual size and without it the will be taken as
an absolute size.
The number can also be expressed as a percentage of the total space
in the Volume Group with the suffix %VG or relative to the existing
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
free space in the Volume Group with the suffix %FREE.
.TP
.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtT]
Reduce or set the logical volume size in units of megabyte by default.

View File

@@ -6,7 +6,7 @@ lvresize \- resize a logical volume
[\-\-alloc AllocationPolicy]
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
{\-l/\-\-extents [+]LogicalExtentsNumber |
{\-l/\-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}] |
\-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
[\-t/\-\-test]
[\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
@@ -25,10 +25,14 @@ volume use
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.I \-l, \-\-extents [+/-]LogicalExtentsNumber
.I \-l, \-\-extents [+/-]LogicalExtentsNumber[%{VG|LV|FREE}]
Change or set the logical volume size in units of logical extents.
With the + or - sign the value is added to or subtracted from the actual size
of the logical volume and without it, the value is taken as an absolute one.
The number can also be expressed as a percentage of the total space
in the Volume Group with the suffix %VG or relative to the existing
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
free space in the Volume Group with the suffix %FREE.
.TP
.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtT]
Change or set the logical volume size in units of megabytes.

View File

@@ -93,6 +93,24 @@ stop()
return $rtrn
}
wait_for_finish()
{
count=0
while [ "$count" -le 10 -a -n "`pidof clvmd`" ]
do
sleep 1
count=$((count + 1))
done
if [ `pidof clvmd` ]
then
return 1
else
return 0
fi
}
rtrn=1
# See how we were called.
@@ -112,6 +130,7 @@ case "$1" in
restart)
if stop
then
wait_for_finish
start
fi
rtrn=$?

118
scripts/lvm_dump.sh Executable file
View File

@@ -0,0 +1,118 @@
#!/bin/bash
#
# lvm_dump: This script is used to collect pertinent information for
# the debugging of lvm issues.
#
function usage {
echo "$0 [options]"
echo " -h print this message"
echo " -a advanced collection - warning: if lvm is already hung,"
echo " then this script may hang as well if -a is used"
echo " -m gather LVM metadata from the PVs"
echo " -d dump directory to place data in (default=/tmp/lvm_dump.\$\$)"
echo " -c if running clvmd, gather cluster data as well"
echo ""
exit 1
}
advanced=0
clustered=0
metadata=0
while getopts :acd:hm opt; do
case $opt in
a) advanced=1 ;;
c) clustered=1 ;;
d) lvm_dir=$OPTARG ;;
h) usage ;;
m) metadata=1 ;;
:) echo "$0: $OPTARG requires a value:"; usage ;;
\?) echo "$0: unknown option $OPTARG"; usage ;;
*) usage ;;
esac
done
dir=`mktemp -d -p /tmp lvm_dump.XXXXXX` || exit 2
lvm_dir="$dir/lvm_dump"
echo " "
echo "Creating dump directory: $lvm_dir"
echo " "
mkdir -p $lvm_dir || exit 3
if (( $advanced )); then
echo "Gathering LVM volume info..."
echo " vgscan..."
vgscan -vvvv > $lvm_dir/vgscan 2>&1
echo " pvscan..."
pvscan -v >> $lvm_dir/pvscan 2>/dev/null
echo " lvs..."
lvs -a -o +devices >> $lvm_dir/lvs 2>/dev/null
echo " pvs..."
pvs -a -v > $lvm_dir/pvs 2>/dev/null
echo " vgs..."
vgs -v > $lvm_dir/vgs 2>/dev/null
fi
if (( $clustered )); then
echo "Gathering cluster info..."
echo "STATUS: " > $lvm_dir/cluster_info
echo "----------------------------------" >> $lvm_dir/cluster_info
cman_tool status >> $lvm_dir/cluster_info
echo " " >> $lvm_dir/lvm_info
echo "SERVICES: " >> $lvm_dir/cluster_info
echo "----------------------------------" >> $lvm_dir/cluster_info
cman_tool services >> $lvm_dir/cluster_info
echo " " >> $lvm_dir/lvm_info
fi
echo "Gathering LVM & device-mapper version info..."
echo "LVM VERSION:" > $lvm_dir/versions
lvs --version >> $lvm_dir/versions
echo "DEVICE MAPPER VERSION:" >> $lvm_dir/versions
dmsetup --version >> $lvm_dir/versions
echo "Gathering dmsetup info..."
dmsetup info -c > $lvm_dir/dmsetup_info
dmsetup table > $lvm_dir/dmsetup_table
dmsetup status > $lvm_dir/dmsetup_status
echo "Gathering process info..."
ps alx > $lvm_dir/ps_info
echo "Gathering console messages..."
tail -n 75 /var/log/messages > $lvm_dir/messages
echo "Gathering /etc/lvm info..."
cp -a /etc/lvm $lvm_dir/lvm
echo "Gathering /dev listing..."
ls -la /dev > $lvm_dir/dev_listing
if (( $metadata )); then
echo "Gathering LVM metadata from Physical Volumes..."
mkdir -p $lvm_dir/metadata
for pv in `pvs --noheadings -o name`
do
echo " $pv"
name=`basename $pv`
dd if=$pv of=$lvm_dir/metadata/$name bs=512 count=`pvs --noheadings --nosuffix --units s -o pe_start $pv | tr -d \ `
done 2>/dev/null
fi
lvm_dump=$lvm_dir.tgz
echo "Creating tarball $lvm_dump..."
tar czf $lvm_dump $lvm_dir 2>/dev/null
exit 0

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
#
# This file is part of the lvm2-cluster package.
#
@@ -21,8 +21,9 @@ function usage
echo "usage: $0 <command>"
echo ""
echo "Commands:"
echo "Enable clvm: --enable-cluster --lockinglibdir <dir> [--lockinglib <lib>]"
echo "Enable clvm: --enable-cluster [--lockinglibdir <dir>] [--lockinglib <lib>]"
echo "Disable clvm: --disable-cluster"
echo "Set locking library: --lockinglibdir <dir> [--lockinglib <lib>]"
echo ""
echo "Global options:"
echo "Config file location: --file <configfile>"
@@ -86,14 +87,13 @@ function validate_args
exit 10
fi
if [ -z "$LOCKING_TYPE" ]; then
if [ -z "$LOCKING_TYPE" ] && [ -z "$LOCKINGLIBDIR" ]; then
usage
exit 1
fi
if [ "$LOCKING_TYPE" == "2" ]; then
if [ -n "$LOCKINGLIBDIR" ]; then
[ -z "$LOCKINGLIBDIR" ] && usage && exit 1
[ -z "$LOCKINGLIB" ] && LOCKINGLIB="liblvm2clusterlock.so"
if [ "${LOCKINGLIBDIR:0:1}" != "/" ]
@@ -109,6 +109,10 @@ function validate_args
fi
fi
if [ "$LOCKING_TYPE" = "1" ] && [ -n "$LOCKINGLIBDIR" -o -n "$LOCKINGLIB" ]; then
echo "Superfluous locking lib parameter, ignoring"
fi
}
umask 0077
@@ -153,11 +157,19 @@ then
fi
fi
if [ "$LOCKING_TYPE" = "2" ] && [ -z "$LOCKINGLIBDIR" ] && [ "$have_dir" = "1" ]; then
echo "no library_dir specified in $CONFIGFILE"
exit 16
fi
# So if we don't have "global {" we need to create one and
# populate it
if [ "$have_global" = "1" ]
then
if [ -z "$LOCKING_TYPE" ]; then
LOCKING_TYPE=1
fi
if [ "$LOCKING_TYPE" = "2" ]; then
cat $CONFIGFILE - <<EOF > $TMPFILE
global {
@@ -180,14 +192,16 @@ else
# locking entries as appropriate
#
if [ "$have_type" = "0" ]
then
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
else
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
if [ -n "$LOCKING_TYPE" ]; then
if [ "$have_type" = "0" ]
then
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
else
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
fi
fi
if [ "$LOCKING_TYPE" = "2" ]; then
if [ -n "$LOCKINGLIBDIR" ]; then
if [ "$have_dir" = "0" ]
then
SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g"
@@ -201,7 +215,9 @@ else
else
SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\""
fi
else
fi
if [ "$LOCKING_TYPE" = "1" ]; then
# if we're not using cluster locking, remove the library dir and locking library name
if [ "$have_dir" = "0" ]
then

View File

@@ -84,7 +84,7 @@ arg(interval_ARG, 'i', "interval", int_arg)
arg(iop_version_ARG, 'i', "iop_version", NULL)
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg)
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg)
arg(extents_ARG, 'l', "extents", int_arg_with_sign)
arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent)
arg(lvmpartition_ARG, 'l', "lvmpartition", NULL)
arg(list_ARG, 'l', "list", NULL)
arg(size_ARG, 'L', "size", size_mb_arg)

View File

@@ -83,6 +83,7 @@ xx(lvconvert,
"Change logical volume layout",
"lvconvert "
"[-m|--mirrors Mirrors [--corelog]]\n"
"\t[-R|--regionsize MirrorLogRegionSize]\n"
"\t[--alloc AllocationPolicy]\n"
"\t[-d|--debug]\n"
"\t[-h|-?|--help]\n"
@@ -100,7 +101,7 @@ xx(lvconvert,
"\t[--version]" "\n"
"\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
alloc_ARG, chunksize_ARG, mirrors_ARG, corelog_ARG,
alloc_ARG, chunksize_ARG, mirrors_ARG, corelog_ARG, regionsize_ARG,
snapshot_ARG, test_ARG, zero_ARG)
xx(lvcreate,
@@ -137,7 +138,7 @@ xx(lvcreate,
"\t[-d|--debug]\n"
"\t[-h|-?|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents LogicalExtentsNumber |\n"
"\t{-l|--extents LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
"\t[-n|--name LogicalVolumeName]\n"
@@ -202,7 +203,7 @@ xx(lvextend,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+]LogicalExtentsNumber |\n"
"\t{-l|--extents [+]LogicalExtentsNumber[%{VG|FREE}] |\n"
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-m|--mirrors Mirrors]\n"
"\t[-n|--nofsck]\n"
@@ -267,7 +268,7 @@ xx(lvreduce,
"\t[-d|--debug]\n"
"\t[-f|--force]\n"
"\t[-h|--help]\n"
"\t{-l|--extents [-]LogicalExtentsNumber |\n"
"\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
"\t -L|--size [-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-n|--nofsck]\n"
"\t[-r|--resizefs]\n"
@@ -315,7 +316,7 @@ xx(lvresize,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+|-]LogicalExtentsNumber |\n"
"\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t[-n|--nofsck]\n"
"\t[-r|--resizefs]\n"

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005 NEC Corperation
*
* This file is part of the device-mapper userspace tools.
@@ -38,6 +38,16 @@
#include <locale.h>
#include <langinfo.h>
#include <fcntl.h>
#include <sys/stat.h>
/* FIXME Unused so far */
#undef HAVE_SYS_STATVFS_H
#ifdef HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
@@ -78,6 +88,11 @@ extern char *optarg;
#define LINE_SIZE 4096
#define ARGS_MAX 256
#define LOOP_TABLE_SIZE (PATH_MAX + 255)
/* FIXME Should be elsewhere */
#define SECTOR_SHIFT 9L
#define DEV_PATH "/dev/"
#define err(msg, x...) fprintf(stderr, msg "\n", ##x)
@@ -93,6 +108,7 @@ enum {
MAJOR_ARG,
MINOR_ARG,
MODE_ARG,
NOFLUSH_ARG,
NOHEADINGS_ARG,
NOLOCKFS_ARG,
NOOPENCOUNT_ARG,
@@ -180,7 +196,7 @@ static int _parse_file(struct dm_task *dmt, const char *file)
#ifndef HAVE_GETLINE
buffer_size = LINE_SIZE;
if (!(buffer = malloc(buffer_size))) {
if (!(buffer = dm_malloc(buffer_size))) {
err("Failed to malloc line buffer.");
return 0;
}
@@ -195,7 +211,7 @@ static int _parse_file(struct dm_task *dmt, const char *file)
r = 1;
out:
free(buffer);
dm_free(buffer);
if (file)
fclose(fp);
return r;
@@ -512,7 +528,7 @@ static int _message(int argc, char **argv, void *data __attribute((unused)))
for (i = 0; i < argc; i++)
sz += strlen(argv[i]) + 1;
str = malloc(sz);
str = dm_malloc(sz);
memset(str, 0, sz);
for (i = 0; i < argc; i++) {
@@ -524,7 +540,7 @@ static int _message(int argc, char **argv, void *data __attribute((unused)))
if (!dm_task_set_message(dmt, str))
goto out;
free(str);
dm_free(str);
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto out;
@@ -603,6 +619,9 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
goto out;
if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto out;
@@ -744,28 +763,28 @@ static int _error_device(int argc __attribute((unused)), char **argv __attribute
return 0;
if (!_set_task_device(dmt, name, 0))
goto err;
goto error;
if (!dm_task_add_target(dmt, 0, size, "error", ""))
goto err;
goto error;
if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
goto err;
goto error;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto err;
goto error;
if (!dm_task_run(dmt))
goto err;
goto error;
if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
_simple(DM_DEVICE_CLEAR, name, 0, 0);
goto err;
goto error;
}
r = 1;
err:
error:
dm_task_destroy(dmt);
return r;
}
@@ -1487,12 +1506,12 @@ struct command {
static struct command _commands[] = {
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
"\t [-u|uuid <uuid>]"
"\t [-u|uuid <uuid>]\n"
"\t [--notable | --table <table> | <table_file>]",
1, 2, _create},
{"remove", "[-f|--force] <device>", 0, 1, _remove},
{"remove_all", "[-f|--force]", 0, 0, _remove_all},
{"suspend", "<device>", 0, 1, _suspend},
{"suspend", "[--noflush] <device>", 0, 1, _suspend},
{"resume", "<device>", 0, 1, _resume},
{"load", "<device> [<table_file>]", 0, 2, _load},
{"clear", "<device>", 0, 1, _clear},
@@ -1529,6 +1548,13 @@ static void _usage(FILE *out)
return;
}
static void _losetup_usage(FILE *out)
{
fprintf(out, "Usage:\n\n");
fprintf(out, "losetup [-d|-a] [-e encryption] "
"[-o offset] [-f|loop_device] [file]\n\n");
}
static struct command *_find_command(const char *name)
{
int i;
@@ -1606,11 +1632,225 @@ static int _process_tree_options(const char *options)
return 1;
}
/*
* Returns the full absolute path, or NULL if the path could
* not be resolved.
*/
static char *_get_abspath(char *path)
{
char *_path;
#ifdef HAVE_CANONICALIZE_FILE_NAME
_path = canonicalize_file_name(path);
#else
/* FIXME Provide alternative */
#endif
return _path;
}
static char *parse_loop_device_name(char *dev)
{
char *buf;
char *device;
if (!(buf = dm_malloc(PATH_MAX)));
return NULL;
if (dev[0] == '/') {
if (!(device = _get_abspath(dev)))
goto error;
if (strncmp(device, DEV_PATH, strlen(DEV_PATH)))
goto error;
strncpy(buf, strrchr(device, '/') + 1, PATH_MAX);
dm_free(device);
} else {
/* check for device number */
if (!strncmp(dev, "loop", strlen("loop")))
strncpy(buf, dev, PATH_MAX);
else
goto error;
}
return buf;
error:
return NULL;
}
/*
* create a table for a mapped device using the loop target.
*/
static int _loop_table(char *table, size_t tlen, char *file, char *dev, off_t off)
{
struct stat fbuf;
off_t size, sectors;
int fd = -1;
#ifdef HAVE_SYS_STATVFS_H
struct statvfs fsbuf;
off_t blksize;
#endif
if (!_switches[READ_ONLY])
fd = open(file, O_RDWR);
if (fd < 0) {
_switches[READ_ONLY]++;
fd = open(file, O_RDONLY);
}
if (fd < 0)
goto error;
if (fstat(fd, &fbuf))
goto error;
size = (fbuf.st_size - off);
sectors = size >> SECTOR_SHIFT;
if (_switches[VERBOSE_ARG])
fprintf(stderr, "losetup: set loop size to %llukB (%llu sectors)\n",
sectors >> 1, sectors);
#ifdef HAVE_SYS_STATVFS_H
if (fstatvfs(fd, &fsbuf))
goto error;
/* FIXME Fragment size currently unused */
blksize = fsbuf.f_frsize;
#endif
close(fd);
if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
(long long unsigned)sectors, file, off) < 0)
return 0;
if (_switches[VERBOSE_ARG] > 1)
fprintf(stderr, "Table: %s\n", table);
return 1;
error:
if (fd > -1)
close(fd);
return 0;
}
static int _process_losetup_switches(const char *base, int *argc, char ***argv)
{
static int ind;
int c;
int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
char *device_name = NULL;
char *loop_file = NULL;
off_t offset = 0;
#ifdef HAVE_GETOPTLONG
static struct option long_options[] = {
{0, 0, 0, 0}
};
#endif
optarg = 0;
optind = OPTIND_INIT;
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
long_options, NULL)) != -1 ) {
if (c == ':' || c == '?')
return 0;
if (c == 'a')
show_all++;
if (c == 'd')
delete++;
if (c == 'e')
encrypt_loop++;
if (c == 'f')
find++;
if (c == 'o')
offset = atoi(optarg);
if (c == 'v')
_switches[VERBOSE_ARG]++;
}
*argv += optind ;
*argc -= optind ;
if (encrypt_loop){
fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
"in this version.\n", base);
return 0;
}
if (show_all) {
fprintf(stderr, "%s: Sorry, show all is not yet implemented "
"in this version.\n", base);
return 0;
}
if (find) {
fprintf(stderr, "%s: Sorry, find is not yet implemented "
"in this version.\n", base);
if (!*argc)
return 0;
}
if (!*argc) {
fprintf(stderr, "%s: Please specify loop_device.\n", base);
_losetup_usage(stderr);
return 0;
}
if (!(device_name = parse_loop_device_name((*argv)[0]))) {
fprintf(stderr, "%s: Could not parse loop_device %s\n",
base, (*argv)[0]);
_losetup_usage(stderr);
return 0;
}
if (delete) {
*argc = 2;
(*argv)[1] = device_name;
(*argv)[0] = (char *) "remove";
return 1;
}
if (*argc != 2) {
fprintf(stderr, "%s: Too few arguments\n", base);
_losetup_usage(stderr);
return 0;
}
/* FIXME move these to make them available to native dmsetup */
if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
fprintf(stderr, "%s: Could not parse loop file name %s\n",
base, (*argv)[1]);
_losetup_usage(stderr);
return 0;
}
/* FIXME Missing free */
_table = dm_malloc(LOOP_TABLE_SIZE);
if (!_loop_table(_table, LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
return 0;
}
_switches[TABLE_ARG]++;
(*argv)[0] = (char *) "create";
(*argv)[1] = device_name ;
return 1;
}
static int _process_switches(int *argc, char ***argv)
{
char *base, *namebase;
static int ind;
int c;
int c, r;
#ifdef HAVE_GETOPTLONG
static struct option long_options[] = {
@@ -1622,6 +1862,7 @@ static int _process_switches(int *argc, char ***argv)
{"major", 1, &ind, MAJOR_ARG},
{"minor", 1, &ind, MINOR_ARG},
{"mode", 1, &ind, MODE_ARG},
{"noflush", 0, &ind, NOFLUSH_ARG},
{"noheadings", 0, &ind, NOHEADINGS_ARG},
{"nolockfs", 0, &ind, NOLOCKFS_ARG},
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
@@ -1678,6 +1919,12 @@ static int _process_switches(int *argc, char ***argv)
return 1;
}
if(!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
r = _process_losetup_switches(base, argc, argv);
free(namebase);
return r;
}
free(namebase);
optarg = 0;
@@ -1733,6 +1980,8 @@ static int _process_switches(int *argc, char ***argv)
_switches[TARGET_ARG]++;
_target = optarg;
}
if ((ind == NOFLUSH_ARG))
_switches[NOFLUSH_ARG]++;
if ((ind == NOHEADINGS_ARG))
_switches[NOHEADINGS_ARG]++;
if ((ind == NOLOCKFS_ARG))

View File

@@ -344,8 +344,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
lp->mirrors - 1);
return 1;
}
}
if (lp->mirrors > existing_mirrors) {
} else if (lp->mirrors > existing_mirrors) {
/* FIXME Unless anywhere, remove PV of log_lv
* from allocatable_pvs & allocate
* (mirrors - existing_mirrors) new areas

View File

@@ -43,6 +43,7 @@ struct lvcreate_params {
/* size */
uint32_t extents;
uint64_t size;
percent_t percent;
uint32_t permission;
uint32_t read_ahead;
@@ -157,6 +158,7 @@ static int _read_size_params(struct lvcreate_params *lp,
return 0;
}
lp->extents = arg_uint_value(cmd, extents_ARG, 0);
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
}
/* Size returned in kilobyte units; held in sectors */
@@ -166,6 +168,7 @@ static int _read_size_params(struct lvcreate_params *lp,
return 0;
}
lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
lp->percent = PERCENT_NONE;
}
return 1;
@@ -556,6 +559,20 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
lp->extents = tmp_size / vg->extent_size;
}
switch(lp->percent) {
case PERCENT_VG:
lp->extents = lp->extents * vg->extent_count / 100;
break;
case PERCENT_FREE:
lp->extents = lp->extents * vg->free_count / 100;
break;
case PERCENT_LV:
log_error("Please express size as %%VG or %%FREE.");
return 0;
case PERCENT_NONE:
break;
}
if ((size_rest = lp->extents % lp->stripes)) {
log_print("Rounding size (%d extents) up to stripe boundary "
"size (%d extents)", lp->extents,

View File

@@ -54,7 +54,7 @@ extern char *optarg;
*/
struct arg the_args[ARG_COUNT + 1] = {
#define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), 0, NULL},
#define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
#include "args.h"
#undef arg
@@ -69,6 +69,7 @@ static int _interactive;
int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
{
a->sign = SIGN_NONE;
a->percent = PERCENT_NONE;
if (!strcmp(a->value, "y")) {
a->i_value = 1;
@@ -90,6 +91,7 @@ int yes_no_excl_arg(struct cmd_context *cmd __attribute((unused)),
struct arg *a)
{
a->sign = SIGN_NONE;
a->percent = PERCENT_NONE;
if (!strcmp(a->value, "e") || !strcmp(a->value, "ey") ||
!strcmp(a->value, "ye")) {
@@ -148,6 +150,8 @@ static int _get_int_arg(struct arg *a, char **ptr)
char *val;
long v;
a->percent = PERCENT_NONE;
val = a->value;
switch (*val) {
case '+':
@@ -186,6 +190,8 @@ static int _size_arg(struct cmd_context *cmd __attribute((unused)), struct arg *
char *val;
double v;
a->percent = PERCENT_NONE;
val = a->value;
switch (*val) {
case '+':
@@ -259,6 +265,33 @@ int int_arg_with_sign(struct cmd_context *cmd __attribute((unused)), struct arg
return 1;
}
int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute((unused)),
struct arg *a)
{
char *ptr;
if (!_get_int_arg(a, &ptr))
return 0;
if (!*ptr)
return 1;
if (*ptr++ != '%')
return 0;
if (!strcasecmp(ptr, "V") || !strcasecmp(ptr, "VG"))
a->percent = PERCENT_VG;
else if (!strcasecmp(ptr, "L") || !strcasecmp(ptr, "LV"))
a->percent = PERCENT_LV;
else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") ||
!strcasecmp(ptr, "FREE"))
a->percent = PERCENT_FREE;
else
return 0;
return 1;
}
int minor_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
{
char *ptr;

View File

@@ -31,6 +31,7 @@ struct lvresize_params {
uint32_t extents;
uint64_t size;
sign_t sign;
percent_t percent;
enum {
LV_ANY = 0,
@@ -68,12 +69,14 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
if (arg_count(cmd, extents_ARG)) {
lp->extents = arg_uint_value(cmd, extents_ARG, 0);
lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
}
/* Size returned in kilobyte units; held in sectors */
if (arg_count(cmd, size_ARG)) {
lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
lp->percent = PERCENT_NONE;
}
if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
@@ -238,6 +241,20 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
lp->extents = lp->size / vg->extent_size;
}
switch(lp->percent) {
case PERCENT_VG:
lp->extents = lp->extents * vg->extent_count / 100;
break;
case PERCENT_FREE:
lp->extents = lp->extents * vg->free_count / 100;
break;
case PERCENT_LV:
lp->extents = lp->extents * lv->le_count / 100;
break;
case PERCENT_NONE:
break;
}
if (lp->sign == SIGN_PLUS)
lp->extents += lv->le_count;

View File

@@ -70,6 +70,11 @@ sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def)
return arg_count(cmd, a) ? cmd->args[a].sign : def;
}
percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def)
{
return arg_count(cmd, a) ? cmd->args[a].percent : def;
}
int arg_count_increment(struct cmd_context *cmd, int a)
{
return cmd->args[a].count++;

View File

@@ -80,6 +80,13 @@ typedef enum {
SIGN_MINUS = 2
} sign_t;
typedef enum {
PERCENT_NONE = 0,
PERCENT_VG,
PERCENT_FREE,
PERCENT_LV
} percent_t;
enum {
CHANGE_AY = 0,
CHANGE_AN = 1,
@@ -103,6 +110,7 @@ struct arg {
int64_t i64_value;
uint64_t ui64_value;
sign_t sign;
percent_t percent;
void *ptr;
};
@@ -126,6 +134,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg *a);
int size_mb_arg(struct cmd_context *cmd, struct arg *a);
int int_arg(struct cmd_context *cmd, struct arg *a);
int int_arg_with_sign(struct cmd_context *cmd, struct arg *a);
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg *a);
int major_arg(struct cmd_context *cmd, struct arg *a);
int minor_arg(struct cmd_context *cmd, struct arg *a);
int string_arg(struct cmd_context *cmd, struct arg *a);
@@ -148,6 +157,7 @@ int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def);
uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def);
const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def);
sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def);
percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def);
int arg_count_increment(struct cmd_context *cmd, int a);
const char *command_name(struct cmd_context *cmd);