mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-22 19:33:16 +03:00
Compare commits
15 Commits
dev-bmr-dm
...
dev-bmr-dm
Author | SHA1 | Date | |
---|---|---|---|
|
63e6ef8491 | ||
|
a20989174f | ||
|
8df54e25c6 | ||
|
8ca04e316e | ||
|
e8eed522a8 | ||
|
cd8e3e28e5 | ||
|
8cc8b30ba7 | ||
|
1638e090fc | ||
|
e33656fc53 | ||
|
13d5b8100a | ||
|
077afe5b23 | ||
|
aa4d97d318 | ||
|
a4b5f8ef39 | ||
|
795c590980 | ||
|
ba2da29c4c |
@@ -1 +1 @@
|
||||
1.02.105-git (2015-08-10)
|
||||
1.02.104-git (2015-07-24)
|
||||
|
20
WHATS_NEW
20
WHATS_NEW
@@ -1,22 +1,8 @@
|
||||
Version 2.02.128 -
|
||||
===================================
|
||||
Check for valid cache mode in validation of cache segment.
|
||||
Enhance internal API cache_set_mode() and cache_set_policy().
|
||||
Enhance toollib's get_cache_params().
|
||||
Runtime detect presence of cache smq policy.
|
||||
Add demo cache-mq and cache-smq profiles.
|
||||
Add cmd profilable allocation/cache_policy,cache_settings,cache_mode.
|
||||
Require cache_check 0.5.4 for use of --clear-needs-check-flag.
|
||||
Fix lvmetad udev rules to not override SYSTEMD_WANTS, add the service instead.
|
||||
|
||||
Version 2.02.127 - 10th August 2015
|
||||
===================================
|
||||
Version 2.02.127 -
|
||||
=================================
|
||||
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
|
||||
Order fields in struct cmd_context more logically.
|
||||
Add lock_type to lvmcache VG summary and info structs.
|
||||
Recognise vg/lv name format in dmsetup.
|
||||
Fix regression in cache causing some PVs to bypass filters (2.02.105).
|
||||
Make configure --enable-realtime the default now.
|
||||
Update .gitignore and configure.in files to reflect usage of current tree.
|
||||
|
||||
Version 2.02.126 - 24th July 2015
|
||||
=================================
|
||||
|
30
WHATS_NEW_DM
30
WHATS_NEW_DM
@@ -1,32 +1,6 @@
|
||||
Version 1.02.105 -
|
||||
===================================
|
||||
Add more arg validation for dm_tree_node_add_cache_target().
|
||||
Add --alldevices switch to replace use of --force for stats create / delete.
|
||||
|
||||
Version 1.02.104 - 10th August 2015
|
||||
===================================
|
||||
Add dmstats.8 man page
|
||||
Add dmstats --segments switch to create one region per device segment.
|
||||
Add dmstats --regionid, --allregions to specify a single / all stats regions.
|
||||
Add dmstats --allprograms for stats commands that filter by program ID.
|
||||
Add dmstats --auxdata and --programid args to specify aux data and program ID.
|
||||
Add report stats sub-command to provide repeating stats reports.
|
||||
Add clear, delete, list, and print stats sub-commands.
|
||||
Add create stats sub-command and --start, --length, --areas and --areasize.
|
||||
Recognize 'dmstats' as an alias for 'dmsetup stats' when run with this name.
|
||||
Add a 'stats' command to dmsetup to configure, manage and report stats data.
|
||||
Add statistics fields to dmsetup -o.
|
||||
Add libdm-stats library to allow management of device-mapper statistics.
|
||||
Add --nosuffix to suppress dmsetup unit suffixes in report output.
|
||||
Add --units to control dmsetup report field output units.
|
||||
Add support to redisplay column headings for repeating column reports.
|
||||
Fix report header and row resource leaks.
|
||||
Report timestamps of ioctls with dmsetup -vvv.
|
||||
Recognize report field name variants without any underscores too.
|
||||
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
||||
Version 1.02.104 -
|
||||
=================================
|
||||
Add dm_timestamp functions to libdevmapper.
|
||||
Recognise vg/lv name format in dmsetup.
|
||||
Move size display code to libdevmapper as dm_size_to_string.
|
||||
|
||||
Version 1.02.103 - 24th July 2015
|
||||
=================================
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -20,11 +20,7 @@ CONFDEST=lvm.conf
|
||||
CONFLOCAL=lvmlocal.conf
|
||||
|
||||
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) \
|
||||
$(srcdir)/cache-mq.profile \
|
||||
$(srcdir)/cache-smq.profile \
|
||||
$(srcdir)/thin-generic.profile \
|
||||
$(srcdir)/thin-performance.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
|
@@ -1,20 +0,0 @@
|
||||
# Demo configuration 'mq' cache policy
|
||||
#
|
||||
# Note: This policy has been deprecated in favor of the smq policy
|
||||
# keyword "default" means, setting is left with kernel defaults.
|
||||
#
|
||||
|
||||
allocation {
|
||||
cache_pool_chunk_size = 64
|
||||
cache_mode = "writethrough"
|
||||
cache_policy = "mq"
|
||||
cache_settings {
|
||||
mq {
|
||||
sequential_threshold = "default" # #nr_sequential_ios
|
||||
random_threshold = "default" # #nr_random_ios
|
||||
read_promote_adjustment = "default"
|
||||
write_promote_adjustment = "default"
|
||||
discard_promote_adjustment = "default"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
# Demo configuration 'smq' cache policy
|
||||
#
|
||||
# The stochastic multi-queue (smq) policy addresses some of the problems
|
||||
# with the multiqueue (mq) policy and uses less memory.
|
||||
#
|
||||
|
||||
allocation {
|
||||
cache_pool_chunk_size = 64
|
||||
cache_mode = "writethrough"
|
||||
cache_policy = "smq"
|
||||
cache_settings {
|
||||
# currently no settins for "smq" policy
|
||||
}
|
||||
}
|
25
configure
vendored
25
configure
vendored
@@ -5734,7 +5734,7 @@ fi
|
||||
done
|
||||
|
||||
|
||||
for ac_header in termios.h sys/statvfs.h sys/timerfd.h
|
||||
for ac_header in termios.h sys/statvfs.h
|
||||
do :
|
||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||
@@ -8813,27 +8813,20 @@ $as_echo "$as_me: WARNING: cache_check not found in path $PATH" >&2;}
|
||||
fi
|
||||
fi
|
||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||
$CACHE_CHECK_CMD -V 2>/dev/null >conftest.tmp
|
||||
read -r CACHE_CHECK_VSN < conftest.tmp
|
||||
IFS=. read -r CACHE_CHECK_VSN_MAJOR CACHE_CHECK_VSN_MINOR CACHE_CHECK_VSN_PATCH < conftest.tmp
|
||||
rm -f conftest.tmp
|
||||
CACHE_CHECK_VSN=`"$CACHE_CHECK_CMD" -V 2>/dev/null`
|
||||
CACHE_CHECK_VSN_MAJOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $1}'`
|
||||
CACHE_CHECK_VSN_MINOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $2}'`
|
||||
|
||||
# Require version >= 0.5.4 for --clear-needs-check-flag
|
||||
if test -z "$CACHE_CHECK_VSN_MAJOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_MINOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_PATCH"; then
|
||||
if test -z "$CACHE_CHECK_VSN_MAJOR" -o -z "$CACHE_CHECK_VSN_MINOR"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $CACHE_CHECK_CMD: Bad version \"$CACHE_CHECK_VSN\" found" >&5
|
||||
$as_echo "$as_me: WARNING: $CACHE_CHECK_CMD: Bad version \"$CACHE_CHECK_VSN\" found" >&2;}
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 ; then
|
||||
if test "$CACHE_CHECK_VSN_MINOR" -lt 5 \
|
||||
|| test "$CACHE_CHECK_VSN_MINOR" -eq 5 -a "$CACHE_CHECK_VSN_PATCH" -lt 4; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $CACHE_CHECK_CMD: Old version \"$CACHE_CHECK_VSN\" found" >&5
|
||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 -a "$CACHE_CHECK_VSN_MINOR" -lt 5; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $CACHE_CHECK_CMD: Old version \"$CACHE_CHECK_VSN\" found" >&5
|
||||
$as_echo "$as_me: WARNING: $CACHE_CHECK_CMD: Old version \"$CACHE_CHECK_VSN\" found" >&2;}
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
fi
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
fi
|
||||
fi
|
||||
# Empty means a config way to ignore cache dumping
|
||||
|
25
configure.in
25
configure.in
@@ -103,7 +103,7 @@ AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
|
||||
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||
unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||
|
||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h)
|
||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
@@ -584,25 +584,18 @@ case "$CACHE" in
|
||||
fi
|
||||
fi
|
||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||
$CACHE_CHECK_CMD -V 2>/dev/null >conftest.tmp
|
||||
read -r CACHE_CHECK_VSN < conftest.tmp
|
||||
IFS=. read -r CACHE_CHECK_VSN_MAJOR CACHE_CHECK_VSN_MINOR CACHE_CHECK_VSN_PATCH < conftest.tmp
|
||||
rm -f conftest.tmp
|
||||
CACHE_CHECK_VSN=`"$CACHE_CHECK_CMD" -V 2>/dev/null`
|
||||
CACHE_CHECK_VSN_MAJOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $1}'`
|
||||
CACHE_CHECK_VSN_MINOR=`echo "$CACHE_CHECK_VSN" | $AWK -F '.' '{print $2}'`
|
||||
|
||||
# Require version >= 0.5.4 for --clear-needs-check-flag
|
||||
if test -z "$CACHE_CHECK_VSN_MAJOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_MINOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_PATCH"; then
|
||||
if test -z "$CACHE_CHECK_VSN_MAJOR" -o -z "$CACHE_CHECK_VSN_MINOR"; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 ; then
|
||||
if test "$CACHE_CHECK_VSN_MINOR" -lt 5 \
|
||||
|| test "$CACHE_CHECK_VSN_MINOR" -eq 5 -a "$CACHE_CHECK_VSN_PATCH" -lt 4; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
fi
|
||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 -a "$CACHE_CHECK_VSN_MINOR" -lt 5; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
fi
|
||||
fi
|
||||
# Empty means a config way to ignore cache dumping
|
||||
|
@@ -17,7 +17,6 @@
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -27,16 +26,14 @@ static int info = 0;
|
||||
static int dump = 0;
|
||||
static int wait_opt = 0;
|
||||
static int force_opt = 0;
|
||||
static int kill_vg = 0;
|
||||
static int drop_vg = 0;
|
||||
static int gl_enable = 0;
|
||||
static int gl_disable = 0;
|
||||
static int stop_lockspaces = 0;
|
||||
static char *arg_vg_name = NULL;
|
||||
static char *able_vg_name = NULL;
|
||||
|
||||
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
|
||||
#define DUMP_BUF_SIZE (1024 * 1024)
|
||||
static char dump_buf[DUMP_BUF_SIZE+1];
|
||||
static char dump_buf[DUMP_BUF_SIZE];
|
||||
static int dump_len;
|
||||
static struct sockaddr_un dump_addr;
|
||||
static socklen_t dump_addrlen;
|
||||
@@ -449,9 +446,9 @@ static int do_able(const char *req_name)
|
||||
int rv;
|
||||
|
||||
reply = _lvmlockd_send(req_name,
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"cmd = %s", "lvmlock",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
"vg_name = %s", able_vg_name,
|
||||
NULL);
|
||||
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
@@ -480,7 +477,7 @@ static int do_stop_lockspaces(void)
|
||||
strcat(opts, "force ");
|
||||
|
||||
reply = _lvmlockd_send("stop_all",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"cmd = %s", "lvmlock",
|
||||
"pid = %d", getpid(),
|
||||
"opts = %s", opts[0] ? opts : "none",
|
||||
NULL);
|
||||
@@ -496,87 +493,6 @@ static int do_stop_lockspaces(void)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int do_kill(void)
|
||||
{
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
|
||||
/* These two lines explain the manual alternative to the FIXME below. */
|
||||
syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
|
||||
syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
|
||||
|
||||
/*
|
||||
* It may not be strictly necessary to notify lvmlockd of the kill, but
|
||||
* lvmlockd can use this information to avoid attempting any new lock
|
||||
* requests in the VG (which would fail anyway), and can return an
|
||||
* error indicating that the VG has been killed.
|
||||
*/
|
||||
|
||||
reply = _lvmlockd_send("kill_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
log_error("lvmlockd result %d", result);
|
||||
rv = result;
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
/*
|
||||
* FIXME: here is where we should implement a strong form of
|
||||
* blkdeactivate, and if it completes successfully, automatically call
|
||||
* do_drop() afterward. (The drop step may not always be necessary
|
||||
* if the lvm commands run while shutting things down release all the
|
||||
* leases.)
|
||||
*
|
||||
* run_strong_blkdeactivate();
|
||||
* do_drop();
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int do_drop(void)
|
||||
{
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
int rv;
|
||||
|
||||
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
|
||||
|
||||
/*
|
||||
* Check for misuse by looking for any active LVs in the VG
|
||||
* and refusing this operation if found? One possible way
|
||||
* to kill LVs (e.g. if fs cannot be unmounted) is to suspend
|
||||
* them, or replace them with the error target. In that
|
||||
* case the LV will still appear to be active, but it is
|
||||
* safe to release the lock.
|
||||
*/
|
||||
|
||||
reply = _lvmlockd_send("drop_vg",
|
||||
"cmd = %s", "lvmlockctl",
|
||||
"pid = %d", getpid(),
|
||||
"vg_name = %s", arg_vg_name,
|
||||
NULL);
|
||||
|
||||
if (!_lvmlockd_result(reply, &result)) {
|
||||
log_error("lvmlockd result %d", result);
|
||||
rv = result;
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
printf("lvmlockctl options\n");
|
||||
@@ -593,16 +509,12 @@ static void print_usage(void)
|
||||
printf(" Wait option for other commands.\n");
|
||||
printf("--force | -f 0|1>\n");
|
||||
printf(" Force option for other commands.\n");
|
||||
printf("--kill | -k <vg_name>\n");
|
||||
printf(" Kill access to the vg when sanlock cannot renew lease.\n");
|
||||
printf("--drop | -r <vg_name>\n");
|
||||
printf(" Clear locks for the vg after it has been killed and is no longer used.\n");
|
||||
printf("--stop-lockspaces | -S\n");
|
||||
printf(" Stop all lockspaces.\n");
|
||||
printf("--gl-enable <vg_name>\n");
|
||||
printf(" Tell lvmlockd to enable the global lock in a sanlock vg.\n");
|
||||
printf("--gl-disable <vg_name>\n");
|
||||
printf(" Tell lvmlockd to disable the global lock in a sanlock vg.\n");
|
||||
printf("--stop-lockspaces | -S\n");
|
||||
printf(" Stop all lockspaces.\n");
|
||||
}
|
||||
|
||||
static int read_options(int argc, char *argv[])
|
||||
@@ -617,8 +529,6 @@ static int read_options(int argc, char *argv[])
|
||||
{"dump", no_argument, 0, 'd' },
|
||||
{"wait", required_argument, 0, 'w' },
|
||||
{"force", required_argument, 0, 'f' },
|
||||
{"kill", required_argument, 0, 'k' },
|
||||
{"drop", required_argument, 0, 'r' },
|
||||
{"gl-enable", required_argument, 0, 'E' },
|
||||
{"gl-disable", required_argument, 0, 'D' },
|
||||
{"stop-lockspaces", no_argument, 0, 'S' },
|
||||
@@ -631,7 +541,7 @@ static int read_options(int argc, char *argv[])
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "hqidE:D:w:S", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
@@ -655,21 +565,13 @@ static int read_options(int argc, char *argv[])
|
||||
case 'w':
|
||||
wait_opt = atoi(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
kill_vg = 1;
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
drop_vg = 1;
|
||||
arg_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
gl_enable = 1;
|
||||
arg_vg_name = strdup(optarg);
|
||||
able_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
gl_disable = 1;
|
||||
arg_vg_name = strdup(optarg);
|
||||
able_vg_name = strdup(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stop_lockspaces = 1;
|
||||
@@ -714,16 +616,6 @@ int main(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kill_vg) {
|
||||
rv = do_kill();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (drop_vg) {
|
||||
rv = do_drop();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gl_enable) {
|
||||
rv = do_able("enable_gl");
|
||||
goto out;
|
||||
|
@@ -45,7 +45,5 @@ static inline void lvmlockd_close(daemon_handle h)
|
||||
#define EMANAGER 214
|
||||
#define EPREPARE 215
|
||||
#define ELOCKD 216
|
||||
#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
|
||||
#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
|
||||
|
||||
#endif /* _LVM_LVMLOCKD_CLIENT_H */
|
||||
|
@@ -735,10 +735,6 @@ static const char *op_str(int x)
|
||||
return "find_free_lock";
|
||||
case LD_OP_FORGET_VG_NAME:
|
||||
return "forget_vg_name";
|
||||
case LD_OP_KILL_VG:
|
||||
return "kill_vg";
|
||||
case LD_OP_DROP_VG:
|
||||
return "drop_vg";
|
||||
default:
|
||||
return "op_unknown";
|
||||
};
|
||||
@@ -790,9 +786,7 @@ int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsi
|
||||
char *major_str, *minor_str, *patch_str;
|
||||
char *n, *d1, *d2;
|
||||
|
||||
memset(version, 0, sizeof(version));
|
||||
strncpy(version, args, MAX_ARGS);
|
||||
version[MAX_ARGS] = '\0';
|
||||
|
||||
n = strstr(version, ":");
|
||||
if (n)
|
||||
@@ -1022,10 +1016,7 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
uint32_t r_version = 0;
|
||||
int rv;
|
||||
|
||||
if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s res_lock mode %s (%s)", ls->name, r->name, mode_str(act->mode), act->lv_name);
|
||||
else
|
||||
log_debug("S %s R %s res_lock mode %s", ls->name, r->name, mode_str(act->mode));
|
||||
log_debug("S %s R %s res_lock mode %s", ls->name, r->name, mode_str(act->mode));
|
||||
|
||||
if (r->mode == LD_LK_SH && act->mode == LD_LK_SH)
|
||||
goto add_lk;
|
||||
@@ -1287,12 +1278,8 @@ static int res_unlock(struct lockspace *ls, struct resource *r,
|
||||
return -ENOENT;
|
||||
|
||||
do_unlock:
|
||||
if (act->op == LD_OP_CLOSE)
|
||||
log_debug("S %s R %s res_unlock from close", ls->name, r->name);
|
||||
else if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s res_unlock (%s)", ls->name, r->name, act->lv_name);
|
||||
else
|
||||
log_debug("S %s R %s res_unlock", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock %s", ls->name, r->name,
|
||||
(act->op == LD_OP_CLOSE) ? "from close" : "");
|
||||
|
||||
/* send unlock to lm when last sh lock is unlocked */
|
||||
if (lk->mode == LD_LK_SH) {
|
||||
@@ -1840,7 +1827,7 @@ static int for_each_lock(struct lockspace *ls, int locks_do)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
|
||||
static int clear_locks(struct lockspace *ls, int free_vg)
|
||||
{
|
||||
struct resource *r, *r_safe;
|
||||
struct lock *lk, *lk_safe;
|
||||
@@ -1859,10 +1846,10 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
|
||||
/*
|
||||
* Stopping a lockspace shouldn't happen with LV locks
|
||||
* still held, but it will be stopped with GL and VG
|
||||
* locks held. The drop_vg case may see LV locks.
|
||||
* locks held.
|
||||
*/
|
||||
|
||||
if (lk->flags & LD_LF_PERSISTENT && !drop_vg)
|
||||
if (lk->flags & LD_LF_PERSISTENT)
|
||||
log_error("S %s R %s clear lock persistent", ls->name, r->name);
|
||||
else
|
||||
log_debug("S %s R %s clear lock mode %s client %d", ls->name, r->name, mode_str(lk->mode), lk->client_id);
|
||||
@@ -1896,8 +1883,8 @@ static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
|
||||
rv = lm_unlock(ls, r, NULL, r_version, free_vg ? LMUF_FREE_VG : 0);
|
||||
if (rv < 0) {
|
||||
/* should never happen */
|
||||
log_error("S %s R %s clear_locks free %d drop %d lm unlock error %d",
|
||||
ls->name, r->name, free_vg, drop_vg, rv);
|
||||
log_error("S %s R %s clear_locks free %d lm unlock error %d",
|
||||
ls->name, r->name, free_vg, rv);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(act, act_safe, &r->actions, list) {
|
||||
@@ -1988,15 +1975,11 @@ static int other_sanlock_vgs_exist(struct lockspace *ls_rem)
|
||||
struct lockspace *ls;
|
||||
|
||||
list_for_each_entry(ls, &lockspaces_inactive, list) {
|
||||
if (ls->lm_type != LD_LM_SANLOCK)
|
||||
continue;
|
||||
log_debug("other sanlock vg exists inactive %s", ls->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
list_for_each_entry(ls, &lockspaces, list) {
|
||||
if (ls->lm_type != LD_LM_SANLOCK)
|
||||
continue;
|
||||
if (!strcmp(ls->name, ls_rem->name))
|
||||
continue;
|
||||
log_debug("other sanlock vg exists %s", ls->name);
|
||||
@@ -2006,28 +1989,6 @@ static int other_sanlock_vgs_exist(struct lockspace *ls_rem)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* LOCK is the main thing we're interested in; the others are unlikely.
|
||||
*/
|
||||
|
||||
static int process_op_during_kill(struct action *act)
|
||||
{
|
||||
if (act->op == LD_OP_LOCK && act->mode == LD_LK_UN)
|
||||
return 1;
|
||||
|
||||
switch (act->op) {
|
||||
case LD_OP_LOCK:
|
||||
case LD_OP_ENABLE:
|
||||
case LD_OP_DISABLE:
|
||||
case LD_OP_UPDATE:
|
||||
case LD_OP_RENAME_BEFORE:
|
||||
case LD_OP_RENAME_FINAL:
|
||||
case LD_OP_FIND_FREE_LOCK:
|
||||
return 0;
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process actions queued for this lockspace by
|
||||
* client_recv_action / add_lock_action.
|
||||
@@ -2048,7 +2009,6 @@ static void *lockspace_thread_main(void *arg_in)
|
||||
struct list_head tmp_act;
|
||||
struct list_head act_close;
|
||||
int free_vg = 0;
|
||||
int drop_vg = 0;
|
||||
int error = 0;
|
||||
int adopt_flag = 0;
|
||||
int wait_flag = 0;
|
||||
@@ -2153,43 +2113,7 @@ static void *lockspace_thread_main(void *arg_in)
|
||||
|
||||
act = list_first_entry(&ls->actions, struct action, list);
|
||||
|
||||
if (act->op == LD_OP_KILL_VG && act->rt == LD_RT_VG) {
|
||||
/* Continue processing until DROP_VG arrives. */
|
||||
log_debug("S %s kill_vg", ls->name);
|
||||
ls->kill_vg = 1;
|
||||
list_del(&act->list);
|
||||
act->result = 0;
|
||||
add_client_result(act);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ls->kill_vg && !process_op_during_kill(act)) {
|
||||
log_debug("S %s disallow op %s after kill_vg", ls->name, op_str(act->op));
|
||||
list_del(&act->list);
|
||||
act->result = -EVGKILLED;
|
||||
add_client_result(act);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_DROP_VG && act->rt == LD_RT_VG) {
|
||||
/*
|
||||
* If leases are released after i/o errors begin
|
||||
* but before lvmlockctl --kill, then the VG is not
|
||||
* killed, but drop is still needed to clean up the
|
||||
* VG, so in that case there would be a drop op without
|
||||
* a preceding kill op.
|
||||
*/
|
||||
if (!ls->kill_vg)
|
||||
log_debug("S %s received drop without kill", ls->name);
|
||||
log_debug("S %s drop_vg", ls->name);
|
||||
ls->thread_work = 0;
|
||||
ls->thread_stop = 1;
|
||||
drop_vg = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (act->op == LD_OP_STOP) {
|
||||
/* thread_stop is already set */
|
||||
ls->thread_work = 0;
|
||||
break;
|
||||
}
|
||||
@@ -2313,9 +2237,6 @@ out_rem:
|
||||
* allowed in emergency/force situations, otherwise it's
|
||||
* obviously dangerous, since the lock holders are still
|
||||
* operating under the assumption that they hold the lock.
|
||||
* drop_vg drops all existing locks, but should only
|
||||
* happen when the VG access has been forcibly and
|
||||
* succesfully terminated.
|
||||
*
|
||||
* For vgremove of a sanlock vg, the vg lock will be held,
|
||||
* and possibly the gl lock if this vg holds the gl.
|
||||
@@ -2324,7 +2245,7 @@ out_rem:
|
||||
|
||||
log_debug("S %s clearing locks", ls->name);
|
||||
|
||||
rv = clear_locks(ls, free_vg, drop_vg);
|
||||
rv = clear_locks(ls, free_vg);
|
||||
|
||||
/*
|
||||
* Tell any other hosts in the lockspace to leave it
|
||||
@@ -2362,8 +2283,6 @@ out_act:
|
||||
act->result = 0;
|
||||
} else if (act->op == LD_OP_STOP)
|
||||
act->result = 0;
|
||||
else if (act->op == LD_OP_DROP_VG)
|
||||
act->result = 0;
|
||||
else if (act->op == LD_OP_RENAME_BEFORE)
|
||||
act->result = 0;
|
||||
else
|
||||
@@ -2397,7 +2316,6 @@ out_act:
|
||||
pthread_mutex_lock(&lockspaces_mutex);
|
||||
ls->thread_done = 1;
|
||||
ls->free_vg = free_vg;
|
||||
ls->drop_vg = drop_vg;
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
/*
|
||||
@@ -2588,8 +2506,18 @@ static int add_dlm_global_lockspace(struct action *act)
|
||||
|
||||
if (gl_running_dlm)
|
||||
return -EEXIST;
|
||||
|
||||
gl_running_dlm = 1;
|
||||
|
||||
/* Keep track of whether we automatically added
|
||||
the global ls, so we know to automatically
|
||||
remove it. */
|
||||
|
||||
if (act)
|
||||
gl_auto_dlm = 0;
|
||||
else
|
||||
gl_auto_dlm = 1;
|
||||
|
||||
/*
|
||||
* There's a short period after which a previous gl lockspace thread
|
||||
* has set gl_running_dlm = 0, but before its ls struct has been
|
||||
@@ -2598,9 +2526,11 @@ static int add_dlm_global_lockspace(struct action *act)
|
||||
*/
|
||||
|
||||
rv = add_lockspace_thread(gl_lsname_dlm, NULL, NULL, LD_LM_DLM, NULL, act);
|
||||
|
||||
if (rv < 0) {
|
||||
log_error("add_dlm_global_lockspace add_lockspace_thread %d", rv);
|
||||
gl_running_dlm = 0;
|
||||
gl_auto_dlm = 0;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -2653,12 +2583,28 @@ out:
|
||||
}
|
||||
|
||||
/*
|
||||
* When the first dlm lockspace is added for a vg, automatically add a separate
|
||||
* dlm lockspace for the global lock.
|
||||
* When the first dlm lockspace is added for a vg,
|
||||
* automatically add a separate dlm lockspace for the
|
||||
* global lock if it hasn't been done explicitly.
|
||||
* This is to make the dlm global lockspace work similarly to
|
||||
* the sanlock global lockspace, which is "automatic" by
|
||||
* nature of being one of the vg lockspaces.
|
||||
*
|
||||
* For sanlock, a separate lockspace is not used for the global lock, but the
|
||||
* gl lock lives in a vg lockspace, (although it's recommended to create a
|
||||
* For sanlock, a separate lockspace is not used for
|
||||
* the global lock, but the gl lock lives in a vg
|
||||
* lockspace, (although it's recommended to create a
|
||||
* special vg dedicated to holding the gl).
|
||||
*
|
||||
* N.B. for dlm, if this is an add+WAIT action for a vg
|
||||
* lockspace, and this triggered the automatic addition
|
||||
* of the global lockspace, then the action may complete
|
||||
* for the vg ls add, while the gl ls add is still in
|
||||
* progress. If the caller wants to ensure that the
|
||||
* gl ls add is complete, they should explicitly add+WAIT
|
||||
* the gl ls.
|
||||
*
|
||||
* If this function returns and error, the caller
|
||||
* will queue the act with that error for the client.
|
||||
*/
|
||||
|
||||
static int add_lockspace(struct action *act)
|
||||
@@ -2668,11 +2614,6 @@ static int add_lockspace(struct action *act)
|
||||
|
||||
memset(ls_name, 0, sizeof(ls_name));
|
||||
|
||||
/*
|
||||
* FIXME: I don't think this is used any more.
|
||||
* Remove it, or add the ability to start the global
|
||||
* dlm lockspace using lvmlockctl?
|
||||
*/
|
||||
if (act->rt == LD_RT_GL) {
|
||||
if (gl_use_dlm) {
|
||||
rv = add_dlm_global_lockspace(act);
|
||||
@@ -2756,13 +2697,13 @@ static int rem_lockspace(struct action *act)
|
||||
pthread_mutex_unlock(&lockspaces_mutex);
|
||||
|
||||
/*
|
||||
* The dlm global lockspace was automatically added when
|
||||
* the first dlm vg lockspace was added, now reverse that
|
||||
* If the dlm global lockspace was automatically added when
|
||||
* the first dlm vg lockspace was added, then reverse that
|
||||
* by automatically removing the dlm global lockspace when
|
||||
* the last dlm vg lockspace is removed.
|
||||
*/
|
||||
|
||||
if (rt == LD_RT_VG && gl_use_dlm)
|
||||
if (rt == LD_RT_VG && gl_use_dlm && gl_auto_dlm)
|
||||
rem_dlm_global_lockspace();
|
||||
|
||||
return 0;
|
||||
@@ -3620,6 +3561,7 @@ static int add_lock_action(struct action *act)
|
||||
if (ls_create_fail)
|
||||
act->flags |= LD_AF_ADD_LS_ERROR;
|
||||
return -ENOLS;
|
||||
|
||||
} else {
|
||||
log_debug("lockspace not found %s", ls_name);
|
||||
return -ENOLS;
|
||||
@@ -3794,16 +3736,6 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "kill_vg")) {
|
||||
*op = LD_OP_KILL_VG;
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(req_name, "drop_vg")) {
|
||||
*op = LD_OP_DROP_VG;
|
||||
*rt = LD_RT_VG;
|
||||
return 0;
|
||||
}
|
||||
out:
|
||||
return -1;
|
||||
}
|
||||
@@ -3954,8 +3886,6 @@ static int print_lockspace(struct lockspace *ls, const char *prefix, int pos, in
|
||||
"thread_work=%d "
|
||||
"thread_stop=%d "
|
||||
"thread_done=%d "
|
||||
"kill_vg=%d "
|
||||
"drop_vg=%d "
|
||||
"sanlock_gl_enabled=%d\n",
|
||||
prefix,
|
||||
ls->name,
|
||||
@@ -3970,8 +3900,6 @@ static int print_lockspace(struct lockspace *ls, const char *prefix, int pos, in
|
||||
ls->thread_work ? 1 : 0,
|
||||
ls->thread_stop ? 1 : 0,
|
||||
ls->thread_done ? 1 : 0,
|
||||
ls->kill_vg,
|
||||
ls->drop_vg,
|
||||
ls->sanlock_gl_enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -4367,8 +4295,6 @@ static void client_recv_action(struct client *cl)
|
||||
case LD_OP_FREE:
|
||||
case LD_OP_RENAME_BEFORE:
|
||||
case LD_OP_FIND_FREE_LOCK:
|
||||
case LD_OP_KILL_VG:
|
||||
case LD_OP_DROP_VG:
|
||||
rv = add_lock_action(act);
|
||||
break;
|
||||
case LD_OP_FORGET_VG_NAME:
|
||||
|
@@ -247,8 +247,10 @@ int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
|
||||
free(lmd);
|
||||
ls->lm_data = NULL;
|
||||
|
||||
if (!strcmp(ls->name, gl_lsname_dlm))
|
||||
if (!strcmp(ls->name, gl_lsname_dlm)) {
|
||||
gl_running_dlm = 0;
|
||||
gl_auto_dlm = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -616,7 +618,6 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
|
||||
|
||||
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
{
|
||||
static const char closedir_err_msg[] = "lm_get_lockspace_dlm: closedir failed";
|
||||
struct lockspace *ls;
|
||||
struct dirent *de;
|
||||
DIR *ls_dir;
|
||||
@@ -633,7 +634,7 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
|
||||
if (!(ls = alloc_lockspace())) {
|
||||
if (closedir(ls_dir))
|
||||
log_error(closedir_err_msg);
|
||||
log_error("lm_get_lockspace_dlm: closedir failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -643,8 +644,7 @@ int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
|
||||
list_add_tail(&ls->list, ls_rejoin);
|
||||
}
|
||||
|
||||
if (closedir(ls_dir))
|
||||
log_error(closedir_err_msg);
|
||||
closedir(ls_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -51,8 +51,6 @@ enum {
|
||||
LD_OP_RUNNING_LM,
|
||||
LD_OP_FIND_FREE_LOCK,
|
||||
LD_OP_FORGET_VG_NAME,
|
||||
LD_OP_KILL_VG,
|
||||
LD_OP_DROP_VG,
|
||||
};
|
||||
|
||||
/* resource types */
|
||||
@@ -186,8 +184,6 @@ struct lockspace {
|
||||
unsigned int sanlock_gl_enabled: 1;
|
||||
unsigned int sanlock_gl_dup: 1;
|
||||
unsigned int free_vg: 1;
|
||||
unsigned int kill_vg: 1;
|
||||
unsigned int drop_vg: 1;
|
||||
|
||||
struct list_head actions; /* new client actions */
|
||||
struct list_head resources; /* resource/lock state for gl/vg/lv */
|
||||
@@ -311,7 +307,6 @@ static inline int list_empty(const struct list_head *head)
|
||||
* or when disable_gl matches.
|
||||
*/
|
||||
|
||||
EXTERN int gl_running_dlm;
|
||||
EXTERN int gl_type_static;
|
||||
EXTERN int gl_use_dlm;
|
||||
EXTERN int gl_use_sanlock;
|
||||
@@ -320,6 +315,9 @@ EXTERN pthread_mutex_t gl_type_mutex;
|
||||
EXTERN char gl_lsname_dlm[MAX_NAME+1];
|
||||
EXTERN char gl_lsname_sanlock[MAX_NAME+1];
|
||||
|
||||
EXTERN int gl_running_dlm;
|
||||
EXTERN int gl_auto_dlm;
|
||||
|
||||
EXTERN int daemon_test; /* run as much as possible without a live lock manager */
|
||||
EXTERN int daemon_debug;
|
||||
EXTERN int daemon_host_id;
|
||||
|
@@ -33,101 +33,52 @@
|
||||
#include <sys/socket.h>
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
For each VG, lvmlockd creates a sanlock lockspace that holds the leases for
|
||||
that VG. There's a lease for the VG lock, and there's a lease for each active
|
||||
LV. sanlock maintains (reads/writes) these leases, which exist on storage.
|
||||
That storage is a hidden LV within the VG: /dev/vg/lvmlock. lvmlockd gives the
|
||||
path of this internal LV to sanlock, which then reads/writes the leases on it.
|
||||
|
||||
# lvs -a cc -o+uuid
|
||||
LV VG Attr LSize LV UUID
|
||||
lv1 cc -wi-a----- 2.00g 7xoDtu-yvNM-iwQx-C94t-BbYs-UzBl-o8hAIa
|
||||
lv2 cc -wi-a----- 100.00g exxNPX-wZdO-uCNy-yiGa-aJGT-JKVl-arfcYT
|
||||
[lvmlock] cc -wi-ao---- 256.00m iLpDel-hR0T-hJ3u-rnVo-PcDh-mcjt-sF9egM
|
||||
|
||||
# sanlock status
|
||||
s lvm_cc:1:/dev/mapper/cc-lvmlock:0
|
||||
r lvm_cc:exxNPX-wZdO-uCNy-yiGa-aJGT-JKVl-arfcYT:/dev/mapper/cc-lvmlock:71303168:13 p 26099
|
||||
r lvm_cc:7xoDtu-yvNM-iwQx-C94t-BbYs-UzBl-o8hAIa:/dev/mapper/cc-lvmlock:70254592:3 p 26099
|
||||
|
||||
This shows that sanlock is maintaining leases on /dev/mapper/cc-lvmlock.
|
||||
|
||||
sanlock acquires a lockspace lease when the lockspace is joined, i.e. when the
|
||||
VG is started by 'vgchange --lock-start cc'. This lockspace lease exists at
|
||||
/dev/mapper/cc-lvmlock offset 0, and sanlock regularly writes to it to maintain
|
||||
ownership of it. Joining the lockspace (by acquiring the lockspace lease in
|
||||
it) then allows standard resource leases to be acquired in the lockspace for
|
||||
whatever the application wants. lvmlockd uses resource leases for the VG lock
|
||||
and LV locks.
|
||||
|
||||
sanlock acquires a resource lease for each actual lock that lvm commands use.
|
||||
Above, there are two LV locks that are held because the two LVs are active.
|
||||
These are on /dev/mapper/cc-lvmlock at offsets 71303168 and 70254592. sanlock
|
||||
does not write to these resource leases except when acquiring and releasing
|
||||
them (e.g. lvchange -ay/-an). The renewal of the lockspace lease maintains
|
||||
ownership of all the resource leases in the lockspace.
|
||||
|
||||
If the host loses access to the disk that the sanlock lv lives on, then sanlock
|
||||
can no longer renew its lockspace lease. The lockspace lease will eventually
|
||||
expire, at which point the host will lose ownership of it, and of all resource
|
||||
leases it holds in the lockspace. Eventually, other hosts will be able to
|
||||
acquire those leases. sanlock ensures that another host will not be able to
|
||||
acquire one of the expired leases until the current host has quit using it.
|
||||
|
||||
It is important that the host "quit using" the leases it is holding if the
|
||||
sanlock storage is lost and they begin expiring. If the host cannot quit using
|
||||
the leases and release them within a limited time, then sanlock will use the
|
||||
local watchdog to forcibly reset the host before any other host can acquire
|
||||
them. This is severe, but preferable to possibly corrupting the data protected
|
||||
by the lease. It ensures that two nodes will not be using the same lease at
|
||||
once. For LV leases, that means that another host will not be able to activate
|
||||
the LV while another host still has it active.
|
||||
|
||||
sanlock notifies the application that it cannot renew the lockspace lease. The
|
||||
application needs to quit using all leases in the lockspace and release them as
|
||||
quickly as possible. In the initial version, lvmlockd ignored this
|
||||
notification, so sanlock would eventually reach the point where it would use
|
||||
the local watchdog to reset the host. However, it's better to attempt a
|
||||
response. If that response succeeds, the host can avoid being reset. If the
|
||||
response fails, then sanlock will eventually reset the host as the last resort.
|
||||
sanlock gives the application about 40 seconds to complete its response and
|
||||
release its leases before resetting the host.
|
||||
|
||||
An application can specify the path and args of a program that sanlock should
|
||||
run to notify it if the lockspace lease cannot be renewed. This program should
|
||||
carry out the application's response to the expiring leases: attempt to quit
|
||||
using the leases and then release them. lvmlockd gives this command to sanlock
|
||||
for each VG when that VG is started: 'lvmlockctl --kill vg_name'
|
||||
|
||||
If sanlock loses access to lease storage in that VG, it runs lvmlockctl --kill,
|
||||
which:
|
||||
|
||||
1. Uses syslog to explain what is happening.
|
||||
|
||||
2. Notifies lvmlockd that the VG is being killed, so lvmlockd can
|
||||
immediatley return an error for this condition if any new lock
|
||||
requests are made. (This step would not be strictly necessary.)
|
||||
|
||||
3. Attempts to quit using the VG. This is not yet implemented, but
|
||||
will eventually use blkdeactivate on the VG (or a more forceful
|
||||
equivalent.)
|
||||
|
||||
4. If step 3 was successful at terminating all use of the VG, then
|
||||
lvmlockd is told to release all the leases for the VG. If this
|
||||
is all done without about 40 seconds, the host can avoid being
|
||||
reset.
|
||||
|
||||
Until steps 3 and 4 are fully implemented, manual steps can be substituted.
|
||||
This is primarily for testing since the problem needs to be noticed and
|
||||
responded to in a very short time. The manual alternative to step 3 is to kill
|
||||
any processes using file systems on LV's in the VG, unmount all file systems on
|
||||
the LVs, and deactivate all the LVs. Once this is done, the manual alternative
|
||||
to step 4 is to run 'lvmlockctl --drop vg_name', which tells lvmlockd to
|
||||
release all the leases for the VG.
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
* If access to the pv containing the vg's leases is lost, sanlock cannot renew
|
||||
* the leases we have acquired for locked LVs. This means that we could soon
|
||||
* loose the lease to another host which could activate our LV exclusively. We
|
||||
* do not want to get to the point of two hosts having the same LV active
|
||||
* exclusively (it obviously violates the purpose of LV locks.)
|
||||
*
|
||||
* The default method of preventing this problem is for lvmlockd to do nothing,
|
||||
* which produces a safe but potentially inconvenient result. Doing nothing
|
||||
* leads to our LV leases not being released, which leads to sanlock using the
|
||||
* local watchdog to reset us before another host can acquire our lock. It
|
||||
* would often be preferrable to avoid the abrupt hard reset from the watchdog.
|
||||
*
|
||||
* There are other options to avoid being reset by our watchdog. If we can
|
||||
* quickly stop using the LVs in question and release the locks for them, then
|
||||
* we could avoid a reset (there's a certain grace period of about 40 seconds
|
||||
* in which we can attempt this.) To do this, we can tell sanlock to run a
|
||||
* specific program when it has lost access to our leases. We could use this
|
||||
* program to:
|
||||
*
|
||||
* 1. Deactivate all lvs in the effected vg. If all the leases are
|
||||
* deactivated, then our LV locks would be released and sanlock would no longer
|
||||
* use the watchdog to reset us. If file systems are mounted on the active
|
||||
* lvs, then deactivating them would fail, so this option would be of limited
|
||||
* usefulness.
|
||||
*
|
||||
* 2. Option 1 could be extended to kill pids using the fs on the lv, unmount
|
||||
* the fs, and deactivate the lv. This is probably out of scope for lvm
|
||||
* directly, and would likely need the help of another system service.
|
||||
*
|
||||
* 3. Use dmsetup suspend to block access to lvs in the effected vg. If this
|
||||
* was successful, the local host could no longer write to the lvs, we could
|
||||
* safely release the LV locks, and sanlock would no longer reset us. At this
|
||||
* point, with suspended lvs, the host would be in a fairly hobbled state, and
|
||||
* would almost certainly need a manual, forcible reset.
|
||||
*
|
||||
* 4. Option 3 could be extended to monitor the lost storage, and if it is
|
||||
* reconnected, the leases could be reacquired, and the suspended lvs resumed
|
||||
* (reacquiring leases will fail if another host has acquired them since they
|
||||
* were released.) This complexity of this option, combined with the fact that
|
||||
* the error conditions are often not as simple as storage being lost and then
|
||||
* later connecting, will result in this option being too unreliable.
|
||||
*
|
||||
* Add a config option that we could use to select a different behavior than
|
||||
* the default. Then implement one of the simpler options as a proof of
|
||||
* concept, which could be extended if needed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each lockspace thread has its own sanlock daemon connection.
|
||||
@@ -1010,24 +961,12 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
char lock_lv_name[MAX_ARGS+1];
|
||||
char lsname[SANLK_NAME_LEN + 1];
|
||||
char disk_path[SANLK_PATH_LEN];
|
||||
char killpath[SANLK_PATH_LEN];
|
||||
char killargs[SANLK_PATH_LEN];
|
||||
int gl_found;
|
||||
int ret, rv;
|
||||
|
||||
memset(disk_path, 0, sizeof(disk_path));
|
||||
memset(lock_lv_name, 0, sizeof(lock_lv_name));
|
||||
|
||||
/*
|
||||
* Construct the path to lvmlockctl by using the path to the lvm binary
|
||||
* and appending "lockctl" to get /path/to/lvmlockctl.
|
||||
*/
|
||||
memset(killpath, 0, sizeof(killpath));
|
||||
snprintf(killpath, SANLK_PATH_LEN - 1, "%slockctl", LVM_PATH);
|
||||
|
||||
memset(killargs, 0, sizeof(killargs));
|
||||
snprintf(killargs, SANLK_PATH_LEN - 1, "--kill %s", ls->vg_name);
|
||||
|
||||
rv = check_args_version(ls->vg_args, VG_LOCK_ARGS_MAJOR);
|
||||
if (rv < 0) {
|
||||
ret = -EARGS;
|
||||
@@ -1112,15 +1051,6 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
log_debug("set killpath to %s %s", killpath, killargs);
|
||||
|
||||
rv = sanlock_killpath(lms->sock, 0, killpath, killargs);
|
||||
if (rv < 0) {
|
||||
log_error("S %s killpath error %d", lsname, rv);
|
||||
ret = -EMANAGER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = sanlock_restrict(lms->sock, SANLK_RESTRICT_SIGKILL);
|
||||
if (rv < 0) {
|
||||
log_error("S %s restrict error %d", lsname, rv);
|
||||
@@ -1467,6 +1397,11 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
log_error("S %s R %s lock_san acquire error %d",
|
||||
ls->name, r->name, rv);
|
||||
|
||||
if (added) {
|
||||
lm_rem_resource_sanlock(ls, r);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* if the gl has been disabled, remove and free the gl resource */
|
||||
if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) {
|
||||
if (!lm_gl_is_enabled(ls)) {
|
||||
@@ -1478,22 +1413,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
lm_rem_resource_sanlock(ls, r);
|
||||
|
||||
/* sanlock gets i/o errors trying to read/write the leases. */
|
||||
if (rv == -EIO)
|
||||
rv = -ELOCKIO;
|
||||
|
||||
/*
|
||||
* The sanlock lockspace can disappear if the lease storage fails,
|
||||
* the delta lease renewals fail, the lockspace enters recovery,
|
||||
* lvmlockd holds no leases in the lockspace, so sanlock can
|
||||
* stop and free the lockspace.
|
||||
*/
|
||||
if (rv == -ENOSPC)
|
||||
rv = -ELOCKIO;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1675,11 +1594,9 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
rv = sanlock_release(lms->sock, -1, 0, 1, &rs);
|
||||
if (rv < 0)
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
|
||||
|
||||
if (rv == -EIO)
|
||||
rv = -ELOCKIO;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@@ -566,8 +566,6 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
|
||||
cmdenvp = cmdenvp_ctr(pdlv);
|
||||
if (!cmdenvp) {
|
||||
pdlv_destroy(pdlv);
|
||||
@@ -575,6 +573,7 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
pdlv->cmdenvp = cmdenvp;
|
||||
|
||||
return pdlv;
|
||||
|
@@ -25,11 +25,6 @@
|
||||
#include "lv_alloc.h"
|
||||
#include "defaults.h"
|
||||
|
||||
static const char _cache_module[] = "cache";
|
||||
|
||||
/* TODO: using static field here, maybe should be a part of segment_type */
|
||||
static unsigned _feature_mask;
|
||||
|
||||
#define SEG_LOG_ERROR(t, p...) \
|
||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||
@@ -71,15 +66,23 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
if (dm_config_has_node(sn, "cache_mode")) {
|
||||
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
|
||||
return SEG_LOG_ERROR("cache_mode must be a string in");
|
||||
if (!cache_set_mode(seg, str))
|
||||
if (!set_cache_pool_feature(&seg->feature_flags, str))
|
||||
return SEG_LOG_ERROR("Unknown cache_mode in");
|
||||
}
|
||||
} else
|
||||
/* When missed in metadata, it's an old stuff - use writethrough */
|
||||
seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
|
||||
if (dm_config_has_node(sn, "policy")) {
|
||||
if (!(str = dm_config_find_str(sn, "policy", NULL)))
|
||||
return SEG_LOG_ERROR("policy must be a string in");
|
||||
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
|
||||
return SEG_LOG_ERROR("Failed to duplicate policy in");
|
||||
} else {
|
||||
/* Cannot use 'just' default, so pick one */
|
||||
seg->policy_name = DEFAULT_CACHE_POOL_POLICY; /* FIXME make configurable */
|
||||
/* FIXME maybe here should be always 'mq' */
|
||||
log_warn("WARNING: cache_policy undefined, using default \"%s\" policy.",
|
||||
seg->policy_name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -100,9 +103,6 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
* If the policy is not present, default policy is used.
|
||||
*/
|
||||
if ((sn = dm_config_find_node(sn, "policy_settings"))) {
|
||||
if (!seg->policy_name)
|
||||
return SEG_LOG_ERROR("policy_settings must have a policy_name in");
|
||||
|
||||
if (sn->v)
|
||||
return SEG_LOG_ERROR("policy_settings must be a section in");
|
||||
|
||||
@@ -131,33 +131,28 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
|
||||
{
|
||||
const char *cache_mode;
|
||||
|
||||
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
|
||||
return_0;
|
||||
|
||||
if (!seg->policy_name) {
|
||||
log_error(INTERNAL_ERROR "Policy name for %s is not defined.",
|
||||
display_lvname(seg->lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
|
||||
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
|
||||
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||
|
||||
/*
|
||||
* Cache pool used by a cache LV holds data. Not ideal,
|
||||
* but not worth to break backward compatibility, by shifting
|
||||
* content to cache segment
|
||||
*/
|
||||
if (cache_mode_is_set(seg)) {
|
||||
if (!(cache_mode = get_cache_mode_name(seg)))
|
||||
return_0;
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
}
|
||||
|
||||
if (seg->policy_name) {
|
||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
}
|
||||
if (seg->policy_settings->child)
|
||||
out_config_node(f, seg->policy_settings);
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
}
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -170,29 +165,12 @@ static void _destroy(struct segment_type *segtype)
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _target_present(struct cmd_context *cmd,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
{
|
||||
/* List of features with their kernel target version */
|
||||
static const struct feature {
|
||||
uint32_t maj;
|
||||
uint32_t min;
|
||||
unsigned cache_feature;
|
||||
const char feature[12];
|
||||
const char module[12]; /* check dm-%s */
|
||||
} _features[] = {
|
||||
{ 1, 3, CACHE_FEATURE_POLICY_MQ, "policy_mq", "cache-mq" },
|
||||
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, "policy_smq", "cache-smq" },
|
||||
};
|
||||
static const char _lvmconf[] = "global/cache_disabled_features";
|
||||
static unsigned _attrs = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
static int _cache_checked = 0;
|
||||
static int _cache_present = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
unsigned i;
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
|
||||
if (!_cache_checked) {
|
||||
_cache_present = target_present(cmd, "cache", 1);
|
||||
@@ -206,53 +184,11 @@ static int _target_present(struct cmd_context *cmd,
|
||||
|
||||
if ((maj < 1) ||
|
||||
((maj == 1) && (min < 3))) {
|
||||
_cache_present = 0;
|
||||
log_error("The cache kernel module is version %u.%u.%u. "
|
||||
"Version 1.3.0+ is required.",
|
||||
log_error("The cache kernel module is version %u.%u.%u."
|
||||
" Version 1.3.0+ is required.",
|
||||
maj, min, patchlevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) {
|
||||
if (((maj > _features[i].maj) ||
|
||||
(maj == _features[i].maj && min >= _features[i].min)) &&
|
||||
(!_features[i].module[0] || module_present(cmd, _features[i].module)))
|
||||
_attrs |= _features[i].cache_feature;
|
||||
else
|
||||
log_very_verbose("Target %s does not support %s.",
|
||||
_cache_module, _features[i].feature);
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes) {
|
||||
if (!_feature_mask) {
|
||||
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
|
||||
if ((cn = find_config_tree_array(cmd, global_cache_disabled_features_CFG, NULL))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Ignoring invalid string in config file %s.",
|
||||
_lvmconf);
|
||||
continue;
|
||||
}
|
||||
str = cv->v.str;
|
||||
if (!*str)
|
||||
continue;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||
if (strcasecmp(str, _features[i].feature) == 0)
|
||||
_feature_mask |= _features[i].cache_feature;
|
||||
}
|
||||
}
|
||||
|
||||
_feature_mask = ~_feature_mask;
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||
if ((_attrs & _features[i].cache_feature) &&
|
||||
!(_feature_mask & _features[i].cache_feature))
|
||||
log_very_verbose("Target %s %s support disabled by %s",
|
||||
_cache_module, _features[i].feature, _lvmconf);
|
||||
}
|
||||
*attributes = _attrs & _feature_mask;
|
||||
}
|
||||
|
||||
return _cache_present;
|
||||
@@ -378,9 +314,7 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
metadata_uuid,
|
||||
data_uuid,
|
||||
origin_uuid,
|
||||
seg->cleaner_policy ? "cleaner" :
|
||||
/* undefined policy name -> likely an old "mq" */
|
||||
cache_pool_seg->policy_name ? : "mq",
|
||||
seg->cleaner_policy ? "cleaner" : cache_pool_seg->policy_name,
|
||||
seg->cleaner_policy ? NULL : cache_pool_seg->policy_settings,
|
||||
cache_pool_seg->chunk_size))
|
||||
return_0;
|
||||
@@ -442,8 +376,5 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return_0;
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
/* Reset mask for recalc */
|
||||
_feature_mask = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -2179,6 +2179,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
lvmetad_release_token();
|
||||
lvmetad_disconnect();
|
||||
lvmpolld_disconnect();
|
||||
cmd->initialized.connections = 0;
|
||||
|
||||
release_log_memory();
|
||||
activation_exit();
|
||||
|
@@ -133,7 +133,6 @@ struct cmd_context {
|
||||
unsigned lockd_gl_disable:1;
|
||||
unsigned lockd_vg_disable:1;
|
||||
unsigned lockd_lv_disable:1;
|
||||
unsigned lockd_gl_removed:1;
|
||||
unsigned lockd_vg_default_sh:1;
|
||||
unsigned lockd_vg_enforce_sh:1;
|
||||
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-file.h"
|
||||
#include "memlock.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -2416,27 +2415,3 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
|
||||
{
|
||||
return DEFAULT_CACHE_POOL_CHUNK_SIZE * 2;
|
||||
}
|
||||
|
||||
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||
{
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, "cache");
|
||||
unsigned attr = ~0;
|
||||
|
||||
if (!segtype ||
|
||||
!segtype->ops->target_present ||
|
||||
!segtype->ops->target_present(cmd, NULL, &attr)) {
|
||||
log_warn("WARNING: Cannot detect default cache policy, using \""
|
||||
DEFAULT_CACHE_POLICY "\".");
|
||||
return DEFAULT_CACHE_POLICY;
|
||||
}
|
||||
|
||||
if (attr & CACHE_FEATURE_POLICY_SMQ)
|
||||
return "smq";
|
||||
|
||||
if (attr & CACHE_FEATURE_POLICY_MQ)
|
||||
return "mq";
|
||||
|
||||
log_warn("WARNING: Default cache policy not available.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ struct profile_params {
|
||||
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
||||
};
|
||||
|
||||
#define CFG_PATH_MAX_LEN 128
|
||||
#define CFG_PATH_MAX_LEN 64
|
||||
|
||||
/*
|
||||
* Structures used for definition of a configuration tree.
|
||||
@@ -296,7 +296,5 @@ int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, str
|
||||
#define get_default_unconfigured_allocation_thin_pool_chunk_size_CFG NULL
|
||||
int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
|
||||
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_policy_CFG NULL
|
||||
|
||||
#endif
|
||||
|
@@ -122,7 +122,7 @@ cfg_section(devices_CFG_SECTION, "devices", root_CFG_SECTION, 0, vsn(1, 0, 0), 0
|
||||
"How LVM uses block devices.\n")
|
||||
|
||||
cfg_section(allocation_CFG_SECTION, "allocation", root_CFG_SECTION, CFG_PROFILABLE, vsn(2, 2, 77), 0, NULL,
|
||||
"How LVM selects space and applies properties to LVs.\n")
|
||||
"How LVM selects free space for Logical Volumes.\n")
|
||||
|
||||
cfg_section(log_CFG_SECTION, "log", root_CFG_SECTION, 0, vsn(1, 0, 0), 0, NULL,
|
||||
"How LVM log information is reported.\n")
|
||||
@@ -313,7 +313,7 @@ cfg(devices_md_chunk_alignment_CFG, "md_chunk_alignment", devices_CFG_SECTION, 0
|
||||
|
||||
cfg(devices_default_data_alignment_CFG, "default_data_alignment", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_DATA_ALIGNMENT, vsn(2, 2, 75), NULL, 0, NULL,
|
||||
"Default alignment of the start of a PV data area in MB.\n"
|
||||
"If set to 0, a value of 64KiB will be used.\n"
|
||||
"If set to 0, a value of 64KB will be used.\n"
|
||||
"Set to 1 for 1MiB, 2 for 2MiB, etc.\n")
|
||||
|
||||
cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_DETECTION, vsn(2, 2, 51), NULL, 0, NULL,
|
||||
@@ -329,7 +329,7 @@ cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CF
|
||||
"This setting takes precedence over md_chunk_alignment.\n")
|
||||
|
||||
cfg(devices_data_alignment_CFG, "data_alignment", devices_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(2, 2, 45), NULL, 0, NULL,
|
||||
"Alignment of the start of a PV data area in KiB.\n"
|
||||
"Alignment of the start of a PV data area in KB.\n"
|
||||
"If a PV is placed directly on an md device and\n"
|
||||
"md_chunk_alignment or data_alignment_detection are enabled,\n"
|
||||
"then this setting is ignored. Otherwise, md_chunk_alignment\n"
|
||||
@@ -340,10 +340,10 @@ cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detectio
|
||||
"Detect PV data alignment offset based on sysfs device information.\n"
|
||||
"The start of a PV aligned data area will be shifted by the\n"
|
||||
"alignment_offset exposed in sysfs. This offset is often 0, but\n"
|
||||
"may be non-zero. Certain 4KiB sector drives that compensate for\n"
|
||||
"may be non-zero. Certain 4KB sector drives that compensate for\n"
|
||||
"windows partitioning will have an alignment_offset of 3584 bytes\n"
|
||||
"(sector 7 is the lowest aligned logical block, the 4KiB sectors start\n"
|
||||
"at LBA -1, and consequently sector 63 is aligned on a 4KiB boundary).\n"
|
||||
"(sector 7 is the lowest aligned logical block, the 4KB sectors start\n"
|
||||
"at LBA -1, and consequently sector 63 is aligned on a 4KB boundary).\n"
|
||||
"pvcreate --dataalignmentoffset will skip this detection.\n")
|
||||
|
||||
cfg(devices_ignore_suspended_devices_CFG, "ignore_suspended_devices", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_IGNORE_SUSPENDED_DEVICES, vsn(1, 2, 19), NULL, 0, NULL,
|
||||
@@ -383,9 +383,9 @@ cfg(devices_require_restorefile_with_uuid_CFG, "require_restorefile_with_uuid",
|
||||
"Allow use of pvcreate --uuid without requiring --restorefile.\n")
|
||||
|
||||
cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PV_MIN_SIZE_KB, vsn(2, 2, 85), NULL, 0, NULL,
|
||||
"Minimum size in KiB of block devices which can be used as PVs.\n"
|
||||
"Minimum size (in KB) of block devices which can be used as PVs.\n"
|
||||
"In a clustered environment all nodes must use the same value.\n"
|
||||
"Any value smaller than 512KiB is ignored. The previous built-in\n"
|
||||
"Any value smaller than 512KB is ignored. The previous built-in\n"
|
||||
"value was 512.\n")
|
||||
|
||||
cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ISSUE_DISCARDS, vsn(2, 2, 85), NULL, 0, NULL,
|
||||
@@ -439,7 +439,7 @@ cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_z
|
||||
"Look for and erase any signatures while zeroing a new LV.\n"
|
||||
"Zeroing is controlled by the -Z/--zero option, and if not\n"
|
||||
"specified, zeroing is used by default if possible.\n"
|
||||
"Zeroing simply overwrites the first 4KiB of a new LV\n"
|
||||
"Zeroing simply overwrites the first 4 KiB of a new LV\n"
|
||||
"with zeroes and does no signature detection or wiping.\n"
|
||||
"Signature wiping goes beyond zeroing and detects exact\n"
|
||||
"types and positions of signatures within the whole LV.\n"
|
||||
@@ -462,34 +462,16 @@ cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separa
|
||||
cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
|
||||
"Cache pool metadata and data will always use different PVs.\n")
|
||||
|
||||
cfg(allocation_cache_pool_cachemode_CFG, "cache_pool_cachemode", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 113), NULL, vsn(2, 2, 128),
|
||||
"This has been replaced by the allocation/cache_mode setting.\n",
|
||||
"Cache mode.\n")
|
||||
|
||||
cfg(allocation_cache_mode_CFG, "cache_mode", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 128), NULL, 0, NULL,
|
||||
"The default cache mode used for new cache.\n"
|
||||
cfg(allocation_cache_pool_cachemode_CFG, "cache_pool_cachemode", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_POOL_CACHEMODE, vsn(2, 2, 113), NULL, 0, NULL,
|
||||
"The default cache mode used for new cache pools.\n"
|
||||
"Possible options are: writethrough, writeback.\n"
|
||||
"writethrough - Data blocks are immediately written from\n"
|
||||
"the cache to disk.\n"
|
||||
"writeback - Data blocks are written from the cache back\n"
|
||||
"to disk after some delay to improve performance.\n")
|
||||
|
||||
cfg_runtime(allocation_cache_policy_CFG, "cache_policy", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(2, 2, 127), 0, NULL,
|
||||
"The default cache policy used for new cache volume.\n"
|
||||
"Generally available policies are: mq, smq.\n"
|
||||
"mq - Multiqueue policy with 88 bytes per block\n"
|
||||
"smq - Stochastic multique with 25 bytes per block (kernel >= 4.2).\n")
|
||||
|
||||
cfg_section(allocation_cache_settings_CFG_SECTION, "cache_settings", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 127), 0, NULL,
|
||||
"Individual settings for policies.\n"
|
||||
"See the help for individual policies for more info.\n")
|
||||
|
||||
cfg_section(policy_settings_CFG_SUBSECTION, "policy_settings", allocation_cache_settings_CFG_SECTION, CFG_NAME_VARIABLE | CFG_SECTION_NO_CHECK | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 127), 0, NULL,
|
||||
"Replace this subsection name with a policy name.\n"
|
||||
"Multiple subsections for different policies can be created.\n")
|
||||
|
||||
cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 106), 0, NULL,
|
||||
"The minimal chunk size in KiB for cache pool volumes.\n"
|
||||
cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", allocation_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 106), 0, NULL,
|
||||
"The minimal chunk size (in kiB) for cache pool volumes.\n"
|
||||
"Using a chunk_size that is too large can result in wasteful\n"
|
||||
"use of the cache, where small reads and writes can cause\n"
|
||||
"large sections of an LV to be mapped into the cache. However,\n"
|
||||
@@ -497,8 +479,8 @@ cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", alloc
|
||||
"overhead trying to manage the numerous chunks that become mapped\n"
|
||||
"into the cache. The former is more of a problem than the latter\n"
|
||||
"in most cases, so we default to a value that is on the smaller\n"
|
||||
"end of the spectrum. Supported values range from 32KiB to\n"
|
||||
"1GiB in multiples of 32.\n")
|
||||
"end of the spectrum. Supported values range from 32(kiB) to\n"
|
||||
"1048576 in multiples of 32.\n")
|
||||
|
||||
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
"Thin pool metdata and data will always use different PVs.\n")
|
||||
@@ -524,16 +506,16 @@ cfg(allocation_thin_pool_chunk_size_policy_CFG, "thin_pool_chunk_size_policy", a
|
||||
"The chunk size is always at least 512KiB.\n")
|
||||
|
||||
cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 99), 0, NULL,
|
||||
"The minimal chunk size in KiB for thin pool volumes.\n"
|
||||
"The minimal chunk size (in KB) for thin pool volumes.\n"
|
||||
"Larger chunk sizes may improve performance for plain\n"
|
||||
"thin volumes, however using them for snapshot volumes\n"
|
||||
"is less efficient, as it consumes more space and takes\n"
|
||||
"extra time for copying. When unset, lvm tries to estimate\n"
|
||||
"chunk size starting from 64KiB. Supported values are in\n"
|
||||
"the range 64KiB to 1GiB.\n")
|
||||
"chunk size starting from 64KB. Supported values are in\n"
|
||||
"the range 64 to 1048576.\n")
|
||||
|
||||
cfg(allocation_physical_extent_size_CFG, "physical_extent_size", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_EXTENT_SIZE, vsn(2, 2, 112), NULL, 0, NULL,
|
||||
"Default physical extent size in KiB to use for new VGs.\n")
|
||||
"Default physical extent size to use for new VGs (in KB).\n")
|
||||
|
||||
cfg(log_verbose_CFG, "verbose", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_VERBOSE, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Controls the messages sent to stdout or stderr.\n")
|
||||
@@ -810,11 +792,11 @@ cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECT
|
||||
"The '--type snapshot|thin' option overrides this setting.\n")
|
||||
|
||||
cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_path", global_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH, vsn(2, 2, 89), NULL, 0, NULL,
|
||||
"Enable this to reinstate the previous lvdisplay name format.\n"
|
||||
"The default format for displaying LV names in lvdisplay was changed\n"
|
||||
"in version 2.02.89 to show the LV name and path separately.\n"
|
||||
"Previously this was always shown as /dev/vgname/lvname even when that\n"
|
||||
"was never a valid path in the /dev filesystem.\n")
|
||||
"was never a valid path in the /dev filesystem.\n"
|
||||
"Enable this option to reinstate the previous format.\n")
|
||||
|
||||
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMETAD, vsn(2, 2, 93), "@DEFAULT_USE_LVMETAD@", 0, NULL,
|
||||
"Use lvmetad to cache metadata and reduce disk scanning.\n"
|
||||
@@ -909,14 +891,6 @@ cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CF
|
||||
"Example:\n"
|
||||
"thin_disabled_features = [ \"discards\", \"block_size\" ]\n")
|
||||
|
||||
cfg_array(global_cache_disabled_features_CFG, "cache_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 126), NULL, 0, NULL,
|
||||
"Features to not use in the cache driver.\n"
|
||||
"This can be helpful for testing, or to avoid\n"
|
||||
"using a feature that is causing problems.\n"
|
||||
"Features: policy_mq, policy_smq.\n"
|
||||
"Example:\n"
|
||||
"cache_disabled_features = [ \"policy_smq\" ]\n")
|
||||
|
||||
cfg(global_cache_check_executable_CFG, "cache_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, CACHE_CHECK_CMD, vsn(2, 2, 108), "@CACHE_CHECK_CMD@", 0, NULL,
|
||||
"The full path to the cache_check command.\n"
|
||||
"LVM uses this command to check that a cache metadata\n"
|
||||
@@ -1039,11 +1013,11 @@ cfg(activation_use_linear_target_CFG, "use_linear_target", activation_CFG_SECTIO
|
||||
"that only handles a single stripe.\n")
|
||||
|
||||
cfg(activation_reserved_stack_CFG, "reserved_stack", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RESERVED_STACK, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Stack size in KiB to reserve for use while devices are suspended.\n"
|
||||
"Stack size in KB to reserve for use while devices are suspended.\n"
|
||||
"Insufficent reserve risks I/O deadlock during device suspension.\n")
|
||||
|
||||
cfg(activation_reserved_memory_CFG, "reserved_memory", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RESERVED_MEMORY, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Memory size in KiB to reserve for use while devices are suspended.\n"
|
||||
"Memory size in KB to reserve for use while devices are suspended.\n"
|
||||
"Insufficent reserve risks I/O deadlock during device suspension.\n")
|
||||
|
||||
cfg(activation_process_priority_CFG, "process_priority", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PROCESS_PRIORITY, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
@@ -1110,7 +1084,7 @@ cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activat
|
||||
|
||||
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
|
||||
"This has been replaced by the activation/raid_region_size setting.\n",
|
||||
"Size in KiB of each copy operation when mirroring.\n")
|
||||
"Size (in KB) of each copy operation when mirroring.\n")
|
||||
|
||||
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
|
||||
"Size in KiB of each raid or mirror synchronization region.\n"
|
||||
@@ -1263,7 +1237,7 @@ cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, 0, CFG_TYPE
|
||||
"The '--ignoremonitoring' option overrides this setting.\n")
|
||||
|
||||
cfg(activation_polling_interval_CFG, "polling_interval", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_INTERVAL, vsn(2, 2, 63), NULL, 0, NULL,
|
||||
"Check pvmove or lvconvert progress at this interval (seconds).\n"
|
||||
"Check pvmove or lvconvert progress at this interval (seconds)\n"
|
||||
"When pvmove or lvconvert must wait for the kernel to finish\n"
|
||||
"synchronising or merging data, they check and report progress\n"
|
||||
"at intervals of this number of seconds.\n"
|
||||
|
@@ -117,8 +117,8 @@
|
||||
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||
#define DEFAULT_CACHE_POLICY "mq"
|
||||
#define DEFAULT_CACHE_MODE "writethrough"
|
||||
#define DEFAULT_CACHE_POOL_CACHEMODE "writethrough"
|
||||
#define DEFAULT_CACHE_POOL_POLICY "mq"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
|
@@ -164,7 +164,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && vg_is_exported(vg)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!vg->lvm1_system_id || !*vg->lvm1_system_id ||
|
||||
if ((vg->lvm1_system_id && !*vg->lvm1_system_id) ||
|
||||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
|
@@ -739,19 +739,6 @@ static int _free_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg)
|
||||
if (!_lvmlockd_connected)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* vgremove originally held the global lock, but lost it because the
|
||||
* vgremove command is removing multiple VGs, and removed the VG
|
||||
* holding the global lock before attempting to remove this VG.
|
||||
* To avoid this situation, the user should remove the VG holding
|
||||
* the global lock in a command by itself, or as the last arg in a
|
||||
* vgremove command that removes multiple VGs.
|
||||
*/
|
||||
if (cmd->lockd_gl_removed) {
|
||||
log_error("Global lock failed: global lock was lost by removing a previous VG.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg->lock_args || !strlen(vg->lock_args)) {
|
||||
/* Shouldn't happen in general, but maybe in some error cases? */
|
||||
log_debug("_free_vg_sanlock %s no lock_args", vg->name);
|
||||
@@ -786,21 +773,8 @@ static int _free_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the global lock was been removed by removing this VG, then:
|
||||
*
|
||||
* Print a warning indicating that the global lock should be enabled
|
||||
* in another remaining sanlock VG.
|
||||
*
|
||||
* Do not allow any more VGs to be removed by this command, e.g.
|
||||
* if a command removes two sanlock VGs, like vgremove foo bar,
|
||||
* and the global lock existed in foo, do not continue to remove
|
||||
* VG bar without the global lock. See the corresponding check above.
|
||||
*/
|
||||
if (lockd_flags & LD_RF_WARN_GL_REMOVED) {
|
||||
if (lockd_flags & LD_RF_WARN_GL_REMOVED)
|
||||
log_warn("VG %s held the sanlock global lock, enable global lock in another VG.", vg->name);
|
||||
cmd->lockd_gl_removed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The usleep delay gives sanlock time to close the lock lv,
|
||||
@@ -1383,7 +1357,6 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
const char *mode = NULL;
|
||||
const char *opts = NULL;
|
||||
uint32_t lockd_flags;
|
||||
int force_cache_update = 0;
|
||||
int retries = 0;
|
||||
int result;
|
||||
|
||||
@@ -1428,8 +1401,8 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
/* We can continue reading if a shared lock fails. */
|
||||
if (!strcmp(mode, "sh")) {
|
||||
log_warn("Reading without shared global lock.");
|
||||
force_cache_update = 1;
|
||||
goto allow;
|
||||
lvmetad_validate_global_cache(cmd, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_error("Global lock failed: check that lvmlockd is running.");
|
||||
@@ -1452,19 +1425,9 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
*
|
||||
* ESTARTING: the lockspace with the gl is starting.
|
||||
* The VG with the global lock is starting and should finish shortly.
|
||||
*
|
||||
* ELOCKIO: sanlock gets i/o errors when trying to read/write leases
|
||||
* (This can progress to EVGKILLED.)
|
||||
*
|
||||
* EVGKILLED: the sanlock lockspace is being killed after losing
|
||||
* access to lease storage.
|
||||
*/
|
||||
|
||||
if (result == -ENOLS ||
|
||||
result == -ESTARTING ||
|
||||
result == -EVGKILLED ||
|
||||
result == -ELOCKIO) {
|
||||
|
||||
if (result == -ENOLS || result == -ESTARTING) {
|
||||
if (!strcmp(mode, "un"))
|
||||
return 1;
|
||||
|
||||
@@ -1473,13 +1436,9 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
*/
|
||||
if (strcmp(mode, "sh")) {
|
||||
if (result == -ESTARTING)
|
||||
log_error("Global lock failed: lockspace is starting");
|
||||
log_error("Global lock failed: lockspace is starting.");
|
||||
else if (result == -ENOLS)
|
||||
log_error("Global lock failed: check that global lockspace is started");
|
||||
else if (result == -ELOCKIO)
|
||||
log_error("Global lock failed: storage errors for sanlock leases");
|
||||
else if (result == -EVGKILLED)
|
||||
log_error("Global lock failed: storage failed for sanlock leases");
|
||||
log_error("Global lock failed: check that global lockspace is started.");
|
||||
else
|
||||
log_error("Global lock failed: error %d", result);
|
||||
return 0;
|
||||
@@ -1493,21 +1452,14 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
|
||||
if (result == -ESTARTING) {
|
||||
log_warn("Skipping global lock: lockspace is starting");
|
||||
force_cache_update = 1;
|
||||
goto allow;
|
||||
}
|
||||
|
||||
if (result == -ELOCKIO || result == -EVGKILLED) {
|
||||
log_warn("Skipping global lock: storage %s for sanlock leases",
|
||||
result == -ELOCKIO ? "errors" : "failed");
|
||||
force_cache_update = 1;
|
||||
goto allow;
|
||||
lvmetad_validate_global_cache(cmd, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((lockd_flags & LD_RF_NO_GL_LS) || (lockd_flags & LD_RF_NO_LOCKSPACES)) {
|
||||
log_warn("Skipping global lock: lockspace not found or started");
|
||||
force_cache_update = 1;
|
||||
goto allow;
|
||||
lvmetad_validate_global_cache(cmd, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1523,7 +1475,11 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
log_warn("Duplicate sanlock global locks should be corrected");
|
||||
|
||||
if (result < 0) {
|
||||
if (result == -EAGAIN) {
|
||||
if (ignorelockingfailure()) {
|
||||
log_debug("Ignore failed locking for global lock");
|
||||
lvmetad_validate_global_cache(cmd, 1);
|
||||
return 1;
|
||||
} else if (result == -EAGAIN) {
|
||||
/*
|
||||
* Most of the time, retries should avoid this case.
|
||||
*/
|
||||
@@ -1540,8 +1496,9 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
}
|
||||
}
|
||||
|
||||
allow:
|
||||
lvmetad_validate_global_cache(cmd, force_cache_update);
|
||||
if (!(flags & LDGL_SKIP_CACHE_VALIDATE))
|
||||
lvmetad_validate_global_cache(cmd, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1557,7 +1514,7 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
*
|
||||
* The result of the VG lock operation needs to be saved in lockd_state
|
||||
* because the result needs to be passed into vg_read so it can be
|
||||
* assessed in combination with vg->lock_type.
|
||||
* assessed in combination with vg->lock_state.
|
||||
*
|
||||
* The VG lock protects the VG metadata on disk from concurrent access
|
||||
* among hosts. The VG lock also ensures that the local lvmetad cache
|
||||
@@ -1733,28 +1690,6 @@ int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* sanlock is getting i/o errors while reading/writing leases, or the
|
||||
* lockspace/VG is being killed after failing to renew its lease for
|
||||
* too long.
|
||||
*/
|
||||
if (result == -EVGKILLED || result == -ELOCKIO) {
|
||||
const char *problem = (result == -ELOCKIO ? "errors" : "failed");
|
||||
|
||||
if (!strcmp(mode, "un")) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
} else if (!strcmp(mode, "sh")) {
|
||||
log_warn("VG %s lock skipped: storage %s for sanlock leases", vg_name, problem);
|
||||
ret = 1;
|
||||
goto out;
|
||||
} else {
|
||||
log_error("VG %s lock failed: storage %s for sanlock leases", vg_name, problem);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An unused/previous lockspace for the VG was found.
|
||||
* This means it must be a lockd VG, not local. The
|
||||
@@ -1835,6 +1770,11 @@ out:
|
||||
if ((lockd_flags & LD_RF_DUP_GL_LS) && strcmp(mode, "un"))
|
||||
log_warn("Duplicate sanlock global lock in VG %s", vg_name);
|
||||
|
||||
if (!ret && ignorelockingfailure()) {
|
||||
log_debug("Ignore failed locking for VG %s", vg_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1972,12 +1912,6 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result == -EVGKILLED || result == -ELOCKIO) {
|
||||
const char *problem = (result == -ELOCKIO ? "errors" : "failed");
|
||||
log_error("LV %s/%s lock failed: storage %s for sanlock leases", vg->name, lv_name, problem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
log_error("LV %s/%s lock failed: error %d", vg->name, lv_name, result);
|
||||
return 0;
|
||||
|
@@ -17,7 +17,8 @@
|
||||
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
|
||||
|
||||
/* lockd_gl flags */
|
||||
#define LDGL_UPDATE_NAMES 0x00000001
|
||||
#define LDGL_SKIP_CACHE_VALIDATE 0x00000001
|
||||
#define LDGL_UPDATE_NAMES 0x00000002
|
||||
|
||||
/* lockd_lv flags */
|
||||
#define LDLV_MODE_NO_SH 0x00000001
|
||||
|
@@ -69,7 +69,7 @@ void init_log_file(const char *log_file, int append)
|
||||
static const char statfile[] = "/proc/self/stat";
|
||||
const char *env;
|
||||
int pid;
|
||||
unsigned long long starttime;
|
||||
long long starttime;
|
||||
FILE *st;
|
||||
int i = 0;
|
||||
|
||||
|
@@ -29,17 +29,7 @@
|
||||
#define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
|
||||
#define DM_MAX_HINT_WIDTH (4+16) /* bytes. FIXME Configurable? */
|
||||
|
||||
int cache_mode_is_set(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
return (seg->feature_flags & (DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH)) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *get_cache_mode_name(const struct lv_segment *seg)
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
|
||||
return "writeback";
|
||||
@@ -56,48 +46,19 @@ const char *get_cache_mode_name(const struct lv_segment *seg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cache_set_mode(struct lv_segment *seg, const char *str)
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str)
|
||||
{
|
||||
struct cmd_context *cmd = seg->lv->vg->cmd;
|
||||
int id;
|
||||
uint64_t mode;
|
||||
|
||||
if (!str && !seg_is_cache(seg))
|
||||
return 1; /* Defaults only for cache */
|
||||
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (!str) {
|
||||
if (cache_mode_is_set(seg))
|
||||
return 1; /* Default already set in cache pool */
|
||||
|
||||
id = allocation_cache_mode_CFG;
|
||||
|
||||
/* If present, check backward compatible settings */
|
||||
if (!find_config_node(cmd, cmd->cft, id) &&
|
||||
find_config_node(cmd, cmd->cft, allocation_cache_pool_cachemode_CFG))
|
||||
id = allocation_cache_pool_cachemode_CFG;
|
||||
|
||||
str = find_config_tree_str(cmd, id, NULL);
|
||||
}
|
||||
|
||||
if (!strcmp(str, "writeback"))
|
||||
mode = DM_CACHE_FEATURE_WRITEBACK;
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
else if (!strcmp(str, "writethrough"))
|
||||
mode = DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passthrough"))
|
||||
mode = DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passhrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
else {
|
||||
log_error("Cannot set unknown cache mode \"%s\".", str);
|
||||
log_error("Cache pool feature \"%s\" is unknown.", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->feature_flags &= ~(DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH);
|
||||
seg->feature_flags |= mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -434,72 +395,36 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
|
||||
}
|
||||
|
||||
int cache_set_policy(struct lv_segment *seg, const char *name,
|
||||
const struct dm_config_tree *settings)
|
||||
int lv_cache_set_policy(struct logical_volume *lv, const char *name,
|
||||
const struct dm_config_tree *settings)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
const struct dm_config_node *cns;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
const int passed_seg_is_cache = seg_is_cache(seg);
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
if (passed_seg_is_cache)
|
||||
if (lv_is_cache(lv))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (name) {
|
||||
if (!(seg->policy_name = dm_pool_strdup(seg->lv->vg->vgmem, name))) {
|
||||
log_error("Failed to duplicate policy name.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!seg->policy_name && passed_seg_is_cache)
|
||||
seg->policy_name = find_config_tree_str(seg->lv->vg->cmd, allocation_cache_policy_CFG, NULL);
|
||||
|
||||
if (settings) {
|
||||
if (!seg->policy_name) {
|
||||
log_error(INTERNAL_ERROR "Can't set policy settings without policy name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = settings->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, cn, 0)))
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
} else if (passed_seg_is_cache && /* Look for command's profile cache_policies */
|
||||
(cns = find_config_tree_node(seg->lv->vg->cmd, allocation_cache_settings_CFG_SECTION, NULL))) {
|
||||
/* Try to find our section for given policy */
|
||||
for (cn = cns->child; cn; cn = cn->sib) {
|
||||
/* Only matching section names */
|
||||
if (cn->v || strcmp(cn->key, seg->policy_name) != 0)
|
||||
continue;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = settings->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!cn->child)
|
||||
break;
|
||||
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
|
||||
if (!(new->root = dm_config_clone_node_with_mem(new->mem,
|
||||
cn->child, 1)))
|
||||
goto_out;
|
||||
|
||||
if (!(seg->policy_settings = dm_config_create_node(new, "policy_settings")))
|
||||
goto_out;
|
||||
|
||||
seg->policy_settings->child = new->root;
|
||||
|
||||
break; /* Only first match counts */
|
||||
}
|
||||
if (name && !(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name))) {
|
||||
log_error("Failed to duplicate policy name.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
restart: /* remove any 'default" nodes */
|
||||
|
@@ -131,7 +131,7 @@ char *lvseg_discards_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
|
||||
char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
const char *name = get_cache_mode_name(seg);
|
||||
const char *name = get_cache_pool_cachemode_name(seg);
|
||||
|
||||
if (!name)
|
||||
return_NULL;
|
||||
|
@@ -4205,18 +4205,6 @@ int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lvmlockd LV lock is only acquired here to ensure the LV is not
|
||||
* active on another host. This requests a transient LV lock.
|
||||
* If the LV is active, a persistent LV lock already exists in
|
||||
* lvmlockd, and the transient lock request does nothing.
|
||||
* If the LV is not active, then no LV lock exists and the transient
|
||||
* lock request acquires the LV lock (or fails). The transient lock
|
||||
* is automatically released when the command exits.
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0))
|
||||
return_0;
|
||||
|
||||
if (update_mda && !archive(vg))
|
||||
return_0;
|
||||
|
||||
@@ -6998,7 +6986,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
|
||||
if (seg_is_pool(lp))
|
||||
status |= LVM_WRITE; /* Pool is always writable */
|
||||
else if (seg_is_cache(lp) || seg_is_thin_volume(lp)) {
|
||||
else if (seg_is_cache(lp) || seg_is_thin_volume(lp)) {
|
||||
/* Resolve pool volume */
|
||||
if (!lp->pool_name) {
|
||||
/* Should be already checked */
|
||||
@@ -7074,11 +7062,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
display_lvname(origin_lv));
|
||||
return NULL;
|
||||
}
|
||||
} else if (seg_is_cache(lp)) {
|
||||
if (!pool_lv) {
|
||||
log_error(INTERNAL_ERROR "Pool LV for cache is missing.");
|
||||
return NULL;
|
||||
}
|
||||
} else if (pool_lv && seg_is_cache(lp)) {
|
||||
if (!lv_is_cache_pool(pool_lv)) {
|
||||
log_error("Logical volume %s is not a cache pool.",
|
||||
display_lvname(pool_lv));
|
||||
@@ -7222,7 +7206,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
if (!archive(vg))
|
||||
return_NULL;
|
||||
|
||||
|
||||
if (pool_lv && seg_is_thin_volume(lp)) {
|
||||
/* Ensure all stacked messages are submitted */
|
||||
if ((pool_is_active(pool_lv) || is_change_activating(lp->activate)) &&
|
||||
@@ -7269,25 +7252,16 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
memlock_unlock(vg->cmd);
|
||||
|
||||
if (seg_is_cache_pool(lp) || seg_is_cache(lp)) {
|
||||
if (!cache_set_mode(first_seg(lv), lp->cache_mode)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
pool_lv = pool_lv ? : lv;
|
||||
if (lp->chunk_size) {
|
||||
first_seg(pool_lv)->chunk_size = lp->chunk_size;
|
||||
/* TODO: some calc_policy solution for cache ? */
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
|
||||
THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
if (!lv_cache_set_policy(pool_lv, lp->policy_name, lp->policy_settings))
|
||||
return_NULL; /* revert? */
|
||||
first_seg(pool_lv)->chunk_size = lp->chunk_size;
|
||||
first_seg(pool_lv)->feature_flags = lp->feature_flags;
|
||||
/* TODO: some calc_policy solution for cache ? */
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
|
||||
THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
} else if (seg_is_raid(lp)) {
|
||||
first_seg(lv)->min_recovery_rate = lp->min_recovery_rate;
|
||||
@@ -7492,12 +7466,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
lv = tmp_lv;
|
||||
|
||||
if (!cache_set_mode(first_seg(lv), lp->cache_mode))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
if (!lv_update_and_reload(lv)) {
|
||||
/* FIXME Do a better revert */
|
||||
log_error("Aborting. Manual intervention required.");
|
||||
|
@@ -208,21 +208,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
}
|
||||
|
||||
}
|
||||
if (seg_is_cache_pool(seg) &&
|
||||
!dm_list_empty(&seg->lv->segs_using_this_lv)) {
|
||||
switch (seg->feature_flags &
|
||||
(DM_CACHE_FEATURE_PASSTHROUGH |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_WRITEBACK)) {
|
||||
case DM_CACHE_FEATURE_PASSTHROUGH:
|
||||
case DM_CACHE_FEATURE_WRITETHROUGH:
|
||||
case DM_CACHE_FEATURE_WRITEBACK:
|
||||
break;
|
||||
default:
|
||||
log_error("LV %s has invalid cache's feature flag.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (seg_is_cache_pool(seg)) {
|
||||
if (!seg->policy_name) {
|
||||
log_error("LV %s is missing cache policy name.", lv->name);
|
||||
inc_error_count;
|
||||
|
@@ -901,7 +901,7 @@ struct lvcreate_params {
|
||||
uint32_t min_recovery_rate; /* RAID */
|
||||
uint32_t max_recovery_rate; /* RAID */
|
||||
|
||||
const char *cache_mode; /* cache */
|
||||
uint64_t feature_flags; /* cache */
|
||||
const char *policy_name; /* cache */
|
||||
struct dm_config_tree *policy_settings; /* cache */
|
||||
|
||||
@@ -1153,11 +1153,8 @@ struct lv_status_cache {
|
||||
dm_percent_t dirty_usage;
|
||||
};
|
||||
|
||||
const char *get_cache_mode_name(const struct lv_segment *cache_seg);
|
||||
int cache_mode_is_set(const struct lv_segment *seg);
|
||||
int cache_set_mode(struct lv_segment *cache_seg, const char *str);
|
||||
int cache_set_policy(struct lv_segment *cache_seg, const char *name,
|
||||
const struct dm_config_tree *settings);
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg);
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str);
|
||||
int update_cache_pool_params(const struct segment_type *segtype,
|
||||
struct volume_group *vg, unsigned attr,
|
||||
int passed_args, uint32_t pool_data_extents,
|
||||
@@ -1168,6 +1165,8 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv);
|
||||
struct logical_volume *lv_cache_create(struct logical_volume *pool,
|
||||
struct logical_volume *origin);
|
||||
int lv_cache_remove(struct logical_volume *cache_lv);
|
||||
int lv_cache_set_policy(struct logical_volume *cache_lv, const char *name,
|
||||
const struct dm_config_tree *settings);
|
||||
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
|
||||
/* -- metadata/cache_manip.c */
|
||||
|
||||
|
@@ -191,9 +191,6 @@ int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
int init_cache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
#endif
|
||||
|
||||
#define CACHE_FEATURE_POLICY_MQ (1U << 0)
|
||||
#define CACHE_FEATURE_POLICY_SMQ (1U << 1)
|
||||
|
||||
#define SNAPSHOT_FEATURE_FIXED_LEAK (1U << 0) /* version 1.12 */
|
||||
|
||||
#ifdef SNAPSHOT_INTERNAL
|
||||
|
@@ -516,9 +516,6 @@
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/timerfd.h> header file. */
|
||||
#undef HAVE_SYS_TIMERFD_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
|
@@ -2079,7 +2079,7 @@ static int _cachemode_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (seg_is_cache_pool(seg)) {
|
||||
if (!(cachemode_str = get_cache_mode_name(seg)))
|
||||
if (!(cachemode_str = get_cache_pool_cachemode_name(seg)))
|
||||
return_0;
|
||||
|
||||
return dm_report_field_string(rh, field, &cachemode_str);
|
||||
|
@@ -1,4 +1,16 @@
|
||||
dm_report_add_header_row
|
||||
dm_report_clear
|
||||
dm_report_column_headings
|
||||
dm_report_get_interval
|
||||
dm_report_get_interval_ms
|
||||
dm_report_get_last_interval
|
||||
dm_report_header
|
||||
dm_report_header_set_content
|
||||
dm_report_output_headers
|
||||
dm_report_set_headers
|
||||
dm_report_set_interval
|
||||
dm_report_set_interval_ms
|
||||
dm_report_wait
|
||||
dm_size_to_string
|
||||
dm_stats_bind_devno
|
||||
dm_stats_bind_name
|
||||
@@ -9,6 +21,7 @@ dm_stats_create
|
||||
dm_stats_create_region
|
||||
dm_stats_delete_region
|
||||
dm_stats_destroy
|
||||
dm_stats_get_area_len
|
||||
dm_stats_get_area_start
|
||||
dm_stats_get_average_queue_size
|
||||
dm_stats_get_average_rd_wait_time
|
||||
@@ -18,17 +31,16 @@ dm_stats_get_average_wr_wait_time
|
||||
dm_stats_get_current_area
|
||||
dm_stats_get_current_area_len
|
||||
dm_stats_get_current_area_start
|
||||
dm_stats_get_current_nr_areas
|
||||
dm_stats_get_current_region
|
||||
dm_stats_get_current_region_area_len
|
||||
dm_stats_get_current_region_aux_data
|
||||
dm_stats_get_current_region_len
|
||||
dm_stats_get_current_region_program_id
|
||||
dm_stats_get_current_region_start
|
||||
dm_stats_get_interval
|
||||
dm_stats_get_interval_ms
|
||||
dm_stats_get_io_in_progress
|
||||
dm_stats_get_io_nsecs
|
||||
dm_stats_get_nr_areas
|
||||
dm_stats_get_nr_regions
|
||||
dm_stats_get_rd_merges_per_sec
|
||||
dm_stats_get_read_nsecs
|
||||
dm_stats_get_reads
|
||||
@@ -39,11 +51,8 @@ dm_stats_get_reads_per_sec
|
||||
dm_stats_get_region_area_len
|
||||
dm_stats_get_region_aux_data
|
||||
dm_stats_get_region_len
|
||||
dm_stats_get_region_nr_areas
|
||||
dm_stats_get_region_program_id
|
||||
dm_stats_get_region_start
|
||||
dm_stats_get_sampling_interval_ms
|
||||
dm_stats_get_sampling_interval_ns
|
||||
dm_stats_get_service_time
|
||||
dm_stats_get_throughput
|
||||
dm_stats_get_total_read_nsecs
|
||||
@@ -57,22 +66,25 @@ dm_stats_get_write_sectors_per_sec
|
||||
dm_stats_get_writes_merged
|
||||
dm_stats_get_writes_per_sec
|
||||
dm_stats_get_wr_merges_per_sec
|
||||
dm_stats_init
|
||||
dm_stats_list
|
||||
dm_stats_nr_areas
|
||||
dm_stats_nr_areas_current
|
||||
dm_stats_nr_areas_region
|
||||
dm_stats_nr_regions
|
||||
dm_stats_populate
|
||||
dm_stats_populate_region
|
||||
dm_stats_print_region
|
||||
dm_stats_region_present
|
||||
dm_stats_set_interval
|
||||
dm_stats_set_interval_ms
|
||||
dm_stats_set_program_id
|
||||
dm_stats_set_sampling_interval_ms
|
||||
dm_stats_set_sampling_interval_ns
|
||||
dm_stats_walk_end
|
||||
dm_stats_walk_next
|
||||
dm_stats_walk_next_region
|
||||
dm_stats_walk_start
|
||||
dm_task_get_ioctl_timestamp
|
||||
dm_task_set_record_timestamp
|
||||
dm_timestamp_alloc
|
||||
dm_timestamp_compare
|
||||
dm_timestamp_copy
|
||||
dm_timestamp_delta
|
||||
dm_timestamp_destroy
|
||||
dm_timestamp_get
|
||||
|
@@ -68,7 +68,6 @@ static unsigned _dm_version = DM_VERSION_MAJOR;
|
||||
static unsigned _dm_version_minor = 0;
|
||||
static unsigned _dm_version_patchlevel = 0;
|
||||
static int _log_suppress = 0;
|
||||
static struct dm_timestamp *_dm_ioctl_timestamp = NULL;
|
||||
|
||||
/*
|
||||
* If the kernel dm driver only supports one major number
|
||||
@@ -920,24 +919,6 @@ int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_record_timestamp(struct dm_task *dmt)
|
||||
{
|
||||
if (!_dm_ioctl_timestamp)
|
||||
_dm_ioctl_timestamp = dm_timestamp_alloc();
|
||||
|
||||
if (!_dm_ioctl_timestamp)
|
||||
return_0;
|
||||
|
||||
dmt->record_timestamp = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_timestamp *dm_task_get_ioctl_timestamp(struct dm_task *dmt)
|
||||
{
|
||||
return dmt->record_timestamp ? _dm_ioctl_timestamp : NULL;
|
||||
}
|
||||
|
||||
struct target *create_target(uint64_t start, uint64_t len, const char *type,
|
||||
const char *params)
|
||||
{
|
||||
@@ -1735,7 +1716,6 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
{
|
||||
struct dm_ioctl *dmi;
|
||||
int ioctl_with_uevent;
|
||||
int r;
|
||||
|
||||
dmt->ioctl_errno = 0;
|
||||
|
||||
@@ -1823,13 +1803,8 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmt->sector, _sanitise_message(dmt->message),
|
||||
dmi->data_size, retry_repeat_count);
|
||||
#ifdef DM_IOCTLS
|
||||
r = ioctl(_control_fd, command, dmi);
|
||||
|
||||
if (dmt->record_timestamp)
|
||||
if (!dm_timestamp_get(_dm_ioctl_timestamp))
|
||||
stack;
|
||||
|
||||
if (r < 0 && dmt->expected_errno != errno) {
|
||||
if (ioctl(_control_fd, command, dmi) < 0 &&
|
||||
dmt->expected_errno != errno) {
|
||||
dmt->ioctl_errno = errno;
|
||||
if (dmt->ioctl_errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
|
||||
(dmt->type == DM_DEVICE_MKNODES) ||
|
||||
@@ -2074,8 +2049,6 @@ repeat_ioctl:
|
||||
void dm_lib_release(void)
|
||||
{
|
||||
_close_control_fd();
|
||||
dm_timestamp_destroy(_dm_ioctl_timestamp);
|
||||
_dm_ioctl_timestamp = NULL;
|
||||
update_devs();
|
||||
}
|
||||
|
||||
|
@@ -70,8 +70,6 @@ struct dm_task {
|
||||
int expected_errno;
|
||||
int ioctl_errno;
|
||||
|
||||
int record_timestamp;
|
||||
|
||||
char *uuid;
|
||||
char *mangled_uuid;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -277,7 +277,6 @@ struct dm_task *dm_task_create(int type)
|
||||
dmt->query_inactive_table = 0;
|
||||
dmt->new_uuid = 0;
|
||||
dmt->secure_data = 0;
|
||||
dmt->record_timestamp = 0;
|
||||
|
||||
return dmt;
|
||||
}
|
||||
|
@@ -159,7 +159,7 @@ struct load_segment {
|
||||
uint32_t stripe_size; /* Striped + raid */
|
||||
|
||||
int persistent; /* Snapshot */
|
||||
uint32_t chunk_size; /* Snapshot */
|
||||
uint32_t chunk_size; /* Snapshot + cache */
|
||||
struct dm_tree_node *cow; /* Snapshot */
|
||||
struct dm_tree_node *origin; /* Snapshot + Snapshot origin + Cache */
|
||||
struct dm_tree_node *merge; /* Snapshot */
|
||||
@@ -200,7 +200,7 @@ struct load_segment {
|
||||
struct dm_list thin_messages; /* Thin_pool */
|
||||
uint64_t transaction_id; /* Thin_pool */
|
||||
uint64_t low_water_mark; /* Thin_pool */
|
||||
uint32_t data_block_size; /* Thin_pool + cache */
|
||||
uint32_t data_block_size; /* Thin_pool */
|
||||
unsigned skip_block_zeroing; /* Thin_pool */
|
||||
unsigned ignore_discard; /* Thin_pool target vsn 1.1 */
|
||||
unsigned no_discard_passdown; /* Thin_pool target vsn 1.1 */
|
||||
@@ -2429,8 +2429,8 @@ static int _cache_emit_segment_line(struct dm_task *dmt,
|
||||
|
||||
EMIT_PARAMS(pos, " %s %s %s", metadata, data, origin);
|
||||
|
||||
/* Data block size */
|
||||
EMIT_PARAMS(pos, " %u", seg->data_block_size);
|
||||
/* Chunk size */
|
||||
EMIT_PARAMS(pos, " %u", seg->chunk_size);
|
||||
|
||||
/* Features */
|
||||
/* feature_count = hweight32(seg->flags); */
|
||||
@@ -3353,37 +3353,11 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
const char *origin_uuid,
|
||||
const char *policy_name,
|
||||
const struct dm_config_node *policy_settings,
|
||||
uint32_t data_block_size)
|
||||
uint32_t chunk_size)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
struct load_segment *seg;
|
||||
|
||||
switch (feature_flags &
|
||||
(DM_CACHE_FEATURE_PASSTHROUGH |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_WRITEBACK)) {
|
||||
case DM_CACHE_FEATURE_PASSTHROUGH:
|
||||
case DM_CACHE_FEATURE_WRITETHROUGH:
|
||||
case DM_CACHE_FEATURE_WRITEBACK:
|
||||
break;
|
||||
default:
|
||||
log_error("Invalid cache's feature flag " FMTu64 ".",
|
||||
feature_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_block_size < DM_CACHE_MIN_DATA_BLOCK_SIZE) {
|
||||
log_error("Data block size %u is lower then %u sectors.",
|
||||
data_block_size, DM_CACHE_MIN_DATA_BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data_block_size > DM_CACHE_MAX_DATA_BLOCK_SIZE) {
|
||||
log_error("Data block size %u is higher then %u sectors.",
|
||||
data_block_size, DM_CACHE_MAX_DATA_BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = _add_segment(node, SEG_CACHE, size)))
|
||||
return_0;
|
||||
|
||||
@@ -3405,6 +3379,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
if (!_link_tree_nodes(node, seg->metadata))
|
||||
return_0;
|
||||
|
||||
|
||||
if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree,
|
||||
origin_uuid))) {
|
||||
log_error("Missing cache's origin uuid %s.",
|
||||
@@ -3414,7 +3389,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
if (!_link_tree_nodes(node, seg->origin))
|
||||
return_0;
|
||||
|
||||
seg->data_block_size = data_block_size;
|
||||
seg->chunk_size = chunk_size;
|
||||
seg->flags = feature_flags;
|
||||
seg->policy_name = policy_name;
|
||||
|
||||
@@ -3433,6 +3408,7 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -48,18 +48,30 @@ struct dm_report {
|
||||
const char *field_prefix;
|
||||
uint32_t flags;
|
||||
const char *separator;
|
||||
/* reporting interval in ms */
|
||||
uint32_t interval;
|
||||
/* duration of last wait in ns */
|
||||
uint64_t last_wait;
|
||||
|
||||
uint32_t keys_count;
|
||||
|
||||
/* Ordered list of headers to be output before the report. */
|
||||
struct dm_list header_props;
|
||||
|
||||
/* Rows of headers */
|
||||
struct dm_list header_rows;
|
||||
|
||||
/* Ordered list of fields needed for this report */
|
||||
struct dm_list field_props;
|
||||
|
||||
/* Rows of report data */
|
||||
struct dm_list rows;
|
||||
|
||||
/* Array of header definitions */
|
||||
const struct dm_report_header_type *headers;
|
||||
|
||||
/* Array of field definitions */
|
||||
const struct dm_report_field_type *fields;
|
||||
const char **canonical_field_ids;
|
||||
const struct dm_report_object_type *types;
|
||||
|
||||
/* To store caller private data */
|
||||
@@ -92,6 +104,14 @@ struct field_properties {
|
||||
int implicit;
|
||||
};
|
||||
|
||||
struct header_properties {
|
||||
struct dm_list list;
|
||||
uint32_t hdr_num;
|
||||
int32_t width;
|
||||
const struct dm_report_object_type *type;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Report selection
|
||||
*/
|
||||
@@ -158,18 +178,18 @@ static struct op_def _op_cmp[] = {
|
||||
#define SEL_LIST_SUBSET_LE 0x00080000
|
||||
|
||||
static struct op_def _op_log[] = {
|
||||
{ "&&", SEL_AND, "All fields must match" },
|
||||
{ "&&", SEL_AND, "All fields must match" },
|
||||
{ ",", SEL_AND, "All fields must match" },
|
||||
{ "||", SEL_OR, "At least one field must match" },
|
||||
{ "||", SEL_OR, "At least one field must match" },
|
||||
{ "#", SEL_OR, "At least one field must match" },
|
||||
{ "!", SEL_MODIFIER_NOT, "Logical negation" },
|
||||
{ "(", SEL_PRECEDENCE_PS, "Left parenthesis" },
|
||||
{ ")", SEL_PRECEDENCE_PE, "Right parenthesis" },
|
||||
{ "[", SEL_LIST_LS, "List start" },
|
||||
{ "]", SEL_LIST_LE, "List end"},
|
||||
{ "{", SEL_LIST_SUBSET_LS, "List subset start"},
|
||||
{ "}", SEL_LIST_SUBSET_LE, "List subset end"},
|
||||
{ NULL, 0, NULL},
|
||||
{ "!", SEL_MODIFIER_NOT, "Logical negation" },
|
||||
{ "(", SEL_PRECEDENCE_PS, "Left parenthesis" },
|
||||
{ ")", SEL_PRECEDENCE_PE, "Right parenthesis" },
|
||||
{ "[", SEL_LIST_LS, "List start" },
|
||||
{ "]", SEL_LIST_LE, "List end"},
|
||||
{ "{", SEL_LIST_SUBSET_LS, "List subset start"},
|
||||
{ "}", SEL_LIST_SUBSET_LE, "List subset end"},
|
||||
{ NULL, 0, NULL},
|
||||
};
|
||||
|
||||
struct selection_str_list {
|
||||
@@ -229,6 +249,18 @@ struct row {
|
||||
int selected;
|
||||
};
|
||||
|
||||
struct dm_report_header {
|
||||
struct dm_list list;
|
||||
struct header_properties *props;
|
||||
const char *header_string;
|
||||
};
|
||||
|
||||
struct header_row {
|
||||
struct dm_list list;
|
||||
struct dm_report *rh;
|
||||
struct dm_list headers;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implicit report types and fields.
|
||||
*/
|
||||
@@ -671,6 +703,11 @@ void dm_report_field_set_value(struct dm_report_field *field, const void *value,
|
||||
log_warn(INTERNAL_ERROR "Using string as sort value for numerical field.");
|
||||
}
|
||||
|
||||
void dm_report_header_set_content(struct dm_report_header *hdr, const void *content)
|
||||
{
|
||||
hdr->header_string = (const char *) content;
|
||||
}
|
||||
|
||||
static const char *_get_field_type_name(unsigned field_type)
|
||||
{
|
||||
switch (field_type) {
|
||||
@@ -699,6 +736,18 @@ static size_t _get_longest_field_id_len(const struct dm_report_field_type *field
|
||||
return id_len;
|
||||
}
|
||||
|
||||
static size_t _get_longest_header_id_len(const struct dm_report_header_type *headers)
|
||||
{
|
||||
uint32_t f;
|
||||
size_t id_len = 0;
|
||||
|
||||
for (f = 0; headers[f].report_fn; f++)
|
||||
if (strlen(headers[f].id) > id_len)
|
||||
id_len = strlen(headers[f].id);
|
||||
|
||||
return id_len;
|
||||
}
|
||||
|
||||
static void _display_fields_more(struct dm_report *rh,
|
||||
const struct dm_report_field_type *fields,
|
||||
size_t id_len, int display_all_fields_item,
|
||||
@@ -743,6 +792,45 @@ static void _display_fields_more(struct dm_report *rh,
|
||||
}
|
||||
}
|
||||
|
||||
static void _display_headers_more(struct dm_report *rh,
|
||||
const struct dm_report_header_type *headers,
|
||||
size_t id_len, int display_all_headers_item)
|
||||
{
|
||||
uint32_t h;
|
||||
const struct dm_report_object_type *type;
|
||||
const char *desc, *last_desc = "";
|
||||
|
||||
for (h = 0; headers[h].report_fn; h++)
|
||||
if (strlen(headers[h].id) > id_len)
|
||||
id_len = strlen(headers[h].id);
|
||||
|
||||
for (type = rh->types; type->data_fn; type++)
|
||||
if (strlen(type->prefix) + 3 > id_len)
|
||||
id_len = strlen(type->prefix) + 3;
|
||||
|
||||
for (h = 0; headers[h].report_fn; h++) {
|
||||
if ((type = _find_type(rh, headers[h].type)) && type->desc)
|
||||
desc = type->desc;
|
||||
else
|
||||
desc = " ";
|
||||
if (desc != last_desc) {
|
||||
if (*last_desc)
|
||||
log_warn(" ");
|
||||
log_warn("%s Fields", desc);
|
||||
log_warn("%*.*s", (int) strlen(desc) + 7,
|
||||
(int) strlen(desc) + 7,
|
||||
"-------------------------------------------------------------------------------");
|
||||
if (display_all_headers_item && type->id != SPECIAL_REPORT_TYPE)
|
||||
log_warn(" %sall%-*s - %s", type->prefix,
|
||||
(int) (id_len - 3 - strlen(type->prefix)), "",
|
||||
"All headers in this section.");
|
||||
}
|
||||
/* FIXME Add line-wrapping at terminal width (or 80 cols) */
|
||||
log_warn(" %-*s - %s", (int) id_len, headers[h].id, headers[h].desc);
|
||||
last_desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* show help message
|
||||
*/
|
||||
@@ -764,6 +852,20 @@ static void _display_fields(struct dm_report *rh, int display_all_fields_item,
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* show help message
|
||||
*/
|
||||
static void _display_headers(struct dm_report *rh, int display_all_headers_item,
|
||||
int display_header_types)
|
||||
{
|
||||
size_t tmp, id_len = 0;
|
||||
|
||||
if ((tmp = _get_longest_header_id_len(rh->headers)) > id_len)
|
||||
id_len = tmp;
|
||||
|
||||
_display_headers_more(rh, rh->headers, id_len, display_all_headers_item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise report handle
|
||||
*/
|
||||
@@ -821,52 +923,68 @@ static struct field_properties * _add_field(struct dm_report *rh,
|
||||
return fp;
|
||||
}
|
||||
|
||||
static int _get_canonical_field_name(const char *field,
|
||||
size_t flen,
|
||||
char *canonical_field,
|
||||
size_t fcanonical_len,
|
||||
int *differs)
|
||||
static int _copy_header(struct dm_report *rh, struct header_properties *dest,
|
||||
uint32_t hdr_num)
|
||||
{
|
||||
size_t i;
|
||||
int diff = 0;
|
||||
const struct dm_report_header_type *headers = rh->headers;
|
||||
|
||||
for (i = 0; *field && flen; field++, flen--) {
|
||||
if (*field == '_') {
|
||||
diff = 1;
|
||||
continue;
|
||||
}
|
||||
if (i >= fcanonical_len) {
|
||||
log_error("%s: field name too long", field);
|
||||
return 0;
|
||||
}
|
||||
canonical_field[i++] = *field;
|
||||
dest->hdr_num = hdr_num;
|
||||
dest->width = headers[hdr_num].width;
|
||||
dest->flags = headers[hdr_num].flags & DM_REPORT_FIELD_MASK;
|
||||
|
||||
/* set object type method */
|
||||
dest->type = _find_type(rh, headers[hdr_num].type);
|
||||
if (!dest->type) {
|
||||
log_error("dm_report: no matching header: %s",
|
||||
headers[hdr_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
canonical_field[i] = '\0';
|
||||
if (differs)
|
||||
*differs = diff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct header_properties * _add_header(struct dm_report *rh,
|
||||
uint32_t hdr_num, uint32_t flags)
|
||||
{
|
||||
struct header_properties *hp;
|
||||
|
||||
if (!(hp = dm_pool_zalloc(rh->mem, sizeof(*hp)))) {
|
||||
log_error("dm_report: struct header_properties allocation "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_copy_header(rh, hp, hdr_num)) {
|
||||
stack;
|
||||
dm_pool_free(rh->mem, hp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hp->flags |= flags;
|
||||
dm_list_add(&rh->header_props, &hp->list);
|
||||
|
||||
return hp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare canonical_name1 against canonical_name2 or prefix
|
||||
* plus canonical_name2. Canonical name is a name where all
|
||||
* superfluous characters are removed (underscores for now).
|
||||
* Both names are always null-terminated.
|
||||
* Compare name1 against name2 or prefix plus name2
|
||||
* name2 is not necessarily null-terminated.
|
||||
* len2 is the length of name2.
|
||||
*/
|
||||
static int _is_same_field(const char *canonical_name1, const char *canonical_name2,
|
||||
const char *prefix)
|
||||
static int _is_same_name(const char *name1, const char *name2,
|
||||
size_t len2, const char *prefix)
|
||||
{
|
||||
size_t prefix_len;
|
||||
|
||||
/* Exact match? */
|
||||
if (!strcasecmp(canonical_name1, canonical_name2))
|
||||
if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
|
||||
return 1;
|
||||
|
||||
/* Match including prefix? */
|
||||
prefix_len = strlen(prefix) - 1;
|
||||
if (!strncasecmp(prefix, canonical_name1, prefix_len) &&
|
||||
!strcasecmp(canonical_name1 + prefix_len, canonical_name2))
|
||||
prefix_len = strlen(prefix);
|
||||
if (!strncasecmp(prefix, name1, prefix_len) &&
|
||||
!strncasecmp(name1 + prefix_len, name2, len2) &&
|
||||
strlen(name1) == prefix_len + len2)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -880,20 +998,15 @@ static void _all_match_combine(const struct dm_report_object_type *types,
|
||||
const char *field, size_t flen,
|
||||
uint32_t *report_types)
|
||||
{
|
||||
char field_canon[DM_REPORT_FIELD_TYPE_ID_LEN];
|
||||
const struct dm_report_object_type *t;
|
||||
size_t prefix_len;
|
||||
|
||||
if (!_get_canonical_field_name(field, flen, field_canon, DM_REPORT_FIELD_TYPE_ID_LEN, NULL))
|
||||
return;
|
||||
flen = strlen(field_canon);
|
||||
|
||||
for (t = types; t->data_fn; t++) {
|
||||
prefix_len = strlen(t->prefix) - 1;
|
||||
prefix_len = strlen(t->prefix);
|
||||
|
||||
if (!strncasecmp(t->prefix, field_canon, prefix_len) &&
|
||||
if (!strncasecmp(t->prefix, field, prefix_len) &&
|
||||
((unprefixed_all_matched && (flen == prefix_len)) ||
|
||||
(!strncasecmp(field_canon + prefix_len, "all", 3) &&
|
||||
(!strncasecmp(field + prefix_len, "all", 3) &&
|
||||
(flen == prefix_len + 3))))
|
||||
*report_types |= t->id;
|
||||
}
|
||||
@@ -938,17 +1051,13 @@ static int _add_all_fields(struct dm_report *rh, uint32_t type)
|
||||
static int _get_field(struct dm_report *rh, const char *field, size_t flen,
|
||||
uint32_t *f_ret, int *implicit)
|
||||
{
|
||||
char field_canon[DM_REPORT_FIELD_TYPE_ID_LEN];
|
||||
uint32_t f;
|
||||
|
||||
if (!flen)
|
||||
return 0;
|
||||
|
||||
if (!_get_canonical_field_name(field, flen, field_canon, DM_REPORT_FIELD_TYPE_ID_LEN, NULL))
|
||||
return 0;
|
||||
|
||||
for (f = 0; _implicit_report_fields[f].report_fn; f++) {
|
||||
if (_is_same_field(_implicit_report_fields[f].id, field_canon, rh->field_prefix)) {
|
||||
if (_is_same_name(_implicit_report_fields[f].id, field, flen, rh->field_prefix)) {
|
||||
*f_ret = f;
|
||||
*implicit = 1;
|
||||
return 1;
|
||||
@@ -956,7 +1065,7 @@ static int _get_field(struct dm_report *rh, const char *field, size_t flen,
|
||||
}
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if (_is_same_field(rh->canonical_field_ids[f], field_canon, rh->field_prefix)) {
|
||||
if (_is_same_name(rh->fields[f].id, field, flen, rh->field_prefix)) {
|
||||
*f_ret = f;
|
||||
*implicit = 0;
|
||||
return 1;
|
||||
@@ -995,6 +1104,51 @@ static int _field_match(struct dm_report *rh, const char *field, size_t flen,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add all headers with a matching type.
|
||||
*/
|
||||
static int _add_all_headers(struct dm_report *rh, uint32_t type)
|
||||
{
|
||||
uint32_t h;
|
||||
|
||||
for (h = 0; rh->headers[h].report_fn; h++)
|
||||
if ((rh->headers[h].type & type) && !_add_header(rh, h, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_header(struct dm_report *rh, const char *header,
|
||||
size_t hlen, uint32_t *h_ret)
|
||||
{
|
||||
uint32_t h;
|
||||
|
||||
if (!hlen)
|
||||
return 0;
|
||||
|
||||
for (h = 0; rh->headers[h].report_fn; h++) {
|
||||
if (_is_same_name(rh->headers[h].id, header, hlen, "")) {
|
||||
*h_ret = h;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _header_match(struct dm_report *rh, const char *header, size_t hlen)
|
||||
{
|
||||
uint32_t h /*, type*/;
|
||||
|
||||
if (!hlen)
|
||||
return 0;
|
||||
|
||||
if ((_get_header(rh, header, hlen, &h)))
|
||||
return _add_header(rh, h, 0) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _add_sort_key(struct dm_report *rh, uint32_t field_num, int implicit,
|
||||
uint32_t flags, unsigned report_type_only)
|
||||
{
|
||||
@@ -1035,7 +1189,6 @@ static int _add_sort_key(struct dm_report *rh, uint32_t field_num, int implicit,
|
||||
static int _key_match(struct dm_report *rh, const char *key, size_t len,
|
||||
unsigned report_type_only)
|
||||
{
|
||||
char key_canon[DM_REPORT_FIELD_TYPE_ID_LEN];
|
||||
uint32_t f;
|
||||
uint32_t flags;
|
||||
|
||||
@@ -1058,15 +1211,12 @@ static int _key_match(struct dm_report *rh, const char *key, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_get_canonical_field_name(key, len, key_canon, DM_REPORT_FIELD_TYPE_ID_LEN, NULL))
|
||||
return 0;
|
||||
|
||||
for (f = 0; _implicit_report_fields[f].report_fn; f++)
|
||||
if (_is_same_field(_implicit_report_fields[f].id, key_canon, rh->field_prefix))
|
||||
if (_is_same_name(_implicit_report_fields[f].id, key, len, rh->field_prefix))
|
||||
return _add_sort_key(rh, f, 1, flags, report_type_only);
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (_is_same_field(rh->canonical_field_ids[f], key_canon, rh->field_prefix))
|
||||
if (_is_same_name(rh->fields[f].id, key, len, rh->field_prefix))
|
||||
return _add_sort_key(rh, f, 0, flags, report_type_only);
|
||||
|
||||
return 0;
|
||||
@@ -1126,6 +1276,32 @@ static int _parse_keys(struct dm_report *rh, const char *keys,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_headers(struct dm_report *rh, const char *format)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = format; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
|
||||
/* start of the header name */
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
|
||||
if (!_header_match(rh, ws, (size_t) (we - ws))) {
|
||||
_display_headers(rh, 1, 0);
|
||||
log_warn(" ");
|
||||
log_error("Unrecognised header: %.*s", (int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _contains_reserved_report_type(const struct dm_report_object_type *types)
|
||||
{
|
||||
const struct dm_report_object_type *type, *implicit_type;
|
||||
@@ -1174,36 +1350,6 @@ static int _help_requested(struct dm_report *rh)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _canonicalize_field_ids(struct dm_report *rh)
|
||||
{
|
||||
size_t registered_field_count = 0, i;
|
||||
char canonical_field[DM_REPORT_FIELD_TYPE_ID_LEN];
|
||||
char *canonical_field_dup;
|
||||
int differs;
|
||||
|
||||
while (*rh->fields[registered_field_count].id)
|
||||
registered_field_count++;
|
||||
|
||||
if (!(rh->canonical_field_ids = dm_pool_alloc(rh->mem, registered_field_count * sizeof(const char *)))) {
|
||||
log_error("_canonicalize_field_ids: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < registered_field_count; i++) {
|
||||
if (!_get_canonical_field_name(rh->fields[i].id, strlen(rh->fields[i].id),
|
||||
canonical_field, DM_REPORT_FIELD_TYPE_ID_LEN, &differs))
|
||||
return_0;
|
||||
|
||||
if (differs) {
|
||||
canonical_field_dup = dm_pool_strdup(rh->mem, canonical_field);
|
||||
rh->canonical_field_ids[i] = canonical_field_dup;
|
||||
} else
|
||||
rh->canonical_field_ids[i] = rh->fields[i].id;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
@@ -1236,6 +1382,7 @@ struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
rh->fields = fields;
|
||||
rh->types = types;
|
||||
rh->private = private_data;
|
||||
rh->interval = 0; /* no interval */
|
||||
|
||||
rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
|
||||
|
||||
@@ -1251,6 +1398,8 @@ struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
rh->flags |= RH_SORT_REQUIRED;
|
||||
|
||||
dm_list_init(&rh->field_props);
|
||||
dm_list_init(&rh->header_props);
|
||||
dm_list_init(&rh->header_rows);
|
||||
dm_list_init(&rh->rows);
|
||||
|
||||
if ((type = _find_type(rh, rh->report_types)) && type->prefix)
|
||||
@@ -1264,11 +1413,6 @@ struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_canonicalize_field_ids(rh)) {
|
||||
dm_report_free(rh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* To keep the code needed to add the "all" field to a minimum, we parse
|
||||
* the field lists twice. The first time we only update the report type.
|
||||
@@ -1322,6 +1466,21 @@ static char *_toupperstr(char *str)
|
||||
return str;
|
||||
}
|
||||
|
||||
int dm_report_set_headers(struct dm_report *rh,
|
||||
const struct dm_report_header_type *headers)
|
||||
{
|
||||
if (headers)
|
||||
rh->headers = headers;
|
||||
else
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_add_header_row(struct dm_report *rh, const char *output_headers)
|
||||
{
|
||||
return _parse_headers(rh, output_headers);
|
||||
}
|
||||
|
||||
int dm_report_set_output_field_name_prefix(struct dm_report *rh, const char *output_field_name_prefix)
|
||||
{
|
||||
char *prefix;
|
||||
@@ -1362,6 +1521,21 @@ static void *_report_get_implicit_field_data(struct dm_report *rh __attribute__(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create part of a line of header data
|
||||
*/
|
||||
static void *_report_get_header_data(struct dm_report *rh, struct
|
||||
header_properties *hp, void *object)
|
||||
{
|
||||
const struct dm_report_header_type *headers = rh->headers;
|
||||
char *ret = hp->type->data_fn(object);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
return (void *)(ret + headers[hp->hdr_num].offset);
|
||||
}
|
||||
|
||||
static int _dbl_equal(double d1, double d2)
|
||||
{
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
@@ -2052,6 +2226,82 @@ int dm_report_object_is_selected(struct dm_report *rh, void *object, int do_outp
|
||||
return _do_report_object(rh, object, do_output, selected);
|
||||
}
|
||||
|
||||
int dm_report_header(struct dm_report *rh, void *object)
|
||||
{
|
||||
const struct dm_report_header_type *headers;
|
||||
struct header_properties *hp;
|
||||
struct header_row *row = NULL;
|
||||
struct dm_report_header *header;
|
||||
void *data = NULL;
|
||||
int len;
|
||||
int r = 0;
|
||||
|
||||
if (!rh) {
|
||||
log_error(INTERNAL_ERROR "dm_report_header: dm_report handler is NULL.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rh->flags & RH_ALREADY_REPORTED)
|
||||
return 1;
|
||||
|
||||
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
|
||||
log_error("dm_report_header: struct header_row allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
row->rh = rh;
|
||||
headers = rh->headers;
|
||||
dm_list_init(&row->headers);
|
||||
|
||||
/* For each field to be displayed, call its report_fn */
|
||||
dm_list_iterate_items(hp, &rh->header_props) {
|
||||
if (!(header = dm_pool_zalloc(rh->mem, sizeof(*header)))) {
|
||||
log_error("do_report_header: "
|
||||
"struct dm_report_header allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
header->props = hp;
|
||||
|
||||
data = _report_get_header_data(rh, hp, object);
|
||||
if (!data) {
|
||||
log_error("do_report_header:"
|
||||
"no data assigned to header %s",
|
||||
headers[hp->hdr_num].id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!headers[hp->hdr_num].report_fn(rh, rh->mem,
|
||||
header, data,
|
||||
rh->private)) {
|
||||
log_error("do_report_header:"
|
||||
"report function failed for header %s",
|
||||
headers[hp->hdr_num].id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dm_list_add(&row->headers, &header->list);
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
dm_list_add(&rh->header_rows, &row->list);
|
||||
|
||||
dm_list_iterate_items(header, &row->headers) {
|
||||
len = (int) strlen(header->header_string);
|
||||
if ((len > header->props->width))
|
||||
header->props->width = len;
|
||||
}
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
|
||||
return dm_report_output_headers(rh);
|
||||
|
||||
out:
|
||||
if (!r)
|
||||
dm_pool_free(rh->mem, row);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Selection parsing
|
||||
*/
|
||||
@@ -3994,9 +4244,6 @@ static int _report_headings(struct dm_report *rh)
|
||||
|
||||
int dm_report_column_headings(struct dm_report *rh)
|
||||
{
|
||||
/* Columns-as-rows does not use _report_headings. */
|
||||
if (rh->flags & DM_REPORT_OUTPUT_COLUMNS_AS_ROWS)
|
||||
return 1;
|
||||
return _report_headings(rh);
|
||||
}
|
||||
|
||||
@@ -4178,13 +4425,80 @@ bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce header output
|
||||
*/
|
||||
static int _output_header(struct dm_report *rh, struct dm_report_header *header)
|
||||
{
|
||||
int32_t width, labelwidth;
|
||||
uint32_t align;
|
||||
const char *hdrstr, *labelstr;
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
|
||||
if (rh->flags & DM_REPORT_OUTPUT_HEADER_LABELS)
|
||||
labelstr = rh->headers[header->props->hdr_num].label;
|
||||
else
|
||||
labelstr = "";
|
||||
|
||||
labelwidth = strlen(labelstr) + 1;
|
||||
hdrstr = header->header_string;
|
||||
width = header->props->width - labelwidth;
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
|
||||
if (!dm_pool_grow_object(rh->mem, hdrstr, 0)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!(align = header->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
|
||||
align = ((header->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
|
||||
(header->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
|
||||
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
|
||||
|
||||
/* Including trailing '\0'! */
|
||||
buf_size = labelwidth + width + 1;
|
||||
if (!(buf = dm_malloc(buf_size))) {
|
||||
log_error("dm_report: Could not allocate memory for output line buffer.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
|
||||
if (dm_snprintf(buf, buf_size, "%-*.*s%-*.*s",
|
||||
/* FIXME: handle label width better */
|
||||
labelwidth, labelwidth, labelstr, width, width, hdrstr) < 0) {
|
||||
log_error("dm_report: left-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, labelwidth + width)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
|
||||
if (dm_snprintf(buf, buf_size, "%*.*s%*.*s",
|
||||
/* FIXME: handle label width better */
|
||||
labelwidth, labelwidth, labelstr, width, width, hdrstr) < 0) {
|
||||
log_error("dm_report: right-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, labelwidth + width)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dm_free(buf);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _destroy_rows(struct dm_report *rh)
|
||||
{
|
||||
/*
|
||||
* free the first row allocated to this report: since this is a
|
||||
* pool allocation this will also free all subsequently allocated
|
||||
* rows from the report and any associated string data.
|
||||
*/
|
||||
/* free the first row allocated to this report */
|
||||
if(rh->first_row)
|
||||
dm_pool_free(rh->mem, rh->first_row);
|
||||
rh->first_row = NULL;
|
||||
@@ -4305,6 +4619,27 @@ static int _output_as_columns(struct dm_report *rh)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_report_clear(struct dm_report *rh)
|
||||
{
|
||||
struct dm_list *fh, *rowh, *ftmp, *rtmp;
|
||||
struct row *row = NULL;
|
||||
struct dm_report_field *field;
|
||||
|
||||
/* clear buffer */
|
||||
dm_list_iterate_safe(rowh, rtmp, &rh->rows) {
|
||||
row = dm_list_item(rowh, struct row);
|
||||
dm_list_iterate_safe(fh, ftmp, &row->fields) {
|
||||
field = dm_list_item(fh, struct dm_report_field);
|
||||
dm_list_del(&field->list);
|
||||
}
|
||||
dm_list_del(&row->list);
|
||||
}
|
||||
|
||||
_destroy_rows(rh);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_output(struct dm_report *rh)
|
||||
{
|
||||
if (dm_list_empty(&rh->rows))
|
||||
@@ -4318,3 +4653,128 @@ int dm_report_output(struct dm_report *rh)
|
||||
else
|
||||
return _output_as_columns(rh);
|
||||
}
|
||||
|
||||
int dm_report_output_headers(struct dm_report *rh)
|
||||
{
|
||||
struct dm_list *hh, *rowh, *htmp;
|
||||
struct header_row *row = NULL;
|
||||
struct dm_report_header *header;
|
||||
|
||||
/* Print and clear buffer */
|
||||
dm_list_iterate_safe(rowh, htmp, &rh->header_rows) {
|
||||
if (!dm_pool_begin_object(rh->mem, 512)) {
|
||||
log_error("dm_report: Unable to allocate output line");
|
||||
return 0;
|
||||
}
|
||||
row = dm_list_item(rowh, struct header_row);
|
||||
|
||||
/* don't attempt to print an empty header row. */
|
||||
if (dm_list_empty(&row->headers)) {
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
dm_list_del(&row->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
dm_list_iterate_safe(hh, htmp, &row->headers) {
|
||||
header = dm_list_item(hh, struct dm_report_header);
|
||||
|
||||
if (!_output_header(rh, header))
|
||||
goto bad;
|
||||
|
||||
dm_list_del(&header->list);
|
||||
if (!dm_list_end(&row->headers, hh))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator, 0)) {
|
||||
log_error("dm_report: Unable to extend header output line");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("dm_report: Unable to terminate header output line");
|
||||
goto bad;
|
||||
}
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
dm_list_del(&row->list);
|
||||
if (dm_list_end(&rh->header_rows, rowh))
|
||||
break;
|
||||
}
|
||||
|
||||
dm_pool_free(rh->mem, row);
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NSEC_PER_USEC 1000L
|
||||
#define NSEC_PER_MSEC 1000000L
|
||||
#define NSEC_PER_SEC 1000000000L
|
||||
|
||||
void dm_report_set_interval(struct dm_report *rh, uint64_t interval)
|
||||
{
|
||||
rh->interval = interval;
|
||||
}
|
||||
|
||||
void dm_report_set_interval_ms(struct dm_report *rh, uint64_t interval_ms)
|
||||
{
|
||||
rh->interval = interval_ms * NSEC_PER_MSEC;
|
||||
}
|
||||
|
||||
uint64_t dm_report_get_interval(struct dm_report *rh)
|
||||
{
|
||||
return rh->interval;
|
||||
}
|
||||
|
||||
uint64_t dm_report_get_interval_ms(struct dm_report *rh)
|
||||
{
|
||||
return (rh->interval / NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
uint64_t dm_report_get_last_interval(struct dm_report *rh)
|
||||
{
|
||||
if (rh->last_wait)
|
||||
return rh->last_wait;
|
||||
return rh->interval;
|
||||
}
|
||||
|
||||
int dm_report_wait(struct dm_report *rh)
|
||||
{
|
||||
struct dm_timestamp *ts_start, *ts_now;
|
||||
int r = 1;
|
||||
|
||||
if (!rh->interval)
|
||||
return_0;
|
||||
|
||||
if(!(ts_start = dm_timestamp_alloc()))
|
||||
return_0;
|
||||
|
||||
if(!(ts_now = dm_timestamp_alloc()))
|
||||
return_0;
|
||||
|
||||
if (!dm_timestamp_get(ts_start)) {
|
||||
log_error("Could not obtain initial timestamp.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (usleep(rh->interval / NSEC_PER_USEC)) {
|
||||
if (errno == EINTR)
|
||||
log_error("Report interval interrupted by signal.");
|
||||
if (errno == EINVAL)
|
||||
log_error("Report interval too short.");
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!dm_timestamp_get(ts_now)) {
|
||||
log_error("Could not obtain current timestamp.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store interval duration in nanoseconds */
|
||||
rh->last_wait = dm_timestamp_delta(ts_now, ts_start);
|
||||
|
||||
dm_timestamp_destroy(ts_start);
|
||||
dm_timestamp_destroy(ts_now);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ struct dm_stats_region {
|
||||
uint64_t step;
|
||||
char *program_id;
|
||||
char *aux_data;
|
||||
uint64_t timescale; /* precise_timestamps is per-region */
|
||||
int timescale; /* precise_timestamps is per-region */
|
||||
struct dm_stats_counters *counters;
|
||||
};
|
||||
|
||||
@@ -60,10 +60,10 @@ struct dm_stats {
|
||||
char *uuid; /* device-mapper UUID */
|
||||
char *program_id; /* default program_id for this handle */
|
||||
struct dm_pool *mem; /* memory pool for region and counter tables */
|
||||
uint64_t nr_regions; /* total number of present regions */
|
||||
uint64_t nr_regions; /* total number of valid regions */
|
||||
uint64_t max_region; /* size of the regions table */
|
||||
uint64_t interval_ns; /* sampling interval in nanoseconds */
|
||||
uint64_t timescale; /* sample value multiplier */
|
||||
uint64_t interval; /* sampling interval in nanoseconds */
|
||||
int timescale; /* sample value multiplier */
|
||||
struct dm_stats_region *regions;
|
||||
/* statistics cursor */
|
||||
uint64_t cur_region;
|
||||
@@ -77,17 +77,10 @@ static char *_program_id_from_proc(void)
|
||||
char buf[256];
|
||||
|
||||
if (!(comm = fopen(PROC_SELF_COMM, "r")))
|
||||
return_NULL;
|
||||
|
||||
if (!fgets(buf, sizeof(buf), comm)) {
|
||||
log_error("Could not read from %s", PROC_SELF_COMM);
|
||||
if(fclose(comm))
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fclose(comm))
|
||||
stack;
|
||||
if (!fgets(buf, sizeof(buf), comm))
|
||||
return NULL;
|
||||
|
||||
return dm_strdup(buf);
|
||||
}
|
||||
@@ -96,10 +89,10 @@ struct dm_stats *dm_stats_create(const char *program_id)
|
||||
{
|
||||
struct dm_stats *dms = NULL;
|
||||
|
||||
if (!(dms = dm_zalloc(sizeof(*dms))))
|
||||
if (!(dms = dm_malloc(sizeof(*dms))))
|
||||
return_NULL;
|
||||
if (!(dms->mem = dm_pool_create("stats_pool", 4096)))
|
||||
goto_out;
|
||||
return_NULL;
|
||||
|
||||
if (!program_id || !strlen(program_id))
|
||||
dms->program_id = _program_id_from_proc();
|
||||
@@ -111,7 +104,6 @@ struct dm_stats *dm_stats_create(const char *program_id)
|
||||
dms->name = NULL;
|
||||
dms->uuid = NULL;
|
||||
|
||||
/* all regions currently use msec precision */
|
||||
dms->timescale = NSEC_PER_MSEC;
|
||||
|
||||
dms->nr_regions = DM_STATS_REGION_NOT_PRESENT;
|
||||
@@ -119,15 +111,12 @@ struct dm_stats *dm_stats_create(const char *program_id)
|
||||
dms->regions = NULL;
|
||||
|
||||
return dms;
|
||||
out:
|
||||
dm_free(dms);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the stats region pointed to by region is present.
|
||||
*/
|
||||
static int _stats_region_present(const struct dm_stats_region *region)
|
||||
static int _stats_region_present(struct dm_stats_region *region)
|
||||
{
|
||||
return !(region->region_id == DM_STATS_REGION_NOT_PRESENT);
|
||||
}
|
||||
@@ -151,13 +140,13 @@ static void _stats_region_destroy(struct dm_stats_region *region)
|
||||
static void _stats_regions_destroy(struct dm_stats *dms)
|
||||
{
|
||||
struct dm_pool *mem = dms->mem;
|
||||
uint64_t i;
|
||||
int i;
|
||||
|
||||
if (!dms->regions)
|
||||
return;
|
||||
|
||||
/* walk backwards to obey pool order */
|
||||
for (i = dms->max_region; (i != DM_STATS_REGION_NOT_PRESENT); i--)
|
||||
for (i = dms->max_region; (i >= 0); i--)
|
||||
_stats_region_destroy(&dms->regions[i]);
|
||||
dm_pool_free(mem, dms->regions);
|
||||
}
|
||||
@@ -178,8 +167,7 @@ static int _stats_bound(struct dm_stats *dms)
|
||||
{
|
||||
if (dms->major > 0 || dms->name || dms->uuid)
|
||||
return 1;
|
||||
/* %p format specifier expects a void pointer. */
|
||||
log_debug("Stats handle at %p is not bound.", (void *) dms);
|
||||
log_debug("Stats handle at %p is not bound.", dms);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -227,6 +215,29 @@ int dm_stats_bind_uuid(struct dm_stats *dms, const char *uuid)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_init(struct dm_stats *dms, uint64_t max_regions)
|
||||
{
|
||||
uint64_t cur = max_regions;
|
||||
size_t region_table_size = max_regions * sizeof(*dms->regions);
|
||||
|
||||
if (!max_regions)
|
||||
return_0;
|
||||
|
||||
if (dms->regions)
|
||||
_stats_regions_destroy(dms);
|
||||
|
||||
dms->regions = dm_pool_alloc(dms->mem, region_table_size);
|
||||
if (!dms->regions)
|
||||
return_0;
|
||||
|
||||
dms->max_region = max_regions - 1;
|
||||
|
||||
while(--cur != UINT64_MAX)
|
||||
dms->regions[cur].region_id = DM_STATS_REGION_NOT_PRESENT;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dm_task *_stats_send_message(struct dm_stats *dms, char *msg)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
@@ -245,7 +256,8 @@ static struct dm_task *_stats_send_message(struct dm_stats *dms, char *msg)
|
||||
|
||||
return dmt;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
if(dmt)
|
||||
dm_task_destroy(dmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -256,8 +268,8 @@ static int _stats_parse_list_region(struct dm_stats_region *region, char *line)
|
||||
int r;
|
||||
|
||||
/* line format:
|
||||
* <region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
|
||||
*/
|
||||
* <region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
|
||||
*/
|
||||
r = sscanf(line, FMTu64 ": " FMTu64 "+" FMTu64 " " FMTu64 "%255s %255s",
|
||||
®ion->region_id, ®ion->start, ®ion->len, ®ion->step,
|
||||
program_id, aux_data);
|
||||
@@ -291,7 +303,7 @@ static int _stats_parse_list(struct dm_stats *dms, const char *resp)
|
||||
char line[256];
|
||||
|
||||
if (!resp) {
|
||||
log_error("Could not parse NULL @stats_list response.");
|
||||
log_error("Could not parse NULL or empty @stats_list response.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -305,10 +317,7 @@ static int _stats_parse_list(struct dm_stats *dms, const char *resp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* dm_task_get_message_response() returns a 'const char *' but
|
||||
* since fmemopen also permits "w" it expects a 'char *'.
|
||||
*/
|
||||
/* dm_task_get_message_response() returns a 'const char *' */
|
||||
if (!(list_rows = fmemopen((char *)resp, strlen(resp), "r")))
|
||||
return_0;
|
||||
|
||||
@@ -334,7 +343,7 @@ static int _stats_parse_list(struct dm_stats *dms, const char *resp)
|
||||
if (!dm_pool_grow_object(mem, &cur, sizeof(cur)))
|
||||
goto_out;
|
||||
|
||||
max_region++;
|
||||
max_region++;
|
||||
nr_regions++;
|
||||
}
|
||||
|
||||
@@ -342,13 +351,10 @@ static int _stats_parse_list(struct dm_stats *dms, const char *resp)
|
||||
dms->max_region = max_region - 1;
|
||||
dms->regions = dm_pool_end_object(mem);
|
||||
|
||||
if (fclose(list_rows))
|
||||
stack;
|
||||
|
||||
fclose(list_rows);
|
||||
return 1;
|
||||
out:
|
||||
if(fclose(list_rows))
|
||||
stack;
|
||||
fclose(list_rows);
|
||||
dm_pool_abandon_object(mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -390,8 +396,7 @@ out:
|
||||
}
|
||||
|
||||
static int _stats_parse_region(struct dm_pool *mem, const char *resp,
|
||||
struct dm_stats_region *region,
|
||||
uint64_t timescale)
|
||||
struct dm_stats_region *region, int timescale)
|
||||
{
|
||||
struct dm_stats_counters cur;
|
||||
FILE *stats_rows = NULL;
|
||||
@@ -409,10 +414,6 @@ static int _stats_parse_region(struct dm_pool *mem, const char *resp,
|
||||
if (!dm_pool_begin_object(mem, 512))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* dm_task_get_message_response() returns a 'const char *' but
|
||||
* since fmemopen also permits "w" it expects a 'char *'.
|
||||
*/
|
||||
stats_rows = fmemopen((char *)resp, strlen(resp), "r");
|
||||
if (!stats_rows)
|
||||
goto_out;
|
||||
@@ -488,16 +489,13 @@ static int _stats_parse_region(struct dm_pool *mem, const char *resp,
|
||||
region->timescale = timescale;
|
||||
region->counters = dm_pool_end_object(mem);
|
||||
|
||||
if (fclose(stats_rows))
|
||||
stack;
|
||||
|
||||
fclose(stats_rows);
|
||||
return 1;
|
||||
|
||||
out:
|
||||
|
||||
if (stats_rows)
|
||||
if(fclose(stats_rows))
|
||||
stack;
|
||||
fclose(stats_rows);
|
||||
dm_pool_abandon_object(mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -511,7 +509,8 @@ static uint64_t _nr_areas(uint64_t len, uint64_t step)
|
||||
* treat the entire region as a single area. Any partial area at the
|
||||
* end of the region is treated as an additional complete area.
|
||||
*/
|
||||
return (len / (step ? : len)) + !!(len % step);
|
||||
return (len && step)
|
||||
? (len / (step ? step : len)) + !!(len % step) : 0;
|
||||
}
|
||||
|
||||
static uint64_t _nr_areas_region(struct dm_stats_region *region)
|
||||
@@ -519,7 +518,7 @@ static uint64_t _nr_areas_region(struct dm_stats_region *region)
|
||||
return _nr_areas(region->len, region->step);
|
||||
}
|
||||
|
||||
static void _stats_walk_next(const struct dm_stats *dms, int region,
|
||||
static void _stats_walk_next(struct dm_stats *dms, int region,
|
||||
uint64_t *cur_r, uint64_t *cur_a)
|
||||
{
|
||||
struct dm_stats_region *cur = NULL;
|
||||
@@ -539,13 +538,12 @@ static void _stats_walk_next(const struct dm_stats *dms, int region,
|
||||
while(!dm_stats_region_present(dms, ++(*cur_r))
|
||||
&& *cur_r < dms->max_region)
|
||||
; /* keep walking until a present region is found
|
||||
* or the end of the table is reached. */
|
||||
* or the end of the table is reached. */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void _stats_walk_start(const struct dm_stats *dms,
|
||||
uint64_t *cur_r, uint64_t *cur_a)
|
||||
static void _stats_walk_start(struct dm_stats *dms, uint64_t *cur_r, uint64_t *cur_a)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
return;
|
||||
@@ -565,16 +563,15 @@ void dm_stats_walk_start(struct dm_stats *dms)
|
||||
|
||||
void dm_stats_walk_next(struct dm_stats *dms)
|
||||
{
|
||||
_stats_walk_next(dms, 0, &dms->cur_region, &dms->cur_area);
|
||||
return _stats_walk_next(dms, 0, &dms->cur_region, &dms->cur_area);
|
||||
}
|
||||
|
||||
void dm_stats_walk_next_region(struct dm_stats *dms)
|
||||
{
|
||||
_stats_walk_next(dms, 1, &dms->cur_region, &dms->cur_area);
|
||||
return _stats_walk_next(dms, 1, &dms->cur_region, &dms->cur_area);
|
||||
}
|
||||
|
||||
static int _stats_walk_end(const struct dm_stats *dms,
|
||||
uint64_t *cur_r, uint64_t *cur_a)
|
||||
static int _stats_walk_end(struct dm_stats *dms, uint64_t *cur_r, uint64_t *cur_a)
|
||||
{
|
||||
struct dm_stats_region *region = NULL;
|
||||
int end = 0;
|
||||
@@ -595,19 +592,18 @@ int dm_stats_walk_end(struct dm_stats *dms)
|
||||
return _stats_walk_end(dms, &dms->cur_region, &dms->cur_area);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_region_nr_areas(const struct dm_stats *dms,
|
||||
uint64_t region_id)
|
||||
uint64_t dm_stats_nr_areas_region(struct dm_stats *dms, uint64_t region_id)
|
||||
{
|
||||
struct dm_stats_region *region = &dms->regions[region_id];
|
||||
return _nr_areas_region(region);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_nr_areas(const struct dm_stats *dms)
|
||||
uint64_t dm_stats_nr_areas_current(struct dm_stats *dms)
|
||||
{
|
||||
return dm_stats_get_region_nr_areas(dms, dms->cur_region);
|
||||
return dm_stats_nr_areas_region(dms, dms->cur_region);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_nr_areas(const struct dm_stats *dms)
|
||||
uint64_t dm_stats_nr_areas(struct dm_stats *dms)
|
||||
{
|
||||
uint64_t nr_areas = 0;
|
||||
/* use a separate cursor */
|
||||
@@ -615,15 +611,15 @@ uint64_t dm_stats_get_nr_areas(const struct dm_stats *dms)
|
||||
|
||||
_stats_walk_start(dms, &cur_region, &cur_area);
|
||||
do {
|
||||
nr_areas += dm_stats_get_current_nr_areas(dms);
|
||||
nr_areas += dm_stats_nr_areas_current(dms);
|
||||
_stats_walk_next(dms, 1, &cur_region, &cur_area);
|
||||
} while (!_stats_walk_end(dms, &cur_region, &cur_area));
|
||||
return nr_areas;
|
||||
}
|
||||
|
||||
int dm_stats_create_region(struct dm_stats *dms, uint64_t *region_id,
|
||||
uint64_t start, uint64_t len, int64_t step,
|
||||
const char *program_id, const char *aux_data)
|
||||
uint64_t start, uint64_t len, int64_t step,
|
||||
const char *program_id, const char *aux_data)
|
||||
{
|
||||
struct dm_task *dmt = NULL;
|
||||
char msg[1024], range[64];
|
||||
@@ -724,8 +720,8 @@ out:
|
||||
}
|
||||
|
||||
static struct dm_task *_stats_print_region(struct dm_stats *dms,
|
||||
uint64_t region_id, unsigned start_line,
|
||||
unsigned num_lines, unsigned clear)
|
||||
uint64_t region_id, int start_line,
|
||||
int num_lines, int clear)
|
||||
{
|
||||
struct dm_task *dmt = NULL;
|
||||
/* @stats_print[_clear] <region_id> [<start_line> <num_lines>] */
|
||||
@@ -786,7 +782,7 @@ void dm_stats_buffer_destroy(struct dm_stats *dms, char *buffer)
|
||||
dm_pool_free(dms->mem, buffer);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_nr_regions(const struct dm_stats *dms)
|
||||
int dm_stats_nr_regions(struct dm_stats *dms)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
return 0;
|
||||
@@ -796,7 +792,7 @@ uint64_t dm_stats_get_nr_regions(const struct dm_stats *dms)
|
||||
/**
|
||||
* Test whether region_id is present in this set of stats data
|
||||
*/
|
||||
int dm_stats_region_present(const struct dm_stats *dms, uint64_t region_id)
|
||||
int dm_stats_region_present(struct dm_stats *dms, uint64_t region_id)
|
||||
{
|
||||
if (!dms->regions)
|
||||
return 0;
|
||||
@@ -807,8 +803,8 @@ int dm_stats_region_present(const struct dm_stats *dms, uint64_t region_id)
|
||||
return _stats_region_present(&dms->regions[region_id]);
|
||||
}
|
||||
|
||||
static int _dm_stats_populate_region(struct dm_stats *dms, uint64_t region_id,
|
||||
const char *resp)
|
||||
int dm_stats_populate_region(struct dm_stats *dms, uint64_t region_id,
|
||||
const char *resp)
|
||||
{
|
||||
struct dm_stats_region *region = &dms->regions[region_id];
|
||||
|
||||
@@ -857,7 +853,7 @@ int dm_stats_populate(struct dm_stats *dms, const char *program_id,
|
||||
goto_out;
|
||||
|
||||
resp = dm_task_get_message_response(dmt);
|
||||
if (!_dm_stats_populate_region(dms, region_id, resp)) {
|
||||
if (!dm_stats_populate_region(dms, region_id, resp)) {
|
||||
dm_task_destroy(dmt);
|
||||
goto_out;
|
||||
}
|
||||
@@ -871,7 +867,6 @@ int dm_stats_populate(struct dm_stats *dms, const char *program_id,
|
||||
|
||||
out:
|
||||
_stats_regions_destroy(dms);
|
||||
dms->regions = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -896,8 +891,8 @@ void dm_stats_destroy(struct dm_stats *dms)
|
||||
* Where the two integer arguments are the region_id and area_id
|
||||
* respectively.
|
||||
*/
|
||||
#define MK_STATS_GET_COUNTER_FN(counter) \
|
||||
uint64_t dm_stats_get_ ## counter(const struct dm_stats *dms, \
|
||||
#define __mk_stats_get_counter_fn(counter) \
|
||||
uint64_t dm_stats_get_ ## counter(struct dm_stats *dms, \
|
||||
uint64_t region_id, uint64_t area_id) \
|
||||
{ \
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT) \
|
||||
@@ -907,27 +902,28 @@ uint64_t dm_stats_get_ ## counter(const struct dm_stats *dms, \
|
||||
return dms->regions[region_id].counters[area_id].counter; \
|
||||
}
|
||||
|
||||
MK_STATS_GET_COUNTER_FN(reads)
|
||||
MK_STATS_GET_COUNTER_FN(reads_merged)
|
||||
MK_STATS_GET_COUNTER_FN(read_sectors)
|
||||
MK_STATS_GET_COUNTER_FN(read_nsecs)
|
||||
MK_STATS_GET_COUNTER_FN(writes)
|
||||
MK_STATS_GET_COUNTER_FN(writes_merged)
|
||||
MK_STATS_GET_COUNTER_FN(write_sectors)
|
||||
MK_STATS_GET_COUNTER_FN(write_nsecs)
|
||||
MK_STATS_GET_COUNTER_FN(io_in_progress)
|
||||
MK_STATS_GET_COUNTER_FN(io_nsecs)
|
||||
MK_STATS_GET_COUNTER_FN(weighted_io_nsecs)
|
||||
MK_STATS_GET_COUNTER_FN(total_read_nsecs)
|
||||
MK_STATS_GET_COUNTER_FN(total_write_nsecs)
|
||||
#undef MK_STATS_GET_COUNTER_FN
|
||||
__mk_stats_get_counter_fn(reads)
|
||||
__mk_stats_get_counter_fn(reads_merged)
|
||||
__mk_stats_get_counter_fn(read_sectors)
|
||||
__mk_stats_get_counter_fn(read_nsecs)
|
||||
__mk_stats_get_counter_fn(writes)
|
||||
__mk_stats_get_counter_fn(writes_merged)
|
||||
__mk_stats_get_counter_fn(write_sectors)
|
||||
__mk_stats_get_counter_fn(write_nsecs)
|
||||
__mk_stats_get_counter_fn(io_in_progress)
|
||||
__mk_stats_get_counter_fn(io_nsecs)
|
||||
__mk_stats_get_counter_fn(weighted_io_nsecs)
|
||||
__mk_stats_get_counter_fn(total_read_nsecs)
|
||||
__mk_stats_get_counter_fn(total_write_nsecs)
|
||||
|
||||
int dm_stats_get_rd_merges_per_sec(const struct dm_stats *dms, double *rrqm,
|
||||
#undef __dm_stats_get_counter_fn
|
||||
|
||||
int dm_stats_get_rd_merges_per_sec(struct dm_stats *dms, double *rrqm,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -936,16 +932,16 @@ int dm_stats_get_rd_merges_per_sec(const struct dm_stats *dms, double *rrqm,
|
||||
? dms->cur_area : area_id ;
|
||||
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
*rrqm = ((double) c->reads_merged) / (double) dms->interval_ns;
|
||||
*rrqm = ((double) c->reads_merged) / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_wr_merges_per_sec(const struct dm_stats *dms, double *wrqm,
|
||||
int dm_stats_get_wr_merges_per_sec(struct dm_stats *dms, double *wrqm,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -954,16 +950,16 @@ int dm_stats_get_wr_merges_per_sec(const struct dm_stats *dms, double *wrqm,
|
||||
? dms->cur_area : area_id ;
|
||||
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
*wrqm = ((double) c->writes_merged) / (double) dms->interval_ns;
|
||||
*wrqm = ((double) c->writes_merged) / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_reads_per_sec(const struct dm_stats *dms, double *rd_s,
|
||||
int dm_stats_get_reads_per_sec(struct dm_stats *dms, double *rd_s,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -972,16 +968,16 @@ int dm_stats_get_reads_per_sec(const struct dm_stats *dms, double *rd_s,
|
||||
? dms->cur_area : area_id ;
|
||||
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
*rd_s = ((double) c->reads * NSEC_PER_SEC) / (double) dms->interval_ns;
|
||||
*rd_s = ((double) c->reads * NSEC_PER_SEC) / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_writes_per_sec(const struct dm_stats *dms, double *wr_s,
|
||||
int dm_stats_get_writes_per_sec(struct dm_stats *dms, double *wr_s,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -990,18 +986,16 @@ int dm_stats_get_writes_per_sec(const struct dm_stats *dms, double *wr_s,
|
||||
? dms->cur_area : area_id ;
|
||||
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
*wr_s = ((double) c->writes * (double) NSEC_PER_SEC)
|
||||
/ (double) dms->interval_ns;
|
||||
|
||||
*wr_s = ((double) c->writes * NSEC_PER_SEC) / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_read_sectors_per_sec(const struct dm_stats *dms, double *rsec_s,
|
||||
int dm_stats_get_read_sectors_per_sec(struct dm_stats *dms, double *rsec_s,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -1010,18 +1004,16 @@ int dm_stats_get_read_sectors_per_sec(const struct dm_stats *dms, double *rsec_s
|
||||
? dms->cur_area : area_id ;
|
||||
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
*rsec_s = ((double) c->read_sectors * (double) NSEC_PER_SEC)
|
||||
/ (double) dms->interval_ns;
|
||||
|
||||
*rsec_s = ((double) c->read_sectors * NSEC_PER_SEC) / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_write_sectors_per_sec(const struct dm_stats *dms, double *wsec_s,
|
||||
int dm_stats_get_write_sectors_per_sec(struct dm_stats *dms, double *wsec_s,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -1030,18 +1022,17 @@ int dm_stats_get_write_sectors_per_sec(const struct dm_stats *dms, double *wsec_
|
||||
? dms->cur_area : area_id ;
|
||||
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
*wsec_s = ((double) c->write_sectors * (double) NSEC_PER_SEC)
|
||||
/ (double) dms->interval_ns;
|
||||
*wsec_s = ((double) c->write_sectors * NSEC_PER_SEC) / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_average_request_size(const struct dm_stats *dms, double *arqsz,
|
||||
int dm_stats_get_average_request_size(struct dm_stats *dms, double *arqsz,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
uint64_t nr_ios, nr_sectors;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
*arqsz = 0.0;
|
||||
@@ -1055,17 +1046,17 @@ int dm_stats_get_average_request_size(const struct dm_stats *dms, double *arqsz,
|
||||
nr_ios = c->reads + c->writes;
|
||||
nr_sectors = c->read_sectors + c->write_sectors;
|
||||
if (nr_ios)
|
||||
*arqsz = (double) nr_sectors / (double) nr_ios;
|
||||
*arqsz = nr_sectors / nr_ios;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_average_queue_size(const struct dm_stats *dms, double *qusz,
|
||||
int dm_stats_get_average_queue_size(struct dm_stats *dms, double *qusz,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
uint64_t io_ticks;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
*qusz = 0.0;
|
||||
@@ -1078,17 +1069,17 @@ int dm_stats_get_average_queue_size(const struct dm_stats *dms, double *qusz,
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
io_ticks = c->weighted_io_nsecs;
|
||||
if (io_ticks)
|
||||
*qusz = (double) io_ticks / (double) dms->interval_ns;
|
||||
*qusz = io_ticks / dms->interval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_average_wait_time(const struct dm_stats *dms, double *await,
|
||||
int dm_stats_get_average_wait_time(struct dm_stats *dms, double *await,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
uint64_t io_ticks, nr_ios;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
*await = 0.0;
|
||||
@@ -1102,18 +1093,17 @@ int dm_stats_get_average_wait_time(const struct dm_stats *dms, double *await,
|
||||
io_ticks = c->read_nsecs + c->write_nsecs;
|
||||
nr_ios = c->reads + c->writes;
|
||||
if (nr_ios)
|
||||
*await = (double) io_ticks / (double) nr_ios;
|
||||
*await = io_ticks / nr_ios;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_average_rd_wait_time(const struct dm_stats *dms,
|
||||
double *await, uint64_t region_id,
|
||||
uint64_t area_id)
|
||||
int dm_stats_get_average_rd_wait_time(struct dm_stats *dms, double *await,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
uint64_t rd_io_ticks, nr_rd_ios;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
*await = 0.0;
|
||||
@@ -1127,18 +1117,17 @@ int dm_stats_get_average_rd_wait_time(const struct dm_stats *dms,
|
||||
rd_io_ticks = c->read_nsecs;
|
||||
nr_rd_ios = c->reads;
|
||||
if (rd_io_ticks)
|
||||
*await = (double) rd_io_ticks / (double) nr_rd_ios;
|
||||
*await = rd_io_ticks / nr_rd_ios;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_average_wr_wait_time(const struct dm_stats *dms,
|
||||
double *await, uint64_t region_id,
|
||||
uint64_t area_id)
|
||||
int dm_stats_get_average_wr_wait_time(struct dm_stats *dms, double *await,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
uint64_t wr_io_ticks, nr_wr_ios;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
*await = 0.0;
|
||||
@@ -1152,11 +1141,11 @@ int dm_stats_get_average_wr_wait_time(const struct dm_stats *dms,
|
||||
wr_io_ticks = c->write_nsecs;
|
||||
nr_wr_ios = c->writes;
|
||||
if (wr_io_ticks && nr_wr_ios)
|
||||
*await = (double) wr_io_ticks / (double) nr_wr_ios;
|
||||
*await = wr_io_ticks / nr_wr_ios;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_service_time(const struct dm_stats *dms, double *svctm,
|
||||
int dm_stats_get_service_time(struct dm_stats *dms, double *svctm,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
dm_percent_t util;
|
||||
@@ -1178,12 +1167,12 @@ int dm_stats_get_service_time(const struct dm_stats *dms, double *svctm,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_throughput(const struct dm_stats *dms, double *tput,
|
||||
int dm_stats_get_throughput(struct dm_stats *dms, double *tput,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -1194,17 +1183,17 @@ int dm_stats_get_throughput(const struct dm_stats *dms, double *tput,
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
|
||||
*tput = (( NSEC_PER_SEC * ((double) c->reads + (double) c->writes))
|
||||
/ (double) (dms->interval_ns));
|
||||
/ (double) (dms->interval));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_utilization(const struct dm_stats *dms, dm_percent_t *util,
|
||||
int dm_stats_get_utilization(struct dm_stats *dms, dm_percent_t *util,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
struct dm_stats_counters *c;
|
||||
uint64_t io_nsecs;
|
||||
|
||||
if (!dms->interval_ns)
|
||||
if (!dms->interval)
|
||||
return_0;
|
||||
|
||||
region_id = (region_id == DM_STATS_REGION_CURRENT)
|
||||
@@ -1215,42 +1204,42 @@ int dm_stats_get_utilization(const struct dm_stats *dms, dm_percent_t *util,
|
||||
c = &(dms->regions[region_id].counters[area_id]);
|
||||
|
||||
/**
|
||||
* If io_nsec > interval_ns there is something wrong with the clock
|
||||
* If io_nsec > interval there is something wrong with the clock
|
||||
* for the last interval; do not allow a value > 100% utilization
|
||||
* to be passed to a dm_make_percent() call. We expect to see these
|
||||
* at startup if counters have not been cleared before the first read.
|
||||
*/
|
||||
io_nsecs = (c->io_nsecs <= dms->interval_ns) ? c->io_nsecs : dms->interval_ns;
|
||||
*util = dm_make_percent(io_nsecs, dms->interval_ns);
|
||||
io_nsecs = (c->io_nsecs <= dms->interval) ? c->io_nsecs : dms->interval;
|
||||
*util = dm_make_percent(io_nsecs, dms->interval);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_stats_set_sampling_interval_ms(struct dm_stats *dms, uint64_t interval_ms)
|
||||
void dm_stats_set_interval_ms(struct dm_stats *dms, uint64_t interval_ms)
|
||||
{
|
||||
/* All times use nsecs internally. */
|
||||
dms->interval_ns = interval_ms * NSEC_PER_MSEC;
|
||||
dms->interval = interval_ms * NSEC_PER_MSEC;
|
||||
}
|
||||
|
||||
void dm_stats_set_sampling_interval_ns(struct dm_stats *dms, uint64_t interval_ns)
|
||||
void dm_stats_set_interval(struct dm_stats *dms, uint64_t interval)
|
||||
{
|
||||
dms->interval_ns = interval_ns;
|
||||
dms->interval = interval;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_sampling_interval_ms(const struct dm_stats *dms)
|
||||
uint64_t dm_stats_get_interval_ms(struct dm_stats *dms)
|
||||
{
|
||||
/* All times use nsecs internally. */
|
||||
return (dms->interval_ns / NSEC_PER_MSEC);
|
||||
return (dms->interval / NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_sampling_interval_ns(const struct dm_stats *dms)
|
||||
uint64_t dm_stats_get_interval(struct dm_stats *dms)
|
||||
{
|
||||
/* All times use nsecs internally. */
|
||||
return (dms->interval_ns);
|
||||
return (dms->interval);
|
||||
}
|
||||
|
||||
int dm_stats_set_program_id(struct dm_stats *dms, int allow_empty,
|
||||
const char *program_id)
|
||||
const char *program_id)
|
||||
{
|
||||
if (!allow_empty && (!program_id || !strlen(program_id))) {
|
||||
log_error("Empty program_id not permitted without "
|
||||
@@ -1270,17 +1259,17 @@ int dm_stats_set_program_id(struct dm_stats *dms, int allow_empty,
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_region(const struct dm_stats *dms)
|
||||
uint64_t dm_stats_get_current_region(struct dm_stats *dms)
|
||||
{
|
||||
return dms->cur_region;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_area(const struct dm_stats *dms)
|
||||
uint64_t dm_stats_get_current_area(struct dm_stats *dms)
|
||||
{
|
||||
return dms->cur_area;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_region_start(const struct dm_stats *dms, uint64_t *start,
|
||||
int dm_stats_get_region_start(struct dm_stats *dms, uint64_t *start,
|
||||
uint64_t region_id)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
@@ -1289,7 +1278,7 @@ uint64_t dm_stats_get_region_start(const struct dm_stats *dms, uint64_t *start,
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_region_len(const struct dm_stats *dms, uint64_t *len,
|
||||
int dm_stats_get_region_len(struct dm_stats *dms, uint64_t *len,
|
||||
uint64_t region_id)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
@@ -1298,7 +1287,7 @@ uint64_t dm_stats_get_region_len(const struct dm_stats *dms, uint64_t *len,
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_region_area_len(const struct dm_stats *dms, uint64_t *step,
|
||||
int dm_stats_get_region_area_len(struct dm_stats *dms, uint64_t *step,
|
||||
uint64_t region_id)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
@@ -1307,26 +1296,23 @@ uint64_t dm_stats_get_region_area_len(const struct dm_stats *dms, uint64_t *step
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_region_start(const struct dm_stats *dms,
|
||||
uint64_t *start)
|
||||
int dm_stats_get_current_region_start(struct dm_stats *dms, uint64_t *start)
|
||||
{
|
||||
return dm_stats_get_region_start(dms, start, dms->cur_region);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_region_len(const struct dm_stats *dms,
|
||||
uint64_t *len)
|
||||
int dm_stats_get_current_region_len(struct dm_stats *dms, uint64_t *len)
|
||||
{
|
||||
return dm_stats_get_region_len(dms, len, dms->cur_region);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_region_area_len(const struct dm_stats *dms,
|
||||
uint64_t *step)
|
||||
int dm_stats_get_current_region_area_len(struct dm_stats *dms, uint64_t *step)
|
||||
{
|
||||
return dm_stats_get_region_area_len(dms, step, dms->cur_region);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_area_start(const struct dm_stats *dms, uint64_t *start,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
int dm_stats_get_area_start(struct dm_stats *dms, uint64_t *start,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
return_0;
|
||||
@@ -1334,39 +1320,46 @@ uint64_t dm_stats_get_area_start(const struct dm_stats *dms, uint64_t *start,
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_area_start(const struct dm_stats *dms,
|
||||
uint64_t *start)
|
||||
int dm_stats_get_area_len(struct dm_stats *dms, uint64_t *len,
|
||||
uint64_t region_id, uint64_t area_id)
|
||||
{
|
||||
if (!dms || !dms->regions)
|
||||
return_0;
|
||||
*len = dms->regions[region_id].step;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_stats_get_current_area_start(struct dm_stats *dms, uint64_t *start)
|
||||
{
|
||||
return dm_stats_get_area_start(dms, start,
|
||||
dms->cur_region, dms->cur_area);
|
||||
}
|
||||
|
||||
uint64_t dm_stats_get_current_area_len(const struct dm_stats *dms,
|
||||
uint64_t *len)
|
||||
int dm_stats_get_current_area_len(struct dm_stats *dms, uint64_t *len)
|
||||
{
|
||||
return dm_stats_get_region_area_len(dms, len, dms->cur_region);
|
||||
return dm_stats_get_area_len(dms, len, dms->cur_region, dms->cur_area);
|
||||
}
|
||||
|
||||
const char *dm_stats_get_region_program_id(const struct dm_stats *dms,
|
||||
const char *dm_stats_get_region_program_id(struct dm_stats *dms,
|
||||
uint64_t region_id)
|
||||
{
|
||||
const char *program_id = dms->regions[region_id].program_id;
|
||||
return (program_id) ? program_id : "";
|
||||
}
|
||||
|
||||
const char *dm_stats_get_region_aux_data(const struct dm_stats *dms,
|
||||
const char *dm_stats_get_region_aux_data(struct dm_stats *dms,
|
||||
uint64_t region_id)
|
||||
{
|
||||
const char *aux_data = dms->regions[region_id].aux_data;
|
||||
return (aux_data) ? aux_data : "" ;
|
||||
}
|
||||
|
||||
const char *dm_stats_get_current_region_program_id(const struct dm_stats *dms)
|
||||
const char *dm_stats_get_current_region_program_id(struct dm_stats *dms)
|
||||
{
|
||||
return dm_stats_get_region_program_id(dms, dms->cur_region);
|
||||
}
|
||||
|
||||
const char *dm_stats_get_current_region_aux_data(const struct dm_stats *dms)
|
||||
const char *dm_stats_get_current_region_aux_data(struct dm_stats *dms)
|
||||
{
|
||||
return dm_stats_get_region_aux_data(dms, dms->cur_region);
|
||||
}
|
||||
|
@@ -54,7 +54,7 @@ struct dm_timestamp *dm_timestamp_alloc(void)
|
||||
{
|
||||
struct dm_timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = dm_zalloc(sizeof(*ts))))
|
||||
if (!(ts = dm_malloc(sizeof(*ts))))
|
||||
stack;
|
||||
|
||||
return ts;
|
||||
@@ -67,8 +67,6 @@ int dm_timestamp_get(struct dm_timestamp *ts)
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
|
||||
log_sys_error("clock_gettime", "get_timestamp");
|
||||
ts->t.tv_sec = 0;
|
||||
ts->t.tv_nsec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -115,8 +113,6 @@ int dm_timestamp_get(struct dm_timestamp *ts)
|
||||
|
||||
if (gettimeofday(&ts->t, NULL)) {
|
||||
log_sys_error("gettimeofday", "get_timestamp");
|
||||
ts->t.tv_sec = 0;
|
||||
ts->t.tv_usec = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -168,11 +164,6 @@ uint64_t dm_timestamp_delta(struct dm_timestamp *ts1, struct dm_timestamp *ts2)
|
||||
return t2 - t1;
|
||||
}
|
||||
|
||||
void dm_timestamp_copy(struct dm_timestamp *ts_new, struct dm_timestamp *ts_old)
|
||||
{
|
||||
*ts_new = *ts_old;
|
||||
}
|
||||
|
||||
void dm_timestamp_destroy(struct dm_timestamp *ts)
|
||||
{
|
||||
dm_free(ts);
|
||||
|
@@ -32,7 +32,6 @@ dmsetup \(em low level logical volume management
|
||||
.br
|
||||
.B dmsetup info
|
||||
.BR \-c | \-C | \-\-columns
|
||||
.RB [ \-\-nameprefixes ]
|
||||
.RB [ \-\-noheadings ]
|
||||
.RB [ \-\-separator
|
||||
.IR separator ]
|
||||
@@ -43,10 +42,6 @@ dmsetup \(em low level logical volume management
|
||||
.IR sort_fields ]
|
||||
.RB [ \-S | \-\-select
|
||||
.IR Selection ]
|
||||
.RB [ \-\-interval
|
||||
.IR seconds ]
|
||||
.RB [ \-\-count
|
||||
.IR count ]
|
||||
.RI [ device_name ]
|
||||
.RE
|
||||
.br
|
||||
@@ -192,10 +187,6 @@ In some cases these checks may slow down operations noticeably.
|
||||
.BR \-c | \-C | \-\-columns
|
||||
Display output in columns rather than as Field: Value lines.
|
||||
.TP
|
||||
.B \-\-count \fIcount
|
||||
Specify the number of times to repeat a report. Set this to zero
|
||||
continue until interrupted. The default interval is one second.
|
||||
.TP
|
||||
.BR \-h | \-\-help
|
||||
Outputs a summary of the commands available, optionally including
|
||||
the list of report fields (synonym with \fBhelp\fP command).
|
||||
@@ -205,12 +196,6 @@ When returning any table information from the kernel report on the
|
||||
inactive table instead of the live table.
|
||||
Requires kernel driver version 4.16.0 or above.
|
||||
.TP
|
||||
.B \-\-interval \fIseconds
|
||||
Specify the interval in seconds between successive iterations for
|
||||
repeating reports. If \-\-interval is specified but \-\-count is not,
|
||||
reports will continue to repeat until interrupted.
|
||||
The default interval is one second.
|
||||
.TP
|
||||
.IR \fB\-\-manglename \ { none | hex | auto }
|
||||
Mangle any character not on a whitelist using mangling_mode when
|
||||
processing device-mapper device names and UUIDs. The names and UUIDs
|
||||
@@ -237,10 +222,6 @@ Specify the minor number.
|
||||
.BR \-n | \-\-notable
|
||||
When creating a device, don't load any table.
|
||||
.TP
|
||||
.BR \-\-nameprefixes
|
||||
Add a "DM_" prefix plus the field name to the output. Useful with --noheadings to produce a list of
|
||||
field=value pairs that can be used to set environment variables (for example, in udev(7) rules).
|
||||
.TP
|
||||
.BR \-\-noheadings
|
||||
Suppress the headings line when using columnar output.
|
||||
.TP
|
||||
@@ -374,10 +355,6 @@ Outputs some brief information about the device in the form:
|
||||
.IR fields ]
|
||||
.RB [ \-O | \-\-sort
|
||||
.IR sort_fields ]
|
||||
.RB [ \-\-interval
|
||||
.IR seconds ]
|
||||
.RB [ \-\-count
|
||||
.IR count ]
|
||||
.RI [ device_name ]
|
||||
.br
|
||||
Output you can customise.
|
||||
|
113
man/dmstats.8.in
113
man/dmstats.8.in
@@ -27,7 +27,6 @@ dmstats \(em device-mapper statistics management
|
||||
.br
|
||||
.B dmstats create
|
||||
.I device_name
|
||||
.RB [ \-\-alldevices ]
|
||||
.RB [[ \-\-areas
|
||||
.IR nr_areas ]
|
||||
.RB |[ \-\-areasize
|
||||
@@ -36,7 +35,7 @@ dmstats \(em device-mapper statistics management
|
||||
.IR start_sector ]
|
||||
.RB [ \-\-length
|
||||
.IR length ]
|
||||
.RB |[ \-\-segments ]]
|
||||
.RB |[ \-\-targets ]]
|
||||
.RB [ \-\-auxdata
|
||||
.IR data ]
|
||||
.RB [ \-\-programid
|
||||
@@ -44,7 +43,7 @@ dmstats \(em device-mapper statistics management
|
||||
.br
|
||||
.B dmstats delete
|
||||
.I device_name
|
||||
.RB [ \-\-alldevices ]
|
||||
.RB [ \-\-force ]
|
||||
.RB [ \-\-allregions
|
||||
.RB | \-\-regionid
|
||||
.IR id ]
|
||||
@@ -80,11 +79,14 @@ dmstats \(em device-mapper statistics management
|
||||
.IR seconds ]
|
||||
.RB [ \-\-count
|
||||
.IR count ]
|
||||
.RB [ \-\-timestamps ]
|
||||
.RB [ \-\-units
|
||||
.IR units ]
|
||||
.RB [ \-\-allprograms ]
|
||||
.RB [ \-\-programid
|
||||
.IR id ]
|
||||
.RB [ \-\-headers
|
||||
.IR headers ]
|
||||
.RB [ \-\-regionid
|
||||
.IR id ]
|
||||
.RB [ \-O | \-\-sort
|
||||
@@ -116,14 +118,10 @@ when run as 'dmsetup stats'.
|
||||
|
||||
When no device argument is given dmstats will by default operate on all
|
||||
device-mapper devices present. The \fBcreate\fP and \fBdelete\fP
|
||||
commands require the use of \fB--alldevices\fP when used in this way.
|
||||
commands require the use of \fB--force\fP when used in this way.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-\-alldevices
|
||||
If no device arguments are given allow operation on all devices when
|
||||
creating or deleting regions.
|
||||
.TP
|
||||
.B \-\-allprograms
|
||||
Include regions from all program IDs for list and report operations.
|
||||
.TP
|
||||
@@ -145,12 +143,19 @@ instead of 1024.
|
||||
Specify auxilliary data (a string) to be stored with a new region.
|
||||
.TP
|
||||
.B \-\-clear
|
||||
When printing statistics counters, also atomically reset them to zero.
|
||||
When printing statistics counters also atomically reset them to zero.
|
||||
.TP
|
||||
.B \-\-count \fIcount
|
||||
Specify the iteration count for repeating reports. If the count
|
||||
argument is zero reports will continue to repeat until interrupted.
|
||||
.TP
|
||||
.B \-\-headers \fIheader_list
|
||||
Specify which headers to display.
|
||||
.TP
|
||||
.B \-\-interval \fIinterval
|
||||
Specify the interval, in seconds, between successive iterations for
|
||||
repeating reports.
|
||||
.TP
|
||||
.B \-\-interval \fIseconds
|
||||
Specify the interval in seconds between successive iterations for
|
||||
repeating reports. If \-\-interval is specified but \-\-count is not,
|
||||
@@ -185,10 +190,10 @@ string is stored with the region. Subsequent operations may supply a
|
||||
program ID in order to select only regions with a matching value. The
|
||||
default program ID for dmstats-managed regions is "dmstats".
|
||||
.TP
|
||||
.BR \-S | \-\-select \ \fIselection
|
||||
Display only rows that match selection criteria. All rows with the
|
||||
.BR \-S | \-\-select \ \fISelection
|
||||
Display only rows that match Selection criteria. All rows with the
|
||||
additional "selected" column (-o selected) showing 1 if the row matches
|
||||
the selection and 0 otherwise. The selection criteria are defined by
|
||||
the Selection and 0 otherwise. The Selection criteria are defined by
|
||||
specifying column names and their valid values while making use of
|
||||
supported comparison operators.
|
||||
.TP
|
||||
@@ -199,11 +204,14 @@ optional suffix selects units of bBsSkKmMgGtTpPeE: (b)ytes,
|
||||
(p)etabytes, (e)xabytes. Capitalise to use multiples of 1000 (S.I.)
|
||||
instead of 1024.
|
||||
.TP
|
||||
.B \-\-segments
|
||||
.B \-\-targets
|
||||
Create a new statistics region for each target contained in the target
|
||||
device. This causes a separate region to be allocated for each segment
|
||||
of the device.
|
||||
.TP
|
||||
.B \-\-timestamps
|
||||
Output a timestamp before each statistics report.
|
||||
.TP
|
||||
.BR \-\-units \ hHbBsSkKmMgGtTpPeE
|
||||
Set the display units for report output. All sizes are output in these
|
||||
units: (h)uman-readable, (b)ytes, (s)ectors, (k)ilobytes, (m)egabytes,
|
||||
@@ -242,7 +250,7 @@ regions (with the exception of in-flight IO counters).
|
||||
.IR start_sector ]
|
||||
.RB [ \-\-length
|
||||
.IR length ]
|
||||
.RB |[ \-\-segments ]]
|
||||
.RB |[ \-\-targets ]]
|
||||
.RB [ \-\-auxdata
|
||||
.IR data ]
|
||||
.RB [ \-\-programid
|
||||
@@ -253,7 +261,7 @@ Creates one or more new statistics regions on the specified device(s).
|
||||
The region will span the entire device unless \fB\-\-start\fP and
|
||||
\fB\-\-length\fP or \fB\-\-target\fP are given. The \fB\-\-start\fP and
|
||||
\fB\-\-length\fP options allow a region of arbitrary length to be placed
|
||||
at an arbitrary offset into the device. The \fB\-\-segments\fP option
|
||||
at an arbitrary offset into the device. The \fB\-\-targets\fP option
|
||||
causes a new region to be created for each target in the corresponding
|
||||
device-mapper device's table.
|
||||
|
||||
@@ -272,7 +280,7 @@ stdout.
|
||||
.TP
|
||||
.B delete
|
||||
.I [ device_name ]
|
||||
.RB [ \-\-alldevices ]
|
||||
.RB [ \-\-force ]
|
||||
.RB [ \-\-allregions
|
||||
.RB | \-\-regionid
|
||||
.IR id ]
|
||||
@@ -287,8 +295,7 @@ of subsequent list, print, or report operations.
|
||||
All regions registered on a device may be removed using
|
||||
\fB\-\-allregions\fP.
|
||||
|
||||
To remove all regions on all devices both \fB--allregions\fP and
|
||||
\fB\-\-alldevices\fP must be used.
|
||||
To remove all regions on all devices \fB\-\-force\fP must be used.
|
||||
.br
|
||||
.TP
|
||||
.B help
|
||||
@@ -327,8 +334,11 @@ present regions.
|
||||
.RB [ \-\-allprograms ]
|
||||
.RB [ \-\-interval
|
||||
.IR seconds ]
|
||||
.RB [ \-\-headers
|
||||
.IR headers ]
|
||||
.RB [ \-\-count
|
||||
.IR count ]
|
||||
.RB [ \-\-timestamps ]
|
||||
.RB [ \-\-units
|
||||
.IR unit ]
|
||||
.RB [ \-\-regionid
|
||||
@@ -349,6 +359,10 @@ one second.
|
||||
|
||||
If the \fB\-\-allprograms\fP switch is given, all regions will be
|
||||
listed, regardless of region program ID values.
|
||||
|
||||
A header row is optionally printed before each statistics report is
|
||||
displayed. The list of headers to include is specified using the
|
||||
\fB\-\-headers\fP option.
|
||||
.br
|
||||
.SH REGIONS AND AREAS
|
||||
The device-mapper statistics facility allows separate performance
|
||||
@@ -373,7 +387,7 @@ reference the region in subsequent operations. Region identifiers are
|
||||
unique within a given device (including across different \fBprogram_id\fP
|
||||
values).
|
||||
.br
|
||||
Depending on the sequence of create and delete operations, gaps may
|
||||
Depending on the sequence of create and delete operations gaps, may
|
||||
exist in the sequence of \fBregion_id\fP values for a particular device.
|
||||
|
||||
.SH REPORT FIELDS
|
||||
@@ -410,7 +424,6 @@ Write requests per second.
|
||||
Sectors read per second.
|
||||
.HP
|
||||
.B wsec
|
||||
.br
|
||||
Sectors written per second.
|
||||
.HP
|
||||
.B arqsz
|
||||
@@ -438,7 +451,6 @@ The average wait time for write requests.
|
||||
The device throughput in requests per second.
|
||||
.HP
|
||||
.B svctm
|
||||
.br
|
||||
The average service time (in milliseconds) for I/O requests that
|
||||
were issued to the device.
|
||||
.HP
|
||||
@@ -451,7 +463,7 @@ when this value is close to 100%.
|
||||
.SS Region and area meta fields
|
||||
Meta fields provide information about the region or area that the
|
||||
statistics values relate to. This includes the region and area
|
||||
identifier, start, length, and counts, as well as the program ID and
|
||||
identifier, start, length, and counts as well as the program ID and
|
||||
auxiliary data values.
|
||||
.br
|
||||
.HP
|
||||
@@ -490,7 +502,6 @@ The area start sector in units of 512 byte sectors.
|
||||
The length of the area in units of 512 byte sectors.
|
||||
.HP
|
||||
.B area_count
|
||||
.br
|
||||
The number of areas in this region.
|
||||
.HP
|
||||
.B program_id
|
||||
@@ -501,20 +512,6 @@ The program ID value associated with this region.
|
||||
.br
|
||||
The auxiliary data value associated with this region.
|
||||
.br
|
||||
.HP
|
||||
.B interval_ns
|
||||
.br
|
||||
The estimated interval over which the current counter values have
|
||||
accumulated. The vaulue is reported as an interger expressed in units
|
||||
of nanoseconds.
|
||||
.br
|
||||
.HP
|
||||
.B interval
|
||||
.br
|
||||
The estimated interval over which the current counter values have
|
||||
accumulated. The value is reported as a real number in units of
|
||||
seconds.
|
||||
.br
|
||||
.SS Basic counters
|
||||
Basic counters provide access to the raw counter data from the kernel,
|
||||
allowing further processing to be carried out by another program.
|
||||
@@ -572,18 +569,18 @@ The number of nanoseconds spent reading and writing.
|
||||
.B weighted_io_nsecs
|
||||
.br
|
||||
This field is incremented at each I/O start, I/O completion, I/O merge,
|
||||
or read of these stats by the number of I/Os in progress multiplied by
|
||||
the number of milliseconds spent doing I/O since the last update of this
|
||||
or read of these stats by the number of I/Os in progress times the
|
||||
number of milliseconds spent doing I/O since the last update of this
|
||||
field. This can provide an easy measure of both I/O completion time and
|
||||
the backlog that may be accumulating.
|
||||
.br
|
||||
.br
|
||||
.P
|
||||
.SH EXAMPLES
|
||||
Create a whole-device region with one area on vg00/lvol1
|
||||
Create a whole-device region with one area on vg_hex-lv_root
|
||||
.br
|
||||
.br
|
||||
# dmstats create vg00/lvol1
|
||||
# dmstats create vg_hex-lv_root
|
||||
.br
|
||||
Created region: 0
|
||||
.br
|
||||
@@ -621,31 +618,31 @@ Created region: 0
|
||||
Delete all regions on all devices
|
||||
.br
|
||||
.br
|
||||
# dmstats delete --alldevices --allregions
|
||||
# dmstats delete --allregions --force
|
||||
.br
|
||||
.br
|
||||
|
||||
Create a whole-device region with areas 10GiB in size on vg00/lvol1
|
||||
Create a whole-device region with areas 10GiB in size on vg_hex-lv_root
|
||||
using dmsetup
|
||||
.br
|
||||
.br
|
||||
# dmsetup stats create --areasize 10G vg00/lvol1
|
||||
# dmsetup stats create --areasize 10G vg_hex-lv_root
|
||||
.br
|
||||
Created region: 1
|
||||
.br
|
||||
.br
|
||||
|
||||
Create a 1GiB region with 16 areas at the start of vg00/lvol1
|
||||
Create a 1GiB region with 16 areas at the start of vg_hex-lv_root
|
||||
.br
|
||||
# dmstats create --start 0 --len 1G --areas=16 vg00/lvol1
|
||||
# dmstats create --start 0 --len 1G --areas=16 vg_hex-lv_root
|
||||
.br
|
||||
Created region: 2
|
||||
.br
|
||||
.br
|
||||
|
||||
List the statistics regions registered on vg00/lvol1
|
||||
List the statistics regions registered on vg_hex-lv_root
|
||||
.br
|
||||
# dmstats list vg00/lvol1
|
||||
# dmstats list vg_hex-lv_root
|
||||
.br
|
||||
RegionID RegStart RegLen AreaSize ProgramID AuxData
|
||||
.br
|
||||
@@ -657,31 +654,33 @@ RegionID RegStart RegLen AreaSize ProgramID AuxData
|
||||
.br
|
||||
.br
|
||||
|
||||
Display five statistics reports for vg00/lvol1 at an interval of one second
|
||||
Display five statistics reports, with timestamps, for vg_hex-lv_root at an interval of one second
|
||||
.br
|
||||
.br
|
||||
# dmstats report --interval 1 --count 5 vg00/lvol1
|
||||
# dmstats report --time --interval 1 --count 5
|
||||
.br
|
||||
21/07/15 21:04:26
|
||||
.br
|
||||
Name RgID ArID RRqM/s WRqM/s R/s W/s RSz/s WSz/s AvRqSz QSize SvcTm Util% AWait
|
||||
.br
|
||||
vg00-lvol1 0 0 0.00 0.00 8.00 0.00 48.00k 0 6.00k 0.00 5.50 4.40 6.62
|
||||
vg_hex-lv_root 0 0 0.00 0.00 8.00 0.00 48.00k 0 6.00k 0.00 5.50 4.40 6.62
|
||||
.br
|
||||
vg00-lvol1 0 1 0.00 0.00 22.00 0.00 624.00k 0 28.00k 0.00 5.23 11.50 5.36
|
||||
vg_hex-lv_root 0 1 0.00 0.00 22.00 0.00 624.00k 0 28.00k 0.00 5.23 11.50 5.36
|
||||
.br
|
||||
vg00-lvol1 0 2 0.00 0.00 353.00 0.00 1.84m 0 5.00k 0.00 1.34 47.40 1.33
|
||||
vg_hex-lv_root 0 2 0.00 0.00 353.00 0.00 1.84m 0 5.00k 0.00 1.34 47.40 1.33
|
||||
.br
|
||||
vg00-lvol1 0 3 0.00 0.00 73.00 0.00 592.00k 0 8.00k 0.00 2.10 15.30 2.10
|
||||
vg_hex-lv_root 0 3 0.00 0.00 73.00 0.00 592.00k 0 8.00k 0.00 2.10 15.30 2.10
|
||||
.br
|
||||
vg00-lvol1 0 4 0.00 0.00 5.00 0.00 52.00k 0 10.00k 0.00 4.00 2.00 4.00
|
||||
vg_hex-lv_root 0 4 0.00 0.00 5.00 0.00 52.00k 0 10.00k 0.00 4.00 2.00 4.00
|
||||
.br
|
||||
[...]
|
||||
.br
|
||||
.br
|
||||
|
||||
Create one region for reach target contained in device vg00/lvol1
|
||||
Create one region for reach target contained in device vg_hex-lv_home
|
||||
.br
|
||||
.br
|
||||
# dmstats create --segments vg00/lvol1
|
||||
# dmstats create --targets vg_hex-lv_home
|
||||
.br
|
||||
Created region: 0
|
||||
.br
|
||||
|
@@ -162,10 +162,6 @@ lvconvert \(em convert a logical volume from linear to mirror or snapshot
|
||||
.IR ChunkSize [ bBsSkKmMgG ]]
|
||||
.RB [ \-\-cachemode
|
||||
.RI { writeback | writethrough }]
|
||||
.RB [ \-\-cachepolicy
|
||||
.IR policy ]
|
||||
.RB [ \-\-cachesettings
|
||||
.IR key=value ]
|
||||
.RB [ \-\-poolmetadata
|
||||
.IR CachePoolMetadataLogicalVolume { Name | Path }
|
||||
|
|
||||
@@ -226,21 +222,10 @@ Converts logical volume to a cached LV with the use of cache pool
|
||||
specified with \fB\-\-cachepool\fP.
|
||||
For more information on cache pool LVs and cache LVs, see \fBlvmcache\fP(7).
|
||||
.TP
|
||||
.B \-\-cachepolicy \fIpolicy
|
||||
Only applicable to cached LVs; see also \fBlvmcache(7)\fP. Sets
|
||||
the cache policy. \fImq\fP is the basic policy name. \fIsqm\fP is more advanced
|
||||
version available in newer kernels.
|
||||
.TP
|
||||
.BR \-\-cachepool " " \fICachePoolLV
|
||||
This argument is necessary when converting a logical volume to a cache LV.
|
||||
For more information on cache pool LVs and cache LVs, see \fBlvmcache\fP(7).
|
||||
.TP
|
||||
.BR \-\-cachesettings " " \fIkey=value
|
||||
Only applicable to cached LVs; see also \fBlvmcache(7)\fP. Sets
|
||||
the cache tunable settings. In most use-cases, default values should be adequate.
|
||||
Special string value \fIdefault\fP switches setting back to its default kernel value
|
||||
and removes it from the list of settings stored in lvm2 metadata.
|
||||
.TP
|
||||
.BR \-m ", " \-\-mirrors " " \fIMirrors
|
||||
Specifies the degree of the mirror you wish to create.
|
||||
For example, "\fB\-m 1\fP" would convert the original logical
|
||||
@@ -511,7 +496,7 @@ See \fBlvmthin\fP(7) for more info about thin provisioning support.
|
||||
Uncaches \fICacheLogicalVolume\fP.
|
||||
Before the volume becomes uncached, cache is flushed.
|
||||
Unlike with \fB\-\-splitcache\fP the cache pool volume is removed.
|
||||
This option could be seen as an inverse of \fB\-\-cache\fP.
|
||||
This option could seen as an inverse of \fB\-\-cache\fP.
|
||||
|
||||
.SH Examples
|
||||
Converts the linear logical volume "vg00/lvol1" to a two-way mirror
|
||||
|
@@ -13,13 +13,13 @@ lvcreate \- create a logical volume in an existing volume group
|
||||
.RI { y | n }]
|
||||
.RB [ \-H | \-\-cache ]
|
||||
.RB [ \-\-cachemode
|
||||
.RI { passthrough | writeback | writethrough }]
|
||||
.RI { writeback | writethrough }]
|
||||
.RB [ \-\-cachepolicy
|
||||
.IR policy ]
|
||||
.RB [ \-\-cachepool
|
||||
.IR CachePoolLogicalVolume { Name | Path }
|
||||
.RB [ \-\-cachesettings
|
||||
.IR key=value ]
|
||||
.RB [ \-\-cachepool
|
||||
.IR CachePoolLogicalVolume { Name | Path }
|
||||
.RB [ \-c | \-\-chunksize
|
||||
.IR ChunkSize [ bBsSkKmMgG ]]
|
||||
.RB [ \-\-commandprofile
|
||||
@@ -188,7 +188,7 @@ See \fBlvmcache\fP(7) for more info about caching support.
|
||||
Note that the cache segment type requires a dm-cache kernel module version
|
||||
1.3.0 or greater.
|
||||
.TP
|
||||
.IR \fB\-\-cachemode " {" passthrough | writeback | writethrough }
|
||||
.IR \fB\-\-cachemode " {" writeback | writethrough }
|
||||
Specifying a cache mode determines when the writes to a cache LV
|
||||
are considered complete. When \fIwriteback\fP is specified, a write is
|
||||
considered complete as soon as it is stored in the cache pool LV.
|
||||
@@ -198,21 +198,10 @@ While \fIwritethrough\fP may be slower for writes, it is more
|
||||
resilient if something should happen to a device associated with the
|
||||
cache pool LV.
|
||||
.TP
|
||||
.B \-\-cachepolicy \fIpolicy
|
||||
Only applicable to cached LVs; see also \fBlvmcache(7)\fP. Sets
|
||||
the cache policy. \fImq\fP is the basic policy name. \fIsqm\fP is more advanced
|
||||
version available in newer kernels.
|
||||
.TP
|
||||
.IR \fB\-\-cachepool " " CachePoolLogicalVolume { Name | Path }
|
||||
Specifies the name of cache pool volume name. The other way to specify pool name
|
||||
is to append name to Volume group name argument.
|
||||
.TP
|
||||
.BR \-\-cachesettings " " \fIkey=value
|
||||
Only applicable to cached LVs; see also \fBlvmcache(7)\fP. Sets
|
||||
the cache tunable settings. In most use-cases, default values should be adequate.
|
||||
Special string value \fIdefault\fP switches setting back to its default kernel value
|
||||
and removes it from the list of settings stored in lvm2 metadata.
|
||||
.TP
|
||||
.BR \-c ", " \-\-chunksize " " \fIChunkSize [ \fIbBsSkKmMgG ]
|
||||
Gives the size of chunk for snapshot, cache pool and thin pool logical volumes.
|
||||
Default unit is in kilobytes.
|
||||
@@ -262,6 +251,11 @@ Ignore the flag to skip Logical Volumes during activation.
|
||||
Use \fB\-\-setactivationskip\fP option to set or reset
|
||||
activation skipping flag persistently for logical volume.
|
||||
.TP
|
||||
.BR \-\-cachepolicy " " policy ", " \-\-cachesettings " " key=value
|
||||
Only applicable to cached LVs; see also \fBlvmcache(7)\fP. Sets
|
||||
the cache policy and its associated tunable settings. In most use-cases,
|
||||
default values should be adequate.
|
||||
.TP
|
||||
.B \-\-ignoremonitoring
|
||||
Make no attempt to interact with dmeventd unless \fB\-\-monitor\fP
|
||||
is specified.
|
||||
|
@@ -261,11 +261,6 @@ It can be used to report or display a VG that is owned by another host.
|
||||
This option can cause a command to perform poorly because lvmetad caching
|
||||
is not used and metadata is read from disks.
|
||||
.TP
|
||||
.B \-\-shared
|
||||
Cause the command to access shared VGs, that would otherwise be skipped
|
||||
when lvmlockd is not being used. It can be used to report or display a
|
||||
lockd VG without locking.
|
||||
.TP
|
||||
.B \-\-addtag \fITag
|
||||
Add the tag \fITag\fP to a PV, VG or LV.
|
||||
Supply this argument multiple times to add more than one tag at once.
|
||||
|
@@ -16,7 +16,7 @@ origin LV to increase speed. The cache metadata LV holds the
|
||||
accounting information that specifies where data blocks are stored (e.g.
|
||||
on the origin LV or on the cache data LV). Users should be familiar with
|
||||
these LVs if they wish to create the best and most robust cached
|
||||
logical volumes. All of these associated LVs must be in the same VG.
|
||||
logical volumes.
|
||||
|
||||
.SH Cache Terms
|
||||
.nf
|
||||
|
@@ -8,75 +8,75 @@ LVM commands use lvmlockd to coordinate access to shared storage.
|
||||
.br
|
||||
When LVM is used on devices shared by multiple hosts, locks will:
|
||||
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
coordinate reading and writing of LVM metadata
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
validate caching of LVM metadata
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
prevent concurrent activation of logical volumes
|
||||
.br
|
||||
|
||||
.P
|
||||
|
||||
lvmlockd uses an external lock manager to perform basic locking.
|
||||
.br
|
||||
Lock manager (lock type) options are:
|
||||
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
sanlock: places locks on disk within LVM storage.
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
dlm: uses network communication and a cluster manager.
|
||||
.br
|
||||
|
||||
.P
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
lvmlockd [options]
|
||||
|
||||
For default settings, see lvmlockd \-h.
|
||||
For default settings, see lvmlockd -h.
|
||||
|
||||
.B \-\-help | \-h
|
||||
.B --help | -h
|
||||
Show this help information.
|
||||
|
||||
.B \-\-version | \-V
|
||||
.B --version | -V
|
||||
Show version of lvmlockd.
|
||||
|
||||
.B \-\-test | \-T
|
||||
.B --test | -T
|
||||
Test mode, do not call lock manager.
|
||||
|
||||
.B \-\-foreground | \-f
|
||||
.B --foreground | -f
|
||||
Don't fork.
|
||||
|
||||
.B \-\-daemon\-debug | \-D
|
||||
.B --daemon-debug | -D
|
||||
Don't fork and print debugging to stdout.
|
||||
|
||||
.B \-\-pid\-file | \-p
|
||||
.B --pid-file | -p
|
||||
.I path
|
||||
Set path to the pid file.
|
||||
|
||||
.B \-\-socket\-path | \-s
|
||||
.B --socket-path | -s
|
||||
.I path
|
||||
Set path to the socket to listen on.
|
||||
|
||||
.B \-\-syslog\-priority | \-S err|warning|debug
|
||||
.B --syslog-priority | -S err|warning|debug
|
||||
Write log messages from this level up to syslog.
|
||||
|
||||
.B \-\-gl\-type | \-g sanlock|dlm
|
||||
Set global lock type to be sanlock or dlm.
|
||||
.B --gl-type | -g
|
||||
.I str
|
||||
Set global lock type to be sanlock|dlm.
|
||||
|
||||
.B \-\-host\-id | \-i
|
||||
.B --host-id | -i
|
||||
.I num
|
||||
Set the local sanlock host id.
|
||||
|
||||
.B \-\-host\-id\-file | \-F
|
||||
.B --host-id-file | -F
|
||||
.I path
|
||||
A file containing the local sanlock host_id.
|
||||
|
||||
.B \-\-sanlock\-timeout | \-o
|
||||
.B --sanlock-timeout | -o
|
||||
.I seconds
|
||||
Override the default sanlock I/O timeout.
|
||||
|
||||
.B \-\-adopt | \-A 0|1
|
||||
.B --adopt | A 0|1
|
||||
Adopt locks from a previous instance of lvmlockd.
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ For default settings, see lvmlockd \-h.
|
||||
|
||||
.SS Initial set up
|
||||
|
||||
Using LVM with lvmlockd for the first time includes some one\-time set up
|
||||
Using LVM with lvmlockd for the first time includes some one-time set up
|
||||
steps:
|
||||
|
||||
.SS 1. choose a lock manager
|
||||
@@ -112,9 +112,9 @@ use_lvmetad = 1
|
||||
|
||||
.I sanlock
|
||||
.br
|
||||
Assign each host a unique host_id in the range 1\-2000 by setting
|
||||
Assign each host a unique host_id in the range 1-2000 by setting
|
||||
.br
|
||||
/etc/lvm/lvmlocal.conf local/host_id
|
||||
/etc/lvm/lvmlocal.conf local/host_id = <num>
|
||||
|
||||
.SS 3. start lvmlockd
|
||||
|
||||
@@ -132,32 +132,32 @@ Follow external clustering documentation when applicable, otherwise:
|
||||
.br
|
||||
systemctl start corosync dlm
|
||||
|
||||
.SS 5. create VG on shared devices
|
||||
.SS 5. create VGs on shared devices
|
||||
|
||||
vgcreate \-\-shared <vgname> <devices>
|
||||
vgcreate --shared <vg_name> <devices>
|
||||
|
||||
The shared option sets the VG lock type to sanlock or dlm depending on
|
||||
which lock manager is running. LVM commands will perform locking for the
|
||||
VG using lvmlockd.
|
||||
The vgcreate --shared option sets the VG lock type to sanlock or dlm
|
||||
depending on which lock manager is running. LVM commands will perform
|
||||
locking for the VG using lvmlockd.
|
||||
|
||||
.SS 6. start VG on all hosts
|
||||
.SS 6. start VGs on all hosts
|
||||
|
||||
vgchange \-\-lock\-start
|
||||
vgchange --lock-start
|
||||
|
||||
lvmlockd requires shared VGs to be started before they are used. This is
|
||||
a lock manager operation to start (join) the VG lockspace, and it may take
|
||||
some time. Until the start completes, locks for the VG are not available.
|
||||
LVM commands are allowed to read the VG while start is in progress. (An
|
||||
init/unit file can also be used to start VGs.)
|
||||
lvmlockd requires shared VGs to be "started" before they are used. This
|
||||
is a lock manager operation to start/join the VG lockspace, and it may
|
||||
take some time. Until the start completes, locks for the VG are not
|
||||
available. LVM commands are allowed to read the VG while start is in
|
||||
progress. (A service/init file can be used to start VGs.)
|
||||
|
||||
.SS 7. create and activate LVs
|
||||
|
||||
Standard lvcreate and lvchange commands are used to create and activate
|
||||
LVs in a shared VG.
|
||||
LVs in a lockd VG.
|
||||
|
||||
An LV activated exclusively on one host cannot be activated on another.
|
||||
When multiple hosts need to use the same LV concurrently, the LV can be
|
||||
activated with a shared lock (see lvchange options \-aey vs \-asy.)
|
||||
activated with a shared lock (see lvchange options -aey vs -asy.)
|
||||
(Shared locks are disallowed for certain LV types that cannot be used from
|
||||
multiple hosts.)
|
||||
|
||||
@@ -165,51 +165,43 @@ multiple hosts.)
|
||||
.SS Normal start up and shut down
|
||||
|
||||
After initial set up, start up and shut down include the following general
|
||||
steps. They can be performed manually or using the system service
|
||||
steps. They can be performed manually or using the system init/service
|
||||
manager.
|
||||
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
start lvmetad
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
start lvmlockd
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
start lock manager
|
||||
.br
|
||||
\[bu]
|
||||
vgchange \-\-lock\-start
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
vgchange --lock-start
|
||||
.IP \[bu] 2
|
||||
activate LVs in shared VGs
|
||||
.br
|
||||
|
||||
.P
|
||||
|
||||
The shut down sequence is the reverse:
|
||||
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
deactivate LVs in shared VGs
|
||||
.br
|
||||
\[bu]
|
||||
vgchange \-\-lock\-stop
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
vgchange --lock-stop
|
||||
.IP \[bu] 2
|
||||
stop lock manager
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
stop lvmlockd
|
||||
.br
|
||||
\[bu]
|
||||
.IP \[bu] 2
|
||||
stop lvmetad
|
||||
.br
|
||||
|
||||
.P
|
||||
|
||||
.SH TOPICS
|
||||
|
||||
.SS VG access control
|
||||
.SS locking terms
|
||||
|
||||
The following terms are used to describe different forms of VG access
|
||||
control.
|
||||
The following terms are used to distinguish VGs that require locking from
|
||||
those that do not.
|
||||
|
||||
.I "lockd VG"
|
||||
|
||||
@@ -218,19 +210,18 @@ Using it requires lvmlockd. These VGs exist on shared storage that is
|
||||
visible to multiple hosts. LVM commands use lvmlockd to perform locking
|
||||
for these VGs when they are used.
|
||||
|
||||
If the lock manager for the lock type is not available (e.g. not started
|
||||
or failed), lvmlockd is unable to acquire locks for LVM commands. LVM
|
||||
commands that only read the VG will generally be allowed to continue
|
||||
without locks in this case (with a warning). Commands to modify or
|
||||
activate the VG will fail without the necessary locks. Maintaining a
|
||||
properly running lock manager requires knowledge covered in separate
|
||||
documentation.
|
||||
If the lock manager for a lock type is not available (e.g. not started or
|
||||
failed), lvmlockd is not able to acquire locks from it, and LVM commands
|
||||
are unable to fully use VGs with the given lock type. Commands generally
|
||||
allow reading VGs in this condition, but changes and activation are not
|
||||
allowed. Maintaining a properly running lock manager can require
|
||||
background not covered here.
|
||||
|
||||
.I "local VG"
|
||||
|
||||
A "local VG" is meant to be used by a single host. It has no lock type or
|
||||
lock type "none". LVM commands and lvmlockd do not perform locking for
|
||||
these VGs. A local VG typically exists on local (non\-shared) devices and
|
||||
these VGs. A local VG typically exists on local (non-shared) devices and
|
||||
cannot be used concurrently from different hosts.
|
||||
|
||||
If a local VG does exist on shared devices, it should be owned by a single
|
||||
@@ -249,25 +240,21 @@ clvmd for clustering. See below for converting a clvm VG to a lockd VG.
|
||||
|
||||
.SS lockd VGs from hosts not using lvmlockd
|
||||
|
||||
Only hosts that use lockd VGs should be configured to run lvmlockd.
|
||||
Only hosts that will use lockd VGs should be configured to run lvmlockd.
|
||||
However, devices with lockd VGs may be visible from hosts not using
|
||||
lvmlockd. From a host not using lvmlockd, visible lockd VGs are ignored
|
||||
in the same way as foreign VGs, i.e. those with a foreign system ID, see
|
||||
.BR lvmsystemid (7).
|
||||
|
||||
The \-\-shared option for reporting and display commands causes lockd VGs
|
||||
to be displayed on a host not using lvmlockd, like the \-\-foreign option
|
||||
does for foreign VGs.
|
||||
The --shared option displays lockd VGs on a host not using lvmlockd, like
|
||||
the --foreign option does for foreign VGs.
|
||||
|
||||
|
||||
.SS vgcreate comparison
|
||||
.SS vgcreate differences
|
||||
|
||||
The type of VG access control is specified in the vgcreate command.
|
||||
See
|
||||
.BR vgcreate (8)
|
||||
for all vgcreate options.
|
||||
Forms of the vgcreate command:
|
||||
|
||||
.B vgcreate <vgname> <devices>
|
||||
.B vgcreate <vg_name> <devices>
|
||||
|
||||
.IP \[bu] 2
|
||||
Creates a local VG with the local system ID when neither lvmlockd nor clvm are configured.
|
||||
@@ -278,12 +265,11 @@ Creates a clvm VG when clvm is configured.
|
||||
|
||||
.P
|
||||
|
||||
.B vgcreate \-\-shared <vgname> <devices>
|
||||
.B vgcreate --shared <vg_name> <devices>
|
||||
.IP \[bu] 2
|
||||
Requires lvmlockd to be configured and running.
|
||||
Requires lvmlockd to be configured (use_lvmlockd=1).
|
||||
.IP \[bu] 2
|
||||
Creates a lockd VG with lock type sanlock|dlm depending on which lock
|
||||
manager is running.
|
||||
Creates a lockd VG with lock type sanlock|dlm depending on which is running.
|
||||
.IP \[bu] 2
|
||||
LVM commands request locks from lvmlockd to use the VG.
|
||||
.IP \[bu] 2
|
||||
@@ -291,9 +277,9 @@ lvmlockd obtains locks from the selected lock manager.
|
||||
|
||||
.P
|
||||
|
||||
.B vgcreate \-c|\-\-clustered y <vgname> <devices>
|
||||
.B vgcreate -c|--clustered y <vg_name> <devices>
|
||||
.IP \[bu] 2
|
||||
Requires clvm to be configured and running.
|
||||
Requires clvm to be configured (locking_type=3).
|
||||
.IP \[bu] 2
|
||||
Creates a clvm VG with the "clustered" flag.
|
||||
.IP \[bu] 2
|
||||
@@ -303,79 +289,62 @@ LVM commands request locks from clvmd to use the VG.
|
||||
|
||||
.SS using lockd VGs
|
||||
|
||||
There are some special considerations to be aware of when using lockd VGs.
|
||||
|
||||
When use_lvmlockd is first enabled, and before the first lockd VG is
|
||||
created, no global lock will exist. In this initial state, LVM commands
|
||||
try and fail to acquire the global lock, producing a warning, and some
|
||||
commands are disallowed. Once the first lockd VG is created, the global
|
||||
lock will be available, and LVM will be fully operational.
|
||||
created, no global lock will exist, and LVM commands will try and fail to
|
||||
acquire it. LVM commands will report a warning until the first lockd VG
|
||||
is created which will create the global lock. Before the global lock
|
||||
exists, VGs can still be read, but commands that require the global lock
|
||||
exclusively will fail.
|
||||
|
||||
When a new lockd VG is created, its lockspace is automatically started on
|
||||
the host that creates it. Other hosts need to run 'vgchange
|
||||
\-\-lock\-start' to start the new VG before they can use it.
|
||||
the host that creates the VG. Other hosts will need to run 'vgchange
|
||||
--lock-start' to start the new VG before they can use it.
|
||||
|
||||
From the 'vgs' command, lockd VGs are indicated by "s" (for shared) in the
|
||||
sixth attr field. The specific lock type and lock args for a lockd VG can
|
||||
be displayed with 'vgs \-o+locktype,lockargs'.
|
||||
|
||||
lockd VGs need to be "started" and "stopped", unlike other types of VGs.
|
||||
See the following section for a full description of starting and stopping.
|
||||
be displayed with 'vgs -o+locktype,lockargs'.
|
||||
|
||||
|
||||
.SS starting and stopping VGs
|
||||
|
||||
Starting a lockd VG (vgchange \-\-lock\-start) causes the lock manager to
|
||||
start (join) the lockspace for the VG on the host where it is run. This
|
||||
makes locks for the VG available to LVM commands on the host. Before a VG
|
||||
is started, only LVM commands that read/display the VG without locks are
|
||||
allowed.
|
||||
Starting a lockd VG (vgchange --lock-start) causes the lock manager to
|
||||
start or join the lockspace for the VG. This makes locks for the VG
|
||||
accessible to the host. Stopping the VG leaves the lockspace and makes
|
||||
locks for the VG inaccessible to the host.
|
||||
|
||||
Stopping a lockd VG (vgchange \-\-lock\-stop) causes the lock manager to
|
||||
stop (leave) the lockspace for the VG on the host where it is run. This
|
||||
makes locks for the VG inaccessible to the host. A VG cannot be stopped
|
||||
while it has active LVs.
|
||||
Lockspaces should be started as early as possible because starting
|
||||
(joining) a lockspace can take a long time (potentially minutes after a
|
||||
host failure when using sanlock.) A VG can be started after all the
|
||||
following are true:
|
||||
|
||||
When using the lock type sanlock, starting a VG can take a long time
|
||||
(potentially minutes if the host was previously shut down without cleanly
|
||||
stopping the VG.)
|
||||
|
||||
A lockd VG can be started after all the following are true:
|
||||
.br
|
||||
\[bu]
|
||||
lvmlockd is running
|
||||
.br
|
||||
\[bu]
|
||||
the lock manager is running
|
||||
.br
|
||||
\[bu]
|
||||
the VG is visible to the system
|
||||
.br
|
||||
|
||||
A lockd VG can be stopped if all LVs are deactivated.
|
||||
.nf
|
||||
- lvmlockd is running
|
||||
- lock manager is running
|
||||
- VG is visible to the system
|
||||
.fi
|
||||
|
||||
All lockd VGs can be started/stopped using:
|
||||
.br
|
||||
vgchange \-\-lock-start
|
||||
vgchange --lock-start
|
||||
.br
|
||||
vgchange \-\-lock-stop
|
||||
vgchange --lock-stop
|
||||
|
||||
|
||||
Individual VGs can be started/stopped using:
|
||||
.br
|
||||
vgchange \-\-lock\-start <vgname> ...
|
||||
vgchange --lock-start <vg_name> ...
|
||||
.br
|
||||
vgchange \-\-lock\-stop <vgname> ...
|
||||
vgchange --lock-stop <vg_name> ...
|
||||
|
||||
To make vgchange not wait for start to complete:
|
||||
.br
|
||||
vgchange \-\-lock\-start \-\-lock\-opt nowait
|
||||
vgchange --lock-start --lock-opt nowait
|
||||
.br
|
||||
vgchange \-\-lock\-start \-\-lock\-opt nowait <vgname>
|
||||
vgchange --lock-start --lock-opt nowait <vg_name>
|
||||
|
||||
To stop all lockspaces and wait for all to complete:
|
||||
.br
|
||||
lvmlockctl \-\-stop\-lockspaces \-\-wait
|
||||
lvmlockctl --stop-lockspaces --wait
|
||||
|
||||
To start only selected lockd VGs, use the lvm.conf
|
||||
activation/lock_start_list. When defined, only VG names in this list are
|
||||
@@ -397,7 +366,7 @@ Scripts or programs on a host that automatically start VGs will use the
|
||||
"auto" option to indicate that the command is being run automatically by
|
||||
the system:
|
||||
|
||||
vgchange \-\-lock\-start \-\-lock\-opt auto [<vgname> ...]
|
||||
vgchange --lock-start --lock-opt auto [vg_name ...]
|
||||
|
||||
Without any additional configuration, including the "auto" option has no
|
||||
effect; all VGs are started unless restricted by lock_start_list.
|
||||
@@ -418,25 +387,21 @@ To use auto activation of lockd LVs (see auto_activation_volume_list),
|
||||
auto starting of the corresponding lockd VGs is necessary.
|
||||
|
||||
|
||||
.SS internal command locking
|
||||
.SS locking activity
|
||||
|
||||
To optimize the use of LVM with lvmlockd, be aware of the three kinds of
|
||||
locks and when they are used:
|
||||
To optimize the use of LVM with lvmlockd, consider the three kinds of
|
||||
locks in lvmlockd and when they are used:
|
||||
|
||||
.I GL lock
|
||||
|
||||
The global lock (GL lock) is associated with global information, which is
|
||||
information not isolated to a single VG. This includes:
|
||||
|
||||
\[bu]
|
||||
The global VG namespace.
|
||||
- The global VG namespace.
|
||||
.br
|
||||
\[bu]
|
||||
The set of orphan PVs and unused devices.
|
||||
.br
|
||||
\[bu]
|
||||
The properties of orphan PVs, e.g. PV size.
|
||||
- The set of orphan PVs and unused devices.
|
||||
.br
|
||||
- The properties of orphan PVs, e.g. PV size.
|
||||
|
||||
The global lock is used in shared mode by commands that read this
|
||||
information, or in exclusive mode by commands that change it.
|
||||
@@ -449,7 +414,12 @@ creates a new VG name, and it takes a PV from the list of unused PVs.
|
||||
|
||||
When an LVM command is given a tag argument, or uses select, it must read
|
||||
all VGs to match the tag or selection, which causes the global lock to be
|
||||
acquired.
|
||||
acquired. To avoid use of the global lock, avoid using tags and select,
|
||||
and specify VG name arguments.
|
||||
|
||||
When use_lvmlockd is enabled, LVM commands attempt to acquire the global
|
||||
lock even if no lockd VGs exist. For this reason, lvmlockd should not be
|
||||
enabled unless lockd VGs will be used.
|
||||
|
||||
.I VG lock
|
||||
|
||||
@@ -462,7 +432,7 @@ The command 'vgs' will not only acquire the GL lock to read the list of
|
||||
all VG names, but will acquire the VG lock for each VG prior to reading
|
||||
it.
|
||||
|
||||
The command 'vgs <vgname>' does not acquire the GL lock (it does not need
|
||||
The command 'vgs <vg_name>' does not acquire the GL lock (it does not need
|
||||
the list of all VG names), but will acquire the VG lock on each VG name
|
||||
argument.
|
||||
|
||||
@@ -474,14 +444,14 @@ activated. LV locks are persistent and remain in place after the
|
||||
activation command is done. GL and VG locks are transient, and are held
|
||||
only while an LVM command is running.
|
||||
|
||||
.I lock retries
|
||||
.I retries
|
||||
|
||||
If a request for a GL or VG lock fails due to a lock conflict with another
|
||||
host, lvmlockd automatically retries for a short time before returning a
|
||||
failure to the LVM command. If those retries are insufficient, the LVM
|
||||
command will retry the entire lock request a number of times specified by
|
||||
global/lvmlockd_lock_retries before failing. If a request for an LV lock
|
||||
fails due to a lock conflict, the command fails immediately.
|
||||
failure to the LVM command. The LVM command will then retry the entire
|
||||
lock request a number of times specified by global/lvmlockd_lock_retries
|
||||
before failing. If a request for an LV lock fails due to a lock conflict,
|
||||
the command fails immediately.
|
||||
|
||||
|
||||
.SS sanlock global lock
|
||||
@@ -500,22 +470,21 @@ are moved or removed.
|
||||
|
||||
The vgcreate command typically acquires the global lock, but in the case
|
||||
of the first sanlock VG, there will be no global lock to acquire until the
|
||||
first vgcreate is complete. So, creating the first sanlock VG is a
|
||||
initial vgcreate is complete. So, creating the first sanlock VG is a
|
||||
special case that skips the global lock.
|
||||
|
||||
vgcreate for a sanlock VG determines it is the first one to exist if no
|
||||
other sanlock VGs are visible. It is possible that other sanlock VGs do
|
||||
exist but are not visible on the host running vgcreate. In this case,
|
||||
vgcreate would create a new sanlock VG with the global lock enabled. When
|
||||
the other VG containing a global lock appears, lvmlockd will see more than
|
||||
one VG with a global lock enabled, and LVM commands will report that there
|
||||
are duplicate global locks.
|
||||
exist but are not visible or started on the host running vgcreate. This
|
||||
raises the possibility of more than one global lock existing. If this
|
||||
happens, commands will warn of the condition, and it should be manually
|
||||
corrected.
|
||||
|
||||
If the situation arises where more than one sanlock VG contains a global
|
||||
lock, the global lock should be manually disabled in all but one of them
|
||||
with the command:
|
||||
|
||||
lvmlockctl \-\-gl\-disable <vgname>
|
||||
lvmlockctl --gl-disable <vg_name>
|
||||
|
||||
(The one VG with the global lock enabled must be visible to all hosts.)
|
||||
|
||||
@@ -525,18 +494,55 @@ and subsequent LVM commands will fail to acquire it. In this case, the
|
||||
global lock needs to be manually enabled in one of the remaining sanlock
|
||||
VGs with the command:
|
||||
|
||||
lvmlockctl \-\-gl\-enable <vgname>
|
||||
lvmlockctl --gl-enable <vg_name>
|
||||
|
||||
A small sanlock VG dedicated to holding the global lock can avoid the case
|
||||
where the GL lock must be manually enabled after a vgremove.
|
||||
|
||||
|
||||
.SS sanlock VG usage
|
||||
.SS changing a local VG to a lockd VG
|
||||
|
||||
There are some special cases related to using a sanlock VG.
|
||||
All LVs must be inactive to change the lock type.
|
||||
|
||||
lvmlockd must be configured and running as described in USAGE.
|
||||
|
||||
Change a local VG to a lockd VG with the command:
|
||||
.br
|
||||
vgchange \-\-lock\-type sanlock|dlm <vg_name>
|
||||
|
||||
Start the VG on any hosts that need to use it:
|
||||
.br
|
||||
vgchange \-\-lock\-start <vg_name>
|
||||
|
||||
|
||||
.SS changing a clvm VG to a lockd VG
|
||||
|
||||
All LVs must be inactive to change the lock type.
|
||||
|
||||
1. Change the clvm VG to a local VG.
|
||||
|
||||
Within a running clvm cluster, change a clvm VG to a local VG with the
|
||||
command:
|
||||
|
||||
vgchange \-cn <vg_name>
|
||||
|
||||
If the clvm cluster is no longer running on any nodes, then extra options
|
||||
can be used forcibly make the VG local. Caution: this is only safe if all
|
||||
nodes have stopped using the VG:
|
||||
|
||||
vgchange \-\-config 'global/locking_type=0 global/use_lvmlockd=0'
|
||||
.RS
|
||||
\-cn <vg_name>
|
||||
.RE
|
||||
|
||||
2. After the VG is local, follow the steps described in "changing a local
|
||||
VG to a lockd VG".
|
||||
|
||||
|
||||
.SS vgremove and vgreduce with sanlock VGs
|
||||
|
||||
vgremove of a sanlock VG will fail if other hosts have the VG started.
|
||||
Run vgchange \-\-lock-stop <vgname> on all other hosts before vgremove.
|
||||
Run vgchange --lock-stop <vg_name> on all other hosts before vgremove.
|
||||
|
||||
(It may take several seconds before vgremove recognizes that all hosts
|
||||
have stopped.)
|
||||
@@ -544,20 +550,17 @@ have stopped.)
|
||||
A sanlock VG contains a hidden LV called "lvmlock" that holds the sanlock
|
||||
locks. vgreduce cannot yet remove the PV holding the lvmlockd LV.
|
||||
|
||||
To place the lvmlock LV on a specific device, create the VG with only that
|
||||
device, then use vgextend to add other devices.
|
||||
|
||||
|
||||
.SS shared LVs
|
||||
|
||||
When an LV is used concurrently from multiple hosts (e.g. by a
|
||||
multi\-host/cluster application or file system), the LV can be activated
|
||||
on multiple hosts concurrently using a shared lock.
|
||||
multi-host/cluster application or file system), the LV can be activated on
|
||||
multiple hosts concurrently using a shared lock.
|
||||
|
||||
To activate the LV with a shared lock: lvchange \-asy vg/lv.
|
||||
To activate the LV with a shared lock: lvchange -asy vg/lv.
|
||||
|
||||
With lvmlockd, an unspecified activation mode is always exclusive, i.e.
|
||||
\-ay defaults to \-aey.
|
||||
-ay defaults to -aey.
|
||||
|
||||
If the LV type does not allow the LV to be used concurrently from multiple
|
||||
hosts, then a shared activation lock is not allowed and the lvchange
|
||||
@@ -575,13 +578,57 @@ locks if the PV holding the locks is lost. Contact the LVM group for
|
||||
help with this process.
|
||||
|
||||
|
||||
.\" This is not clean or safe enough to suggest using without help.
|
||||
.\"
|
||||
.\" .SS recover from lost PV holding sanlock locks
|
||||
.\"
|
||||
.\" In a sanlock VG, the locks are stored on a PV within the VG. If this PV
|
||||
.\" is lost, the locks need to be reconstructed as follows:
|
||||
.\"
|
||||
.\" 1. Enable the unsafe lock modes option in lvm.conf so that default locking requirements can be overriden.
|
||||
.\"
|
||||
.\" .nf
|
||||
.\" allow_override_lock_modes = 1
|
||||
.\" .fi
|
||||
.\"
|
||||
.\" 2. Remove missing PVs and partial LVs from the VG.
|
||||
.\"
|
||||
.\" Warning: this is a dangerous operation. Read the man page
|
||||
.\" for vgreduce first, and try running with the test option.
|
||||
.\" Verify that the only missing PV is the PV holding the sanlock locks.
|
||||
.\"
|
||||
.\" .nf
|
||||
.\" vgreduce --removemissing --force --lock-gl na --lock-vg na <vg>
|
||||
.\" .fi
|
||||
.\"
|
||||
.\" 3. If step 2 does not remove the internal/hidden "lvmlock" lv, it should be removed.
|
||||
.\"
|
||||
.\" .nf
|
||||
.\" lvremove --lock-vg na --lock-lv na <vg>/lvmlock
|
||||
.\" .fi
|
||||
.\"
|
||||
.\" 4. Change the lock type to none.
|
||||
.\"
|
||||
.\" .nf
|
||||
.\" vgchange --lock-type none --force --lock-gl na --lock-vg na <vg>
|
||||
.\" .fi
|
||||
.\"
|
||||
.\" 5. VG space is needed to recreate the locks. If there is not enough space, vgextend the vg.
|
||||
.\"
|
||||
.\" 6. Change the lock type back to sanlock. This creates a new internal
|
||||
.\" lvmlock lv, and recreates locks.
|
||||
.\"
|
||||
.\" .nf
|
||||
.\" vgchange --lock-type sanlock <vg>
|
||||
.\" .fi
|
||||
|
||||
.SS locking system failures
|
||||
|
||||
.B lvmlockd failure
|
||||
|
||||
If lvmlockd fails or is killed while holding locks, the locks are orphaned
|
||||
in the lock manager. lvmlockd can be restarted with an option to adopt
|
||||
locks in the lock manager that had been held by the previous instance.
|
||||
in the lock manager. lvmlockd can be restarted, and it will adopt the
|
||||
locks from the lock manager that had been held by the previous instance.
|
||||
|
||||
.B dlm/corosync failure
|
||||
|
||||
@@ -591,33 +638,37 @@ method configured within the dlm/corosync clustering environment.
|
||||
LVM commands on other hosts will be blocked from acquiring any locks until
|
||||
the dlm/corosync recovery process is complete.
|
||||
|
||||
.B sanlock lease storage failure
|
||||
.B sanlock lock storage failure
|
||||
|
||||
If a host loses access to the device holding a VG's locks, sanlock cannot
|
||||
renew the VG's lockspace lease for those locks. After some time, the
|
||||
lease will expire, and locks held by the host can be acquired by other
|
||||
hosts.
|
||||
If access to the device containing the VG's locks is lost, sanlock cannot
|
||||
renew its leases for locked LVs. This means that the host could soon lose
|
||||
the lease to another host which could activate the LV exclusively.
|
||||
sanlock is designed to never reach the point where two hosts hold the
|
||||
same lease exclusively at once, so the same LV should never be active on
|
||||
two hosts at once when activated exclusively.
|
||||
|
||||
If no LVs are active in the VG, the lockspace with an expiring lease will
|
||||
be shut down, and errors will be reported when trying to use the VG. Use
|
||||
the lvmlockctl \-\-drop command to clear the stale lockspace from
|
||||
lvmlockd.
|
||||
The current method of handling this involves no action from lvmlockd,
|
||||
which allows sanlock to protect the leases itself. This produces a safe
|
||||
but potentially inconvenient result. Doing nothing from lvmlockd leads to
|
||||
the host's LV locks not being released, which leads to sanlock using the
|
||||
local watchdog to reset the host before another host can acquire any locks
|
||||
held by the local host.
|
||||
|
||||
If the VG has active LVs, the LVs must be quickly deactivated before the
|
||||
lockspace lease expires. After all LVs are deactivated, run lvmlockctl
|
||||
\-\-drop <vgname> to clear the expiring lockspace from lvmlockd. If all
|
||||
LVs in the VG are not deactivated within about 40 seconds, sanlock will
|
||||
reset the host using the local watchdog. The host reset is ultimately a
|
||||
severe form of "deactivating" LVs before they can be activated on other
|
||||
hosts. The reset is considered a better alternative than having LVs used
|
||||
by multiple hosts at once, which could easily damage or destroy their
|
||||
content. A future enhancement may automatically attempt to deactivate LVs
|
||||
before the lockspace lease expires.
|
||||
LVM commands on other hosts will be blocked from acquiring locks held by
|
||||
the failed/reset host until the sanlock recovery time expires (2-4
|
||||
minutes). This includes activation of any LVs that were locked by the
|
||||
failed host. It also includes GL/VG locks held by any LVM commands that
|
||||
happened to be running on the failed host at the time of the failure.
|
||||
|
||||
(In the future, lvmlockd may have the option to suspend locked LVs in
|
||||
response the sanlock leases expiring. This would avoid the need for
|
||||
sanlock to reset the host.)
|
||||
|
||||
.B sanlock daemon failure
|
||||
|
||||
If the sanlock daemon fails or exits while a lockspace is started, the
|
||||
local watchdog will reset the host.
|
||||
local watchdog will reset the host. See previous section for the impact
|
||||
on other hosts.
|
||||
|
||||
|
||||
.SS changing dlm cluster name
|
||||
@@ -637,84 +688,44 @@ cluster name for the dlm VG must be changed. To do this:
|
||||
|
||||
3. Change the VG lock type to none:
|
||||
.br
|
||||
vgchange \-\-lock\-type none \-\-force <vgname>
|
||||
vgchange --lock-type none --force <vg_name>
|
||||
|
||||
4. Change the VG lock type back to dlm which sets the new cluster name:
|
||||
.br
|
||||
vgchange \-\-lock\-type dlm <vgname>
|
||||
vgchange --lock-type dlm <vg_name>
|
||||
|
||||
|
||||
.SS changing a local VG to a lockd VG
|
||||
|
||||
All LVs must be inactive to change the lock type.
|
||||
|
||||
lvmlockd must be configured and running as described in USAGE.
|
||||
|
||||
Change a local VG to a lockd VG with the command:
|
||||
.br
|
||||
vgchange \-\-lock\-type sanlock|dlm <vgname>
|
||||
|
||||
Start the VG on any hosts that need to use it:
|
||||
.br
|
||||
vgchange \-\-lock\-start <vgname>
|
||||
|
||||
|
||||
.SS changing a clvm VG to a lockd VG
|
||||
|
||||
All LVs must be inactive to change the lock type.
|
||||
|
||||
First change the clvm VG to a local VG. Within a running clvm cluster,
|
||||
change a clvm VG to a local VG with the command:
|
||||
|
||||
vgchange \-cn <vgname>
|
||||
|
||||
If the clvm cluster is no longer running on any nodes, then extra options
|
||||
can be used forcibly make the VG local. Caution: this is only safe if all
|
||||
nodes have stopped using the VG:
|
||||
|
||||
vgchange \-\-config 'global/locking_type=0 global/use_lvmlockd=0'
|
||||
.RS
|
||||
\-cn <vgname>
|
||||
.RE
|
||||
|
||||
After the VG is local, follow the steps described in "changing a local VG
|
||||
to a lockd VG".
|
||||
|
||||
|
||||
.SS limitations of lockd VGs
|
||||
.SS limitations of lvmlockd and lockd VGs
|
||||
|
||||
lvmlockd currently requires using lvmetad and lvmpolld.
|
||||
|
||||
If a lockd VG becomes visible after the initial system startup, it is not
|
||||
automatically started through the system service/init manager, and LVs in
|
||||
it are not autoactivated.
|
||||
|
||||
Things that do not yet work in lockd VGs:
|
||||
.br
|
||||
\[bu]
|
||||
creating a new thin pool and a new thin LV in a single command
|
||||
- creating a new thin pool and a new thin LV in a single command
|
||||
.br
|
||||
\[bu]
|
||||
using lvcreate to create cache pools or cache LVs (use lvconvert)
|
||||
- using lvcreate to create cache pools or cache LVs (use lvconvert)
|
||||
.br
|
||||
\[bu]
|
||||
using external origins for thin LVs
|
||||
- using external origins for thin LVs
|
||||
.br
|
||||
\[bu]
|
||||
splitting mirrors and snapshots from LVs
|
||||
- splitting mirrors and snapshots from LVs
|
||||
.br
|
||||
\[bu]
|
||||
vgsplit
|
||||
- vgsplit
|
||||
.br
|
||||
\[bu]
|
||||
vgmerge
|
||||
- vgmerge
|
||||
.br
|
||||
\[bu]
|
||||
resizing an LV that is active in the shared mode on multiple hosts
|
||||
- resizing an LV that is active in the shared mode on multiple hosts
|
||||
|
||||
|
||||
.SS lvmlockd changes from clvmd
|
||||
.SS clvmd to lvmlockd transition
|
||||
|
||||
(See above for converting an existing clvm VG to a lockd VG.)
|
||||
|
||||
While lvmlockd and clvmd are entirely different systems, LVM command usage
|
||||
remains similar. Differences are more notable when using lvmlockd's
|
||||
While lvmlockd and clvmd are entirely different systems, LVM usage remains
|
||||
largely the same. Differences are more notable when using lvmlockd's
|
||||
sanlock option.
|
||||
|
||||
Visible usage differences between lockd VGs with lvmlockd and clvm VGs
|
||||
@@ -725,16 +736,19 @@ lvm.conf must be configured to use either lvmlockd (use_lvmlockd=1) or
|
||||
clvmd (locking_type=3), but not both.
|
||||
|
||||
.IP \[bu] 2
|
||||
vgcreate \-\-shared creates a lockd VG, and vgcreate \-\-clustered y
|
||||
creates a clvm VG.
|
||||
vgcreate --shared creates a lockd VG, and vgcreate --clustered y creates a
|
||||
clvm VG.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmlockd adds the option of using sanlock for locking, avoiding the
|
||||
need for network clustering.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmlockd does not require all hosts to see all the same shared devices.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmlockd defaults to the exclusive activation mode whenever the activation
|
||||
mode is unspecified, i.e. \-ay means \-aey, not \-asy.
|
||||
mode is unspecified, i.e. -ay means -aey, not -asy.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmlockd commands always apply to the local host, and never have an effect
|
||||
@@ -748,13 +762,13 @@ lvmlockd saves the cluster name for a lockd VG using dlm. Only hosts in
|
||||
the matching cluster can use the VG.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmlockd requires starting/stopping lockd VGs with vgchange \-\-lock-start
|
||||
and \-\-lock-stop.
|
||||
lvmlockd requires starting/stopping lockd VGs with vgchange --lock-start
|
||||
and --lock-stop.
|
||||
|
||||
.IP \[bu] 2
|
||||
vgremove of a sanlock VG may fail indicating that all hosts have not
|
||||
stopped the VG lockspace. Stop the VG on all hosts using vgchange
|
||||
\-\-lock-stop.
|
||||
stopped the lockspace for the VG. Stop the VG lockspace on all uses using
|
||||
vgchange --lock-stop.
|
||||
|
||||
.IP \[bu] 2
|
||||
vgreduce of a PV in a sanlock VG may fail if it holds the internal
|
||||
@@ -763,15 +777,12 @@ vgreduce of a PV in a sanlock VG may fail if it holds the internal
|
||||
.IP \[bu] 2
|
||||
lvmlockd uses lock retries instead of lock queueing, so high lock
|
||||
contention may require increasing global/lvmlockd_lock_retries to
|
||||
avoid transient lock failures.
|
||||
avoid transient lock contention failures.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmlockd includes VG reporting options lock_type and lock_args, and LV
|
||||
reporting option lock_args to view the corresponding metadata fields.
|
||||
|
||||
.IP \[bu] 2
|
||||
In the 'vgs' command's sixth VG attr field, "s" for "shared" is displayed
|
||||
for lockd VGs.
|
||||
The reporting options locktype and lockargs can be used to view lockd VG
|
||||
and LV lock_type and lock_args fields, i.g. vgs -o+locktype,lockargs.
|
||||
In the sixth VG attr field, "s" for "shared" is displayed for lockd VGs.
|
||||
|
||||
.IP \[bu] 2
|
||||
If lvmlockd fails or is killed while in use, locks it held remain but are
|
||||
|
@@ -34,10 +34,6 @@ vgchange \(em change attributes of a volume group
|
||||
.RB [ \-\-ignoreskippedcluster ]
|
||||
.RB [ \-\-sysinit ]
|
||||
.RB [ \-\-noudevsync ]
|
||||
.RB [ \-\-lock\-start ]
|
||||
.RB [ \-\-lock\-stop ]
|
||||
.RB [ \-\-lock\-type
|
||||
.IR LockType ]
|
||||
.RB [ \-l | \-\-logicalvolume
|
||||
.IR MaxLogicalVolumes ]
|
||||
.RB [ \-p | \-\-maxphysicalvolumes
|
||||
@@ -131,30 +127,6 @@ LVs with snapshots are always activated exclusively because they can only
|
||||
be used on one node at once.
|
||||
|
||||
For local VGs, \-ay, \-aey, and \-asy are all equivalent.
|
||||
.IP
|
||||
In a shared VG, lvmlockd is used for locking, and the following options
|
||||
are possible:
|
||||
|
||||
With \-aey, the command activates the LV in exclusive mode, allowing a
|
||||
single host to activate the LV (the host running the command). Before
|
||||
activating the LV, the command uses lvmlockd to acquire an exclusive lock
|
||||
on the LV. If the lock cannot be acquired, the LV is not activated and an
|
||||
error is reported. This would happen if the LV is active on another host.
|
||||
|
||||
With \-asy, the command activates the LV in shared mode, allowing multiple
|
||||
hosts to activate the LV concurrently. Before activating the LV, the
|
||||
command uses lvmlockd to acquire a shared lock on the LV. If the lock
|
||||
cannot be acquired, the LV is not activated and an error is reported.
|
||||
This would happen if the LV is active exclusively on another host. If the
|
||||
LV type prohibits shared access, such as a snapshot, the command will
|
||||
report an error and fail.
|
||||
|
||||
With \-an, the command deactivates the LV on the host running the command.
|
||||
After deactivating the LV, the command uses lvmlockd to release the
|
||||
current lock on the LV.
|
||||
|
||||
With lvmlockd, an unspecified mode is always exclusive, \-ay defaults to
|
||||
\-aey.
|
||||
|
||||
.TP
|
||||
.BR \-\-activationmode " {" \fIcomplete | \fIdegraded | \fIpartial }
|
||||
@@ -241,20 +213,6 @@ Make no attempt to interact with dmeventd unless
|
||||
is specified.
|
||||
Do not use this if dmeventd is already monitoring a device.
|
||||
.TP
|
||||
.BR \-\-lock\-start
|
||||
Start the lockspace of a shared VG in lvmlockd. lvmlockd locks becomes
|
||||
available for the VG, allowing LVM to use the VG. See
|
||||
.BR lvmlockd (8).
|
||||
.TP
|
||||
.BR \-\-lock\-stop
|
||||
Stop the lockspace of a shared VG in lvmlockd. lvmlockd locks become
|
||||
unavailable for the VG, preventing LVM from using the VG. See
|
||||
.BR lvmlockd (8).
|
||||
.TP
|
||||
.BR \-\-lock\-type " " \fILockType
|
||||
Change the VG lock type to or from a shared lock type used with lvmlockd. See
|
||||
.BR lvmlockd (8).
|
||||
.TP
|
||||
.BR \-l ", " \-\-logicalvolume " " \fIMaxLogicalVolumes
|
||||
Changes the maximum logical volume number of an existing inactive
|
||||
volume group.
|
||||
|
@@ -27,7 +27,6 @@ vgcreate \(em create a volume group
|
||||
.IR NumberOfCopies | unmanaged | all ]
|
||||
.RB [ \-s | \-\-physicalextentsize
|
||||
.IR PhysicalExtentSize [ bBsSkKmMgGtTpPeE ]]
|
||||
.RB [ \-\-shared ]
|
||||
.RB [ \-\-systemid
|
||||
.IR SystemID ]
|
||||
.RB [ \-t | \-\-test ]
|
||||
@@ -128,13 +127,6 @@ impact on I/O performance to the logical volume. The smallest PE is 1KiB
|
||||
|
||||
The 2.4 kernel has a limitation of 2TiB per block device.
|
||||
|
||||
.TP
|
||||
.B \-\-shared
|
||||
Create a shared VG using lvmlockd. lvmlockd will select lock type sanlock
|
||||
or dlm depending on which lock manager is running. This allows multiple
|
||||
hosts to share a VG on shared devices. See
|
||||
.BR lvmlockd (8).
|
||||
|
||||
.TP
|
||||
.BR \-\-systemid " " \fISystemID
|
||||
Specifies the system ID that will be given to the new VG, overriding the
|
||||
|
@@ -20,8 +20,6 @@ You can then move all the Physical Volumes in that Volume Group to
|
||||
a different system for later
|
||||
.BR vgimport (8).
|
||||
Most LVM2 tools ignore exported Volume Groups.
|
||||
vgexport clears the VG system ID, and vgimport sets the VG system ID
|
||||
to match the host running vgimport (if the host has a system ID).
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP(8) for common options.
|
||||
.TP
|
||||
@@ -31,5 +29,4 @@ Export all inactive Volume Groups.
|
||||
.BR lvm (8),
|
||||
.BR pvscan (8),
|
||||
.BR vgimport (8),
|
||||
.BR vgscan (8),
|
||||
.BR lvmsystemid (7)
|
||||
.BR vgscan (8)
|
||||
|
@@ -16,8 +16,6 @@ exported using
|
||||
.BR vgexport (8)
|
||||
known to the system again, perhaps after moving its Physical Volumes
|
||||
from a different machine.
|
||||
vgexport clears the VG system ID, and vgimport sets the VG system ID
|
||||
to match the host running vgimport (if the host has a system ID).
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP(8) for common options.
|
||||
.TP
|
||||
@@ -32,5 +30,4 @@ failed and they cannot be restored.
|
||||
.BR lvm (8),
|
||||
.BR pvscan (8),
|
||||
.BR vgexport (8),
|
||||
.BR vgscan (8),
|
||||
.BR lvmsystemid (7)
|
||||
.BR vgscan (8)
|
||||
|
@@ -93,7 +93,7 @@ are missing from the system
|
||||
.IP 5 3
|
||||
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere
|
||||
.IP 6 3
|
||||
(c)lustered, (s)hared
|
||||
(c)lustered
|
||||
.RE
|
||||
.TP
|
||||
.BR \-O ", " \-\-sort
|
||||
|
@@ -398,9 +398,7 @@ for the kernel device-mapper.
|
||||
%defattr(-,root,root,-)
|
||||
%doc COPYING COPYING.LIB WHATS_NEW_DM VERSION_DM README INSTALL
|
||||
%attr(755,root,root) %{_sbindir}/dmsetup
|
||||
%{_sbindir}/dmstats
|
||||
%{_mandir}/man8/dmsetup.8.gz
|
||||
%{_mandir}/man8/dmstats.8.gz
|
||||
%if %{enable_udev}
|
||||
%doc udev/12-dm-permissions.rules
|
||||
%dir %{_udevbasedir}
|
||||
|
@@ -199,8 +199,7 @@ install: .tests-stamp lib/paths-installed
|
||||
$(INSTALL_PROGRAM) api/*.{t,py} $(DATADIR)/api/
|
||||
$(INSTALL_DATA) lib/paths-installed $(DATADIR)/lib/paths
|
||||
$(INSTALL_DATA) $(LIB_FLAVOURS) $(DATADIR)/lib/
|
||||
for i in cache-mq cache-smq thin-performance ; do \
|
||||
$(INSTALL_DATA) $(abs_top_srcdir)/conf/$$i.profile $(DATADIR)/lib/$$i.profile; done
|
||||
$(INSTALL_DATA) $(abs_top_srcdir)/conf/thin-performance.profile $(DATADIR)/lib/thin-performance.profile
|
||||
$(INSTALL_SCRIPT) $(LIB_SHARED) $(DATADIR)/lib/
|
||||
for i in $(CMDS); do (cd $(DATADIR)/lib && $(LN_S) -f lvm-wrapper $$i); done
|
||||
|
||||
|
@@ -16,8 +16,6 @@ test -e LOCAL_LVMPOLLD && skip
|
||||
aux have_cache 1 3 0 || skip
|
||||
aux prepare_vg 3
|
||||
|
||||
aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
|
||||
|
||||
lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
|
||||
lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
|
||||
lvcreate -n noncache -l 1 $vg
|
||||
|
@@ -18,8 +18,6 @@ test -e LOCAL_LVMPOLLD && skip
|
||||
aux have_cache 1 3 0 || skip
|
||||
aux have_raid 1 0 0 || skip
|
||||
|
||||
aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
|
||||
|
||||
aux prepare_vg 5 80
|
||||
|
||||
# Bug 1095843
|
||||
|
@@ -23,7 +23,6 @@ aux have_cache 1 3 0 || skip
|
||||
# FIXME: parallel cache metadata allocator is crashing when used value 8000!
|
||||
aux prepare_vg 5 80000
|
||||
|
||||
aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
|
||||
|
||||
#######################
|
||||
# Cache_Pool creation #
|
||||
|
@@ -204,11 +204,9 @@ install_tools_static: lvm.static
|
||||
|
||||
install_dmsetup_dynamic: dmsetup
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
$(LN_S) -f $(<F) $(sbindir)/dmstats
|
||||
|
||||
install_dmsetup_static: dmsetup.static
|
||||
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
|
||||
$(LN_S) -f $(<F) $(sbindir)/dmstats
|
||||
|
||||
install_device-mapper: $(INSTALL_DMSETUP_TARGETS)
|
||||
|
||||
|
1671
tools/dmsetup.c
1671
tools/dmsetup.c
File diff suppressed because it is too large
Load Diff
@@ -690,9 +690,9 @@ static int _lvchange_cachepolicy(struct cmd_context *cmd, struct logical_volume
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!get_cache_params(cmd, NULL, &name, &settings))
|
||||
if (!get_cache_policy_params(cmd, &name, &settings))
|
||||
goto_out;
|
||||
if (!cache_set_policy(first_seg(lv), name, settings))
|
||||
if (!lv_cache_set_policy(lv, name, settings))
|
||||
goto_out;
|
||||
if (!lv_update_and_reload(lv))
|
||||
goto_out;
|
||||
@@ -1296,9 +1296,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
*/
|
||||
if (arg_count(cmd, activate_ARG) || arg_count(cmd, refresh_ARG)) {
|
||||
cmd->lockd_vg_default_sh = 1;
|
||||
/* Allow deactivating if locks fail. */
|
||||
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv,
|
||||
|
@@ -50,7 +50,7 @@ struct lvconvert_params {
|
||||
uint32_t stripes;
|
||||
uint32_t stripe_size;
|
||||
uint32_t read_ahead;
|
||||
const char *cache_mode; /* cache */
|
||||
uint64_t feature_flags; /* cache_pool */
|
||||
const char *policy_name; /* cache */
|
||||
struct dm_config_tree *policy_settings; /* cache */
|
||||
|
||||
@@ -299,14 +299,26 @@ static int _read_pool_params(struct cmd_context *cmd, int *pargc, char ***pargv,
|
||||
} else if (!strcmp(type_str, "thin-pool"))
|
||||
thinpool = 1;
|
||||
|
||||
if (lp->cache && !cachepool) {
|
||||
log_error("--cache requires --cachepool.");
|
||||
return 0;
|
||||
}
|
||||
if ((lp->cache || cachepool) &&
|
||||
!get_cache_params(cmd, &lp->cache_mode, &lp->policy_name, &lp->policy_settings)) {
|
||||
log_error("Failed to parse cache policy and/or settings.");
|
||||
return 0;
|
||||
if (cachepool) {
|
||||
const char *cachemode = arg_str_value(cmd, cachemode_ARG, NULL);
|
||||
if (!cachemode)
|
||||
cachemode = find_config_tree_str(cmd, allocation_cache_pool_cachemode_CFG, NULL);
|
||||
|
||||
if (!set_cache_pool_feature(&lp->feature_flags, cachemode))
|
||||
return_0;
|
||||
|
||||
if (!get_cache_policy_params(cmd, &lp->policy_name, &lp->policy_settings)) {
|
||||
log_error("Failed to parse cache policy and/or settings.");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (arg_from_list_is_set(cmd, "is valid only with cache pools",
|
||||
cachepool_ARG, cachemode_ARG, -1))
|
||||
return_0;
|
||||
if (lp->cache) {
|
||||
log_error("--cache requires --cachepool.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (thinpool) {
|
||||
@@ -3068,9 +3080,10 @@ mda_write:
|
||||
seg->chunk_size = lp->chunk_size;
|
||||
seg->discards = lp->discards;
|
||||
seg->zero_new_blocks = lp->zero ? 1 : 0;
|
||||
seg->feature_flags = lp->feature_flags; /* cache-pool */
|
||||
|
||||
if ((lp->policy_name || lp->policy_settings) &&
|
||||
!cache_set_policy(seg, lp->policy_name, lp->policy_settings))
|
||||
!lv_cache_set_policy(seg->lv, lp->policy_name, lp->policy_settings))
|
||||
return_0;
|
||||
|
||||
/* Rename deactivated metadata LV to have _tmeta suffix */
|
||||
@@ -3178,12 +3191,6 @@ static int _lvconvert_cache(struct cmd_context *cmd,
|
||||
if (!(cache_lv = lv_cache_create(pool_lv, origin_lv)))
|
||||
return_0;
|
||||
|
||||
if (!cache_set_mode(first_seg(cache_lv), lp->cache_mode))
|
||||
return_0;
|
||||
|
||||
if (!cache_set_policy(first_seg(cache_lv), lp->policy_name, lp->policy_settings))
|
||||
return_0;
|
||||
|
||||
if (!lv_update_and_reload(cache_lv))
|
||||
return_0;
|
||||
|
||||
@@ -3420,12 +3427,14 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
|
||||
}
|
||||
|
||||
/*
|
||||
* Request a transient lock. If the LV is active, it has a persistent
|
||||
* lock already, and this request does nothing. If the LV is not
|
||||
* active, this acquires a transient lock that will be released when
|
||||
* the command exits.
|
||||
* If the lv is inactive before and after the command, the
|
||||
* use of PERSISTENT here means the lv will remain locked as
|
||||
* an effect of running the lvconvert.
|
||||
* To unlock it, it would need to be activated+deactivated.
|
||||
* Or, we could identify the commands for which the lv remains
|
||||
* inactive, and not use PERSISTENT here for those cases.
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0))
|
||||
if (!lockd_lv(cmd, lv, "ex", LDLV_PERSISTENT))
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
|
@@ -567,15 +567,22 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
|
||||
static int _read_cache_params(struct cmd_context *cmd,
|
||||
struct lvcreate_params *lp)
|
||||
{
|
||||
const char *cachemode;
|
||||
|
||||
if (!seg_is_cache(lp) && !seg_is_cache_pool(lp))
|
||||
return 1;
|
||||
|
||||
if (!get_cache_params(cmd,
|
||||
&lp->cache_mode,
|
||||
&lp->policy_name,
|
||||
&lp->policy_settings))
|
||||
if (!(cachemode = arg_str_value(cmd, cachemode_ARG, NULL)))
|
||||
cachemode = find_config_tree_str(cmd, allocation_cache_pool_cachemode_CFG, NULL);
|
||||
|
||||
if (!set_cache_pool_feature(&lp->feature_flags, cachemode))
|
||||
return_0;
|
||||
|
||||
if (!get_cache_policy_params(cmd, &lp->policy_name, &lp->policy_settings)) {
|
||||
log_error("Failed to parse cache policy and/or settings.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1082,6 +1089,8 @@ static int _determine_cache_argument(struct volume_group *vg,
|
||||
/* If cache args not given, use those from cache pool */
|
||||
if (!arg_is_set(cmd, chunksize_ARG))
|
||||
lp->chunk_size = first_seg(lv)->chunk_size;
|
||||
if (!arg_is_set(cmd, cachemode_ARG))
|
||||
lp->feature_flags = first_seg(lv)->feature_flags;
|
||||
} else if (lv) {
|
||||
/* Origin exists, create cache pool volume */
|
||||
if (!validate_lv_cache_create_origin(lv))
|
||||
|
@@ -461,14 +461,13 @@ static int _lvmpolld_init_poll_vg(struct cmd_context *cmd, const char *vgname,
|
||||
if (!id.display_name && !lpdp->parms->aborting)
|
||||
continue;
|
||||
|
||||
id.vg_name = lv->vg->name;
|
||||
id.lv_name = lv->name;
|
||||
|
||||
if (!*lv->lvid.s) {
|
||||
log_print_unless_silent("Missing LV uuid within: %s/%s", id.vg_name, id.lv_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
id.vg_name = lv->vg->name;
|
||||
id.lv_name = lv->name;
|
||||
id.uuid = lv->lvid.s;
|
||||
|
||||
r = lvmpolld_poll_init(cmd, &id, lpdp->parms);
|
||||
|
@@ -1399,10 +1399,8 @@ static int _validate_cachepool_params(const char *name,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_cache_params(struct cmd_context *cmd,
|
||||
const char **mode,
|
||||
const char **name,
|
||||
struct dm_config_tree **settings)
|
||||
int get_cache_policy_params(struct cmd_context *cmd, const char **name,
|
||||
struct dm_config_tree **settings)
|
||||
{
|
||||
const char *str;
|
||||
struct arg_value_group_list *group;
|
||||
@@ -1410,14 +1408,7 @@ int get_cache_params(struct cmd_context *cmd,
|
||||
struct dm_config_node *cn;
|
||||
int ok = 0;
|
||||
|
||||
if (mode)
|
||||
*mode = arg_str_value(cmd, cachemode_ARG, NULL);
|
||||
|
||||
if (name)
|
||||
*name = arg_str_value(cmd, cachepolicy_ARG, NULL);
|
||||
|
||||
if (!settings)
|
||||
return 1;
|
||||
*name = arg_str_value(cmd, cachepolicy_ARG, DEFAULT_CACHE_POOL_POLICY);
|
||||
|
||||
dm_list_iterate_items(group, &cmd->arg_value_groups) {
|
||||
if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
|
||||
@@ -1438,9 +1429,6 @@ int get_cache_params(struct cmd_context *cmd,
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!current)
|
||||
return 1;
|
||||
|
||||
if (!(result = dm_config_flatten(current)))
|
||||
goto_out;
|
||||
|
||||
|
@@ -190,10 +190,9 @@ int get_pool_params(struct cmd_context *cmd,
|
||||
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
|
||||
uint32_t *stripe_size);
|
||||
|
||||
int get_cache_params(struct cmd_context *cmd,
|
||||
const char **mode,
|
||||
const char **name,
|
||||
struct dm_config_tree **settings);
|
||||
int get_cache_policy_params(struct cmd_context *cmd,
|
||||
const char **name,
|
||||
struct dm_config_tree **settings);
|
||||
|
||||
int change_tag(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct physical_volume *pv, int arg);
|
||||
|
@@ -204,7 +204,7 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
if (vg->system_id && vg->system_id[0] &&
|
||||
cmd->system_id && cmd->system_id[0] &&
|
||||
strcmp(vg->system_id, cmd->system_id) &&
|
||||
do_activate) {
|
||||
is_change_activating(activate)) {
|
||||
log_error("Cannot activate LVs in a foreign VG.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
@@ -1026,9 +1026,7 @@ static int _lockd_vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
if (arg_is_set(cmd, activate_ARG) || arg_is_set(cmd, refresh_ARG)) {
|
||||
cmd->lockd_vg_default_sh = 1;
|
||||
/* Allow deactivating if locks fail. */
|
||||
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
}
|
||||
|
||||
/* Starting a vg lockspace means there are no locks available yet. */
|
||||
|
@@ -47,7 +47,7 @@ BLKID_RULE=IMPORT{program}=\"${SBIN}\/blkid -o udev -p \$$tempnode\"
|
||||
endif
|
||||
|
||||
ifeq ("@UDEV_SYSTEMD_BACKGROUND_JOBS@", "yes")
|
||||
PVSCAN_RULE=ACTION\!=\"remove\", ENV{LVM_PV_GONE}==\"1\", RUN\+=\"@bindir@/systemd-run $(LVM_EXEC)\/lvm pvscan --cache \$$major\:\$$minor\", GOTO=\"lvm_end\"\nENV{SYSTEMD_ALIAS}=\"\/dev\/block\/\$$major:\$$minor\"\nENV{ID_MODEL}=\"LVM PV \$$env{ID_FS_UUID_ENC} on \/dev\/\$$name\"\nENV{SYSTEMD_WANTS}\+=\"lvm2-pvscan@\$$major:\$$minor.service\"
|
||||
PVSCAN_RULE=ACTION\!=\"remove\", ENV{LVM_PV_GONE}==\"1\", RUN\+=\"@bindir@/systemd-run $(LVM_EXEC)\/lvm pvscan --cache \$$major\:\$$minor\", GOTO=\"lvm_end\"\nENV{SYSTEMD_ALIAS}=\"\/dev\/block\/\$$major:\$$minor\"\nENV{ID_MODEL}=\"LVM PV \$$env{ID_FS_UUID_ENC} on \/dev\/\$$name\"\nENV{SYSTEMD_WANTS}=\"lvm2-pvscan@\$$major:\$$minor.service\"
|
||||
else
|
||||
PVSCAN_RULE=RUN\+\=\"$(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major \$$major --minor \$$minor\", ENV{LVM_SCANNED}=\"1\"
|
||||
endif
|
||||
|
Reference in New Issue
Block a user