1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-30 17:44:21 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Petr Rockai
4aaffe0650 lvmetad: Avoid duplicate entries in the list of alternate devices. 2015-04-28 17:25:06 +02:00
503 changed files with 7634 additions and 52286 deletions

11
.gitignore vendored
View File

@@ -1,16 +1,13 @@
*.5
*.7
*.8
*.a
*.d
*.o
*.orig
*.pc
*.pot
*.rej
*.so
*.so.*
*.sw*
*.swp
*~
.export.sym
@@ -20,11 +17,11 @@
Makefile
make.tmpl
configure.h
version.h
/autom4te.cache/
/autoscan.log
/config.log
/config.status
/configure.scan
/cscope.out
/tags
/tmp/

View File

@@ -1,6 +1,6 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# 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.
#
@@ -15,8 +15,6 @@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
@@ -93,41 +91,12 @@ cscope.out:
all: cscope.out
endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
check check_system check_cluster check_local check_lvmetad unit: all
$(MAKE) -C test $(@)
conf.generate: tools
# how to use parenthesis in makefiles
leftparen:=(
LVM_VER := $(firstword $(subst $(leftparen), ,$(LVM_VERSION)))
VER := LVM2.$(LVM_VER)
# release file name
FILE_VER := $(VER).tgz
CLEAN_TARGETS += $(FILE_VER)
CLEAN_DIRS += $(rpmbuilddir)
dist:
@echo "Generating $(FILE_VER)";\
(cd $(top_srcdir); git ls-tree -r HEAD --name-only | xargs tar --transform "s,^,$(VER)/," -c) | gzip >$(FILE_VER)
rpm: dist
$(RM) -r $(rpmbuilddir)/SOURCES
$(MKDIR_P) $(rpmbuilddir)/SOURCES
$(LN_S) -f $(abs_top_builddir)/$(FILE_VER) $(rpmbuilddir)/SOURCES
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
sed -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
generate: conf.generate
$(MAKE) -C conf generate
@@ -223,13 +192,3 @@ memcheck: test-programs
ruby-test:
$(RUBY) report-generators/test/ts.rb
endif
ifneq ($(shell which ctags),)
.PHONY: tags
all: tags
tags:
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags | head -1)" || $(RM) tags
test -f tags || find $(top_srcdir) -maxdepth 4 -type f -name '*.[ch]' -exec ctags -a '{}' +
DISTCLEAN_TARGETS += tags
endif

View File

@@ -1 +1 @@
2.02.129(2)-git (2015-08-17)
2.02.119(2)-git (2015-03-24)

View File

@@ -1 +1 @@
1.02.106-git (2015-08-17)
1.02.96-git (2015-03-24)

154
WHATS_NEW
View File

@@ -1,146 +1,5 @@
Version 2.02.129 -
===================================
Enable usage of --cachepolicy and --cachesetting with lvconvert.
Don't allow to reduce size of thin-pool metadata.
Fix debug buffer overflows in cmirrord logging.
Add --foreground and --help to cmirrord.
Version 2.02.128 - 17th August 2015
===================================
Allocation setting cache_pool_cachemode is replaced by cache_mode.
Don't attempt to close config file that couldn't be opened.
Check for valid cache mode in validation of cache segment.
Change internal interface handling cache mode and policy.
When no cache policy specified, prefer smq (if available) over mq.
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
===================================
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.
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
=================================
Fix long option hyphen removal. (2.02.122)
Fix clvmd freeze if client disappears without first releasing its locks.
Fix lvconvert segfaults while performing snapshots merge.
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
Fix alloc segfault when extending LV with fewer stripes than in first seg.
Fix handling of cache policy name.
Set cache policy before with the first lvm2 cache pool metadata commit.
Fix detection of thin-pool overprovisioning (2.02.124).
Fix lvmpolld segfaults on 32 bit architectures.
Add lvmlockd lock_args validation to vg_validate.
Fix ignored --startstopservices option if running lvmconf with systemd.
Hide sanlock LVs when processing LVs in VG unless named or --all used.
Version 2.02.125 - 7th July 2015
================================
Fix getline memory usage in lvmpolld.
Add support --clear-needs-check-flag for cache_check of cache pool metadata.
Add lvmetactl for developer use only.
Rename global/lock_retries to lvmlockd_retries.
Replace --enable-lvmlockd by --enable-lockd-sanlock and --enable-lockd-dlm.
Version 2.02.124 - 3rd July 2015
================================
Move sending thin pool messages from resume to suspend phase.
Report warning when pool is overprovisioned and not auto resized.
Recognize free-form date/time values for lv_time field in selection criteria.
Added experimental lvmlockd with configure --enable-lvmlockd.
Fix regression in select to match string fields if using synonyms (2.02.123).
Fix regression when printing more lv names via display_lvname (2.02.122).
Add missing error logging to unlock_vg and sync_local_dev_names callers.
Version 2.02.123 - 30th June 2015
=================================
Add report/time_format lvm.conf option to define time format for report.
Fix makefile shell compare == when building lvmetad lvmpolld (2.02.120).
Add --type full to lvmconfig for full configuration tree view.
Add undocumented environment variables to lvm man page. (2.02.119)
Add device synchronization point before activating a new snapshot.
Add --withspaces to lvmconfig to add spaces in output for better readability.
Add custom main function to libdaemon.
Use lvmetad to track out-of-date metadata discovered.
Version 2.02.122 - 20th June 2015
=================================
Flush stdout before printing to stderr.
Use pre-allocated buffer for printed LV names in display_lvname.
Support thins with size of external origin unaligned with thin pool chunk.
Allow extension of reduced thin volumes with external origins.
Consider snapshot and origin LV as unusable if component devices suspended.
Fix lvmconfig segfault on settings with undefined default value (2.02.120).
Add explicit 's' (shared) LV activation mode.
Ignore hyphens in long options names (i.e. --long-option == --longoption).
Version 2.02.121 - 12th June 2015
=================================
Distinguish between on-disk and lvmetad versions of text metadata.
Remove DL_LIBS from Makefiles for daemons that don't need them.
Zero errno in before strtoul call in dmsetup if tested after the call.
Zero errno in before strtoul call in lvmpolld.
Fix a segfault in pvscan --cache --background command.
Fix test for AREA_PV when checking for failed mirrors.
Do not use --sysinit in lvm2-activation{-early,-net}.service if lvmpolld used.
Maintain outdated PV info in lvmetad till all old metadata is gone from disk.
Do not fail polling when poll LV not found (already finished or removed).
Replace poll_get_copy_vg/lv fns with vg_read() and find_lv() in polldaemon.
Close all device fds only in before sleep call in polldaemon.
Simplify Makefile targets that generate exported symbols.
Move various -D settings from Makefiles to configure.h.
Version 2.02.120 - 15th May 2015
================================
Make various adjustments to Makefile compilation flags.
Add lvmpolld debug message class.
Add lvmpolld client mode for querying running server instance for status info.
Fix some libdaemon socket creation and reuse error paths.
Daemons (libdaemon) support exit on idle also in non-systemd environment.
Provide make dist and make rpm targets
Configure lvm.conf for use_lvmetad and use_lvmpolld.
Add lvpoll for cmdline communication with lvmpolld.
Add lvmpolld acting as a free-standing version of polldaemon.
Avoid repeated identical lvmetad VG lookups in commands processing all VGs.
Handle switches to alternative duplicate PVs efficiently with lvmetad.
Properly validate PV size for pvcreate --restorefile.
Fix check if pvcreate wiped device (2.02.117).
Fix storing of vgid when caching metadata (2.02.118).
Fix recursive lvm-config man page. (2.02.119)
Refactor polldaemon interfaces to poll every operation by VG/LV couple
Skip wait after testing in _wait_for_single_lv when polling finished
Return 'None' in python for empty string properties instead of crashing.
Distinguish signed numerical property type in reports for lvm2app library.
Reread raid completion status immediately when progress appears to be zero.
lvm2app closes locking on lvm_quit().
Configure detects /run or /var/run.
Add missing newline in clvmd --help output.
Version 2.02.119 - 2nd May 2015
===============================
New LVM_LOG_FILE_EPOCH, LVM_EXPECTED_EXIT_STATUS env vars. Man page to follow.
Remove detailed content from lvm.conf man page: use lvmconfig instead.
Generate complete config files with lvmconfig or 'make generate'.
Also display info on deprecated config with lvmconfig --withcomments.
Display version since which config is deprecated in lvmconfig --withversions.
Add --showdeprecated to lvmconfig to also display deprecated settings.
Hide deprecated settings in lvmconfig output for all types but current,diff.
Introduce support for exit on idle feature in libdaemon
Add --showunsupported to lvmconfig to also display unsupported settings.
Display unsupported settings for lvmconfig --type current,diff only by default
Honour lvmconfig --ignoreunsupported and --ignoreadvanced for all --type.
Make python bindings usable with python3 (and compatible with 2.6 & 2.7).
Add lvmconfig -l|--list as shortcut for lvmconfig --type list --withsummary.
Add lvmconfig --type list to display plain list of configuration settings.
Introduce lvmconfig as the preferred form of 'lvm dumpconfig'.
Version 2.02.119 -
==================================
Add lv_ancestors and lv_descendants reporting fields.
Add --ignorelocal option to dumpconfig to ignore the local section.
Close connection to lvmetad after fork.
@@ -148,26 +7,19 @@ Version 2.02.119 - 2nd May 2015
Split pvmove update metadata fn in an initial one and a subsequent one.
Refactor shared pvmove and lvconvert code into new _poll files.
Add --unconfigured option to dumpconfig to print strings unconfigured.
Add --withsummary option to dumpconfig to print first line - summary comment.
Use number of device holders to help choose between duplicate PVs.
Try to make lvmetad and non-lvmetad duplicate PV handling as similar as poss.
Issue warnings about duplicate PVs discovered by lvmetad.
Track alternative devices with matching PVIDs in lvmetad.
Add --withfullcomments option to dumpconfig to print full comment.
Check for lvm binary in blkdeactivate and skip LVM processing if not present.
Add --enable-halvm and --disable-halvm options to lvmconf script.
Add --services, --mirrorservice and --startstopservices option to lvmconf.
Use proper default value of global/use_lvmetad when processing lvmconf script.
Respect allocation/cling_tag_list during intial contiguous allocation.
Add A_PARTITION_BY_TAGS set when allocated areas should not share tags.
Make changes persist with python addTag/removeTag.
Set correct vgid when updating cache when writing PV metadata.
More efficient clvmd singlenode locking emulation.
Reject lvcreate -m with raid4/5/6 to avoid unexpected layout.
Don't skip invalidation of cached orphans if vg write lck is held (2.02.118).
Log relevant PV tags when using cling allocation.
Add str_list_add_list() to combine two lists.
Fix LV processing with selection to always do the selection on initial state.
Add internal LV_REMOVED LV status flag.
Version 2.02.118 - 23rd March 2015
==================================

View File

@@ -1,93 +1,5 @@
Version 1.02.106 -
===================================
Version 1.02.105 - 17th August 2015
===================================
Fix 'dmstats list -o all' segfault.
Separate dmstats statistics fields from region information fields.
Add interval and interval_ns fields to dmstats reports.
Do not include internal glibc headers in libdm-timestamp.c (1.02.104)
Exit immediately if no device is supplied to dmsetup wipe_table.
Suppress dmsetup report headings when no data is output. (1.02.104)
Adjust dmsetup usage/help output selection to match command invoked.
Fix dmsetup -o all to select correct fields in splitname report.
Restructure internal dmsetup argument handling across all commands.
Add dm_report_is_empty() to indicate there is no data awaiting output.
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.
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
Version 1.02.96 -
=================================
Introduce libdevmapper wrappers for all malloc-related functions.
Version 1.02.102 - 7th July 2015
================================
Include tool.h for default non-library use.
Introduce format macros with embedded % such as FMTu64.
Version 1.02.101 - 3rd July 2015
================================
Add experimental support to passing messages in suspend tree.
Add dm_report_value_cache_{set,get} to support caching during report/select.
Add dm_report_reserved_handler to handle report reserved value actions.
Support dynamic value in select: DM_REPORT_FIELD_RESERVED_VALUE_DYNAMIC_VALUE.
Support fuzzy names in select: DM_REPORT_FIELD_RESERVED_VALUE_FUZZY_NAMES.
Thin pool trace messages show a device name and major:minor.
Version 1.02.100 - 30th June 2015
=================================
Add since, after, until and before time operators to be used in selection.
Add support for time in reports and selection: DM_REPORT_FIELD_TYPE_TIME.
Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
Support report reserved value names: DM_REPORT_FIELD_RESERVED_VALUE_NAMED.
Add DM_CONFIG_VALUE_FMT_{INT_OCTAL,STRING_NO_QUOTES} config value format flag.
Add DM_CONFIG_VALUE_FMT_COMMON_{ARRAY,EXTRA_SPACE} config value format flag.
Add dm_config_value_{get,set}_format_flags to get and set config value format.
Version 1.02.99 - 20th June 2015
================================
New dm_tree_node_set_thin_pool_read_only(DM_1_02_99) for read-only thin pool.
Enhance error message when thin-pool message fails.
Fix dmeventd logging to avoid threaded use of static variable.
Remove redundant dmeventd SIGALRM coded.
Version 1.02.98 - 12th June 2015
================================
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
Use copy of errno made after each dm ioctl call in case errno changes later.
Version 1.02.97 - 15th May 2015
===============================
New dm_task_get_info(DM_1_02_97) supports internal_suspend state.
New symbols are versioned and comes with versioned symbol name (DM_1_02_97).
Version 1.02.96 - 2nd May 2015
==============================
Fix selection to not match if using reserved value in criteria with >,<,>=,<.
Fix selection to not match reserved values for size fields if using >,<,>=,<.
Include uuid or device number in log message after ioctl failure.

4
aclocal.m4 vendored
View File

@@ -1,6 +1,6 @@
# generated automatically by aclocal 1.15 -*- Autoconf -*-
# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

4
conf/.gitignore vendored
View File

@@ -1,4 +0,0 @@
command_profile_template.profile
example.conf
lvmlocal.conf
metadata_profile_template.profile

View File

@@ -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,19 +20,15 @@ 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
.PHONY: install_conf install_localconf install_profiles
generate:
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal --withspaces) > example.conf.in
(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --withspaces local) > lvmlocal.conf.in
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withfullcomments --ignorelocal) > example.conf.in
(cat $(top_srcdir)/conf/lvmlocal.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withfullcomments local) > lvmlocal.conf.in
install_conf: $(CONFSRC)
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \

View File

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

View File

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

View File

@@ -4,17 +4,6 @@
#
# Refer to 'man lvm.conf' for further information including the file layout.
#
# Refer to 'man lvm.conf' for information about how settings configured in
# this file are combined with built-in values and command line options to
# arrive at the final values used by LVM.
#
# Refer to 'man lvmconfig' for information about displaying the built-in
# and configured values used by LVM.
#
# If a default value is set in this file (not commented out), then a
# new version of LVM using this file will continue using that value,
# even if the new version of LVM changes the built-in default value.
#
# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
# the environment variable LVM_SYSTEM_DIR before running the tools.
#

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,8 @@ local {
# Example:
# Set the system_id to the string 'host1'.
# system_id = "host1"
# system_id = ""
# This configuration option does not have a default value defined.
# system_id=""
# Configuration option local/extra_system_ids.
# A list of extra VG system IDs the local host can access.
@@ -48,10 +49,5 @@ local {
# Use this only after consulting 'man lvmsystemid'
# to be certain of correct usage and possible dangers.
# This configuration option does not have a default value defined.
# Configuration option local/host_id.
# The lvmlockd sanlock host_id.
# This must be a unique among all hosts,
# and must be between 1 and 2000.
# host_id = 0
# extra_system_ids=[]
}

1411
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
###############################################################################
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
## Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
##
## This copyrighted material is made available to anyone wishing to use,
## modify, copy, or redistribute it subject to the terms and conditions
@@ -26,9 +26,10 @@ AC_CONFIG_AUX_DIR(autoconf)
dnl -- Get system type
AC_CANONICAL_TARGET([])
AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
case "$host_os" in
linux*)
CFLAGS="$CFLAGS"
COPTIMISE_FLAG="-O2"
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
ELDFLAGS="-Wl,--export-dynamic"
# FIXME Generate list and use --dynamic-list=.dlopen.sym
@@ -38,10 +39,6 @@ case "$host_os" in
LIB_SUFFIX=so
DEVMAPPER=yes
LVMETAD=no
LVMPOLLD=no
LVMLOCKD=no
LOCKDSANLOCK=no
LOCKDDLM=no
ODIRECT=yes
DM_IOCTLS=yes
SELINUX=yes
@@ -51,6 +48,7 @@ case "$host_os" in
;;
darwin*)
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
COPTIMISE_FLAG="-O2"
CLDFLAGS="$CLDFLAGS"
ELDFLAGS=
CLDWHOLEARCHIVE="-all_load"
@@ -70,12 +68,8 @@ esac
dnl -- Checks for programs.
AC_PROG_SED
AC_PROG_AWK
save_CFLAGS=$CFLAGS
save_CXXFLAGS=$CXXFLAGS
AC_PROG_CC
AC_PROG_CXX
CFLAGS=$save_CFLAGS
CXXFLAGS=$save_CXXFLAGS
dnl probably no longer needed in 2008, but...
AC_PROG_GCC_TRADITIONAL
@@ -91,19 +85,14 @@ AC_PATH_TOOL(CSCOPE_CMD, cscope)
dnl -- Check for header files.
AC_HEADER_DIRENT
AC_HEADER_MAJOR
AC_HEADER_STDBOOL
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.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([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
sys/wait.h time.h], ,
[AC_MSG_ERROR(bailing out)])
case "$host_os" in
linux*)
@@ -112,13 +101,16 @@ case "$host_os" in
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
esac
AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
################################################################################
dnl -- Check for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_TYPES([ptrdiff_t])
AC_STRUCT_TM
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIGNAL
@@ -134,13 +126,15 @@ AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_STRUCT_TM
################################################################################
dnl -- Check for functions
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_FUNCS([ftruncate gethostname getpagesize \
gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
AC_FUNC_ALLOCA
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_CHOWN
@@ -148,7 +142,6 @@ AC_FUNC_FORK
AC_FUNC_LSTAT
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_MKTIME
AC_FUNC_MMAP
AC_FUNC_REALLOC
AC_FUNC_STAT
@@ -175,9 +168,6 @@ AC_SUBST(HAVE_FULL_RELRO)
################################################################################
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
AC_PREFIX_DEFAULT(/usr)
if test "$prefix" = NONE; then
datarootdir=${ac_default_prefix}/share
fi
################################################################################
dnl -- Setup the ownership of the files
@@ -208,7 +198,6 @@ AC_ARG_WITH(device-uid,
[set the owner used for new device nodes [UID=0]]),
DM_DEVICE_UID=$withval, DM_DEVICE_UID=0)
AC_MSG_RESULT($DM_DEVICE_UID)
AC_DEFINE_UNQUOTED([DM_DEVICE_UID], [$DM_DEVICE_UID], [Define default owner for device node])
################################################################################
dnl -- Setup device group ownership
@@ -219,7 +208,6 @@ AC_ARG_WITH(device-gid,
[set the group used for new device nodes [GID=0]]),
DM_DEVICE_GID=$withval, DM_DEVICE_GID=0)
AC_MSG_RESULT($DM_DEVICE_GID)
AC_DEFINE_UNQUOTED([DM_DEVICE_GID], [$DM_DEVICE_GID], [Define default group for device node])
################################################################################
dnl -- Setup device mode
@@ -230,7 +218,6 @@ AC_ARG_WITH(device-mode,
[set the mode used for new device nodes [MODE=0600]]),
DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600)
AC_MSG_RESULT($DM_DEVICE_MODE)
AC_DEFINE_UNQUOTED([DM_DEVICE_MODE], [$DM_DEVICE_MODE], [Define default mode for device node])
AC_MSG_CHECKING(when to create device nodes)
AC_ARG_WITH(device-nodes-on,
@@ -270,13 +257,8 @@ AC_ARG_ENABLE(lvm1_fallback,
AC_MSG_RESULT($LVM1_FALLBACK)
if test "$LVM1_FALLBACK" = yes; then
DEFAULT_FALLBACK_TO_LVM1=1
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
else
DEFAULT_FALLBACK_TO_LVM1=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1],
[Fall back to LVM1 by default if device-mapper is missing from the kernel.])
################################################################################
dnl -- format1 inclusion type
@@ -564,12 +546,6 @@ case "$CACHE" in
*) AC_MSG_ERROR([--with-cache parameter invalid]) ;;
esac
dnl -- cache_check needs-check flag
AC_ARG_ENABLE(cache_check_needs_check,
AC_HELP_STRING([--disable-cache_check_needs_check],
[required if cache_check version is < 0.5]),
CACHE_CHECK_NEEDS_CHECK=$enableval, CACHE_CHECK_NEEDS_CHECK=yes)
# Test if necessary cache tools are available
# if not - use plain defaults and warn user
case "$CACHE" in
@@ -583,28 +559,6 @@ case "$CACHE" in
CACHE_CONFIGURE_WARN=y
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
# 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
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
fi
fi
# Empty means a config way to ignore cache dumping
if test "$CACHE_DUMP_CMD" = "autodetect"; then
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
@@ -632,12 +586,6 @@ case "$CACHE" in
CACHE_CONFIGURE_WARN=y
}
fi
AC_MSG_CHECKING([whether cache_check supports the needs-check flag])
AC_MSG_RESULT([$CACHE_CHECK_NEEDS_CHECK])
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
AC_DEFINE([CACHE_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'cache_check' tool requires the --clear-needs-check-flag option])
fi
;;
esac
@@ -666,8 +614,8 @@ AC_MSG_RESULT($READLINE)
dnl -- Disable realtime clock support
AC_MSG_CHECKING(whether to enable realtime support)
AC_ARG_ENABLE(realtime,
AC_HELP_STRING([--disable-realtime], [disable realtime clock support]),
REALTIME=$enableval, REALTIME=yes)
AC_HELP_STRING([--enable-realtime], [enable realtime clock support]),
REALTIME=$enableval)
AC_MSG_RESULT($REALTIME)
################################################################################
@@ -697,32 +645,28 @@ pkg_config_init() {
}
################################################################################
AC_MSG_CHECKING(for default run directory)
RUN_DIR="/run"
test -d "/run" || RUN_DIR="/var/run"
AC_MSG_RESULT($RUN_DIR)
dnl -- Set up pidfile and run directory
AH_TEMPLATE(DEFAULT_PID_DIR)
AC_ARG_WITH(default-pid-dir,
AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
[Default directory to keep PID files in. [autodetect]]),
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR=$RUN_DIR)
[Default directory to keep PID files in. [/var/run]]),
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR="/var/run")
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
[Default directory to keep PID files in.])
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
AC_ARG_WITH(default-dm-run-dir,
AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
[ Default DM run directory. [autodetect]]),
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR=$RUN_DIR)
[ Default DM run directory. [/var/run]]),
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR="/var/run")
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
[Default DM run directory.])
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
AC_ARG_WITH(default-run-dir,
AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
[Default LVM run directory. [autodetect_run_dir/lvm]]),
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="$RUN_DIR/lvm")
[Default LVM run directory. [/var/run/lvm]]),
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="/var/run/lvm")
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
[Default LVM run directory.])
@@ -1072,13 +1016,6 @@ if test "$TESTING" = yes; then
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
fi
################################################################################
dnl -- Set LVM2 testsuite data
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
AC_DEFINE_UNQUOTED(TESTSUITE_DATA, ["$(eval echo $(eval echo $TESTSUITE_DATA))"], [Path to testsuite data])
################################################################################
dnl -- Enable valgrind awareness of memory pools
AC_MSG_CHECKING(whether to enable valgrind awareness of pools)
@@ -1124,106 +1061,7 @@ AC_MSG_RESULT($LVMETAD)
BUILD_LVMETAD=$LVMETAD
################################################################################
dnl -- Build lvmpolld
AC_MSG_CHECKING(whether to build lvmpolld)
AC_ARG_ENABLE(lvmpolld,
AC_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
################################################################################
dnl -- Build lockdsanlock
AC_MSG_CHECKING(whether to build lockdsanlock)
AC_ARG_ENABLE(lockd-sanlock,
AC_HELP_STRING([--enable-lockd-sanlock],
[enable the LVM lock daemon using sanlock]),
LOCKDSANLOCK=$enableval)
AC_MSG_RESULT($LOCKDSANLOCK)
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
if test "$BUILD_LOCKDSANLOCK" = yes; then
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
fi
################################################################################
dnl -- Look for sanlock libraries
if test "$BUILD_LOCKDSANLOCK" = yes; then
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
BUILD_LVMLOCKD=yes
fi
################################################################################
dnl -- Build lockddlm
AC_MSG_CHECKING(whether to build lockddlm)
AC_ARG_ENABLE(lockd-dlm,
AC_HELP_STRING([--enable-lockd-dlm],
[enable the LVM lock daemon using dlm]),
LOCKDDLM=$enableval)
AC_MSG_RESULT($LOCKDDLM)
BUILD_LOCKDDLM=$LOCKDDLM
if test "$BUILD_LOCKDDLM" = yes; then
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
fi
################################################################################
dnl -- Look for dlm libraries
if test "$BUILD_LOCKDDLM" = yes; then
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
BUILD_LVMLOCKD=yes
fi
################################################################################
dnl -- Build lvmlockd
AC_MSG_CHECKING(whether to build lvmlockd)
AC_MSG_RESULT($BUILD_LVMLOCKD)
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
AC_MSG_CHECKING([defaults for use_lvmlockd])
AC_ARG_ENABLE(use_lvmlockd,
AC_HELP_STRING([--disable-use-lvmlockd],
[disable usage of LVM lock daemon]),
[case ${enableval} in
yes) DEFAULT_USE_LVMLOCKD=1 ;;
*) DEFAULT_USE_LVMLOCKD=0 ;;
esac], DEFAULT_USE_LVMLOCKD=1)
AC_MSG_RESULT($DEFAULT_USE_LVMLOCKD)
AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.])
AC_ARG_WITH(lvmlockd-pidfile,
AC_HELP_STRING([--with-lvmlockd-pidfile=PATH],
[lvmlockd pidfile [PID_DIR/lvmlockd.pid]]),
LVMLOCKD_PIDFILE=$withval,
LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid")
AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"],
[Path to lvmlockd pidfile.])
else
DEFAULT_USE_LVMLOCKD=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
[Use lvmlockd by default.])
################################################################################
dnl -- Check lvmetad
if test "$BUILD_LVMETAD" = yes; then
AC_MSG_CHECKING([defaults for use_lvmetad])
AC_ARG_ENABLE(use_lvmetad,
AC_HELP_STRING([--disable-use-lvmetad],
[disable usage of LVM Metadata Daemon]),
[case ${enableval} in
yes) DEFAULT_USE_LVMETAD=1 ;;
*) DEFAULT_USE_LVMETAD=0 ;;
esac], DEFAULT_USE_LVMETAD=1)
AC_MSG_RESULT($DEFAULT_USE_LVMETAD)
AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
AC_ARG_WITH(lvmetad-pidfile,
@@ -1233,41 +1071,9 @@ if test "$BUILD_LVMETAD" = yes; then
LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
[Path to lvmetad pidfile.])
else
DEFAULT_USE_LVMETAD=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
[Use lvmetad by default.])
################################################################################
dnl -- Check lvmpolld
if test "$BUILD_LVMPOLLD" = yes; then
AC_MSG_CHECKING([defaults for use_lvmpolld])
AC_ARG_ENABLE(use_lvmpolld,
AC_HELP_STRING([--disable-use-lvmpolld],
[disable usage of LVM Poll Daemon]),
[case ${enableval} in
yes) DEFAULT_USE_LVMPOLLD=1 ;;
*) DEFAULT_USE_LVMPOLLD=0 ;;
esac], DEFAULT_USE_LVMPOLLD=1)
AC_MSG_RESULT($DEFAULT_USE_LVMPOLLD)
AC_DEFINE([LVMPOLLD_SUPPORT], 1, [Define to 1 to include code that uses lvmpolld.])
AC_ARG_WITH(lvmpolld-pidfile,
AC_HELP_STRING([--with-lvmpolld-pidfile=PATH],
[lvmpolld pidfile [PID_DIR/lvmpolld.pid]]),
LVMPOLLD_PIDFILE=$withval,
LVMPOLLD_PIDFILE="$DEFAULT_PID_DIR/lvmpolld.pid")
AC_DEFINE_UNQUOTED(LVMPOLLD_PIDFILE, ["$LVMPOLLD_PIDFILE"],
[Path to lvmpolld pidfile.])
else
DEFAULT_USE_LVMPOLLD=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
[Use lvmpolld by default.])
################################################################################
dnl -- Enable blkid wiping functionality
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
AC_ARG_ENABLE(blkid_wiping,
@@ -1287,16 +1093,9 @@ if test "$BLKID_WIPING" != no; then
fi])
if test "$BLKID_WIPING" = yes; then
BLKID_PC="blkid"
DEFAULT_USE_BLKID_WIPING=1
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
else
DEFAULT_USE_BLKID_WIPING=1
fi
else
DEFAULT_USE_BLKID_WIPING=0
fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_BLKID_WIPING, [$DEFAULT_USE_BLKID_WIPING],
[Use blkid wiping by default.])
################################################################################
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
@@ -1369,11 +1168,11 @@ AC_ARG_ENABLE(compat,
[enable support for old device-mapper versions]),
DM_COMPAT=$enableval, DM_COMPAT=no)
AS_IF([test "$DM_COMPAT" = yes],
[AC_DEFINE([DM_COMPAT], 1, [Define to enable compat protocol])
AC_MSG_ERROR([--enable-compat is not currently supported.
if test "$DM_COMPAT" = yes; then
AC_MSG_ERROR([--enable-compat is not currently supported.
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
ioctl protocol is supported.])])
ioctl protocol is supported.])
fi
################################################################################
dnl -- Compatible units suffix mode
@@ -1393,8 +1192,6 @@ AC_ARG_ENABLE(ioctl,
AC_HELP_STRING([--disable-ioctl],
[disable ioctl calls to device-mapper in the kernel]),
DM_IOCTLS=$enableval)
AS_IF([test "$DM_IOCTLS" = yes],
[AC_DEFINE([DM_IOCTLS], 1, [Define to enable ioctls calls to kernel])])
################################################################################
dnl -- Disable O_DIRECT
@@ -1537,10 +1334,6 @@ if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
fi
################################################################################
AC_CHECK_LIB(m, log10,
[M_LIBS="-lm"], hard_bailout)
################################################################################
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
[PTHREAD_LIBS="-lpthread"], hard_bailout)
@@ -1581,11 +1374,9 @@ if test "$REALTIME" = yes; then
if test "$HAVE_REALTIME" = yes; then
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
LIBS="-lrt $LIBS"
RT_PC="librt"
else
AC_MSG_WARN(Disabling realtime clock)
fi
AC_MSG_RESULT($HAVE_REALTIME)
fi
dnl Check if the system has struct stat st_ctim.
@@ -1659,16 +1450,14 @@ if test "$INTL" = yes; then
# FIXME - Move this - can be device-mapper too
INTL_PACKAGE="lvm2"
AC_PATH_TOOL(MSGFMT, msgfmt)
AS_IF([test -z "$MSGFMT"], [AC_MSG_ERROR([msgfmt not found in path $PATH])])
if [[ -z "$MSGFMT" ]]; then
AC_MSG_ERROR([msgfmt not found in path $PATH])
fi
AC_ARG_WITH(localedir,
AC_HELP_STRING([--with-localedir=DIR],
[locale-dependent data [DATAROOTDIR/locale]]),
localedir=$withval, localedir=${localedir-'${datarootdir}/locale'})
AC_DEFINE_UNQUOTED([INTL_PACKAGE], ["$INTL_PACKAGE"], [Internalization package])
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
AC_DEFINE_UNQUOTED([LOCALEDIR], ["$(eval echo $(eval echo $localedir))"], [Locale-dependent data])
[translation files in DIR [PREFIX/share/locale]]),
LOCALEDIR=$withval, LOCALEDIR='${prefix}/share/locale')
fi
################################################################################
@@ -1733,19 +1522,6 @@ if test "$READLINE" = yes; then
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
fi
if test "$BUILD_CMIRRORD" = yes; then
AC_CHECK_FUNCS(atexit,,hard_bailout)
fi
if test "$BUILD_LVMLOCKD" = yes; then
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
fi
if test "$BUILD_LVMPOLLD" = yes; then
AC_CHECK_FUNCS(strpbrk,,hard_bailout)
AC_FUNC_STRERROR_R
fi
if test "$CLVMD" != none; then
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
@@ -1903,13 +1679,10 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
AC_SUBST(APPLIB)
AC_SUBST(AWK)
AC_SUBST(BLKID_PC)
AC_SUBST(BLKID_WIPING)
AC_SUBST(BUILD_CMIRRORD)
AC_SUBST(BUILD_DMEVENTD)
AC_SUBST(BUILD_LVMETAD)
AC_SUBST(BUILD_LVMPOLLD)
AC_SUBST(BUILD_LVMLOCKD)
AC_SUBST(BUILD_LOCKDSANLOCK)
AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
@@ -1939,7 +1712,6 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR)
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
AC_SUBST(DEFAULT_DM_RUN_DIR)
AC_SUBST(DEFAULT_LOCK_DIR)
AC_SUBST(DEFAULT_FALLBACK_TO_LVM1)
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
AC_SUBST(DEFAULT_PID_DIR)
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
@@ -1947,16 +1719,17 @@ AC_SUBST(DEFAULT_RAID10_SEGTYPE)
AC_SUBST(DEFAULT_RUN_DIR)
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
AC_SUBST(DEFAULT_SYS_DIR)
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
AC_SUBST(DEFAULT_USE_LVMETAD)
AC_SUBST(DEFAULT_USE_LVMPOLLD)
AC_SUBST(DEFAULT_USE_LVMLOCKD)
AC_SUBST(DEVMAPPER)
AC_SUBST(DLM_CFLAGS)
AC_SUBST(DLM_LIBS)
AC_SUBST(DL_LIBS)
AC_SUBST(DMEVENTD)
AC_SUBST(DMEVENTD_PATH)
AC_SUBST(DM_COMPAT)
AC_SUBST(DM_DEVICE_GID)
AC_SUBST(DM_DEVICE_MODE)
AC_SUBST(DM_DEVICE_UID)
AC_SUBST(DM_IOCTLS)
AC_SUBST(DM_LIB_VERSION)
AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
@@ -1966,10 +1739,12 @@ AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_REALTIME)
AC_SUBST(HAVE_VALGRIND)
AC_SUBST(INTL)
AC_SUBST(INTL_PACKAGE)
AC_SUBST(JOBS)
AC_SUBST(LDDEPS)
AC_SUBST(LIBS)
AC_SUBST(LIB_SUFFIX)
AC_SUBST(LOCALEDIR)
AC_SUBST(LVM1)
AC_SUBST(LVM1_FALLBACK)
AC_SUBST(LVM_VERSION)
@@ -1980,7 +1755,6 @@ AC_SUBST(LVM_PATCHLEVEL)
AC_SUBST(LVM_PATH)
AC_SUBST(LVM_RELEASE)
AC_SUBST(LVM_RELEASE_DATE)
AC_SUBST(localedir)
AC_SUBST(MANGLING)
AC_SUBST(MIRRORS)
AC_SUBST(MSGFMT)
@@ -1988,7 +1762,6 @@ AC_SUBST(OCF)
AC_SUBST(OCFDIR)
AC_SUBST(PKGCONFIG)
AC_SUBST(POOL)
AC_SUBST(M_LIBS)
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PYTHON)
AC_SUBST(PYTHON_BINDINGS)
@@ -1997,7 +1770,6 @@ AC_SUBST(PYTHON_LIBDIRS)
AC_SUBST(QUORUM_CFLAGS)
AC_SUBST(QUORUM_LIBS)
AC_SUBST(RAID)
AC_SUBST(RT_PC)
AC_SUBST(READLINE_LIBS)
AC_SUBST(REPLICATORS)
AC_SUBST(SACKPT_CFLAGS)
@@ -2010,7 +1782,6 @@ AC_SUBST(SNAPSHOTS)
AC_SUBST(STATICDIR)
AC_SUBST(STATIC_LINK)
AC_SUBST(TESTING)
AC_SUBST(TESTSUITE_DATA)
AC_SUBST(THIN)
AC_SUBST(THIN_CHECK_CMD)
AC_SUBST(THIN_DUMP_CMD)
@@ -2030,8 +1801,6 @@ AC_SUBST(VALGRIND_POOL)
AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE)
AC_SUBST(LVMETAD_PIDFILE)
AC_SUBST(LVMPOLLD_PIDFILE)
AC_SUBST(LVMLOCKD_PIDFILE)
AC_SUBST(CLVMD_PIDFILE)
AC_SUBST(CMIRRORD_PIDFILE)
AC_SUBST(interface)
@@ -2065,8 +1834,6 @@ daemons/dmeventd/plugins/mirror/Makefile
daemons/dmeventd/plugins/snapshot/Makefile
daemons/dmeventd/plugins/thin/Makefile
daemons/lvmetad/Makefile
daemons/lvmpolld/Makefile
daemons/lvmlockd/Makefile
conf/Makefile
conf/example.conf
conf/lvmlocal.conf
@@ -2110,11 +1877,6 @@ scripts/lvm2_cmirrord_systemd_red_hat.service
scripts/lvm2_lvmetad_init_red_hat
scripts/lvm2_lvmetad_systemd_red_hat.service
scripts/lvm2_lvmetad_systemd_red_hat.socket
scripts/lvm2_lvmpolld_init_red_hat
scripts/lvm2_lvmpolld_systemd_red_hat.service
scripts/lvm2_lvmpolld_systemd_red_hat.socket
scripts/lvm2_lvmlockd_systemd_red_hat.service
scripts/lvm2_lvmlocking_systemd_red_hat.service
scripts/lvm2_monitoring_init_red_hat
scripts/lvm2_monitoring_systemd_red_hat.service
scripts/lvm2_pvscan_systemd_red_hat@.service
@@ -2131,14 +1893,10 @@ unit-tests/mm/Makefile
])
AC_OUTPUT
AS_IF([test -n "$THIN_CONFIGURE_WARN"],
[AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])])
test -n "$THIN_CONFIGURE_WARN" && AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])
AS_IF([test -n "$THIN_CHECK_VERSION_WARN"],
[AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])])
test -n "$THIN_CHECK_VERSION_WARN" && AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])
AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
[AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])])
test -n "$CACHE_CONFIGURE_WARN" && AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])
AS_IF([test "$ODIRECT" != yes],
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
test "$ODIRECT" = yes || AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
.PHONY: dmeventd clvmd cmirrord lvmetad
ifneq ("@CLVMD@", "none")
SUBDIRS += clvmd
@@ -36,16 +36,8 @@ ifeq ("@BUILD_LVMETAD@", "yes")
SUBDIRS += lvmetad
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
SUBDIRS += lvmpolld
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
SUBDIRS += lvmlockd
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
SUBDIRS = clvmd cmirrord dmeventd lvmetad
endif
include $(top_builddir)/make.tmpl

View File

@@ -1 +0,0 @@
clvmd

View File

@@ -36,6 +36,10 @@ SOURCES = \
lvm-functions.c \
refresh_clvmd.c
ifeq ("@DEBUG@", "yes")
DEFS += -DDEBUG
endif
ifneq (,$(findstring cman,, "@CLVMD@,"))
SOURCES += clvmd-cman.c
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)

View File

@@ -323,7 +323,6 @@ void cmd_client_cleanup(struct local_client *client)
int lkid;
char *lockname;
DEBUGLOG("Client thread cleanup (%p)\n", client);
if (!client->bits.localsock.private)
return;
@@ -332,7 +331,7 @@ void cmd_client_cleanup(struct local_client *client)
dm_hash_iterate(v, lock_hash) {
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
lockname = dm_hash_get_key(lock_hash, v);
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
(void) sync_unlock(lockname, lkid);
}
@@ -340,6 +339,7 @@ void cmd_client_cleanup(struct local_client *client)
client->bits.localsock.private = NULL;
}
static int restart_clvmd(void)
{
const char **argv;

View File

@@ -18,10 +18,15 @@
#ifndef _LVM_CLVMD_COMMON_H
#define _LVM_CLVMD_COMMON_H
#include "configure.h"
#define _REENTRANT
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "tool.h"
#include "libdevmapper.h"
#include "lvm-logging.h"
#include <unistd.h>
#endif

View File

@@ -243,7 +243,7 @@ static void openais_cpg_confchg_callback(cpg_handle_t handle,
struct node_info *ninfo;
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
FMTsize_t " left, %" PRIsize_t " members\n",
"%" PRIsize_t " left, %" PRIsize_t " members\n",
joined_list_entries, left_list_entries, member_list_entries);
for (i=0; i<joined_list_entries; i++) {

View File

@@ -172,7 +172,6 @@ static void usage(const char *prog, FILE *file)
#ifdef USE_SINGLENODE
"singlenode "
#endif
"\n"
" -R Tell all running clvmds in the cluster to reload their device cache\n"
" -S Restart clvmd, preserving exclusive locks\n"
" -t<secs> Command timeout (default: 60 seconds)\n"
@@ -223,7 +222,6 @@ void debuglog(const char *fmt, ...)
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
break;
case DEBUG_SYSLOG:
if (!syslog_init) {
@@ -599,9 +597,7 @@ int main(int argc, char *argv[])
/* This needs to be started after cluster initialisation
as it may need to take out locks */
DEBUGLOG("Starting LVM thread\n");
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
local_client_head.fd, &local_client_head, newfd->fd, newfd);
DEBUGLOG("starting LVM thread\n");
/* Don't let anyone else to do work until we are started */
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
@@ -701,7 +697,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->type = LOCAL_SOCK;
newfd->callback = local_sock_callback;
newfd->bits.localsock.all_success = 1;
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
*new_client = newfd;
}
return 1;
@@ -853,48 +849,18 @@ static void main_loop(int cmd_timeout)
struct local_client *thisfd;
struct timeval tv = { cmd_timeout, 0 };
int quorate = clops->is_quorate();
int client_count = 0;
int max_fd = 0;
struct local_client *lastfd = &local_client_head;
struct local_client *nextfd = local_client_head.next;
/* Wait on the cluster FD and all local sockets/pipes */
local_client_head.fd = clops->get_main_cluster_fd();
FD_ZERO(&in);
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
client_count++;
max_fd = max(max_fd, thisfd->fd);
}
if (max_fd > FD_SETSIZE - 32) {
fprintf(stderr, "WARNING: There are too many connections to clvmd. Investigate and take action now!\n");
fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
}
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
struct local_client *free_fd = thisfd;
lastfd->next = nextfd;
DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
continue;
}
lastfd = thisfd;
if (thisfd->removeme)
continue;
/* if the cluster is not quorate then don't listen for new requests */
if ((thisfd->type != LOCAL_RENDEZVOUS &&
thisfd->type != LOCAL_SOCK) || quorate)
if (thisfd->fd < FD_SETSIZE)
FD_SET(thisfd->fd, &in);
FD_SET(thisfd->fd, &in);
}
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
@@ -910,20 +876,31 @@ static void main_loop(int cmd_timeout)
}
if (select_status > 0) {
struct local_client *lastfd = NULL;
char csid[MAX_CSID_LEN];
char buf[max_cluster_message];
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
if (thisfd->fd < FD_SETSIZE && FD_ISSET(thisfd->fd, &in)) {
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
struct local_client *free_fd = thisfd;
lastfd->next = thisfd->next;
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
break;
}
if (FD_ISSET(thisfd->fd, &in)) {
struct local_client *newfd = NULL;
int ret;
/* FIXME Remove from main thread in case it blocks! */
/* Do callback */
ret = thisfd->callback(thisfd, buf, sizeof(buf),
csid, &newfd);
/* Ignore EAGAIN */
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
lastfd = thisfd;
continue;
}
@@ -939,16 +916,17 @@ static void main_loop(int cmd_timeout)
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
thisfd->removeme = 1;
continue;
break;
}
/* New client...simply add it to the list */
if (newfd) {
newfd->next = thisfd->next;
thisfd->next = newfd;
thisfd = newfd;
break;
}
}
lastfd = thisfd;
}
}
@@ -1441,7 +1419,7 @@ static int read_from_local_sock(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
thisfd->bits.localsock.cleanup_needed = 1;
DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
DEBUGLOG("Creating pre&post thread\n");
status = pthread_create(&thisfd->bits.localsock.threadid,
&stack_attr, pre_and_post_thread, thisfd);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
@@ -1695,7 +1673,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
sigset_t ss;
int pipe_fd = client->bits.localsock.pipe;
DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
DEBUGLOG("Pre&post thread (%p), pipe %d\n", client, pipe_fd);
pthread_mutex_lock(&client->bits.localsock.mutex);
/* Ignore SIGUSR1 (handled by master process) but enable
@@ -1715,7 +1693,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
if ((status = do_pre_command(client)))
client->bits.localsock.all_success = 0;
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe %d\n",
client, status, pipe_fd);
/* Tell the parent process we have finished this bit */
@@ -1997,7 +1975,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
{
/* If msg is NULL then this is a cleanup request */
if (cmd->msg == NULL) {
DEBUGLOG("process_work_item: free %p\n", cmd->client);
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
cmd_client_cleanup(cmd->client);
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
pthread_cond_destroy(&cmd->client->bits.localsock.cond);

View File

@@ -510,7 +510,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
if (!cmd->initialized.config || config_files_changed(cmd)) {
if (!cmd->config_initialized || config_files_changed(cmd)) {
/* Reinitialise various settings inc. logging, filters */
if (do_refresh_cache()) {
log_error("Updated config file invalid. Aborting.");
@@ -899,7 +899,7 @@ int init_clvm(struct dm_hash_table *excl_uuid)
if (!get_initial_state(excl_uuid))
log_error("Cannot load initial lock states.");
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
if (!(cmd = create_toolcontext(1, NULL, 0, 1))) {
log_error("Failed to allocate command context");
return 0;
}

View File

@@ -1 +0,0 @@
cmirrord

View File

@@ -15,7 +15,6 @@
#include "link_mon.h"
#include "local.h"
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
@@ -33,49 +32,14 @@ static void daemonize(void);
static void init_all(void);
static void cleanup_all(void);
static void usage (FILE *dest)
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
{
fprintf (dest, "Usage: cmirrord [options]\n"
" -f, --foreground stay in the foreground, log to the terminal\n"
" -h, --help print this help\n");
}
int main(int argc, char *argv[])
{
int foreground_mode = 0;
struct option longopts[] = {
{ "foreground", no_argument, NULL, 'f' },
{ "help" , no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
int opt;
while ((opt = getopt_long (argc, argv, "fh", longopts, NULL)) != -1) {
switch (opt) {
case 'f':
foreground_mode = 1;
break;
case 'h':
usage (stdout);
exit (0);
default:
usage (stderr);
exit (2);
}
}
if (optind < argc) {
usage (stderr);
exit (2);
}
if (!foreground_mode)
daemonize();
daemonize();
init_all();
/* Parent can now exit, we're ready to handle requests */
if (!foreground_mode)
kill(getppid(), SIGTERM);
kill(getppid(), SIGTERM);
LOG_PRINT("Starting cmirrord:");
LOG_PRINT(" Built: "__DATE__" "__TIME__"\n");
@@ -245,16 +209,6 @@ static void daemonize(void)
}
LOG_OPEN("cmirrord", LOG_PID, LOG_DAEMON);
}
/*
* init_all
*
* Initialize modules. Exit on failure.
*/
static void init_all(void)
{
int r;
(void) dm_prepare_selinux_context(CMIRRORD_PIDFILE, S_IFREG);
if (dm_create_lockfile(CMIRRORD_PIDFILE) == 0)
@@ -273,6 +227,16 @@ static void init_all(void)
signal(SIGUSR2, &sig_handler);
sigemptyset(&signal_mask);
signal_received = 0;
}
/*
* init_all
*
* Initialize modules. Exit on failure.
*/
static void init_all(void)
{
int r;
if ((r = init_local()) ||
(r = init_cluster())) {

View File

@@ -104,11 +104,10 @@ static SaVersionT version = { 'B', 1, 1 };
#endif
#define DEBUGGING_HISTORY 100
#define DEBUGGING_BUFLEN 128
#define LOG_SPRINT(cc, f, arg...) do { \
cc->idx++; \
cc->idx = cc->idx % DEBUGGING_HISTORY; \
snprintf(cc->debugging[cc->idx], DEBUGGING_BUFLEN, f, ## arg); \
sprintf(cc->debugging[cc->idx], f, ## arg); \
} while (0)
static int log_resp_rec = 0;
@@ -151,7 +150,7 @@ struct clog_cpg {
uint32_t checkpoint_requesters[MAX_CHECKPOINT_REQUESTERS];
struct checkpoint_data *checkpoint_list;
int idx;
char debugging[DEBUGGING_HISTORY][DEBUGGING_BUFLEN];
char debugging[DEBUGGING_HISTORY][128];
};
static struct dm_list clog_cpg_list;
@@ -1295,9 +1294,7 @@ static void cpg_join_callback(struct clog_cpg *match,
uint32_t my_pid = (uint32_t)getpid();
uint32_t lowest = match->lowest_id;
struct clog_request *rq;
char dbuf[64] = { 0 };
char *dbuf_p = dbuf;
size_t dbuf_rem = sizeof dbuf;
char dbuf[32] = { 0 };
/* Assign my_cluster_id */
if ((my_cluster_id == 0xDEAD) && (joined->pid == my_pid))
@@ -1313,17 +1310,9 @@ static void cpg_join_callback(struct clog_cpg *match,
if (joined->nodeid == my_cluster_id)
goto out;
for (i = 0; i < member_list_entries - 1; i++) {
int written = snprintf(dbuf_p, dbuf_rem, "%u-", member_list[i].nodeid);
if (written < 0) continue; /* impossible */
if ((unsigned)written >= dbuf_rem) {
dbuf_rem = 0;
break;
}
dbuf_rem -= written;
dbuf_p += written;
}
snprintf(dbuf_p, dbuf_rem, "(%u)", joined->nodeid);
for (i = 0; i < member_list_entries - 1; i++)
sprintf(dbuf+strlen(dbuf), "%u-", member_list[i].nodeid);
sprintf(dbuf+strlen(dbuf), "(%u)", joined->nodeid);
LOG_COND(log_checkpoint, "[%s] Joining node, %u needs checkpoint [%s]",
SHORT_UUID(match->name.value), joined->nodeid, dbuf);

View File

@@ -32,13 +32,12 @@
#define LOG_OFFSET 2
#define RESYNC_HISTORY 50
#define RESYNC_BUFLEN 128
//static char resync_history[RESYNC_HISTORY][128];
//static int idx = 0;
#define LOG_SPRINT(_lc, f, arg...) do { \
lc->idx++; \
lc->idx = lc->idx % RESYNC_HISTORY; \
snprintf(lc->resync_history[lc->idx], RESYNC_BUFLEN, f, ## arg); \
sprintf(lc->resync_history[lc->idx], f, ## arg); \
} while (0)
struct log_header {
@@ -89,7 +88,7 @@ struct log_c {
size_t disk_size; /* size of disk_buffer in bytes */
void *disk_buffer; /* aligned memory for O_DIRECT */
int idx;
char resync_history[RESYNC_HISTORY][RESYNC_BUFLEN];
char resync_history[RESYNC_HISTORY][128];
};
struct mark_entry {

View File

@@ -1 +0,0 @@
dmeventd

View File

@@ -16,21 +16,26 @@
* dmeventd - dm event daemon to monitor active mapped devices
*/
#include "tool.h"
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "configure.h"
#include "libdevmapper.h"
#include "libdevmapper-event.h"
#include "dmeventd.h"
//#include "libmultilog.h"
#include "dm-logging.h"
#include "libdevmapper-event.h"
#include "dmeventd.h"
#include <stdarg.h>
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h> /* for htonl, ntohl */
#include <fcntl.h> /* for musl libc */
@@ -128,20 +133,51 @@ void debuglog(const char *fmt, ...)
static const char *decode_cmd(uint32_t cmd)
{
static char buf[128];
const char *command;
switch (cmd) {
case DM_EVENT_CMD_ACTIVE: return "ACTIVE";
case DM_EVENT_CMD_REGISTER_FOR_EVENT: return "REGISTER_FOR_EVENT";
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT: return "UNREGISTER_FOR_EVENT";
case DM_EVENT_CMD_GET_REGISTERED_DEVICE: return "GET_REGISTERED_DEVICE";
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE: return "GET_NEXT_REGISTERED_DEVICE";
case DM_EVENT_CMD_SET_TIMEOUT: return "SET_TIMEOUT";
case DM_EVENT_CMD_GET_TIMEOUT: return "GET_TIMEOUT";
case DM_EVENT_CMD_HELLO: return "HELLO";
case DM_EVENT_CMD_DIE: return "DIE";
case DM_EVENT_CMD_GET_STATUS: return "GET_STATUS";
case DM_EVENT_CMD_GET_PARAMETERS: return "GET_PARAMETERS";
default: return "unknown";
case DM_EVENT_CMD_ACTIVE:
command = "ACTIVE";
break;
case DM_EVENT_CMD_REGISTER_FOR_EVENT:
command = "REGISTER_FOR_EVENT";
break;
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT:
command = "UNREGISTER_FOR_EVENT";
break;
case DM_EVENT_CMD_GET_REGISTERED_DEVICE:
command = "GET_REGISTERED_DEVICE";
break;
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE:
command = "GET_NEXT_REGISTERED_DEVICE";
break;
case DM_EVENT_CMD_SET_TIMEOUT:
command = "SET_TIMEOUT";
break;
case DM_EVENT_CMD_GET_TIMEOUT:
command = "GET_TIMEOUT";
break;
case DM_EVENT_CMD_HELLO:
command = "HELLO";
break;
case DM_EVENT_CMD_DIE:
command = "DIE";
break;
case DM_EVENT_CMD_GET_STATUS:
command = "GET_STATUS";
break;
case DM_EVENT_CMD_GET_PARAMETERS:
command = "GET_PARAMETERS";
break;
default:
command = "unknown";
break;
}
snprintf(buf, sizeof(buf), "%s (0x%x)", command, cmd);
return buf;
}
#else
@@ -674,7 +710,6 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
int ret = DM_WAIT_RETRY;
struct dm_task *dmt;
struct dm_info info;
int ioctl_errno;
*task = 0;
@@ -704,27 +739,25 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
* either for a timeout event, or to cancel the thread.
*/
set = _unblock_sigalrm();
errno = 0;
if (dm_task_run(dmt)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
ret = DM_WAIT_INTR;
if ((ret = dm_task_get_info(dmt, &info)))
thread->event_nr = info.event_nr;
} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR;
} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {
ret = DM_WAIT_FATAL;
} else {
ioctl_errno = dm_task_get_errno(dmt);
if (thread->events & DM_EVENT_TIMEOUT && ioctl_errno == EINTR) {
thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR;
} else if (thread->status == DM_THREAD_SHUTDOWN && ioctl_errno == EINTR)
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
errno, strerror(errno));
if (errno == ENXIO) {
syslog(LOG_ERR, "%s disappeared, detaching",
thread->device.name);
ret = DM_WAIT_FATAL;
else {
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
ioctl_errno, strerror(ioctl_errno));
if (ioctl_errno == ENXIO) {
syslog(LOG_ERR, "%s disappeared, detaching",
thread->device.name);
ret = DM_WAIT_FATAL;
}
}
}
DEBUGLOG("Completed waitevent task for %s", thread->device.uuid);
@@ -1562,6 +1595,9 @@ static void _process_request(struct dm_event_fifos *fifos)
{
int die;
struct dm_event_daemon_message msg = { 0 };
#ifdef DEBUG
const char *cmd;
#endif
/*
* Read the request from the client (client_read, client_write
@@ -1570,8 +1606,7 @@ static void _process_request(struct dm_event_fifos *fifos)
if (!_client_read(fifos, &msg))
return;
DEBUGLOG("%s (0x%x) processing...", decode_cmd(msg.cmd), msg.cmd);
DEBUGLOG("%s processing...", cmd = decode_cmd(msg.cmd));
die = (msg.cmd == DM_EVENT_CMD_DIE) ? 1 : 0;
/* _do_process_request fills in msg (if memory allows for
@@ -1583,7 +1618,7 @@ static void _process_request(struct dm_event_fifos *fifos)
dm_free(msg.data);
DEBUGLOG("%s (0x%x) completed.", decode_cmd(msg.cmd), msg.cmd);
DEBUGLOG("%s completed.", cmd);
if (die) {
if (unlink(DMEVENTD_PIDFILE))
@@ -1633,8 +1668,10 @@ static void _cleanup_unused_threads(void)
if (ret == ESRCH) {
thread->status = DM_THREAD_DONE;
} else if (ret) {
syslog(LOG_ERR, "Unable to terminate thread: %s",
strerror(ret));
syslog(LOG_ERR,
"Unable to terminate thread: %s\n",
strerror(-ret));
stack;
}
break;
}
@@ -1666,7 +1703,8 @@ static void _cleanup_unused_threads(void)
static void _sig_alarm(int signum __attribute__((unused)))
{
/* empty SIG_IGN */;
DEBUGLOG("Received SIGALRM.");
pthread_testcancel();
}
/* Init thread signal handling. */

View File

@@ -17,10 +17,15 @@
//#include "libmultilog.h"
#include "dmeventd.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h> /* for htonl, ntohl */

View File

@@ -17,7 +17,6 @@
#include "libdevmapper-event.h"
#include "dmeventd_lvm.h"
#include "defaults.h"
#include "segtype.h"
#include <syslog.h> /* FIXME Replace syslog with multilog */
/* FIXME Missing openlog? */
@@ -180,7 +179,7 @@ void process_event(struct dm_task *dmt,
continue;
}
if (strcmp(target_type, SEG_TYPE_NAME_MIRROR)) {
if (strcmp(target_type, "mirror")) {
syslog(LOG_INFO, "%s has unmirrored portion.", device);
continue;
}

View File

@@ -1,2 +0,0 @@
lvmetad
lvmetactl

View File

@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
SOURCES = lvmetad-core.c
SOURCES2 = testclient.c
TARGETS = lvmetad lvmetactl
TARGETS = lvmetad lvmetad-testclient
.PHONY: install_lvmetad
@@ -39,11 +39,8 @@ CFLAGS += $(EXTRA_EXEC_CFLAGS)
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
# TODO: No idea. No idea how to test either.
#ifneq ("$(CFLOW_CMD)", "")

View File

@@ -1,183 +0,0 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*/
#include "tool.h"
#include "lvmetad-client.h"
daemon_handle h;
static void print_reply(daemon_reply reply)
{
const char *a = daemon_reply_str(reply, "response", NULL);
const char *b = daemon_reply_str(reply, "status", NULL);
const char *c = daemon_reply_str(reply, "reason", NULL);
printf("response \"%s\" status \"%s\" reason \"%s\"\n",
a ? a : "", b ? b : "", c ? c : "");
}
int main(int argc, char **argv)
{
daemon_reply reply;
char *cmd;
char *uuid;
char *name;
int val;
int ver;
if (argc < 2) {
printf("lvmeta dump\n");
printf("lvmeta pv_list\n");
printf("lvmeta vg_list\n");
printf("lvmeta vg_lookup_name <name>\n");
printf("lvmeta vg_lookup_uuid <uuid>\n");
printf("lvmeta pv_lookup_uuid <uuid>\n");
printf("lvmeta set_global_invalid 0|1\n");
printf("lvmeta get_global_invalid\n");
printf("lvmeta set_vg_version <uuid> <version>\n");
printf("lvmeta vg_lock_type <uuid>\n");
return -1;
}
cmd = argv[1];
h = lvmetad_open(NULL);
if (!strcmp(cmd, "dump")) {
reply = daemon_send_simple(h, "dump",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "pv_list")) {
reply = daemon_send_simple(h, "pv_list",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_list")) {
reply = daemon_send_simple(h, "vg_list",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "set_global_invalid")) {
if (argc < 3) {
printf("set_global_invalid 0|1\n");
return -1;
}
val = atoi(argv[2]);
reply = daemon_send_simple(h, "set_global_info",
"global_invalid = %d", val,
"token = %s", "skip",
NULL);
print_reply(reply);
} else if (!strcmp(cmd, "get_global_invalid")) {
reply = daemon_send_simple(h, "get_global_info",
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "set_vg_version")) {
if (argc < 4) {
printf("set_vg_version <uuid> <ver>\n");
return -1;
}
uuid = argv[2];
ver = atoi(argv[3]);
reply = daemon_send_simple(h, "set_vg_info",
"uuid = %s", uuid,
"version = %d", ver,
"token = %s", "skip",
NULL);
print_reply(reply);
} else if (!strcmp(cmd, "vg_lookup_name")) {
if (argc < 3) {
printf("vg_lookup_name <name>\n");
return -1;
}
name = argv[2];
reply = daemon_send_simple(h, "vg_lookup",
"name = %s", name,
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_lookup_uuid")) {
if (argc < 3) {
printf("vg_lookup_uuid <uuid>\n");
return -1;
}
uuid = argv[2];
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_lock_type")) {
struct dm_config_node *metadata;
const char *lock_type;
if (argc < 3) {
printf("vg_lock_type <uuid>\n");
return -1;
}
uuid = argv[2];
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
NULL);
/* printf("%s\n", reply.buffer.mem); */
metadata = dm_config_find_node(reply.cft->root, "metadata");
if (!metadata) {
printf("no metadata\n");
goto out;
}
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
if (!lock_type) {
printf("no lock_type\n");
goto out;
}
printf("lock_type %s\n", lock_type);
} else if (!strcmp(cmd, "pv_lookup_uuid")) {
if (argc < 3) {
printf("pv_lookup_uuid <uuid>\n");
return -1;
}
uuid = argv[2];
reply = daemon_send_simple(h, "pv_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
NULL);
printf("%s\n", reply.buffer.mem);
} else {
printf("unknown command\n");
goto out_close;
}
out:
daemon_reply_destroy(reply);
out_close:
daemon_close(h);
return 0;
}

View File

@@ -14,114 +14,23 @@
#define _XOPEN_SOURCE 500 /* pthread */
#define _REENTRANT
#include "tool.h"
#include "configure.h"
#include "daemon-io.h"
#include "config-util.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "lvm-version.h"
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h> /* fabs() */
#include <float.h> /* DBL_EPSILON */
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
/*
* valid/invalid state of cached metadata
*
* Normally when using lvmetad, the state is kept up-to-date through a
* combination of notifications from clients and updates triggered by uevents.
* When using lvmlockd, the lvmetad state is expected to become out of
* date (invalid/stale) when other hosts make changes to the metadata on disk.
*
* To deal with this, the metadata cached in lvmetad can be flagged as invalid.
* This invalid flag is returned along with the metadata when read by a
* command. The command can check for the invalid flag and decide that it
* should either use the stale metadata (uncommon), or read the latest metadata
* from disk rather than using the invalid metadata that was returned. If the
* command reads the latest metadata from disk, it can choose to send it to
* lvmetad to update the cached copy and clear the invalid flag in lvmetad.
* Otherwise, the next command to read the metadata from lvmetad will also
* receive the invalid metadata with the invalid flag (and like the previous
* command, it too may choose to read the latest metadata from disk and can
* then also choose to update the lvmetad copy.)
*
* For purposes of tracking the invalid state, LVM metadata is considered
* to be either VG-specific or global. VG-specific metadata is metadata
* that is isolated to a VG, such as the LVs it contains. Global
* metadata is metadata that is not isolated to a single VG. Global
* metdata includes:
* . the VG namespace (which VG names are used)
* . the set of orphan PVs (which PVs are in VGs and which are not)
* . properties of orphan PVs (the size of an orphan PV)
*
* If the metadata for a single VG becomes invalid, the VGFL_INVALID
* flag can be set in the vg_info struct for that VG. If the global
* metdata becomes invalid, the GLFL_INVALID flag can be set in the
* lvmetad daemon state.
*
* If a command reads VG metadata and VGFL_INVALID is set, an
* extra config node called "vg_invalid" is added to the config
* data returned to the command.
*
* If a command reads global metdata and GLFL_INVALID is set, an
* extra config node called "global_invalid" is added to the
* config data returned to the command.
*
* If a command sees vg_invalid, and wants the latest VG metadata,
* it only needs to scan disks of the PVs in that VG.
* It can then use vg_update to send the latest metadata to lvmetad
* which clears the VGFL_INVALID flag.
*
* If a command sees global_invalid, and wants the latest metadata,
* it should scan all devices to update lvmetad, and then send
* lvmetad the "set_global_info global_invalid=0" message to clear
* GLFL_INVALID.
*
* (When rescanning devices to update lvmetad, the command must use
* the global filter cmd->lvmetad_filter so that it processes the same
* devices that are seen by lvmetad.)
*
* The lvmetad INVALID flags can be set by sending lvmetad the messages:
*
* . set_vg_info with the latest VG seqno. If the VG seqno is larger
* than the cached VG seqno, VGFL_INVALID is set for the VG.
*
* . set_global_info with global_invalid=1 sets GLFL_INVALID.
*
* Different entities could use these functions to invalidate metadata
* if/when they detected that the cache is stale. How they detect that
* the cache is stale depends on the details of the specific entity.
*
* In the case of lvmlockd, it embeds values into its locks to keep track
* of when other nodes have changed metadata on disk related to those locks.
* When acquring locks it can look at these values and detect that
* the metadata associated with the lock has been changed.
* When the values change, it uses set_vg_info/set_global_info to
* invalidate the lvmetad cache.
*
* The values that lvmlockd distributes through its locks are the
* latest VG seqno in VG locks and a global counter in the global lock.
* When a host acquires a VG lock and sees that the embedded seqno is
* larger than it was previously, it knows that it should invalidate the
* lvmetad cache for the VG. If the host acquires the global lock
* and sees that the counter is larger than previously, it knows that
* it should invalidate the global info in lvmetad. This invalidation
* is done before the lock is returned to the command. This way the
* invalid flag will be set on the metadata before the command reads
* it from lvmetad.
*/
struct vg_info {
int64_t external_version;
uint32_t flags; /* VGFL_ */
};
#define GLFL_INVALID 0x00000001
#define VGFL_INVALID 0x00000001
typedef struct {
log_state *log; /* convenience */
const char *log_config;
@@ -131,8 +40,6 @@ typedef struct {
struct dm_hash_table *vgid_to_metadata;
struct dm_hash_table *vgid_to_vgname;
struct dm_hash_table *vgid_to_outdated_pvs;
struct dm_hash_table *vgid_to_info;
struct dm_hash_table *vgname_to_vgid;
struct dm_hash_table *pvid_to_vgid;
struct {
@@ -143,7 +50,6 @@ typedef struct {
pthread_mutex_t pvid_to_vgid;
} lock;
char token[128];
uint32_t flags; /* GLFL_ */
pthread_mutex_t token_lock;
} lvmetad_state;
@@ -154,17 +60,12 @@ static void destroy_metadata_hashes(lvmetad_state *s)
dm_hash_iterate(n, s->vgid_to_metadata)
dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n));
dm_hash_iterate(n, s->vgid_to_outdated_pvs)
dm_config_destroy(dm_hash_get_data(s->vgid_to_outdated_pvs, n));
dm_hash_iterate(n, s->pvid_to_pvmeta)
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
dm_hash_destroy(s->pvid_to_pvmeta);
dm_hash_destroy(s->vgid_to_metadata);
dm_hash_destroy(s->vgid_to_vgname);
dm_hash_destroy(s->vgid_to_outdated_pvs);
dm_hash_destroy(s->vgid_to_info);
dm_hash_destroy(s->vgname_to_vgid);
dm_hash_destroy(s->device_to_pvid);
@@ -177,8 +78,6 @@ static void create_metadata_hashes(lvmetad_state *s)
s->device_to_pvid = dm_hash_create(32);
s->vgid_to_metadata = dm_hash_create(32);
s->vgid_to_vgname = dm_hash_create(32);
s->vgid_to_outdated_pvs = dm_hash_create(32);
s->vgid_to_info = dm_hash_create(32);
s->pvid_to_vgid = dm_hash_create(32);
s->vgname_to_vgid = dm_hash_create(32);
}
@@ -342,30 +241,6 @@ static int update_pv_status(lvmetad_state *s,
return complete;
}
static struct dm_config_node *add_last_node(struct dm_config_tree *cft, const char *node_name)
{
struct dm_config_node *cn, *last;
cn = cft->root;
last = cn;
while (cn->sib) {
last = cn->sib;
cn = last;
}
cn = dm_config_create_node(cft, node_name);
if (!cn)
return NULL;
cn->v = NULL;
cn->sib = NULL;
cn->parent = cft->root;
last->sib = cn;
return cn;
}
static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid,
struct dm_config_tree *cft,
struct dm_config_node *parent,
@@ -429,9 +304,6 @@ static response pv_list(lvmetad_state *s, request r)
cn = make_pv_node(s, id, res.cft, cn_pvs, cn);
}
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
unlock_pvid_to_pvmeta(s);
return res;
@@ -476,9 +348,6 @@ static response pv_lookup(lvmetad_state *s, request r)
pv->key = "physical_volume";
unlock_pvid_to_pvmeta(s);
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
return res;
}
@@ -547,87 +416,14 @@ static response vg_list(lvmetad_state *s, request r)
}
unlock_vgid_to_metadata(s);
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
bad:
return res;
}
static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvid)
{
struct dm_config_tree *pvmeta, *outdated_pvs;
struct dm_config_node *list, *cft_vgid;
struct dm_config_value *v;
lock_pvid_to_pvmeta(s);
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
unlock_pvid_to_pvmeta(s);
/* if the MDA exists and is used, it will have ignore=0 set */
if (!pvmeta ||
(dm_config_find_int64(pvmeta->root, "pvmeta/mda0/ignore", 1) &&
dm_config_find_int64(pvmeta->root, "pvmeta/mda1/ignore", 1)))
return;
WARN(s, "PV %s has outdated metadata", pvid);
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
if (!outdated_pvs) {
if (!(outdated_pvs = dm_config_from_string("outdated_pvs/pv_list = []")) ||
!(cft_vgid = make_text_node(outdated_pvs, "vgid", dm_pool_strdup(outdated_pvs->mem, vgid),
outdated_pvs->root, NULL)))
abort();
if(!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
abort();
DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
}
list = dm_config_find_node(outdated_pvs->root, "outdated_pvs/pv_list");
v = list->v;
while (v) {
if (v->type != DM_CFG_EMPTY_ARRAY && !strcmp(v->v.str, pvid))
return;
v = v->next;
}
if (!(v = dm_config_create_value(outdated_pvs)))
abort();
v->type = DM_CFG_STRING;
v->v.str = dm_pool_strdup(outdated_pvs->mem, pvid);
v->next = list->v;
list->v = v;
}
static void chain_outdated_pvs(lvmetad_state *s, const char *vgid, struct dm_config_tree *metadata_cft, struct dm_config_node *metadata)
{
struct dm_config_tree *cft = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid), *pvmeta;
struct dm_config_node *pv, *res, *out_pvs = cft ? dm_config_find_node(cft->root, "outdated_pvs/pv_list") : NULL;
struct dm_config_value *pvs_v = out_pvs ? out_pvs->v : NULL;
if (!pvs_v)
return;
if (!(res = make_config_node(metadata_cft, "outdated_pvs", metadata_cft->root, 0)))
return; /* oops */
res->sib = metadata->child;
metadata->child = res;
for (; pvs_v && pvs_v->type != DM_CFG_EMPTY_ARRAY; pvs_v = pvs_v->next) {
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvs_v->v.str);
if (!pvmeta) {
WARN(s, "metadata for PV %s not found", pvs_v->v.str);
continue;
}
if (!(pv = dm_config_clone_node(metadata_cft, pvmeta->root, 0)))
continue;
pv->key = dm_config_find_str(pv, "pvmeta/id", NULL);
pv->sib = res->child;
res->child = pv;
}
}
static response vg_lookup(lvmetad_state *s, request r)
{
struct dm_config_tree *cft;
struct dm_config_node *metadata, *n;
struct vg_info *info;
response res = { 0 };
const char *uuid = daemon_request_str(r, "uuid", NULL);
@@ -690,17 +486,6 @@ static response vg_lookup(lvmetad_state *s, request r)
unlock_vg(s, uuid);
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
chain_outdated_pvs(s, uuid, res.cft, n);
if (s->flags & GLFL_INVALID)
add_last_node(res.cft, "global_invalid");
info = dm_hash_lookup(s->vgid_to_info, uuid);
if (info && (info->flags & VGFL_INVALID)) {
n = add_last_node(res.cft, "vg_invalid");
if (!n)
goto bad;
}
return res;
bad:
@@ -708,13 +493,65 @@ bad:
return reply_fail("out of memory");
}
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
/* Test if the doubles are close enough to be considered equal */
static int close_enough(double d1, double d2)
{
return fabs(d1 - d2) < DBL_EPSILON;
}
enum update_pvid_mode { UPDATE_ONLY, REMOVE_EMPTY, MARK_OUTDATED };
static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
{
int r = 0;
if (a->type > b->type)
return 1;
if (a->type < b->type)
return -1;
switch (a->type) {
case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
case DM_CFG_EMPTY_ARRAY: return 0;
}
if (r == 0 && a->next && b->next)
r = compare_value(a->next, b->next);
return r;
}
static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
{
int result = 0;
if (a->v && b->v)
result = compare_value(a->v, b->v);
if (a->v && !b->v)
result = 1;
if (!a->v && b->v)
result = -1;
if (a->child && b->child)
result = compare_config(a->child, b->child);
if (result) {
// DEBUGLOG("config inequality at %s / %s", a->key, b->key);
return result;
}
if (a->sib && b->sib)
result = compare_config(a->sib, b->sib);
if (a->sib && !b->sib)
result = 1;
if (!a->sib && b->sib)
result = -1;
return result;
}
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
/* You need to be holding the pvid_to_vgid lock already to call this. */
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
const char *vgid, int mode)
const char *vgid, int nuke_empty)
{
struct dm_config_node *pv;
struct dm_hash_table *to_check;
@@ -734,14 +571,11 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
continue;
if (mode == REMOVE_EMPTY &&
if (nuke_empty &&
(vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
!dm_hash_insert(to_check, vgid_old, (void*) 1))
goto out;
if (mode == MARK_OUTDATED)
mark_outdated_pv(s, vgid, pvid);
if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
goto out;
@@ -765,11 +599,10 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
/* A pvid map lock needs to be held if update_pvids = 1. */
static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
{
struct dm_config_tree *old, *outdated_pvs;
struct dm_config_tree *old;
const char *oldname;
lock_vgid_to_metadata(s);
old = dm_hash_lookup(s->vgid_to_metadata, vgid);
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
if (!old) {
@@ -783,15 +616,12 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
dm_hash_remove(s->vgid_to_metadata, vgid);
dm_hash_remove(s->vgid_to_vgname, vgid);
dm_hash_remove(s->vgname_to_vgid, oldname);
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
unlock_vgid_to_metadata(s);
if (update_pvids)
/* FIXME: What should happen when update fails */
update_pvid_to_vgid(s, old, "#orphan", 0);
dm_config_destroy(old);
if (outdated_pvs)
dm_config_destroy(outdated_pvs);
return 1;
}
@@ -835,7 +665,7 @@ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_p
* this function, so they can be safely destroyed after update_metadata returns
* (anything that might have been retained is copied). */
static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
struct dm_config_node *metadata, int64_t *oldseq, const char *pvid)
struct dm_config_node *metadata, int64_t *oldseq)
{
struct dm_config_tree *cft = NULL;
struct dm_config_tree *old;
@@ -884,10 +714,6 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
if (seq < haveseq) {
DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
if (pvid)
mark_outdated_pv(s, dm_config_find_str(old->root, "metadata/id", NULL), pvid);
/* TODO: notify the client that their metadata is out of date? */
retval = 1;
goto out;
@@ -910,8 +736,6 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
if (haveseq >= 0 && haveseq < seq) {
INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
if (oldseq)
update_pvid_to_vgid(s, old, vgid, MARK_OUTDATED);
/* temporarily orphan all of our PVs */
update_pvid_to_vgid(s, old, "#orphan", 0);
}
@@ -985,7 +809,8 @@ static response pv_gone(lvmetad_state *s, request r)
int64_t device = daemon_request_int(r, "device", 0);
int64_t alt_device = 0;
struct dm_config_tree *pvmeta;
char *vgid;
struct dm_config_node *pvmeta_tmp;
char *pvid_old, *vgid;
DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device);
@@ -999,8 +824,8 @@ static response pv_gone(lvmetad_state *s, request r)
DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
if (!(pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid)))
return reply_unknown("PVID does not exist");
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
@@ -1022,6 +847,9 @@ static response pv_gone(lvmetad_state *s, request r)
dm_free(vgid);
}
if (!pvmeta)
return reply_unknown("PVID does not exist");
if (!alt_device)
dm_config_destroy(pvmeta);
@@ -1124,8 +952,8 @@ static response pv_found(lvmetad_state *s, request r)
altdev->v->v.i = device_old_pvid;
break;
}
};
altdev_v = altdev->v;
};
altdev_v = altdev->v;
while (altdev_v) {
if (altdev_v->next && altdev_v->next->v.i == device)
altdev_v->next = altdev_v->next->next;
@@ -1166,7 +994,7 @@ out_of_mem:
if (daemon_request_int(r, "metadata/seqno", -1) < 0)
return reply_fail("need VG seqno");
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old, pvid))
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old))
return reply_fail("metadata update failed");
changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1));
} else {
@@ -1214,39 +1042,6 @@ out_of_mem:
NULL);
}
static response vg_clear_outdated_pvs(lvmetad_state *s, request r)
{
struct dm_config_tree *outdated_pvs;
const char *vgid = daemon_request_str(r, "vgid", NULL);
if (!vgid)
return reply_fail("need VG UUID");
if ((outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid))) {
dm_config_destroy(outdated_pvs);
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
}
return daemon_reply_simple("OK", NULL);
}
static void vg_info_update(lvmetad_state *s, const char *uuid,
struct dm_config_node *metadata)
{
struct vg_info *info;
int64_t cache_version;
cache_version = dm_config_find_int64(metadata, "metadata/seqno", -1);
if (cache_version == -1)
return;
info = (struct vg_info *) dm_hash_lookup(s->vgid_to_info, uuid);
if (!info)
return;
if (cache_version >= info->external_version)
info->flags &= ~VGFL_INVALID;
}
static response vg_update(lvmetad_state *s, request r)
{
struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
@@ -1262,10 +1057,8 @@ static response vg_update(lvmetad_state *s, request r)
/* TODO defer metadata update here; add a separate vg_commit
* call; if client does not commit, die */
if (!update_metadata(s, vgname, vgid, metadata, NULL, NULL))
if (!update_metadata(s, vgname, vgid, metadata, NULL))
return reply_fail("metadata update failed");
vg_info_update(s, vgid, metadata);
}
return daemon_reply_simple("OK", NULL);
}
@@ -1286,71 +1079,6 @@ static response vg_remove(lvmetad_state *s, request r)
return daemon_reply_simple("OK", NULL);
}
static response set_global_info(lvmetad_state *s, request r)
{
const int global_invalid = daemon_request_int(r, "global_invalid", -1);
if (global_invalid == 1)
s->flags |= GLFL_INVALID;
else if (global_invalid == 0)
s->flags &= ~GLFL_INVALID;
return daemon_reply_simple("OK", NULL);
}
static response get_global_info(lvmetad_state *s, request r)
{
return daemon_reply_simple("OK", "global_invalid = %d",
(s->flags & GLFL_INVALID) ? 1 : 0,
NULL);
}
static response set_vg_info(lvmetad_state *s, request r)
{
struct dm_config_tree *vg;
struct vg_info *info;
const char *uuid = daemon_request_str(r, "uuid", NULL);
const int64_t new_version = daemon_request_int(r, "version", -1);
int64_t cache_version;
if (!uuid)
goto out;
if (new_version == -1)
goto out;
vg = dm_hash_lookup(s->vgid_to_metadata, uuid);
if (!vg)
goto out;
if (!new_version)
goto inval;
cache_version = dm_config_find_int64(vg->root, "metadata/seqno", -1);
if (cache_version != -1 && new_version != -1 && cache_version >= new_version)
goto out;
inval:
info = dm_hash_lookup(s->vgid_to_info, uuid);
if (!info) {
info = malloc(sizeof(struct vg_info));
if (!info)
goto bad;
memset(info, 0, sizeof(struct vg_info));
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
goto bad;
}
info->external_version = new_version;
info->flags |= VGFL_INVALID;
out:
return daemon_reply_simple("OK", NULL);
bad:
return reply_fail("out of memory");
}
static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr)
{
struct dm_hash_node *n;
@@ -1388,52 +1116,6 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
buffer_append(buf, "}\n");
}
static void _dump_info_version(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
{
char *append;
struct dm_hash_node *n = dm_hash_get_first(ht);
struct vg_info *info;
buffer_append(buf, name);
buffer_append(buf, " {\n");
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
buffer_append(buf, " ");
(void) dm_asprintf(&append, "%s = %lld", key, (long long)info->external_version);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
n = dm_hash_get_next(ht, n);
}
buffer_append(buf, "}\n");
}
static void _dump_info_flags(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
{
char *append;
struct dm_hash_node *n = dm_hash_get_first(ht);
struct vg_info *info;
buffer_append(buf, name);
buffer_append(buf, " {\n");
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
buffer_append(buf, " ");
(void) dm_asprintf(&append, "%s = %llx", key, (long long)info->flags);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
n = dm_hash_get_next(ht, n);
}
buffer_append(buf, "}\n");
}
static response dump(lvmetad_state *s)
{
response res = { 0 };
@@ -1456,9 +1138,6 @@ static response dump(lvmetad_state *s)
buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
_dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
buffer_append(b, "\n# VGID to outdated PVs mapping\n\n");
_dump_cft(b, s->vgid_to_outdated_pvs, "outdated_pvs/vgid");
buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
_dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);
@@ -1468,12 +1147,6 @@ static response dump(lvmetad_state *s)
buffer_append(b, "\n# DEVICE to PVID mapping\n\n");
_dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1);
buffer_append(b, "\n# VGID to INFO version mapping\n\n");
_dump_info_version(b, s->vgid_to_info, "vgid_to_info", 0);
buffer_append(b, "\n# VGID to INFO flags mapping\n\n");
_dump_info_flags(b, s->vgid_to_info, "vgid_to_info", 0);
unlock_pvid_to_vgid(s);
unlock_pvid_to_pvmeta(s);
unlock_vgid_to_metadata(s);
@@ -1495,7 +1168,7 @@ static response handler(daemon_state s, client_handle h, request r)
return daemon_reply_simple("OK", NULL);
}
if (strcmp(token, state->token) && strcmp(rq, "dump") && strcmp(token, "skip")) {
if (strcmp(token, state->token) && strcmp(rq, "dump")) {
pthread_mutex_unlock(&state->token_lock);
return daemon_reply_simple("token_mismatch",
"expected = %s", state->token,
@@ -1524,9 +1197,6 @@ static response handler(daemon_state s, client_handle h, request r)
if (!strcmp(rq, "vg_update"))
return vg_update(state, r);
if (!strcmp(rq, "vg_clear_outdated_pvs"))
return vg_clear_outdated_pvs(state, r);
if (!strcmp(rq, "vg_remove"))
return vg_remove(state, r);
@@ -1539,15 +1209,6 @@ static response handler(daemon_state s, client_handle h, request r)
if (!strcmp(rq, "vg_list"))
return vg_list(state, r);
if (!strcmp(rq, "set_global_info"))
return set_global_info(state, r);
if (!strcmp(rq, "get_global_info"))
return get_global_info(state, r);
if (!strcmp(rq, "set_vg_info"))
return set_vg_info(state, r);
if (!strcmp(rq, "dump"))
return dump(state);

View File

@@ -1,18 +1,3 @@
/*
* Copyright (C) 2011-2014 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tool.h"
#include "lvmetad-client.h"
#include "label.h"
#include "lvmcache.h"
@@ -124,7 +109,7 @@ int main(int argc, char **argv) {
if (argc > 1) {
int i;
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0);
for (i = 1; i < argc; ++i) {
const char *uuid = NULL;
scan(h, argv[i]);

View File

@@ -1,2 +0,0 @@
lvmlockctl
lvmlockd

View File

@@ -1,66 +0,0 @@
#
# Copyright (C) 2014-2015 Red Hat, Inc.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU Lesser General Public License v.2.1.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmlockd-core.c
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
SOURCES += lvmlockd-sanlock.c
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
SOURCES += lvmlockd-dlm.c
endif
TARGETS = lvmlockd lvmlockctl
.PHONY: install_lvmlockd
include $(top_builddir)/make.tmpl
INCLUDES += -I$(top_srcdir)/libdaemon/server
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
LIBS += -lsanlock_client
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
LIBS += -ldlm_lt
endif
LDFLAGS += -L$(top_builddir)/libdaemon/server
CLDFLAGS += -L$(top_builddir)/libdaemon/server
lvmlockd: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(LVMLIBS)
install_lvmlockd: lvmlockd
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvmlockctl: lvmlockctl
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvm2: install_lvmlockd install_lvmlockctl
install: install_lvm2

View File

@@ -1,751 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*/
#include "tool.h"
#include "lvmlockd-client.h"
#include <stddef.h>
#include <getopt.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
static int quit = 0;
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;
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
#define DUMP_BUF_SIZE (1024 * 1024)
static char dump_buf[DUMP_BUF_SIZE+1];
static int dump_len;
static struct sockaddr_un dump_addr;
static socklen_t dump_addrlen;
daemon_handle _lvmlockd;
#define log_error(fmt, args...) \
do { \
printf(fmt "\n", ##args); \
} while (0)
#define MAX_LINE 512
/* copied from lvmlockd-internal.h */
#define MAX_NAME 64
#define MAX_ARGS 64
/*
* lvmlockd dumps the client info before the lockspaces,
* so we can look up client info when printing lockspace info.
*/
#define MAX_CLIENTS 100
struct client_info {
uint32_t client_id;
int pid;
char name[MAX_NAME+1];
};
static struct client_info clients[MAX_CLIENTS];
static int num_clients;
static void save_client_info(char *line)
{
uint32_t pid = 0;
int fd = 0;
int pi = 0;
uint32_t client_id = 0;
char name[MAX_NAME+1] = { 0 };
sscanf(line, "info=client pid=%u fd=%d pi=%d id=%u name=%s",
&pid, &fd, &pi, &client_id, name);
clients[num_clients].client_id = client_id;
clients[num_clients].pid = pid;
strcpy(clients[num_clients].name, name);
num_clients++;
}
static void find_client_info(uint32_t client_id, uint32_t *pid, char *cl_name)
{
int i;
for (i = 0; i < num_clients; i++) {
if (clients[i].client_id == client_id) {
*pid = clients[i].pid;
strcpy(cl_name, clients[i].name);
return;
}
}
}
static int first_ls = 1;
static void format_info_ls(char *line)
{
char ls_name[MAX_NAME+1] = { 0 };
char vg_name[MAX_NAME+1] = { 0 };
char vg_uuid[MAX_NAME+1] = { 0 };
char vg_sysid[MAX_NAME+1] = { 0 };
char lock_args[MAX_ARGS+1] = { 0 };
char lock_type[MAX_NAME+1] = { 0 };
sscanf(line, "info=ls ls_name=%s vg_name=%s vg_uuid=%s vg_sysid=%s vg_args=%s lm_type=%s",
ls_name, vg_name, vg_uuid, vg_sysid, lock_args, lock_type);
if (!first_ls)
printf("\n");
first_ls = 0;
printf("VG %s lock_type=%s %s\n", vg_name, lock_type, vg_uuid);
printf("LS %s %s\n", lock_type, ls_name);
}
static void format_info_ls_action(char *line)
{
uint32_t client_id = 0;
char flags[MAX_NAME+1] = { 0 };
char version[MAX_NAME+1] = { 0 };
char op[MAX_NAME+1] = { 0 };
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
sscanf(line, "info=ls_action client_id=%u %s %s op=%s",
&client_id, flags, version, op);
find_client_info(client_id, &pid, cl_name);
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
}
static void format_info_r(char *line, char *r_name_out, char *r_type_out)
{
char r_name[MAX_NAME+1] = { 0 };
char r_type[4] = { 0 };
char mode[4] = { 0 };
char sh_count[MAX_NAME+1] = { 0 };
uint32_t ver = 0;
sscanf(line, "info=r name=%s type=%s mode=%s %s version=%u",
r_name, r_type, mode, sh_count, &ver);
strcpy(r_name_out, r_name);
strcpy(r_type_out, r_type);
/* when mode is not un, wait and print each lk line */
if (strcmp(mode, "un"))
return;
/* when mode is un, there will be no lk lines, so print now */
if (!strcmp(r_type, "gl")) {
printf("LK GL un ver %u\n", ver);
} else if (!strcmp(r_type, "vg")) {
printf("LK VG un ver %u\n", ver);
} else if (!strcmp(r_type, "lv")) {
printf("LK LV un %s\n", r_name);
}
}
static void format_info_lk(char *line, char *r_name, char *r_type)
{
char mode[4] = { 0 };
uint32_t ver = 0;
char flags[MAX_NAME+1] = { 0 };
uint32_t client_id = 0;
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
if (!r_name[0] || !r_type[0]) {
printf("format_info_lk error r_name %s r_type %s\n", r_name, r_type);
printf("%s\n", line);
return;
}
sscanf(line, "info=lk mode=%s version=%u %s client_id=%u",
mode, &ver, flags, &client_id);
find_client_info(client_id, &pid, cl_name);
if (!strcmp(r_type, "gl")) {
printf("LK GL %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
} else if (!strcmp(r_type, "vg")) {
printf("LK VG %s ver %u pid %u (%s)\n", mode, ver, pid, cl_name);
} else if (!strcmp(r_type, "lv")) {
printf("LK LV %s %s\n", mode, r_name);
}
}
static void format_info_r_action(char *line, char *r_name, char *r_type)
{
uint32_t client_id = 0;
char flags[MAX_NAME+1] = { 0 };
char version[MAX_NAME+1] = { 0 };
char op[MAX_NAME+1] = { 0 };
char rt[4] = { 0 };
char mode[4] = { 0 };
char lm[MAX_NAME+1] = { 0 };
char result[MAX_NAME+1] = { 0 };
char lm_rv[MAX_NAME+1] = { 0 };
uint32_t pid = 0;
char cl_name[MAX_NAME+1] = { 0 };
if (!r_name[0] || !r_type[0]) {
printf("format_info_r_action error r_name %s r_type %s\n", r_name, r_type);
printf("%s\n", line);
return;
}
sscanf(line, "info=r_action client_id=%u %s %s op=%s rt=%s mode=%s %s %s %s",
&client_id, flags, version, op, rt, mode, lm, result, lm_rv);
find_client_info(client_id, &pid, cl_name);
if (strcmp(op, "lock")) {
printf("OP %s pid %u (%s)\n", op, pid, cl_name);
return;
}
if (!strcmp(r_type, "gl")) {
printf("LW GL %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
} else if (!strcmp(r_type, "vg")) {
printf("LW VG %s ver %u pid %u (%s)\n", mode, 0, pid, cl_name);
} else if (!strcmp(r_type, "lv")) {
printf("LW LV %s %s\n", mode, r_name);
}
}
static void format_info_line(char *line, char *r_name, char *r_type)
{
if (!strncmp(line, "info=structs ", strlen("info=structs "))) {
/* only print this in the raw info dump */
} else if (!strncmp(line, "info=client ", strlen("info=client "))) {
save_client_info(line);
} else if (!strncmp(line, "info=ls ", strlen("info=ls "))) {
format_info_ls(line);
} else if (!strncmp(line, "info=ls_action ", strlen("info=ls_action "))) {
format_info_ls_action(line);
} else if (!strncmp(line, "info=r ", strlen("info=r "))) {
/*
* r_name/r_type are reset when a new resource is found.
* They are reused for the lock and action lines that
* follow a resource line.
*/
memset(r_name, 0, MAX_NAME+1);
memset(r_type, 0, MAX_NAME+1);
format_info_r(line, r_name, r_type);
} else if (!strncmp(line, "info=lk ", strlen("info=lk "))) {
/* will use info from previous r */
format_info_lk(line, r_name, r_type);
} else if (!strncmp(line, "info=r_action ", strlen("info=r_action "))) {
/* will use info from previous r */
format_info_r_action(line, r_name, r_type);
} else {
printf("UN %s\n", line);
}
}
static void format_info(void)
{
char line[MAX_LINE];
char r_name[MAX_NAME+1];
char r_type[MAX_NAME+1];
int i, j;
j = 0;
memset(line, 0, sizeof(line));
for (i = 0; i < dump_len; i++) {
line[j++] = dump_buf[i];
if ((line[j-1] == '\n') || (line[j-1] == '\0')) {
format_info_line(line, r_name, r_type);
j = 0;
memset(line, 0, sizeof(line));
}
}
}
static daemon_reply _lvmlockd_send(const char *req_name, ...)
{
va_list ap;
daemon_reply repl;
daemon_request req;
req = daemon_request_make(req_name);
va_start(ap, req_name);
daemon_request_extend_v(req, ap);
va_end(ap);
repl = daemon_send(_lvmlockd, req);
daemon_request_destroy(req);
return repl;
}
/* See the same in lib/locking/lvmlockd.c */
#define NO_LOCKD_RESULT -1000
static int _lvmlockd_result(daemon_reply reply, int *result)
{
int reply_result;
if (reply.error) {
log_error("lvmlockd_result reply error %d", reply.error);
return 0;
}
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("lvmlockd_result bad response");
return 0;
}
reply_result = daemon_reply_int(reply, "op_result", NO_LOCKD_RESULT);
if (reply_result == -1000) {
log_error("lvmlockd_result no op_result");
return 0;
}
*result = reply_result;
return 1;
}
static int do_quit(void)
{
daemon_reply reply;
int rv = 0;
reply = daemon_send_simple(_lvmlockd, "quit", NULL);
if (reply.error) {
log_error("reply error %d", reply.error);
rv = reply.error;
}
daemon_reply_destroy(reply);
return rv;
}
static int setup_dump_socket(void)
{
int s, rv;
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
if (s < 0)
return s;
memset(&dump_addr, 0, sizeof(dump_addr));
dump_addr.sun_family = AF_LOCAL;
strcpy(&dump_addr.sun_path[1], DUMP_SOCKET_NAME);
dump_addrlen = sizeof(sa_family_t) + strlen(dump_addr.sun_path+1) + 1;
rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
if (rv < 0) {
rv = -errno;
if (!close(s))
log_error("failed to close dump socket");
return rv;
}
return s;
}
static int do_dump(const char *req_name)
{
daemon_reply reply;
int result;
int fd, rv = 0;
int count = 0;
fd = setup_dump_socket();
if (fd < 0) {
log_error("socket error %d", fd);
return fd;
}
reply = daemon_send_simple(_lvmlockd, req_name, NULL);
if (reply.error) {
log_error("reply error %d", reply.error);
rv = reply.error;
goto out;
}
result = daemon_reply_int(reply, "result", 0);
dump_len = daemon_reply_int(reply, "dump_len", 0);
daemon_reply_destroy(reply);
if (result < 0) {
rv = result;
log_error("result %d", result);
}
if (!dump_len)
goto out;
memset(dump_buf, 0, sizeof(dump_buf));
retry:
rv = recvfrom(fd, dump_buf + count, dump_len - count, MSG_WAITALL,
(struct sockaddr *)&dump_addr, &dump_addrlen);
if (rv < 0) {
log_error("recvfrom error %d %d", rv, errno);
rv = -errno;
goto out;
}
count += rv;
if (count < dump_len)
goto retry;
rv = 0;
if ((info && dump) || !strcmp(req_name, "dump"))
printf("%s\n", dump_buf);
else
format_info();
out:
if (close(fd))
log_error("failed to close dump socket %d", fd);
return rv;
}
static int do_able(const char *req_name)
{
daemon_reply reply;
int result;
int rv;
reply = _lvmlockd_send(req_name,
"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 int do_stop_lockspaces(void)
{
daemon_reply reply;
char opts[32];
int result;
int rv;
memset(opts, 0, sizeof(opts));
if (wait_opt)
strcat(opts, "wait ");
if (force_opt)
strcat(opts, "force ");
reply = _lvmlockd_send("stop_all",
"cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"opts = %s", opts[0] ? opts : "none",
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_error("lvmlockd result %d", result);
rv = result;
} else {
rv = 0;
}
daemon_reply_destroy(reply);
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");
printf("Options:\n");
printf("--help | -h\n");
printf(" Show this help information.\n");
printf("--quit | -q\n");
printf(" Tell lvmlockd to quit.\n");
printf("--info | -i\n");
printf(" Print lock state information from lvmlockd.\n");
printf("--dump | -d\n");
printf(" Print log buffer from lvmlockd.\n");
printf("--wait | -w 0|1\n");
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("--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[])
{
int option_index = 0;
int c;
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"quit", no_argument, 0, 'q' },
{"info", no_argument, 0, 'i' },
{"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' },
{0, 0, 0, 0 }
};
if (argc == 1) {
print_usage();
exit(0);
}
while (1) {
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
/* --help */
print_usage();
exit(0);
case 'q':
/* --quit */
quit = 1;
break;
case 'i':
/* --info */
info = 1;
break;
case 'd':
/* --dump */
dump = 1;
break;
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);
break;
case 'D':
gl_disable = 1;
arg_vg_name = strdup(optarg);
break;
case 'S':
stop_lockspaces = 1;
break;
default:
print_usage();
exit(1);
}
}
return 0;
}
int main(int argc, char **argv)
{
int rv = 0;
rv = read_options(argc, argv);
if (rv < 0)
return rv;
_lvmlockd = lvmlockd_open(NULL);
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
log_error("Cannot connect to lvmlockd.");
return -1;
}
if (quit) {
rv = do_quit();
goto out;
}
if (info) {
rv = do_dump("info");
goto out;
}
if (dump) {
rv = do_dump("dump");
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;
}
if (gl_disable) {
rv = do_able("disable_gl");
goto out;
}
if (stop_lockspaces) {
rv = do_stop_lockspaces();
goto out;
}
out:
lvmlockd_close(_lvmlockd);
return rv;
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*/
#ifndef _LVM_LVMLOCKD_CLIENT_H
#define _LVM_LVMLOCKD_CLIENT_H
#include "daemon-client.h"
#define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
/* Wrappers to open/close connection */
static inline daemon_handle lvmlockd_open(const char *sock)
{
daemon_info lvmlockd_info = {
.path = "lvmlockd",
.socket = sock ?: LVMLOCKD_SOCKET,
.protocol = "lvmlockd",
.protocol_version = 1,
.autostart = 0
};
return daemon_open(lvmlockd_info);
}
static inline void lvmlockd_close(daemon_handle h)
{
return daemon_close(h);
}
/*
* Errors returned as the lvmlockd result value.
*/
#define ENOLS 210 /* lockspace not found */
#define ESTARTING 211 /* lockspace is starting */
#define EARGS 212
#define EHOSTID 213
#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 */

File diff suppressed because it is too large Load Diff

View File

@@ -1,662 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*/
#define _XOPEN_SOURCE 500 /* pthread */
#define _ISOC99_SOURCE
#include "tool.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include "xlate.h"
#include "lvmlockd-internal.h"
#include "lvmlockd-client.h"
/*
* Using synchronous _wait dlm apis so do not define _REENTRANT and
* link with non-threaded version of library, libdlm_lt.
*/
#include "libdlm.h"
#include <pthread.h>
#include <stddef.h>
#include <poll.h>
#include <errno.h>
#include <endian.h>
#include <fcntl.h>
#include <byteswap.h>
#include <syslog.h>
#include <dirent.h>
#include <sys/socket.h>
struct lm_dlm {
dlm_lshandle_t *dh;
};
struct rd_dlm {
struct dlm_lksb lksb;
struct val_blk *vb;
};
int lm_data_size_dlm(void)
{
return sizeof(struct rd_dlm);
}
/*
* lock_args format
*
* vg_lock_args format for dlm is
* vg_version_string:undefined:cluster_name
*
* lv_lock_args are not used for dlm
*
* version_string is MAJOR.MINOR.PATCH
* undefined may contain ":"
*/
#define VG_LOCK_ARGS_MAJOR 1
#define VG_LOCK_ARGS_MINOR 0
#define VG_LOCK_ARGS_PATCH 0
static int cluster_name_from_args(char *vg_args, char *clustername)
{
return last_string_from_args(vg_args, clustername);
}
static int check_args_version(char *vg_args)
{
unsigned int major = 0;
int rv;
rv = version_from_args(vg_args, &major, NULL, NULL);
if (rv < 0) {
log_error("check_args_version %s error %d", vg_args, rv);
return rv;
}
if (major > VG_LOCK_ARGS_MAJOR) {
log_error("check_args_version %s major %d %d", vg_args, major, VG_LOCK_ARGS_MAJOR);
return -1;
}
return 0;
}
/* This will be set after dlm_controld is started. */
#define DLM_CLUSTER_NAME_PATH "/sys/kernel/config/dlm/cluster/cluster_name"
static int read_cluster_name(char *clustername)
{
static const char close_error_msg[] = "read_cluster_name: close_error %d";
char *n;
int fd;
int rv;
if (daemon_test) {
sprintf(clustername, "%s", "test");
return 0;
}
fd = open(DLM_CLUSTER_NAME_PATH, O_RDONLY);
if (fd < 0) {
log_debug("read_cluster_name: open error %d, check dlm_controld", fd);
return fd;
}
rv = read(fd, clustername, MAX_ARGS);
if (rv < 0) {
log_error("read_cluster_name: cluster name read error %d, check dlm_controld", fd);
if (close(fd))
log_error(close_error_msg, fd);
return rv;
}
n = strstr(clustername, "\n");
if (n)
*n = '\0';
if (close(fd))
log_error(close_error_msg, fd);
return 0;
}
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
char clustername[MAX_ARGS+1];
char lock_args_version[MAX_ARGS+1];
int rv;
memset(clustername, 0, sizeof(clustername));
memset(lock_args_version, 0, sizeof(lock_args_version));
snprintf(lock_args_version, MAX_ARGS, "%u.%u.%u",
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
rv = read_cluster_name(clustername);
if (rv < 0)
return -EMANAGER;
if (strlen(clustername) + strlen(lock_args_version) + 2 > MAX_ARGS) {
log_error("init_vg_dlm args too long");
return -EARGS;
}
snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, clustername);
rv = 0;
log_debug("init_vg_dlm done %s vg_args %s", ls_name, vg_args);
return rv;
}
int lm_prepare_lockspace_dlm(struct lockspace *ls)
{
char sys_clustername[MAX_ARGS+1];
char arg_clustername[MAX_ARGS+1];
struct lm_dlm *lmd;
int rv;
memset(sys_clustername, 0, sizeof(sys_clustername));
memset(arg_clustername, 0, sizeof(arg_clustername));
rv = read_cluster_name(sys_clustername);
if (rv < 0)
return -EMANAGER;
if (!ls->vg_args[0]) {
/* global lockspace has no vg args */
goto skip_args;
}
rv = check_args_version(ls->vg_args);
if (rv < 0)
return -EARGS;
rv = cluster_name_from_args(ls->vg_args, arg_clustername);
if (rv < 0) {
log_error("prepare_lockspace_dlm %s no cluster name from args %s", ls->name, ls->vg_args);
return -EARGS;
}
if (strcmp(sys_clustername, arg_clustername)) {
log_error("prepare_lockspace_dlm %s mismatching cluster names sys %s arg %s",
ls->name, sys_clustername, arg_clustername);
return -EARGS;
}
skip_args:
lmd = malloc(sizeof(struct lm_dlm));
if (!lmd)
return -ENOMEM;
ls->lm_data = lmd;
return 0;
}
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
if (daemon_test)
return 0;
if (adopt)
lmd->dh = dlm_open_lockspace(ls->name);
else
lmd->dh = dlm_new_lockspace(ls->name, 0600, DLM_LSFL_NEWEXCL);
if (!lmd->dh) {
log_error("add_lockspace_dlm %s adopt %d error", ls->name, adopt);
free(lmd);
ls->lm_data = NULL;
return -1;
}
return 0;
}
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
int rv;
if (daemon_test)
goto out;
/*
* If free_vg is set, it means we are doing vgremove, and we may want
* to tell any other nodes to leave the lockspace. This is not really
* necessary since there should be no harm in having an unused
* lockspace sitting around. A new "notification lock" would need to
* be added with a callback to signal this.
*/
rv = dlm_release_lockspace(ls->name, lmd->dh, 1);
if (rv < 0) {
log_error("rem_lockspace_dlm error %d", rv);
return rv;
}
out:
free(lmd);
ls->lm_data = NULL;
if (!strcmp(ls->name, gl_lsname_dlm))
gl_running_dlm = 0;
return 0;
}
static int lm_add_resource_dlm(struct lockspace *ls, struct resource *r, int with_lock_nl)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
uint32_t flags = 0;
char *buf;
int rv;
if (r->type == LD_RT_GL || r->type == LD_RT_VG) {
buf = malloc(sizeof(struct val_blk) + DLM_LVB_LEN);
if (!buf)
return -ENOMEM;
memset(buf, 0, sizeof(struct val_blk) + DLM_LVB_LEN);
rdd->vb = (struct val_blk *)buf;
rdd->lksb.sb_lvbptr = buf + sizeof(struct val_blk);
flags |= LKF_VALBLK;
}
if (!with_lock_nl)
goto out;
/* because this is a new NL lock request */
flags |= LKF_EXPEDITE;
if (daemon_test)
goto out;
rv = dlm_ls_lock_wait(lmd->dh, LKM_NLMODE, &rdd->lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv < 0) {
log_error("S %s R %s add_resource_dlm lock error %d", ls->name, r->name, rv);
return rv;
}
out:
return 0;
}
int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb;
int rv = 0;
if (daemon_test)
goto out;
lksb = &rdd->lksb;
if (!lksb->sb_lkid)
goto out;
rv = dlm_ls_unlock_wait(lmd->dh, lksb->sb_lkid, 0, lksb);
if (rv < 0) {
log_error("S %s R %s rem_resource_dlm unlock error %d", ls->name, r->name, rv);
}
out:
if (rdd->vb)
free(rdd->vb);
memset(rdd, 0, sizeof(struct rd_dlm));
r->lm_init = 0;
return rv;
}
static int to_dlm_mode(int ld_mode)
{
switch (ld_mode) {
case LD_LK_EX:
return LKM_EXMODE;
case LD_LK_SH:
return LKM_PRMODE;
};
return -1;
}
static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb;
uint32_t flags = 0;
int mode;
int rv;
*r_version = 0;
if (!r->lm_init) {
rv = lm_add_resource_dlm(ls, r, 0);
if (rv < 0)
return rv;
r->lm_init = 1;
}
lksb = &rdd->lksb;
flags |= LKF_PERSISTENT;
flags |= LKF_ORPHAN;
if (rdd->vb)
flags |= LKF_VALBLK;
mode = to_dlm_mode(ld_mode);
if (mode < 0) {
log_error("adopt_dlm invalid mode %d", ld_mode);
rv = -EINVAL;
goto fail;
}
log_debug("S %s R %s adopt_dlm", ls->name, r->name);
if (daemon_test)
return 0;
/*
* dlm returns 0 for success, -EAGAIN if an orphan is
* found with another mode, and -ENOENT if no orphan.
*
* cast/bast/param are (void *)1 because the kernel
* returns errors if some are null.
*/
rv = dlm_ls_lockx(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name), 0,
(void *)1, (void *)1, (void *)1,
NULL, NULL);
if (rv == -EAGAIN) {
log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
ls->name, r->name, ld_mode);
rv = -EUCLEAN;
goto fail;
}
if (rv < 0) {
log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
ls->name, r->name, mode, flags, rv, errno);
goto fail;
}
/*
* FIXME: For GL/VG locks we probably want to read the lvb,
* especially if adopting an ex lock, because when we
* release this adopted ex lock we may want to write new
* lvb values based on the current lvb values (at lease
* in the GL case where we increment the current values.)
*
* It should be possible to read the lvb by requesting
* this lock in the same mode it's already in.
*/
return rv;
fail:
lm_rem_resource_dlm(ls, r);
return rv;
}
/*
* Use PERSISTENT so that if lvmlockd exits while holding locks,
* the locks will remain orphaned in the dlm, still protecting what
* they were acquired to protect.
*/
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int adopt)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb;
struct val_blk vb;
uint32_t flags = 0;
uint16_t vb_version;
int mode;
int rv;
if (adopt) {
/* When adopting, we don't follow the normal method
of acquiring a NL lock then converting it to the
desired mode. */
return lm_adopt_dlm(ls, r, ld_mode, r_version);
}
if (!r->lm_init) {
rv = lm_add_resource_dlm(ls, r, 1);
if (rv < 0)
return rv;
r->lm_init = 1;
}
lksb = &rdd->lksb;
flags |= LKF_CONVERT;
flags |= LKF_NOQUEUE;
flags |= LKF_PERSISTENT;
if (rdd->vb)
flags |= LKF_VALBLK;
mode = to_dlm_mode(ld_mode);
if (mode < 0) {
log_error("lock_dlm invalid mode %d", ld_mode);
return -EINVAL;
}
log_debug("S %s R %s lock_dlm", ls->name, r->name);
if (daemon_test) {
*r_version = 0;
return 0;
}
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv == -EAGAIN) {
log_error("S %s R %s lock_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
return -EAGAIN;
}
if (rv < 0) {
log_error("S %s R %s lock_dlm error %d", ls->name, r->name, rv);
return rv;
}
if (rdd->vb) {
if (lksb->sb_flags & DLM_SBF_VALNOTVALID) {
log_debug("S %s R %s lock_dlm VALNOTVALID", ls->name, r->name);
memset(rdd->vb, 0, sizeof(struct val_blk));
*r_version = 0;
goto out;
}
memcpy(&vb, lksb->sb_lvbptr, sizeof(struct val_blk));
vb_version = le16_to_cpu(vb.version);
if (vb_version && ((vb_version & 0xFF00) > (VAL_BLK_VERSION & 0xFF00))) {
log_error("S %s R %s lock_dlm ignore vb_version %x",
ls->name, r->name, vb_version);
*r_version = 0;
free(rdd->vb);
rdd->vb = NULL;
lksb->sb_lvbptr = NULL;
goto out;
}
*r_version = le32_to_cpu(vb.r_version);
memcpy(rdd->vb, &vb, sizeof(vb)); /* rdd->vb saved as le */
log_debug("S %s R %s lock_dlm get r_version %u",
ls->name, r->name, *r_version);
}
out:
return 0;
}
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb = &rdd->lksb;
uint32_t mode;
uint32_t flags = 0;
int rv;
log_debug("S %s R %s convert_dlm", ls->name, r->name);
flags |= LKF_CONVERT;
flags |= LKF_NOQUEUE;
flags |= LKF_PERSISTENT;
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rdd->vb->version) {
/* first time vb has been written */
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
}
rdd->vb->r_version = cpu_to_le32(r_version);
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
log_debug("S %s R %s convert_dlm set r_version %u",
ls->name, r->name, r_version);
flags |= LKF_VALBLK;
}
mode = to_dlm_mode(ld_mode);
if (daemon_test)
return 0;
rv = dlm_ls_lock_wait(lmd->dh, mode, lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv == -EAGAIN) {
/* FIXME: When does this happen? Should something different be done? */
log_error("S %s R %s convert_dlm mode %d rv EAGAIN", ls->name, r->name, mode);
return -EAGAIN;
}
if (rv < 0) {
log_error("S %s R %s convert_dlm error %d", ls->name, r->name, rv);
}
return rv;
}
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmuf_flags)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
struct rd_dlm *rdd = (struct rd_dlm *)r->lm_data;
struct dlm_lksb *lksb = &rdd->lksb;
uint32_t flags = 0;
int rv;
log_debug("S %s R %s unlock_dlm r_version %u flags %x",
ls->name, r->name, r_version, lmuf_flags);
/*
* Do not set PERSISTENT, because we don't need an orphan
* NL lock to protect anything.
*/
flags |= LKF_CONVERT;
if (rdd->vb && r_version && (r->mode == LD_LK_EX)) {
if (!rdd->vb->version) {
/* first time vb has been written */
rdd->vb->version = cpu_to_le16(VAL_BLK_VERSION);
}
if (r_version)
rdd->vb->r_version = cpu_to_le32(r_version);
memcpy(lksb->sb_lvbptr, rdd->vb, sizeof(struct val_blk));
log_debug("S %s R %s unlock_dlm set r_version %u",
ls->name, r->name, r_version);
flags |= LKF_VALBLK;
}
if (daemon_test)
return 0;
rv = dlm_ls_lock_wait(lmd->dh, LKM_NLMODE, lksb, flags,
r->name, strlen(r->name),
0, NULL, NULL, NULL);
if (rv < 0) {
log_error("S %s R %s unlock_dlm error %d", ls->name, r->name, rv);
}
return rv;
}
/*
* This list could be read from dlm_controld via libdlmcontrol,
* but it's simpler to get it from sysfs.
*/
#define DLM_LOCKSPACES_PATH "/sys/kernel/config/dlm/cluster/spaces"
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;
if (!(ls_dir = opendir(DLM_LOCKSPACES_PATH)))
return -ECONNREFUSED;
while ((de = readdir(ls_dir))) {
if (de->d_name[0] == '.')
continue;
if (strncmp(de->d_name, LVM_LS_PREFIX, strlen(LVM_LS_PREFIX)))
continue;
if (!(ls = alloc_lockspace())) {
if (closedir(ls_dir))
log_error(closedir_err_msg);
return -ENOMEM;
}
ls->lm_type = LD_LM_DLM;
strncpy(ls->name, de->d_name, MAX_NAME);
strncpy(ls->vg_name, ls->name + strlen(LVM_LS_PREFIX), MAX_NAME);
list_add_tail(&ls->list, ls_rejoin);
}
if (closedir(ls_dir))
log_error(closedir_err_msg);
return 0;
}
int lm_is_running_dlm(void)
{
char sys_clustername[MAX_ARGS+1];
int rv;
memset(sys_clustername, 0, sizeof(sys_clustername));
rv = read_cluster_name(sys_clustername);
if (rv < 0)
return 0;
return 1;
}

View File

@@ -1,578 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*/
#ifndef _LVM_LVMLOCKD_INTERNAL_H
#define _LVM_LVMLOCKD_INTERNAL_H
#define MAX_NAME 64
#define MAX_ARGS 64
#define R_NAME_GL_DISABLED "_GLLK_disabled"
#define R_NAME_GL "GLLK"
#define R_NAME_VG "VGLK"
#define S_NAME_GL_DLM "lvm_global"
#define LVM_LS_PREFIX "lvm_" /* ls name is prefix + vg_name */
/* global lockspace name for sanlock is a vg name */
/* lock manager types */
enum {
LD_LM_NONE = 0,
LD_LM_UNUSED = 1, /* place holder so values match lib/locking/lvmlockd.h */
LD_LM_DLM = 2,
LD_LM_SANLOCK = 3,
};
/* operation types */
enum {
LD_OP_HELLO = 1,
LD_OP_QUIT,
LD_OP_INIT,
LD_OP_FREE,
LD_OP_START,
LD_OP_STOP,
LD_OP_LOCK,
LD_OP_UPDATE,
LD_OP_CLOSE,
LD_OP_ENABLE,
LD_OP_DISABLE,
LD_OP_START_WAIT,
LD_OP_STOP_ALL,
LD_OP_DUMP_INFO,
LD_OP_DUMP_LOG,
LD_OP_RENAME_BEFORE,
LD_OP_RENAME_FINAL,
LD_OP_RUNNING_LM,
LD_OP_FIND_FREE_LOCK,
LD_OP_FORGET_VG_NAME,
LD_OP_KILL_VG,
LD_OP_DROP_VG,
};
/* resource types */
enum {
LD_RT_GL = 1,
LD_RT_VG,
LD_RT_LV,
};
/* lock modes, more restrictive must be larger value */
enum {
LD_LK_IV = -1,
LD_LK_UN = 0,
LD_LK_NL = 1,
LD_LK_SH = 2,
LD_LK_EX = 3,
};
struct list_head {
struct list_head *next, *prev;
};
struct client {
struct list_head list;
pthread_mutex_t mutex;
int pid;
int fd;
int pi;
uint32_t id;
unsigned int recv : 1;
unsigned int dead : 1;
unsigned int poll_ignore : 1;
unsigned int lock_ops : 1;
char name[MAX_NAME+1];
};
#define LD_AF_PERSISTENT 0x00000001
#define LD_AF_UNUSED 0x00000002 /* use me */
#define LD_AF_UNLOCK_CANCEL 0x00000004
#define LD_AF_NEXT_VERSION 0x00000008
#define LD_AF_WAIT 0x00000010
#define LD_AF_FORCE 0x00000020
#define LD_AF_EX_DISABLE 0x00000040
#define LD_AF_ENABLE 0x00000080
#define LD_AF_DISABLE 0x00000100
#define LD_AF_SEARCH_LS 0x00000200
#define LD_AF_WAIT_STARTING 0x00001000
#define LD_AF_DUP_GL_LS 0x00002000
#define LD_AF_INACTIVE_LS 0x00004000
#define LD_AF_ADD_LS_ERROR 0x00008000
#define LD_AF_ADOPT 0x00010000
#define LD_AF_WARN_GL_REMOVED 0x00020000
/*
* Number of times to repeat a lock request after
* a lock conflict (-EAGAIN) if unspecified in the
* request.
*/
#define DEFAULT_MAX_RETRIES 4
struct action {
struct list_head list;
uint32_t client_id;
uint32_t flags; /* LD_AF_ */
uint32_t version;
uint64_t host_id;
int8_t op; /* operation type LD_OP_ */
int8_t rt; /* resource type LD_RT_ */
int8_t mode; /* lock mode LD_LK_ */
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
int retries;
int max_retries;
int result;
int lm_rv; /* return value from lm_ function */
char vg_uuid[64];
char vg_name[MAX_NAME+1];
char lv_name[MAX_NAME+1];
char lv_uuid[MAX_NAME+1];
char vg_args[MAX_ARGS+1];
char lv_args[MAX_ARGS+1];
char vg_sysid[MAX_NAME+1];
};
struct resource {
struct list_head list; /* lockspace.resources */
char name[MAX_NAME+1]; /* vg name or lv name */
int8_t type; /* resource type LD_RT_ */
int8_t mode;
unsigned int sh_count; /* number of sh locks on locks list */
uint32_t version;
unsigned int lm_init : 1; /* lm_data is initialized */
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
unsigned int version_zero_valid : 1;
struct list_head locks;
struct list_head actions;
struct val_blk *vb;
char lv_args[MAX_ARGS+1];
char lm_data[0]; /* lock manager specific data */
};
#define LD_LF_PERSISTENT 0x00000001
struct lock {
struct list_head list; /* resource.locks */
int8_t mode; /* lock mode LD_LK_ */
uint32_t version;
uint32_t flags; /* LD_LF_ */
uint32_t client_id; /* may be 0 for persistent or internal locks */
};
struct lockspace {
struct list_head list; /* lockspaces */
char name[MAX_NAME+1];
char vg_name[MAX_NAME+1];
char vg_uuid[64];
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
char vg_sysid[MAX_NAME+1];
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
void *lm_data;
uint64_t host_id;
uint64_t free_lock_offset; /* start search for free lock here */
uint32_t start_client_id; /* client_id that started the lockspace */
pthread_t thread; /* makes synchronous lock requests */
pthread_cond_t cond;
pthread_mutex_t mutex;
unsigned int create_fail : 1;
unsigned int create_done : 1;
unsigned int thread_work : 1;
unsigned int thread_stop : 1;
unsigned int thread_done : 1;
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 */
};
#define VAL_BLK_VERSION 0x0101
struct val_blk {
uint16_t version;
uint16_t flags;
uint32_t r_version;
};
/* lm_unlock flags */
#define LMUF_FREE_VG 0x00000001
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/* to improve readability */
#define WAIT 1
#define NO_WAIT 0
#define FORCE 1
#define NO_FORCE 0
/*
* global variables
*/
#ifndef EXTERN
#define EXTERN extern
#define INIT(X)
#else
#undef EXTERN
#define EXTERN
#define INIT(X) =X
#endif
/*
* gl_type_static and gl_use_ are set by command line or config file
* to specify whether the global lock comes from dlm or sanlock.
* Without a static setting, lvmlockd will figure out where the
* global lock should be (but it could get mixed up in cases where
* both sanlock and dlm vgs exist.)
*
* gl_use_dlm means that the gl should come from lockspace gl_lsname_dlm
* gl_use_sanlock means that the gl should come from lockspace gl_lsname_sanlock
*
* gl_use_dlm has precedence over gl_use_sanlock, so if a node sees both
* dlm and sanlock vgs, it will use the dlm gl.
*
* gl_use_ is set when the first evidence of that lm_type is seen
* in any command.
*
* gl_lsname_sanlock is set when the first vg is seen in which an
* enabled gl is exists, or when init_vg creates a vg with gl enabled,
* or when enable_gl is used.
*
* gl_lsname_sanlock is cleared when free_vg deletes a vg with gl enabled
* 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;
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 daemon_test; /* run as much as possible without a live lock manager */
EXTERN int daemon_debug;
EXTERN int daemon_host_id;
EXTERN const char *daemon_host_id_file;
EXTERN int sanlock_io_timeout;
/*
* This flag is set to 1 if we see multiple vgs with the global
* lock enabled. While this is set, we return a special flag
* with the vg lock result indicating to the lvm command that
* there is a duplicate gl in the vg which should be resolved.
* While this is set, find_lockspace_name has the side job of
* counting the number of lockspaces with enabled gl's so that
* this can be set back to zero when the duplicates are disabled.
*/
EXTERN int sanlock_gl_dup;
void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
#define log_debug(fmt, args...) log_level(LOG_DEBUG, fmt, ##args)
#define log_error(fmt, args...) log_level(LOG_ERR, fmt, ##args)
#define log_warn(fmt, args...) log_level(LOG_WARNING, fmt, ##args)
struct lockspace *alloc_lockspace(void);
int lockspaces_empty(void);
int last_string_from_args(char *args_in, char *last);
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
#ifdef LOCKDDLM_SUPPORT
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int adopt);
int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version);
int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags);
int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r);
int lm_get_lockspaces_dlm(struct list_head *ls_rejoin);
int lm_data_size_dlm(void);
int lm_is_running_dlm(void);
static inline int lm_support_dlm(void)
{
return 1;
}
#else
static inline int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
return -1;
}
static inline int lm_prepare_lockspace_dlm(struct lockspace *ls)
{
return -1;
}
static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
return -1;
}
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{
return -1;
}
static inline int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int adopt)
{
return -1;
}
static inline int lm_convert_dlm(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version)
{
return -1;
}
static inline int lm_unlock_dlm(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags)
{
return -1;
}
static inline int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_get_lockspaces_dlm(struct list_head *ls_rejoin)
{
return -1;
}
static inline int lm_data_size_dlm(void)
{
return -1;
}
static inline int lm_is_running_dlm(void)
{
return 0;
}
static inline int lm_support_dlm(void)
{
return 0;
}
#endif /* dlm support */
#ifdef LOCKDSANLOCK_SUPPORT
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset);
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_sanlock(struct lockspace *ls);
int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt);
int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg);
int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int *retry, int adopt);
int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version);
int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags);
int lm_able_gl_sanlock(struct lockspace *ls, int enable);
int lm_ex_disable_gl_sanlock(struct lockspace *ls);
int lm_hosts_sanlock(struct lockspace *ls, int notify);
int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r);
int lm_gl_is_enabled(struct lockspace *ls);
int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin);
int lm_data_size_sanlock(void);
int lm_is_running_sanlock(void);
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset);
static inline int lm_support_sanlock(void)
{
return 1;
}
#else
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
return -1;
}
static inline int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, uint64_t free_offset)
{
return -1;
}
static inline int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args)
{
return -1;
}
static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls)
{
return -1;
}
static inline int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt)
{
return -1;
}
static inline int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg)
{
return -1;
}
static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
uint32_t *r_version, int *retry, int adopt)
{
return -1;
}
static inline int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
int ld_mode, uint32_t r_version)
{
return -1;
}
static inline int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
uint32_t r_version, uint32_t lmu_flags)
{
return -1;
}
static inline int lm_able_gl_sanlock(struct lockspace *ls, int enable)
{
return -1;
}
static inline int lm_ex_disable_gl_sanlock(struct lockspace *ls)
{
return -1;
}
static inline int lm_hosts_sanlock(struct lockspace *ls, int notify)
{
return -1;
}
static inline int lm_rem_resource_sanlock(struct lockspace *ls, struct resource *r)
{
return -1;
}
static inline int lm_gl_is_enabled(struct lockspace *ls)
{
return -1;
}
static inline int lm_get_lockspaces_sanlock(struct list_head *ls_rejoin)
{
return -1;
}
static inline int lm_data_size_sanlock(void)
{
return -1;
}
static inline int lm_is_running_sanlock(void)
{
return 0;
}
static inline int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
{
return -1;
}
static inline int lm_support_sanlock(void)
{
return 0;
}
#endif /* sanlock support */
#endif /* _LVM_LVMLOCKD_INTERNAL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
lvmpolld

View File

@@ -1,48 +0,0 @@
#
# Copyright (C) 2014-2015 Red Hat, Inc.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU Lesser General Public License v.2.1.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
TARGETS = lvmpolld
.PHONY: install_lvmpolld
CFLOW_LIST = $(SOURCES)
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
CFLOW_TARGET = lvmpolld
include $(top_builddir)/make.tmpl
INCLUDES += -I$(top_srcdir)/libdaemon/server
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
LDFLAGS += -L$(top_builddir)/libdaemon/server $(DAEMON_LDFLAGS)
CLDFLAGS += -L$(top_builddir)/libdaemon/server
CFLAGS += $(DAEMON_CFLAGS)
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
install_lvmpolld: lvmpolld
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvm2: install_lvmpolld
install: install_lvm2

View File

@@ -1,144 +0,0 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lvmpolld-common.h"
/* extract this info from autoconf/automake files */
#define LVPOLL_CMD "lvpoll"
#define MIN_ARGV_SIZE 8
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE,
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN };
const char *polling_op(enum poll_type type)
{
return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
}
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
{
const char **newargv = *cmdargv;
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
if (!newargv)
return 0;
*cmdargv = newargv;
}
*(*cmdargv + (*ind)++) = str;
return 1;
}
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
{
unsigned i = 0;
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
if (!cmd_argv)
return NULL;
/* path to lvm2 binary */
if (!add_to_cmd_arr(&cmd_argv, lvm_binary, &i))
goto err;
/* cmd to execute */
if (!add_to_cmd_arr(&cmd_argv, LVPOLL_CMD, &i))
goto err;
/* transfer internal polling interval */
if (pdlv->sinterval &&
(!add_to_cmd_arr(&cmd_argv, "--interval", &i) ||
!add_to_cmd_arr(&cmd_argv, pdlv->sinterval, &i)))
goto err;
/* pass abort param */
if (abort_polling &&
!add_to_cmd_arr(&cmd_argv, "--abort", &i))
goto err;
/* pass handle-missing-pvs. used by mirror polling operation */
if (handle_missing_pvs &&
!add_to_cmd_arr(&cmd_argv, "--handlemissingpvs", &i))
goto err;
/* one of: "convert", "pvmove", "merge", "merge_thin" */
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
!add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
goto err;
/* vg/lv name */
if (!add_to_cmd_arr(&cmd_argv, pdlv->lvname, &i))
goto err;
/* disable metadata backup */
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
goto err;
/* terminating NULL */
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
goto err;
return cmd_argv;
err:
dm_free(cmd_argv);
return NULL;
}
/* FIXME: in fact exclude should be va list */
static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
{
const char * const* tmp = (const char * const*) environ;
if (!tmp)
return 0;
while (*tmp) {
if (strncmp(*tmp, exclude, strlen(exclude)) && !add_to_cmd_arr(cmd_envp, *tmp, i))
return 0;
tmp++;
}
return 1;
}
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
{
unsigned i = 0;
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
if (!cmd_envp)
return NULL;
/* copy whole environment from lvmpolld, exclude LVM_SYSTEM_DIR if set */
if (!copy_env(&cmd_envp, &i, "LVM_SYSTEM_DIR="))
goto err;
/* Add per client LVM_SYSTEM_DIR variable if set */
if (*pdlv->lvm_system_dir_env && !add_to_cmd_arr(&cmd_envp, pdlv->lvm_system_dir_env, &i))
goto err;
/* terminating NULL */
if (!add_to_cmd_arr(&cmd_envp, NULL, &i))
goto err;
return cmd_envp;
err:
dm_free(cmd_envp);
return NULL;
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_CMD_UTILS_H
#define _LVM_LVMPOLLD_CMD_UTILS_H
#include "lvmpolld-data-utils.h"
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort, unsigned handle_missing_pvs);
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv);
const char *polling_op(enum poll_type);
#endif /* _LVM_LVMPOLLD_CMD_UTILS_H */

View File

@@ -1,989 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lvmpolld-common.h"
#include "lvm-version.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include <getopt.h>
#include <poll.h>
#include <wait.h>
#define LVMPOLLD_SOCKET DEFAULT_RUN_DIR "/lvmpolld.socket"
#define PD_LOG_PREFIX "LVMPOLLD"
#define LVM2_LOG_PREFIX "\tLVPOLL"
/* predefined reason for response = "failed" case */
#define REASON_REQ_NOT_IMPLEMENTED "request not implemented"
#define REASON_MISSING_LVID "request requires lvid set"
#define REASON_MISSING_LVNAME "request requires lvname set"
#define REASON_MISSING_VGNAME "request requires vgname set"
#define REASON_POLLING_FAILED "polling of lvm command failed"
#define REASON_ILLEGAL_ABORT_REQUEST "abort only supported with PVMOVE polling operation"
#define REASON_DIFFERENT_OPERATION_IN_PROGRESS "Different operation on LV already in progress"
#define REASON_INVALID_INTERVAL "request requires interval set"
#define REASON_ENOMEM "not enough memory"
struct lvmpolld_state {
daemon_idle *idle;
log_state *log;
const char *log_config;
const char *lvm_binary;
struct lvmpolld_store *id_to_pdlv_abort;
struct lvmpolld_store *id_to_pdlv_poll;
};
static pthread_key_t key;
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
{
#ifdef _GNU_SOURCE
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
#else
# warning "Can't decide proper strerror_r implementation. lvmpolld will not issue specific system error messages"
return "";
#endif
}
static void _usage(const char *prog, FILE *file)
{
fprintf(file, "Usage:\n"
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path] [-B path] [-p path] [-t secs]\n"
"%s --dump [-s path]\n"
" -V|--version Show version info\n"
" -h|--help Show this help information\n"
" -f|--foreground Don't fork, run in the foreground\n"
" --dump Dump full lvmpolld state\n"
" -l|--log Logging message level (-l {all|wire|debug})\n"
" -p|--pidfile Set path to the pidfile\n"
" -s|--socket Set path to the communication socket\n"
" -B|--binary Path to lvm2 binary\n"
" -t|--timeout Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog, prog);
}
static int _init(struct daemon_state *s)
{
struct lvmpolld_state *ls = s->private;
ls->log = s->log;
if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1))
return 0;
if (pthread_key_create(&key, lvmpolld_thread_data_destroy)) {
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to create pthread key");
return 0;
}
ls->id_to_pdlv_poll = pdst_init("polling");
ls->id_to_pdlv_abort = pdst_init("abort");
if (!ls->id_to_pdlv_poll || !ls->id_to_pdlv_abort) {
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to allocate internal data structures");
return 0;
}
ls->lvm_binary = ls->lvm_binary ?: LVM_PATH;
if (access(ls->lvm_binary, X_OK)) {
FATAL(ls, "%s: %s %s", PD_LOG_PREFIX, "Execute access rights denied on", ls->lvm_binary);
return 0;
}
if (ls->idle)
ls->idle->is_idle = 1;
return 1;
}
static void _lvmpolld_stores_lock(struct lvmpolld_state *ls)
{
pdst_lock(ls->id_to_pdlv_poll);
pdst_lock(ls->id_to_pdlv_abort);
}
static void _lvmpolld_stores_unlock(struct lvmpolld_state *ls)
{
pdst_unlock(ls->id_to_pdlv_abort);
pdst_unlock(ls->id_to_pdlv_poll);
}
static void _lvmpolld_global_lock(struct lvmpolld_state *ls)
{
_lvmpolld_stores_lock(ls);
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_poll);
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_abort);
}
static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
{
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_abort);
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_poll);
_lvmpolld_stores_unlock(ls);
}
static int _fini(struct daemon_state *s)
{
int done;
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
struct lvmpolld_state *ls = s->private;
DEBUGLOG(s, "fini");
DEBUGLOG(s, "sending cancel requests");
_lvmpolld_global_lock(ls);
pdst_locked_send_cancel(ls->id_to_pdlv_poll);
pdst_locked_send_cancel(ls->id_to_pdlv_abort);
_lvmpolld_global_unlock(ls);
DEBUGLOG(s, "waiting for background threads to finish");
while(1) {
_lvmpolld_stores_lock(ls);
done = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
_lvmpolld_stores_unlock(ls);
if (done)
break;
nanosleep(&t, NULL);
}
DEBUGLOG(s, "destroying internal data structures");
_lvmpolld_stores_lock(ls);
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_poll);
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_abort);
_lvmpolld_stores_unlock(ls);
pdst_destroy(ls->id_to_pdlv_poll);
pdst_destroy(ls->id_to_pdlv_abort);
pthread_key_delete(key);
return 1;
}
static response reply(const char *res, const char *reason)
{
return daemon_reply_simple(res, "reason = %s", reason, NULL);
}
static int read_single_line(struct lvmpolld_thread_data *data, int err)
{
ssize_t r = getline(&data->line, &data->line_size, err ? data->ferr : data->fout);
if (r > 0 && *(data->line + r - 1) == '\n')
*(data->line + r - 1) = '\0';
return (r > 0);
}
static void update_idle_state(struct lvmpolld_state *ls)
{
if (!ls->idle)
return;
_lvmpolld_stores_lock(ls);
ls->idle->is_idle = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
_lvmpolld_stores_unlock(ls);
DEBUGLOG(ls, "%s: %s %s%s", PD_LOG_PREFIX, "daemon is", ls->idle->is_idle ? "" : "not ", "idle");
}
/* make this configurable */
#define MAX_TIMEOUT 2
static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data *data)
{
int ch_stat, r, err = 1, fds_count = 2, timeout = 0;
pid_t pid;
struct lvmpolld_cmd_stat cmd_state = { .retcode = -1, .signal = 0 };
struct pollfd fds[] = { { .fd = data->outpipe[0], .events = POLLIN },
{ .fd = data->errpipe[0], .events = POLLIN } };
if (!(data->fout = fdopen(data->outpipe[0], "r")) || !(data->ferr = fdopen(data->errpipe[0], "r"))) {
ERROR(pdlv->ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to open file stream",
errno, _strerror_r(errno, data));
goto out;
}
while (1) {
do {
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
} while (r < 0 && errno == EINTR);
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
if (r < 0) {
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
PD_LOG_PREFIX, "poll() for LVM2 cmd", pdlv->cmd_pid,
errno, _strerror_r(errno, data));
goto out;
} else if (!r) {
timeout++;
WARN(pdlv->ls, "%s: %s (PID %d) %s", PD_LOG_PREFIX,
"polling for output of the lvm cmd", pdlv->cmd_pid,
"has timed out");
if (timeout > MAX_TIMEOUT) {
ERROR(pdlv->ls, "%s: %s (PID %d) (no output for %d seconds)",
PD_LOG_PREFIX,
"LVM2 cmd is unresponsive too long",
pdlv->cmd_pid,
timeout * pdlv_get_timeout(pdlv));
goto out;
}
continue; /* while(1) */
}
timeout = 0;
/* handle the command's STDOUT */
if (fds[0].revents & POLLIN) {
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught input data in STDOUT");
assert(read_single_line(data, 0)); /* may block indef. anyway */
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
pdlv->cmd_pid, "STDOUT", data->line);
} else if (fds[0].revents) {
if (fds[0].revents & POLLHUP)
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught POLLHUP");
else
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
fds[0].fd = -1;
fds_count--;
}
/* handle the command's STDERR */
if (fds[1].revents & POLLIN) {
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
"caught input data in STDERR");
assert(read_single_line(data, 1)); /* may block indef. anyway */
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
pdlv->cmd_pid, "STDERR", data->line);
} else if (fds[1].revents) {
if (fds[1].revents & POLLHUP)
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught err POLLHUP");
else
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
fds[1].fd = -1;
fds_count--;
}
do {
/*
* fds_count == 0 means polling reached EOF
* or received error on both descriptors.
* In such case, just wait for command to finish
*/
pid = waitpid(pdlv->cmd_pid, &ch_stat, fds_count ? WNOHANG : 0);
} while (pid < 0 && errno == EINTR);
if (pid) {
if (pid < 0) {
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
PD_LOG_PREFIX, "waitpid() for lvm2 cmd",
pdlv->cmd_pid, errno,
_strerror_r(errno, data));
goto out;
}
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "child exited");
break;
}
} /* while(1) */
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "about to collect remaining lines");
if (fds[0].fd >= 0)
while (read_single_line(data, 0)) {
assert(r > 0);
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDOUT", data->line);
}
if (fds[1].fd >= 0)
while (read_single_line(data, 1)) {
assert(r > 0);
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDERR", data->line);
}
if (WIFEXITED(ch_stat)) {
INFO(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
"lvm2 cmd", pdlv->cmd_pid, "exited with", WEXITSTATUS(ch_stat));
cmd_state.retcode = WEXITSTATUS(ch_stat);
} else if (WIFSIGNALED(ch_stat)) {
WARN(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
"lvm2 cmd", pdlv->cmd_pid, "got terminated by signal",
WTERMSIG(ch_stat));
cmd_state.signal = WTERMSIG(ch_stat);
}
err = 0;
out:
if (!err)
pdlv_set_cmd_state(pdlv, &cmd_state);
return err;
}
static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
{
const char * const* tmp = ptr;
if (!tmp)
return;
while (*tmp) {
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, *tmp);
tmp++;
}
}
static void *fork_and_poll(void *args)
{
int outfd, errfd, state;
struct lvmpolld_thread_data *data;
pid_t r;
int error = 1;
struct lvmpolld_lv *pdlv = (struct lvmpolld_lv *) args;
struct lvmpolld_state *ls = pdlv->ls;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
data = lvmpolld_thread_data_constructor(pdlv);
pthread_setspecific(key, data);
pthread_setcancelstate(state, &state);
if (!data) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Failed to initialize per-thread data");
goto err;
}
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
debug_print(ls, pdlv->cmdargv);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd environment variables:");
debug_print(ls, pdlv->cmdenvp);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
outfd = data->outpipe[1];
errfd = data->errpipe[1];
r = fork();
if (!r) {
/* child */
/* !!! Do not touch any posix thread primitives !!! */
if ((dup2(outfd, STDOUT_FILENO ) != STDOUT_FILENO) ||
(dup2(errfd, STDERR_FILENO ) != STDERR_FILENO))
_exit(LVMPD_RET_DUP_FAILED);
execve(*(pdlv->cmdargv), (char *const *)pdlv->cmdargv, (char *const *)pdlv->cmdenvp);
_exit(LVMPD_RET_EXC_FAILED);
} else {
/* parent */
if (r == -1) {
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "fork failed",
errno, _strerror_r(errno, data));
goto err;
}
INFO(ls, "%s: LVM2 cmd \"%s\" (PID: %d)", PD_LOG_PREFIX, *(pdlv->cmdargv), r);
pdlv->cmd_pid = r;
/* failure to close write end of any pipe will result in broken polling */
if (close(data->outpipe[1])) {
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of pipe",
errno, _strerror_r(errno, data));
goto err;
}
data->outpipe[1] = -1;
if (close(data->errpipe[1])) {
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of err pipe",
errno, _strerror_r(errno, data));
goto err;
}
data->errpipe[1] = -1;
error = poll_for_output(pdlv, data);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "polling for lvpoll output has finished");
}
err:
r = 0;
pdst_lock(pdlv->pdst);
if (error) {
/* last reader is responsible for pdlv cleanup */
r = pdlv->cmd_pid;
pdlv_set_error(pdlv, 1);
}
pdlv_set_polling_finished(pdlv, 1);
if (data)
data->pdlv = NULL;
pdst_locked_dec(pdlv->pdst);
pdst_unlock(pdlv->pdst);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
lvmpolld_thread_data_destroy(data);
pthread_setspecific(key, NULL);
pthread_setcancelstate(state, &state);
update_idle_state(ls);
/*
* This is unfortunate case where we
* know nothing about state of lvm cmd and
* (eventually) ongoing progress.
*
* harvest zombies
*/
if (r)
while(waitpid(r, NULL, 0) < 0 && errno == EINTR);
return NULL;
}
static response progress_info(client_handle h, struct lvmpolld_state *ls, request req)
{
char *id;
struct lvmpolld_lv *pdlv;
struct lvmpolld_store *pdst;
struct lvmpolld_lv_state st;
response r;
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
if (!lvid)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
id = construct_id(sysdir, lvid);
if (!id) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "progress_info request failed to construct ID.");
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
DEBUGLOG(ls, "%s: %s: %s", PD_LOG_PREFIX, "ID", id);
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
pdst_lock(pdst);
pdlv = pdst_locked_lookup(pdst, id);
if (pdlv) {
/*
* with store lock held, I'm the only reader accessing the pdlv
*/
st = pdlv_get_status(pdlv);
if (st.error || st.polling_finished) {
INFO(ls, "%s: %s %s", PD_LOG_PREFIX,
"Polling finished. Removing related data structure for LV",
lvid);
pdst_locked_remove(pdst, id);
pdlv_destroy(pdlv);
}
}
/* pdlv must not be dereferenced from now on */
pdst_unlock(pdst);
dm_free(id);
if (pdlv) {
if (st.error)
return reply(LVMPD_RESP_FAILED, REASON_POLLING_FAILED);
if (st.polling_finished)
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
LVMPD_PARM_VALUE " = %d", (int64_t)(st.cmd_state.signal ?: st.cmd_state.retcode),
NULL);
else
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
}
else
r = daemon_reply_simple(LVMPD_RESP_NOT_FOUND, NULL);
return r;
}
static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls,
struct lvmpolld_store *pdst,
const char *interval, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
unsigned abort_polling, unsigned uinterval)
{
const char **cmdargv, **cmdenvp;
struct lvmpolld_lv *pdlv;
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
interval, uinterval, pdst);
if (!pdlv) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
return NULL;
}
cmdargv = cmdargv_ctr(pdlv, pdlv->ls->lvm_binary, abort_polling, handle_missing_pvs);
if (!cmdargv) {
pdlv_destroy(pdlv);
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd arguments for lvpoll command");
return NULL;
}
pdlv->cmdargv = cmdargv;
cmdenvp = cmdenvp_ctr(pdlv);
if (!cmdenvp) {
pdlv_destroy(pdlv);
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd environment for lvpoll command");
return NULL;
}
pdlv->cmdenvp = cmdenvp;
return pdlv;
}
static int spawn_detached_thread(struct lvmpolld_lv *pdlv)
{
int r;
pthread_attr_t attr;
if (pthread_attr_init(&attr) != 0)
return 0;
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
return 0;
r = pthread_create(&pdlv->tid, &attr, fork_and_poll, (void *)pdlv);
if (pthread_attr_destroy(&attr) != 0)
return 0;
return !r;
}
static response poll_init(client_handle h, struct lvmpolld_state *ls, request req, enum poll_type type)
{
char *id;
struct lvmpolld_lv *pdlv;
struct lvmpolld_store *pdst;
unsigned uinterval;
const char *interval = daemon_request_str(req, LVMPD_PARM_INTERVAL, NULL);
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
assert(type < POLL_TYPE_MAX);
if (abort_polling && type != PVMOVE)
return reply(LVMPD_RESP_EINVAL, REASON_ILLEGAL_ABORT_REQUEST);
if (!interval || strpbrk(interval, "-") || sscanf(interval, "%u", &uinterval) != 1)
return reply(LVMPD_RESP_EINVAL, REASON_INVALID_INTERVAL);
if (!lvname)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVNAME);
if (!lvid)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
if (!vgname)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_VGNAME);
id = construct_id(sysdir, lvid);
if (!id) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "poll_init request failed to construct ID.");
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
DEBUGLOG(ls, "%s: %s=%s", PD_LOG_PREFIX, "ID", id);
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
pdst_lock(pdst);
pdlv = pdst_locked_lookup(pdst, id);
if (pdlv && pdlv_get_polling_finished(pdlv)) {
WARN(ls, "%s: %s %s", PD_LOG_PREFIX, "Force removal of uncollected info for LV",
lvid);
/*
* lvmpolld has to remove uncollected results in this case.
* otherwise it would have to refuse request for new polling
* lv with same id.
*/
pdst_locked_remove(pdst, id);
pdlv_destroy(pdlv);
pdlv = NULL;
}
if (pdlv) {
if (!pdlv_is_type(pdlv, type)) {
pdst_unlock(pdst);
ERROR(ls, "%s: %s '%s': expected: %s, requested: %s",
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
id,
polling_op(pdlv_get_type(pdlv)), polling_op(type));
dm_free(id);
return reply(LVMPD_RESP_EINVAL,
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
}
pdlv->init_rq_count++; /* safe. protected by store lock */
} else {
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
lvname, sysdir, type, abort_polling, 2 * uinterval);
if (!pdlv) {
pdst_unlock(pdst);
dm_free(id);
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
if (!pdst_locked_insert(pdst, id, pdlv)) {
pdlv_destroy(pdlv);
pdst_unlock(pdst);
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
dm_free(id);
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
if (!spawn_detached_thread(pdlv)) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to spawn detached monitoring thread");
pdst_locked_remove(pdst, id);
pdlv_destroy(pdlv);
pdst_unlock(pdst);
dm_free(id);
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
pdst_locked_inc(pdst);
if (ls->idle)
ls->idle->is_idle = 0;
}
pdst_unlock(pdst);
dm_free(id);
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
}
static response dump_state(client_handle h, struct lvmpolld_state *ls, request r)
{
response res = { 0 };
struct buffer *b = &res.buffer;
buffer_init(b);
_lvmpolld_global_lock(ls);
buffer_append(b, "# Registered polling operations\n\n");
buffer_append(b, "poll {\n");
pdst_locked_dump(ls->id_to_pdlv_poll, b);
buffer_append(b, "}\n\n");
buffer_append(b, "# Registered abort operations\n\n");
buffer_append(b, "abort {\n");
pdst_locked_dump(ls->id_to_pdlv_abort, b);
buffer_append(b, "}");
_lvmpolld_global_unlock(ls);
return res;
}
static response _handler(struct daemon_state s, client_handle h, request r)
{
struct lvmpolld_state *ls = s.private;
const char *rq = daemon_request_str(r, "request", "NONE");
if (!strcmp(rq, LVMPD_REQ_PVMOVE))
return poll_init(h, ls, r, PVMOVE);
else if (!strcmp(rq, LVMPD_REQ_CONVERT))
return poll_init(h, ls, r, CONVERT);
else if (!strcmp(rq, LVMPD_REQ_MERGE))
return poll_init(h, ls, r, MERGE);
else if (!strcmp(rq, LVMPD_REQ_MERGE_THIN))
return poll_init(h, ls, r, MERGE_THIN);
else if (!strcmp(rq, LVMPD_REQ_PROGRESS))
return progress_info(h, ls, r);
else if (!strcmp(rq, LVMPD_REQ_DUMP))
return dump_state(h, ls, r);
else
return reply(LVMPD_RESP_EINVAL, REASON_REQ_NOT_IMPLEMENTED);
}
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
{
char *endptr;
unsigned long l;
errno = 0;
l = strtoul(str, &endptr, 10);
if (errno || *endptr || l >= UINT_MAX)
return 0;
*max_timeouts = (unsigned) l;
return 1;
}
/* Client functionality */
typedef int (*action_fn_t) (void *args);
struct log_line_baton {
const char *prefix;
};
daemon_handle _lvmpolld = { .error = 0 };
static daemon_handle _lvmpolld_open(const char *socket)
{
daemon_info lvmpolld_info = {
.path = "lvmpolld",
.socket = socket ?: DEFAULT_RUN_DIR "/lvmpolld.socket",
.protocol = LVMPOLLD_PROTOCOL,
.protocol_version = LVMPOLLD_PROTOCOL_VERSION
};
return daemon_open(lvmpolld_info);
}
static void _log_line(const char *line, void *baton) {
struct log_line_baton *b = baton;
fprintf(stdout, "%s%s\n", b->prefix, line);
}
static int printout_raw_response(const char *prefix, const char *msg)
{
struct log_line_baton b = { .prefix = prefix };
char *buf;
char *pos;
buf = dm_strdup(msg);
pos = buf;
if (!buf)
return 0;
while (pos) {
char *next = strchr(pos, '\n');
if (next)
*next = 0;
_log_line(pos, &b);
pos = next ? next + 1 : 0;
}
dm_free(buf);
return 1;
}
/* place all action implementations below */
static int action_dump(void *args __attribute__((unused)))
{
daemon_request req;
daemon_reply repl;
int r = 0;
req = daemon_request_make(LVMPD_REQ_DUMP);
if (!req.cft) {
fprintf(stderr, "Failed to create lvmpolld " LVMPD_REQ_DUMP " request.\n");
goto out_req;
}
repl = daemon_send(_lvmpolld, req);
if (repl.error) {
fprintf(stderr, "Failed to send a request or receive response.\n");
goto out_rep;
}
/*
* This is dumb copy & paste from libdaemon log routines.
*/
if (!printout_raw_response(" ", repl.buffer.mem)) {
fprintf(stderr, "Failed to print out the response.\n");
goto out_rep;
}
r = 1;
out_rep:
daemon_reply_destroy(repl);
out_req:
daemon_request_destroy(req);
return r;
}
enum action_index {
ACTION_DUMP = 0,
ACTION_MAX /* keep at the end */
};
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
static int _make_action(enum action_index idx, void *args)
{
return idx < ACTION_MAX ? actions[idx](args) : 0;
}
static int _lvmpolld_client(const char *socket, unsigned action)
{
int r;
_lvmpolld = _lvmpolld_open(socket);
if (_lvmpolld.error || _lvmpolld.socket_fd < 0) {
fprintf(stderr, "Failed to establish connection with lvmpolld.\n");
return 0;
}
r = _make_action(action, NULL);
daemon_close(_lvmpolld);
return r ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int action_idx = ACTION_MAX;
static struct option long_options[] = {
/* Have actions always at the beginning of the array. */
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
/* other options */
{"binary", required_argument, 0, 'B' },
{"foreground", no_argument, 0, 'f' },
{"help", no_argument, 0, 'h' },
{"log", required_argument, 0, 'l' },
{"pidfile", required_argument, 0, 'p' },
{"socket", required_argument, 0, 's' },
{"timeout", required_argument, 0, 't' },
{"version", no_argument, 0, 'V' },
{0, 0, 0, 0 }
};
int main(int argc, char *argv[])
{
int opt;
int option_index = 0;
int client = 0, server = 0;
unsigned action = ACTION_MAX;
struct timeval timeout;
daemon_idle di = { .ptimeout = &timeout };
struct lvmpolld_state ls = { .log_config = "" };
daemon_state s = {
.daemon_fini = _fini,
.daemon_init = _init,
.handler = _handler,
.name = "lvmpolld",
.pidfile = getenv("LVM_LVMPOLLD_PIDFILE") ?: LVMPOLLD_PIDFILE,
.private = &ls,
.protocol = LVMPOLLD_PROTOCOL,
.protocol_version = LVMPOLLD_PROTOCOL_VERSION,
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
};
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
switch (opt) {
case 0 :
if (action < ACTION_MAX) {
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
long_options[action].name);
_usage(argv[0], stderr);
exit(EXIT_FAILURE);
}
action = action_idx;
client = 1;
break;
case '?':
_usage(argv[0], stderr);
exit(EXIT_FAILURE);
case 'B': /* --binary */
ls.lvm_binary = optarg;
server = 1;
break;
case 'V': /* --version */
printf("lvmpolld version: " LVM_VERSION "\n");
exit(EXIT_SUCCESS);
case 'f': /* --foreground */
s.foreground = 1;
server = 1;
break;
case 'h': /* --help */
_usage(argv[0], stdout);
exit(EXIT_SUCCESS);
case 'l': /* --log */
ls.log_config = optarg;
server = 1;
break;
case 'p': /* --pidfile */
s.pidfile = optarg;
server = 1;
break;
case 's': /* --socket */
s.socket_path = optarg;
break;
case 't': /* --timeout in seconds */
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
fprintf(stderr, "Invalid value of timeout parameter.\n");
exit(EXIT_FAILURE);
}
/* 0 equals to wait indefinitely */
if (di.max_timeouts)
s.idle = ls.idle = &di;
server = 1;
break;
}
}
if (client && server) {
fprintf(stderr, "Invalid combination of client and server parameters.\n\n");
_usage(argv[0], stdout);
exit(EXIT_FAILURE);
}
if (client)
return _lvmpolld_client(s.socket_path, action);
/* Server */
daemon_start(s);
return EXIT_SUCCESS;
}

View File

@@ -1,391 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lvmpolld-common.h"
#include "config-util.h"
#include <fcntl.h>
#include <signal.h>
static char *_construct_full_lvname(const char *vgname, const char *lvname)
{
char *name;
size_t l;
l = strlen(vgname) + strlen(lvname) + 2; /* vg/lv and \0 */
name = (char *) dm_malloc(l * sizeof(char));
if (!name)
return NULL;
if (dm_snprintf(name, l, "%s/%s", vgname, lvname) < 0) {
dm_free(name);
name = NULL;
}
return name;
}
static char *_construct_lvm_system_dir_env(const char *sysdir)
{
/*
* Store either "LVM_SYSTEM_DIR=/path/to..."
* - or -
* just single char to store NULL byte
*/
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
char *env = (char *) dm_malloc(l * sizeof(char));
if (!env)
return NULL;
*env = '\0';
if (sysdir && dm_snprintf(env, l, "LVM_SYSTEM_DIR=%s", sysdir) < 0) {
dm_free(env);
env = NULL;
}
return env;
}
static const char *_get_lvid(const char *lvmpolld_id, const char *sysdir)
{
return lvmpolld_id ? (lvmpolld_id + (sysdir ? strlen(sysdir) : 0)) : NULL;
}
char *construct_id(const char *sysdir, const char *uuid)
{
char *id;
int r;
size_t l;
l = strlen(uuid) + (sysdir ? strlen(sysdir) : 0) + 1;
id = (char *) dm_malloc(l * sizeof(char));
if (!id)
return NULL;
r = sysdir ? dm_snprintf(id, l, "%s%s", sysdir, uuid) :
dm_snprintf(id, l, "%s", uuid);
if (r < 0) {
dm_free(id);
id = NULL;
}
return id;
}
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
const char *sinterval, unsigned pdtimeout,
struct lvmpolld_store *pdst)
{
char *lvmpolld_id = dm_strdup(id), /* copy */
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
struct lvmpolld_lv tmp = {
.ls = ls,
.type = type,
.lvmpolld_id = lvmpolld_id,
.lvid = _get_lvid(lvmpolld_id, sysdir),
.lvname = full_lvname,
.lvm_system_dir_env = lvm_system_dir_env,
.sinterval = dm_strdup(sinterval), /* copy */
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
.cmd_state = { .retcode = -1, .signal = 0 },
.pdst = pdst,
.init_rq_count = 1
}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
goto err;
memcpy(pdlv, &tmp, sizeof(*pdlv));
if (pthread_mutex_init(&pdlv->lock, NULL))
goto err;
return pdlv;
err:
dm_free((void *)full_lvname);
dm_free((void *)lvmpolld_id);
dm_free((void *)lvm_system_dir_env);
dm_free((void *)tmp.sinterval);
dm_free((void *)pdlv);
return NULL;
}
void pdlv_destroy(struct lvmpolld_lv *pdlv)
{
dm_free((void *)pdlv->lvmpolld_id);
dm_free((void *)pdlv->lvname);
dm_free((void *)pdlv->sinterval);
dm_free((void *)pdlv->lvm_system_dir_env);
dm_free((void *)pdlv->cmdargv);
dm_free((void *)pdlv->cmdenvp);
pthread_mutex_destroy(&pdlv->lock);
dm_free((void *)pdlv);
}
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
{
unsigned ret;
pdlv_lock(pdlv);
ret = pdlv->polling_finished;
pdlv_unlock(pdlv);
return ret;
}
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv)
{
struct lvmpolld_lv_state r;
pdlv_lock(pdlv);
r.error = pdlv_locked_error(pdlv);
r.polling_finished = pdlv_locked_polling_finished(pdlv);
r.cmd_state = pdlv_locked_cmd_state(pdlv);
pdlv_unlock(pdlv);
return r;
}
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state)
{
pdlv_lock(pdlv);
pdlv->cmd_state = *cmd_state;
pdlv_unlock(pdlv);
}
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error)
{
pdlv_lock(pdlv);
pdlv->error = error;
pdlv_unlock(pdlv);
}
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
{
pdlv_lock(pdlv);
pdlv->polling_finished = finished;
pdlv_unlock(pdlv);
}
struct lvmpolld_store *pdst_init(const char *name)
{
struct lvmpolld_store *pdst = (struct lvmpolld_store *) dm_malloc(sizeof(struct lvmpolld_store));
if (!pdst)
return NULL;
pdst->store = dm_hash_create(32);
if (!pdst->store)
goto err_hash;
if (pthread_mutex_init(&pdst->lock, NULL))
goto err_mutex;
pdst->name = name;
pdst->active_polling_count = 0;
return pdst;
err_mutex:
dm_hash_destroy(pdst->store);
err_hash:
dm_free(pdst);
return NULL;
}
void pdst_destroy(struct lvmpolld_store *pdst)
{
if (!pdst)
return;
dm_hash_destroy(pdst->store);
pthread_mutex_destroy(&pdst->lock);
dm_free(pdst);
}
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
pdlv_lock(dm_hash_get_data(pdst->store, n));
}
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
pdlv_unlock(dm_hash_get_data(pdst->store, n));
}
static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdlv)
{
char tmp[1024];
const struct lvmpolld_cmd_stat *cmd_state = &pdlv->cmd_state;
/* pdlv-section { */
if (dm_snprintf(tmp, sizeof(tmp), "\t%s {\n", pdlv->lvmpolld_id) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvid=\"%s\"\n", pdlv->lvid) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\ttype=\"%s\"\n", polling_op(pdlv->type)) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvname=\"%s\"\n", pdlv->lvname) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvmpolld_internal_timeout=%d\n", pdlv->pdtimeout) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_interval=\"%s\"\n", pdlv->sinterval ?: "<undefined>") > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tLVM_SYSTEM_DIR=\"%s\"\n",
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + strlen("LVM_SYSTEM_DIR=")) : "<undefined>")) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_pid=%d\n", pdlv->cmd_pid) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
buffer_append(buff, tmp);
/* lvm_commmand-section { */
buffer_append(buff, "\t\tlvm_command {\n");
if (cmd_state->retcode == -1 && !cmd_state->signal)
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
else {
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_FINISHED "\"\n");
if (dm_snprintf(tmp, sizeof(tmp), "\t\t\treason=\"%s\"\n\t\t\tvalue=%d\n",
(cmd_state->signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE),
(cmd_state->signal ?: cmd_state->retcode)) > 0)
buffer_append(buff, tmp);
}
buffer_append(buff, "\t\t}\n");
/* } lvm_commmand-section */
buffer_append(buff, "\t}\n");
/* } pdlv-section */
}
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
_pdlv_locked_dump(buff, dm_hash_get_data(pdst->store, n));
}
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst)
{
struct lvmpolld_lv *pdlv;
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store) {
pdlv = dm_hash_get_data(pdst->store, n);
if (!pdlv_locked_polling_finished(pdlv))
pthread_cancel(pdlv->tid);
}
}
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
pdlv_destroy(dm_hash_get_data(pdst->store, n));
}
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv)
{
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) dm_malloc(sizeof(struct lvmpolld_thread_data));
if (!data)
return NULL;
data->pdlv = NULL;
data->line = NULL;
data->line_size = 0;
data->fout = data->ferr = NULL;
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
if (pipe(data->outpipe) || pipe(data->errpipe)) {
lvmpolld_thread_data_destroy(data);
return NULL;
}
if (fcntl(data->outpipe[0], F_SETFD, FD_CLOEXEC) ||
fcntl(data->outpipe[1], F_SETFD, FD_CLOEXEC) ||
fcntl(data->errpipe[0], F_SETFD, FD_CLOEXEC) ||
fcntl(data->errpipe[1], F_SETFD, FD_CLOEXEC)) {
lvmpolld_thread_data_destroy(data);
return NULL;
}
data->pdlv = pdlv;
return data;
}
void lvmpolld_thread_data_destroy(void *thread_private)
{
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) thread_private;
if (!data)
return;
if (data->pdlv) {
pdst_lock(data->pdlv->pdst);
/*
* FIXME: skip this step if lvmpolld is activated
* by systemd.
*/
if (!pdlv_get_polling_finished(data->pdlv))
kill(data->pdlv->cmd_pid, SIGTERM);
pdlv_set_polling_finished(data->pdlv, 1);
pdst_locked_dec(data->pdlv->pdst);
pdst_unlock(data->pdlv->pdst);
}
/* may get reallocated in getline(). dm_free must not be used */
free(data->line);
if (data->fout && !fclose(data->fout))
data->outpipe[0] = -1;
if (data->ferr && !fclose(data->ferr))
data->errpipe[0] = -1;
if (data->outpipe[0] >= 0)
(void) close(data->outpipe[0]);
if (data->outpipe[1] >= 0)
(void) close(data->outpipe[1]);
if (data->errpipe[0] >= 0)
(void) close(data->errpipe[0]);
if (data->errpipe[1] >= 0)
(void) close(data->errpipe[1]);
dm_free(data);
}

View File

@@ -1,215 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
#define _LVM_LVMPOLLD_DATA_UTILS_H
#include <pthread.h>
struct buffer;
struct lvmpolld_state;
enum poll_type {
PVMOVE = 0,
CONVERT,
MERGE,
MERGE_THIN,
POLL_TYPE_MAX
};
struct lvmpolld_cmd_stat {
int retcode;
int signal;
};
struct lvmpolld_store {
pthread_mutex_t lock;
void *store;
const char *name;
unsigned active_polling_count;
};
struct lvmpolld_lv {
/*
* accessing following vars doesn't
* require struct lvmpolld_lv lock
*/
struct lvmpolld_state *const ls;
const enum poll_type type;
const char *const lvid;
const char *const lvmpolld_id;
const char *const lvname; /* full vg/lv name */
const unsigned pdtimeout; /* in seconds */
const char *const sinterval;
const char *const lvm_system_dir_env;
struct lvmpolld_store *const pdst;
const char *const *cmdargv;
const char *const *cmdenvp;
/* only used by write */
pid_t cmd_pid;
pthread_t tid;
pthread_mutex_t lock;
/* block of shared variables protected by lock */
struct lvmpolld_cmd_stat cmd_state;
unsigned init_rq_count; /* for debuging purposes only */
unsigned polling_finished:1; /* no more updates */
unsigned error:1; /* unrecoverable error occured in lvmpolld */
};
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
/* TODO: replace with configuration option */
#define MIN_POLLING_TIMEOUT 60
struct lvmpolld_lv_state {
unsigned error:1;
unsigned polling_finished:1;
struct lvmpolld_cmd_stat cmd_state;
};
struct lvmpolld_thread_data {
char *line;
size_t line_size;
int outpipe[2];
int errpipe[2];
FILE *fout;
FILE *ferr;
char buf[1024];
struct lvmpolld_lv *pdlv;
};
char *construct_id(const char *sysdir, const char *lvid);
/* LVMPOLLD_LV_T section */
/* only call with appropriate struct lvmpolld_store lock held */
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
const char *sinterval, unsigned pdtimeout,
struct lvmpolld_store *pdst);
/* only call with appropriate struct lvmpolld_store lock held */
void pdlv_destroy(struct lvmpolld_lv *pdlv);
static inline void pdlv_lock(struct lvmpolld_lv *pdlv)
{
pthread_mutex_lock(&pdlv->lock);
}
static inline void pdlv_unlock(struct lvmpolld_lv *pdlv)
{
pthread_mutex_unlock(&pdlv->lock);
}
/*
* no struct lvmpolld_lv lock required section
*/
static inline int pdlv_is_type(const struct lvmpolld_lv *pdlv, enum poll_type type)
{
return pdlv->type == type;
}
static inline unsigned pdlv_get_timeout(const struct lvmpolld_lv *pdlv)
{
return pdlv->pdtimeout;
}
static inline enum poll_type pdlv_get_type(const struct lvmpolld_lv *pdlv)
{
return pdlv->type;
}
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv);
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv);
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state);
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error);
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished);
/*
* struct lvmpolld_lv lock required section
*/
static inline struct lvmpolld_cmd_stat pdlv_locked_cmd_state(const struct lvmpolld_lv *pdlv)
{
return pdlv->cmd_state;
}
static inline int pdlv_locked_polling_finished(const struct lvmpolld_lv *pdlv)
{
return pdlv->polling_finished;
}
static inline unsigned pdlv_locked_error(const struct lvmpolld_lv *pdlv)
{
return pdlv->error;
}
/* struct lvmpolld_store manipulation routines */
struct lvmpolld_store *pdst_init(const char *name);
void pdst_destroy(struct lvmpolld_store *pdst);
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff);
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst);
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst);
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst);
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst);
static inline void pdst_lock(struct lvmpolld_store *pdst)
{
pthread_mutex_lock(&pdst->lock);
}
static inline void pdst_unlock(struct lvmpolld_store *pdst)
{
pthread_mutex_unlock(&pdst->lock);
}
static inline void pdst_locked_inc(struct lvmpolld_store *pdst)
{
pdst->active_polling_count++;
}
static inline void pdst_locked_dec(struct lvmpolld_store *pdst)
{
pdst->active_polling_count--;
}
static inline unsigned pdst_locked_get_active_count(const struct lvmpolld_store *pdst)
{
return pdst->active_polling_count;
}
static inline int pdst_locked_insert(struct lvmpolld_store *pdst, const char *key, struct lvmpolld_lv *pdlv)
{
return dm_hash_insert(pdst->store, key, pdlv);
}
static inline struct lvmpolld_lv *pdst_locked_lookup(struct lvmpolld_store *pdst, const char *key)
{
return dm_hash_lookup(pdst->store, key);
}
static inline void pdst_locked_remove(struct lvmpolld_store *pdst, const char *key)
{
dm_hash_remove(pdst->store, key);
}
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv);
void lvmpolld_thread_data_destroy(void *thread_private);
#endif /* _LVM_LVMPOLLD_DATA_UTILS_H */

View File

@@ -1,52 +0,0 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_PROTOCOL_H
#define _LVM_LVMPOLLD_PROTOCOL_H
#include "polling_ops.h"
#define LVMPOLLD_PROTOCOL "lvmpolld"
#define LVMPOLLD_PROTOCOL_VERSION 1
#define LVMPD_REQ_CONVERT CONVERT_POLL
#define LVMPD_REQ_DUMP "dump"
#define LVMPD_REQ_MERGE MERGE_POLL
#define LVMPD_REQ_MERGE_THIN MERGE_THIN_POLL
#define LVMPD_REQ_PROGRESS "progress_info"
#define LVMPD_REQ_PVMOVE PVMOVE_POLL
#define LVMPD_PARM_ABORT "abort"
#define LVMPD_PARM_HANDLE_MISSING_PVS "handle_missing_pvs"
#define LVMPD_PARM_INTERVAL "interval"
#define LVMPD_PARM_LVID "lvid"
#define LVMPD_PARM_LVNAME "lvname"
#define LVMPD_PARM_SYSDIR "sysdir"
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
#define LVMPD_PARM_VGNAME "vgname"
#define LVMPD_RESP_FAILED "failed"
#define LVMPD_RESP_FINISHED "finished"
#define LVMPD_RESP_IN_PROGRESS "in_progress"
#define LVMPD_RESP_EINVAL "invalid"
#define LVMPD_RESP_NOT_FOUND "not_found"
#define LVMPD_RESP_OK "OK"
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating singal */
#define LVMPD_RET_DUP_FAILED 100
#define LVMPD_RET_EXC_FAILED 101
#endif /* _LVM_LVMPOLLD_PROTOCOL_H */

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TOOL_POLLING_OPS_H
#define _LVM_TOOL_POLLING_OPS_H
/* this file is also part of lvmpolld protocol */
#define PVMOVE_POLL "pvmove"
#define CONVERT_POLL "convert"
#define MERGE_POLL "merge"
#define MERGE_THIN_POLL "merge_thin"
#endif /* _LVM_TOOL_POLLING_OPS_H */

View File

@@ -137,17 +137,6 @@ hosts. Overall, this is not hard, but the devil is in the details. I would
possibly disable lvmetad for clustered volume groups in the first phase and
only proceed when the local mode is robust and well tested.
With lvmlockd, lvmetad state is kept up to date by flagging either an
individual VG as "invalid", or the global state as "invalid". When either
the VG or the global state are read, this invalid flag is returned along
with the data. The client command can check for this invalid state and
decide to read the information from disk rather than use the stale cached
data. After the latest data is read from disk, the command may choose to
send it to lvmetad to update the cache. lvmlockd uses version numbers
embedded in its VG and global locks to detect when cached data becomes
invalid, and it then tells lvmetad to set the related invalid flag.
dct, 2015-06-23
Protocol & co.
--------------

View File

@@ -1,81 +0,0 @@
LVM poll daemon overview
========================
(last updated: 2015-05-09)
LVM poll daemon (lvmpolld) is the alternative for lvm2 classical polling
mechanisms. The motivation behind new lvmpolld was to create persistent
system service that would be more durable and transparent. It's suited
particularly for any systemd enabled distribution.
Before lvmpolld any background polling process originating in a lvm2 command
initiated inside cgroup of a systemd service could get killed if the main
process (service) exited in such cgroup. That could lead to premature termination
of such lvm2 polling process.
Also without lvmpolld there were no means to detect a particular polling process
suited for monitoring of specific operation is already in-progress and therefore
it's not desirable to start next one with exactly same task. lvmpolld is able to
detect such duplicate requests and not spawn such redundant process.
lvmpolld is primarily targeted for systems with systemd as init process. For systems
without systemd there's no need to install lvmpolld because there is no issue
with observation described in second paragraph. You can still benefit from
avoiding duplicate polling process being spawned, but without systemd lvmpolld
can't easily be run on-demand (activated by a socket maintained by systemd).
lvmpolld implement shutdown on idle and can shutdown automatically when idle
for requested time. 60 second is recommended default here. This behaviour can be
turned off if found useless.
Data structures
---------------
a) Logical Volume (struct lvmpolld_lv)
Each operation is identified by LV. Internal identifier within lvmpolld
is full LV uuid (vg_uuid+lv_uuid) prefixed with LVM_SYSTEM_DIR if set by client.
such full identifier may look like:
"/etc/lvm/lvm.confWFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
or without LVM_SYSTEM_DIR being set explicitly:
"WFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
LV carries various metadata about polling operation. The most significant are:
VG name
LV name
polling interval (usually --interval passed to lvm2 command or default from lvm2
configuration)
operation type (one of: pvmove, convert, merge, thin_merge)
LVM_SYSTEM_DIR (if set, this is also passed among environment variables of lvpoll
command spawned by lvmpolld)
b) LV stores (struct lvmpolld_store)
lvmpolld uses two stores for Logical volumes (struct lvmpolld_lv). One store for polling
operations in-progress. These operations are as of now: PV move, mirror up-conversion,
classical snapshot merge, thin snapshot merge.
The second store is suited only for pvmove --abort operations in-progress. Both
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
guaranteed by lvm2 locking mechanism).
Locking order
-------------
There are two types of locks in lvmpolld. Each store has own store lock and each LV has
own lv lock.
Locking order is:
1) store lock
2) LV lock
Each LV has to be inside a store. When daemon requires to take both locks it has
to take a store lock first and LV lock has to be taken afterwards (after the
appropriate store lock where the LV is being stored :))

View File

@@ -1,15 +1,11 @@
@top_srcdir@/daemons/clvmd/clvm.h
@top_srcdir@/daemons/dmeventd/libdevmapper-event.h
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
@top_srcdir@/daemons/lvmpolld/lvmpolld-protocol.h
@top_srcdir@/daemons/lvmpolld/polling_ops.h
@top_srcdir@/daemons/lvmlockd/lvmlockd-client.h
@top_srcdir@/liblvm/lvm2app.h
@top_srcdir@/lib/activate/activate.h
@top_srcdir@/lib/activate/targets.h
@top_srcdir@/lib/cache/lvmcache.h
@top_srcdir@/lib/cache/lvmetad.h
@top_srcdir@/lib/locking/lvmlockd.h
@top_srcdir@/lib/commands/toolcontext.h
@top_srcdir@/lib/config/config.h
@top_srcdir@/lib/config/config_settings.h
@@ -33,8 +29,6 @@
@top_srcdir@/lib/locking/locking.h
@top_srcdir@/lib/log/log.h
@top_srcdir@/lib/log/lvm-logging.h
@top_srcdir@/lib/lvmpolld/lvmpolld-client.h
@top_srcdir@/lib/lvmpolld/polldaemon.h
@top_srcdir@/lib/metadata/lv.h
@top_srcdir@/lib/metadata/lv_alloc.h
@top_srcdir@/lib/metadata/metadata.h
@@ -76,4 +70,3 @@
@top_srcdir@/libdm/misc/kdev_t.h
@top_srcdir@/po/pogen.h
@top_srcdir@/tools/lvm2cmd.h
@top_srcdir@/tools/tool.h

View File

@@ -20,12 +20,8 @@ include $(top_builddir)/make.tmpl
all: .symlinks_created
LINKS := $(shell find . -maxdepth 1 -type l)
.symlinks_created: .symlinks
ifneq (,$(firstword $(LINKS)))
$(RM) $(LINKS)
endif
.symlinks_created: .symlinks
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
for i in `cat $<`; do $(LN_S) $$i ; done
touch $@
@@ -35,5 +31,5 @@ device-mapper: all
cflow: all
DISTCLEAN_TARGETS += .symlinks
CLEAN_TARGETS += $(LINKS) .include_symlinks .symlinks_created
DISTCLEAN_TARGETS += $(shell find . -maxdepth 1 -type l)
DISTCLEAN_TARGETS += .include_symlinks .symlinks_created .symlinks

View File

@@ -82,6 +82,7 @@ SOURCES =\
format_text/format-text.c \
format_text/import.c \
format_text/import_vsn1.c \
format_text/tags.c \
format_text/text_label.c \
freeseg/freeseg.c \
label/label.c \
@@ -122,6 +123,11 @@ SOURCES =\
uuid/uuid.c \
zero/zero.c
ifeq ("@HAVE_REALTIME@", "yes")
SOURCES +=\
misc/timestamp.c
endif
ifeq ("@LVM1@", "internal")
SOURCES +=\
format1/disk-rep.c \
@@ -190,16 +196,6 @@ ifeq ("@BUILD_LVMETAD@", "yes")
cache/lvmetad.c
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
SOURCES +=\
lvmpolld/lvmpolld-client.c
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
SOURCES +=\
locking/lvmlockd.c
endif
ifeq ("@DMEVENTD@", "yes")
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
LIBS += -ldevmapper-event

View File

@@ -180,7 +180,7 @@ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_vol
{
const struct dm_config_node *cn;
if (!(cn = find_config_tree_array(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
if (!(cn = find_config_tree_node(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
log_verbose("activation/auto_activation_volume_list configuration setting "
"not defined: All logical volumes will be auto-activated.");
return 1;
@@ -271,12 +271,6 @@ int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent)
{
return 0;
}
int lv_raid_offset_and_sectors(const struct logical_volume *lv,
uint64_t *data_offset,
uint64_t *dev_sectors)
{
return 0;
}
int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
{
return 0;
@@ -473,7 +467,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
{
const struct dm_config_node *cn;
if (!(cn = find_config_tree_array(cmd, activation_volume_list_CFG, NULL))) {
if (!(cn = find_config_tree_node(cmd, activation_volume_list_CFG, NULL))) {
log_verbose("activation/volume_list configuration setting "
"not defined: Checking only host tags for %s/%s",
lv->vg->name, lv->name);
@@ -502,7 +496,7 @@ static int _passes_readonly_filter(struct cmd_context *cmd,
{
const struct dm_config_node *cn;
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
if (!(cn = find_config_tree_node(cmd, activation_read_only_volume_list_CFG, NULL)))
return 0;
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
@@ -654,8 +648,8 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
* in progress - as only those could lead to opened files
*/
if (with_open_count) {
if (locking_is_clustered() && !sync_local_dev_names(cmd)) /* Wait to have udev in sync */
return_0;
if (locking_is_clustered())
sync_local_dev_names(cmd); /* Wait to have udev in sync */
else if (fs_has_non_delete_ops())
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
}
@@ -892,62 +886,6 @@ int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent)
return lv_mirror_percent(lv->vg->cmd, lv, 0, percent, NULL);
}
int lv_raid_dev_count(const struct logical_volume *lv, uint32_t *dev_cnt)
{
struct dev_manager *dm;
struct dm_status_raid *status;
*dev_cnt = 0;
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
return 0;
log_debug_activation("Checking raid device count for LV %s/%s",
lv->vg->name, lv->name);
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
return_0;
if (!dev_manager_raid_status(dm, lv, &status)) {
dev_manager_destroy(dm);
return_0;
}
*dev_cnt = status->dev_count;
dev_manager_destroy(dm);
return 1;
}
int lv_raid_offset_and_sectors(const struct logical_volume *lv,
uint64_t *data_offset,
uint64_t *dev_sectors)
{
int r;
struct dev_manager *dm;
struct dm_status_raid *status;
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
return 0;
log_debug_activation("Checking raid data offset and dev sectors for LV %s/%s",
lv->vg->name, lv->name);
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
return_0;
if (!(r = dev_manager_raid_status(dm, lv, &status)))
stack;
*data_offset = status->data_offset;
if (dev_sectors)
*dev_sectors = status->total_dev_sectors;
dev_manager_destroy(dm);
return r;
}
int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
{
int r;
@@ -1097,8 +1035,7 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
log_error("\"%s\" is not a supported sync operation.", msg);
goto out;
}
if (strcmp(status->sync_action, "idle") &&
strcmp(status->sync_action, "frozen")) {
if (strcmp(status->sync_action, "idle")) {
log_error("%s/%s state is currently \"%s\". Unable to switch to \"%s\".",
lv->vg->name, lv->name, status->sync_action, msg);
goto out;
@@ -1876,9 +1813,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
goto_out;
/* Ignore origin_only unless LV is origin in both old and new metadata */
/* or LV is thin or thin pool volume */
if (!lv_is_thin_volume(ondisk_lv) && !lv_is_thin_pool(ondisk_lv) &&
!(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
if (!lv_is_thin_volume(ondisk_lv) && !(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
laopts->origin_only = 0;
if (test_mode()) {
@@ -2052,6 +1987,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
const struct logical_volume *lv_to_free = NULL;
struct lvinfo info;
int r = 0;
int messages_only = 0;
if (!activation())
return 1;
@@ -2059,7 +1995,10 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
goto_out;
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
if (lv_is_thin_pool(lv) && laopts->origin_only)
messages_only = 1;
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv))
laopts->origin_only = 0;
if (test_mode()) {
@@ -2071,15 +2010,13 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
log_debug_activation("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
error_if_not_active ? "" : " if active",
laopts->origin_only ?
(lv_is_thin_pool(lv) ? " pool only" :
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
laopts->origin_only ? " without snapshots" : "",
laopts->revert ? " (reverting)" : "");
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
goto_out;
if (!info.exists || !info.suspended) {
if (!info.exists || !(info.suspended || messages_only)) {
if (error_if_not_active)
goto_out;
r = 1;
@@ -2335,7 +2272,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
if (info.exists && !info.suspended && info.live_table &&
(info.read_only == read_only_lv(lv, laopts))) {
r = 1;
log_debug_activation("Volume is already active.");
goto out;
}

View File

@@ -167,9 +167,6 @@ int lv_snapshot_percent(const struct logical_volume *lv, dm_percent_t *percent);
int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
int wait, dm_percent_t *percent, uint32_t *event_nr);
int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent);
int lv_raid_dev_count(const struct logical_volume *lv, uint32_t *dev_cnt);
int lv_raid_offset_and_sectors(const struct logical_volume *lv,
uint64_t *data_offset, uint64_t *dev_sectors);
int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health);
int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt);
int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action);

View File

@@ -60,7 +60,6 @@ struct dev_manager {
uint32_t pvmove_mirror_count;
int flush_required;
int activation; /* building activation tree */
int suspend; /* building suspend tree */
int skip_external_lv;
struct dm_list pending_delete; /* str_list of dlid(s) with pending delete */
unsigned track_pending_delete;
@@ -177,16 +176,6 @@ typedef enum {
MKNODES
} info_type_t;
/* Return length of segment depending on type and reshape_len */
static uint32_t _seg_len(const struct lv_segment *seg)
{
if (seg_is_raid(seg))
return seg->len - (((seg->area_count - seg->segtype->parity_devs) * seg->reshape_len) /
(seg_is_any_raid10(seg) ? seg->data_copies : 1));
return seg->len;
}
static int _info_run(info_type_t type, const char *name, const char *dlid,
struct dm_info *dminfo, uint32_t *read_ahead,
struct lv_seg_status *seg_status,
@@ -238,7 +227,7 @@ static int _info_run(info_type_t type, const char *name, const char *dlid,
target = dm_get_next_target(dmt, target, &target_start,
&target_length, &target_name, &target_params);
if (((uint64_t) seg_status->seg->le * extent_size == target_start) &&
((uint64_t) _seg_len(seg_status->seg) * extent_size == target_length)) {
((uint64_t) seg_status->seg->len * extent_size == target_length)) {
params_to_process = target_params;
break;
}
@@ -432,7 +421,7 @@ static int _ignore_blocked_mirror_devices(struct device *dev,
next = dm_get_next_target(dmt, next, &s, &l,
&target_type, &params);
if ((s == start) && (l == length)) {
if (strcmp(target_type, SEG_TYPE_NAME_MIRROR))
if (strcmp(target_type, "mirror"))
goto_out;
if (((p = strstr(params, " block_on_error")) &&
@@ -456,78 +445,6 @@ out:
return r;
}
static int _device_is_suspended(int major, int minor)
{
struct dm_task *dmt;
struct dm_info info;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return 0;
if (!dm_task_set_major_minor(dmt, major, minor, 1))
goto_out;
if (activation_checks() && !dm_task_enable_checks(dmt))
goto_out;
if (!dm_task_run(dmt) ||
!dm_task_get_info(dmt, &info)) {
log_error("Failed to get info for device %d:%d", major, minor);
goto out;
}
r = info.exists && info.suspended;
out:
dm_task_destroy(dmt);
return r;
}
static int _ignore_suspended_snapshot_component(struct device *dev)
{
struct dm_task *dmt;
void *next = NULL;
char *params, *target_type = NULL;
uint64_t start, length;
int major1, minor1, major2, minor2;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
return_0;
if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
goto_out;
if (activation_checks() && !dm_task_enable_checks(dmt))
goto_out;
if (!dm_task_run(dmt)) {
log_error("Failed to get state of snapshot or snapshot origin device");
goto out;
}
do {
next = dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
if (!strcmp(target_type, "snapshot")) {
if (sscanf(params, "%d:%d %d:%d", &major1, &minor1, &major2, &minor2) != 4) {
log_error("Incorrect snapshot table found");
goto_out;
}
r = r || _device_is_suspended(major1, minor1) || _device_is_suspended(major2, minor2);
} else if (!strcmp(target_type, "snapshot-origin")) {
if (sscanf(params, "%d:%d", &major1, &minor1) != 2) {
log_error("Incorrect snapshot-origin table found");
goto_out;
}
r = r || _device_is_suspended(major1, minor1);
}
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
/*
* device_is_usable
* @dev
@@ -615,7 +532,7 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (check.check_blocked && target_type && !strcmp(target_type, SEG_TYPE_NAME_MIRROR)) {
if (check.check_blocked && target_type && !strcmp(target_type, "mirror")) {
if (ignore_lvm_mirrors()) {
log_debug_activation("%s: Scanning mirror devices is disabled.", dev_name(dev));
goto out;
@@ -636,25 +553,15 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
* supported anymore and in general using mirrors in a stack
* is disabled by default (with a warning that if enabled,
* it could cause various deadlocks).
* Similar situation can happen with RAID devices where
* a RAID device can be snapshotted.
* If one of the RAID legs are down and we're doing
* lvconvert --repair, there's a time period in which
* snapshot components are (besides other devs) suspended.
* See also https://bugzilla.redhat.com/show_bug.cgi?id=1219222
* for an example where this causes problems.
*
* This is a quick check for now, but replace it with more
* robust and better check that would check the stack
* correctly, not just snapshots but any cobimnation possible
* in a stack - use proper dm tree to check this instead.
* This is former check used, but it's not correct as it
* disables snapshot-origins to be used in a stack in
* general, not just over mirrors!
*/
if (check.check_suspended && target_type &&
(!strcmp(target_type, "snapshot") || !strcmp(target_type, "snapshot-origin")) &&
_ignore_suspended_snapshot_component(dev)) {
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
/*if (check.check_suspended && target_type && !strcmp(target_type, "snapshot-origin")) {
log_debug_activation("%s: Snapshot-origin device %s not usable.",
dev_name(dev), name);
goto out;
}
}*/
if (target_type && strcmp(target_type, "error"))
only_error_target = 0;
@@ -1928,6 +1835,7 @@ struct pool_cb_data {
int skip_zero; /* to skip zeroed device header (check first 64B) */
int exec; /* which binary to call */
int opts;
const char *defaults;
const char *global;
};
@@ -1935,6 +1843,7 @@ static int _pool_callback(struct dm_tree_node *node,
dm_node_callback_t type, void *cb_data)
{
int ret, status, fd;
char *split;
const struct dm_config_node *cn;
const struct dm_config_value *cv;
const struct pool_cb_data *data = cb_data;
@@ -1949,19 +1858,23 @@ static int _pool_callback(struct dm_tree_node *node,
if (!*argv[0])
return 1; /* Checking disabled */
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
return 0;
}
for (cv = cn->v; cv && args < 16; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "
"global/%s_check_options",
data->global);
if ((cn = find_config_tree_node(mlv->vg->cmd, data->opts, NULL))) {
for (cv = cn->v; cv && args < 16; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "
"global/%s_check_options",
data->global);
return 0;
}
argv[++args] = cv->v.str;
}
} else {
/* Use default options (no support for options with spaces) */
if (!(split = dm_pool_strdup(data->dm->mem, data->defaults))) {
log_error("Failed to duplicate defaults.");
return 0;
}
argv[++args] = cv->v.str;
args = dm_split_words(split, 16, 0, (char**) argv + 1);
}
if (args == 16) {
@@ -2052,12 +1965,14 @@ static int _pool_register_callback(struct dev_manager *dm,
data->skip_zero = 1;
data->exec = global_thin_check_executable_CFG;
data->opts = global_thin_check_options_CFG;
data->defaults = DEFAULT_THIN_CHECK_OPTION1 " " DEFAULT_THIN_CHECK_OPTION2;
data->global = "thin";
} else if (lv_is_cache(lv)) { /* cache pool */
data->pool_lv = first_seg(lv)->pool_lv;
data->skip_zero = dm->activation;
data->exec = global_cache_check_executable_CFG;
data->opts = global_cache_check_options_CFG;
data->defaults = DEFAULT_CACHE_CHECK_OPTION1;
data->global = "cache";
} else {
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
@@ -2069,11 +1984,6 @@ static int _pool_register_callback(struct dev_manager *dm,
return 1;
}
/* Declaration to resolve suspend tree and message passing for thin-pool */
static int _add_target_to_dtree(struct dev_manager *dm,
struct dm_tree_node *dnode,
struct lv_segment *seg,
struct lv_activate_opts *laopts);
/*
* Add LV and any known dependencies
*/
@@ -2142,43 +2052,15 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
*/
if (!_add_dev_to_dtree(dm, dtree, lv, lv_layer(lv)))
return_0;
/*
* TODO: change API and move this code
* Could be easier to handle this in _add_dev_to_dtree()
* and base this according to info.exists ?
*/
if (!dm->activation) {
/* Setup callback for non-activation partial tree */
/* Activation gets own callback when needed */
/* TODO: extend _cached_dm_info() to return dnode */
if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
return_0;
if ((node = dm_tree_find_node_by_uuid(dtree, uuid))) {
if (origin_only) {
struct lv_activate_opts laopts = {
.origin_only = 1,
.send_messages = 1 /* Node with messages */
};
/*
* Add some messsages if right node exist in the table only
* when building SUSPEND tree for origin-only thin-pool.
*
* TODO: Fix call of '_add_target_to_dtree()' to add message
* to thin-pool node as we already know the pool node exists
* in the table. Any better/cleaner API way ?
*
* Probably some 'new' target method to add messages for any node?
*/
if (dm->suspend &&
!dm_list_empty(&(first_seg(lv)->thin_messages)) &&
!_add_target_to_dtree(dm, node, first_seg(lv), &laopts))
return_0;
} else {
/* Setup callback for non-activation partial tree */
/* Activation gets own callback when needed */
/* TODO: extend _cached_dm_info() to return dnode */
if (!_pool_register_callback(dm, node, lv))
return_0;
}
}
if ((node = dm_tree_find_node_by_uuid(dtree, uuid)) &&
!_pool_register_callback(dm, node, lv))
return_0;
}
}
@@ -2252,7 +2134,6 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
!_add_lv_to_dtree(dm, dtree, seg_lv(seg, s), 0))
return_0;
if (seg_is_raid(seg) &&
seg->meta_areas && seg_metalv(seg, s) &&
!_add_lv_to_dtree(dm, dtree, seg_metalv(seg, s), 0))
return_0;
}
@@ -2277,7 +2158,7 @@ static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, const struc
dm_tree_set_optional_uuid_suffixes(dtree, &uuid_suffix_list[0]);
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv) || lv_is_thin_pool(lv)) ? origin_only : 0))
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv)) ? origin_only : 0))
goto_bad;
return dtree;
@@ -2296,7 +2177,7 @@ static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
struct lv_segment *seg_i;
struct dm_info info;
int segno = -1, i = 0;
uint64_t size = (uint64_t) _seg_len(seg) * seg->lv->vg->extent_size;
uint64_t size = (uint64_t) seg->len * seg->lv->vg->extent_size;
dm_list_iterate_items(seg_i, &seg->lv->segments) {
if (seg == seg_i)
@@ -2422,14 +2303,9 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
return_0;
continue;
}
if (seg->meta_areas && seg_metalv(seg, s)) {
if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s), NULL)))
return_0;
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s)))
return_0;
/* One for metadata area */
} else if (!dm_tree_node_add_null_area(node, 0))
if (!(dlid = build_dm_uuid(dm->mem, seg_metalv(seg, s), NULL)))
return_0;
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_metale(seg, s)))
return_0;
if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s), NULL)))
@@ -2437,6 +2313,7 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
return_0;
} else if (seg_type(seg, s) == AREA_LV) {
if (!(dlid = build_dm_uuid(dm->mem, seg_lv(seg, s), NULL)))
return_0;
if (!dm_tree_node_add_target_area(node, NULL, dlid, extent_size * seg_le(seg, s)))
@@ -2571,11 +2448,10 @@ static int _add_target_to_dtree(struct dev_manager *dm,
return 0;
}
PFLA("%s seg->len=%u seg->reshape_len=%u", seg->lv->name ? seg->lv->name : "NOLV", seg->len, seg->reshape_len);
return seg->segtype->ops->add_target_line(dm, dm->mem, dm->cmd,
&dm->target_state, seg,
laopts, dnode,
extent_size * _seg_len(seg),
extent_size * seg->len,
&dm->pvmove_mirror_count);
}
@@ -2737,7 +2613,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
return_0;
/* Add pool layer */
if (seg->pool_lv && !laopts->origin_only &&
if (seg->pool_lv &&
!_add_new_lv_to_dtree(dm, dtree, seg->pool_lv, laopts,
lv_layer(seg->pool_lv)))
return_0;
@@ -2756,7 +2632,6 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
laopts, NULL))
return_0;
if (seg_is_raid(seg) &&
seg->meta_areas && seg_metalv(seg, s) &&
!_add_new_lv_to_dtree(dm, dtree, seg_metalv(seg, s),
laopts, NULL))
return_0;
@@ -2766,7 +2641,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
/* Replace target and all its used devs with error mapping */
log_debug_activation("Using error for pending delete %s.",
seg->lv->name);
if (!dm_tree_node_add_error_target(dnode, (uint64_t) seg->lv->vg->extent_size * _seg_len(seg)))
if (!dm_tree_node_add_error_target(dnode, (uint64_t)seg->lv->vg->extent_size * seg->len))
return_0;
} else if (!_add_target_to_dtree(dm, dnode, seg, laopts))
return_0;
@@ -2944,7 +2819,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
if (lv_is_origin(lv) && !layer) {
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, "real"))
return_0;
if (!laopts->no_merging && lv_is_merging_origin(lv)) {
if (!_add_new_lv_to_dtree(dm, dtree,
find_snapshot(lv)->cow, laopts, "cow"))
@@ -2968,7 +2842,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
} else if (lv_is_cow(lv) && !layer) {
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, "cow"))
return_0;
if (!_add_snapshot_target_to_dtree(dm, dnode, lv, laopts))
return_0;
} else if (!layer && ((lv_is_thin_pool(lv) && !lv_is_new_thin_pool(lv)) ||
@@ -3169,10 +3042,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
int r = 0;
if (action < DM_ARRAY_SIZE(_action_names))
log_debug_activation("Creating %s%s tree for %s.",
_action_names[action],
(laopts->origin_only) ? " origin-only" : "",
display_lvname(lv));
log_debug_activation("Creating %s tree for %s.", _action_names[action], lv->name);
/* Some LV can be used for top level tree */
/* TODO: add more.... */
@@ -3182,7 +3052,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
}
/* Some targets may build bigger tree for activation */
dm->activation = ((action == PRELOAD) || (action == ACTIVATE));
dm->suspend = (action == SUSPEND_WITH_LOCKFS) || (action == SUSPEND);
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
return_0;
@@ -3227,9 +3096,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
case PRELOAD:
case ACTIVATE:
/* Add all required new devices to tree */
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts,
(lv_is_origin(lv) && laopts->origin_only) ? "real" :
(lv_is_thin_pool(lv) && laopts->origin_only) ? "tpool" : NULL))
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL))
goto_out;
/* Preload any devices required before any suspensions */
@@ -3267,6 +3134,7 @@ out_no_root:
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
struct lv_activate_opts *laopts)
{
laopts->send_messages = 1;
if (!_tree_action(dm, lv, laopts, ACTIVATE))
return_0;

379
lib/cache/lvmcache.c vendored
View File

@@ -56,7 +56,6 @@ struct lvmcache_vginfo {
char _padding[7];
struct lvmcache_vginfo *next; /* Another VG with same name? */
char *creation_host;
char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
size_t vgmetadata_size;
@@ -68,7 +67,6 @@ struct lvmcache_vginfo {
unsigned vg_use_count; /* Counter of vg reusage */
unsigned precommitted; /* Is vgmetadata live or precommitted? */
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
unsigned preferred_duplicates; /* preferred duplicate pvs have been set */
};
static struct dm_hash_table *_pvid_hash = NULL;
@@ -117,47 +115,6 @@ int lvmcache_init(void)
return 1;
}
/*
* Once PV info has been populated in lvmcache and
* lvmcache has chosen preferred duplicate devices,
* set this flag so that lvmcache will not try to
* compare and choose preferred duplicate devices
* again (which may result in different preferred
* devices.) PV info can be populated in lvmcache
* multiple times, each time causing lvmcache to
* compare the duplicate devices, so we need to
* record that the comparison/preferences have
* already been done, so the preferrences from the
* first time through are not changed.
*
* This is something of a hack to work around the
* fact that the code isn't really designed to
* handle duplicate PVs, and the fact that lvmetad
* has its own way of picking a preferred duplicate
* and lvmcache has another way based on having
* more information than lvmetad does.
*
* If we come up with a better overall method to
* handle duplicate PVs, then this can probably be
* removed.
*
* FIXME: if we want to make lvmetad work with clvmd,
* then this may need to be changed to set
* preferred_duplicates back to 0.
*/
void lvmcache_set_preferred_duplicates(const char *vgid)
{
struct lvmcache_vginfo *vginfo;
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) {
stack;
return;
}
vginfo->preferred_duplicates = 1;
}
void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
{
if (!lvmetad_active() || _has_scanned)
@@ -906,37 +863,6 @@ int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo
}
// #endif
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct dm_list *vgnameids)
{
struct vgnameid_list *vgnl;
struct lvmcache_vginfo *vginfo;
lvmcache_label_scan(cmd, 0);
dm_list_iterate_items(vginfo, &_vginfos) {
if (!include_internal && is_orphan_vg(vginfo->vgname))
continue;
if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {
log_error("vgnameid_list allocation failed.");
return 0;
}
vgnl->vgid = dm_pool_strdup(cmd->mem, vginfo->vgid);
vgnl->vg_name = dm_pool_strdup(cmd->mem, vginfo->vgname);
if (!vgnl->vgid || !vgnl->vg_name) {
log_error("vgnameid_list member allocation failed.");
return 0;
}
dm_list_add(vgnameids, &vgnl->list);
}
return 1;
}
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
int include_internal)
{
@@ -1448,7 +1374,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
}
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
const char *creation_host, const char *lock_type)
const char *creation_host)
{
if (!info || !info->vginfo)
return 1;
@@ -1461,11 +1387,11 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
info->vginfo->status = vgstatus;
if (!creation_host)
goto set_lock_type;
return 1;
if (info->vginfo->creation_host && !strcmp(creation_host,
info->vginfo->creation_host))
goto set_lock_type;
return 1;
if (info->vginfo->creation_host)
dm_free(info->vginfo->creation_host);
@@ -1479,24 +1405,6 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
log_debug_cache("lvmcache: %s: VG %s: Set creation host to %s.",
dev_name(info->dev), info->vginfo->vgname, creation_host);
set_lock_type:
if (!lock_type)
goto out;
if (info->vginfo->lock_type && !strcmp(lock_type, info->vginfo->lock_type))
goto out;
if (info->vginfo->lock_type)
dm_free(info->vginfo->lock_type);
if (!(info->vginfo->lock_type = dm_strdup(lock_type))) {
log_error("cache creation host alloc failed for %s",
lock_type);
return 0;
}
out:
return 1;
}
@@ -1565,7 +1473,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
vgsummary->creation_host, info->fmt) ||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type) ||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host) ||
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
return_0;
@@ -1580,8 +1488,7 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
struct lvmcache_vgsummary vgsummary = {
.vgname = vg->name,
.vgstatus = vg->status,
.vgid = vg->id,
.lock_type = vg->lock_type
.vgid = vg->id
};
pvid_s[sizeof(pvid_s) - 1] = '\0';
@@ -1622,64 +1529,6 @@ void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
pv->dev = dev;
}
/*
* We can see multiple different devices with the
* same pvid, i.e. duplicates.
*
* There may be different reasons for seeing two
* devices with the same pvid:
* - multipath showing two paths to the same thing
* - one device copied to another, e.g. with dd,
* also referred to as cloned devices.
* - a "subsystem" taking a device and creating
* another device of its own that represents the
* underlying device it is using, e.g. using dm
* to create an identity mapping of a PV.
*
* Given duplicate devices, we have to choose one
* of them to be the "preferred" dev, i.e. the one
* that will be referenced in lvmcache, by pv->dev.
* We can keep the existing dev, that's currently
* used in lvmcache, or we can replace the existing
* dev with the new duplicate.
*
* Regardless of which device is preferred, we need
* to print messages explaining which devices were
* found so that a user can sort out for themselves
* what has happened if the preferred device is not
* the one they are interested in.
*
* If a user wants to use the non-preferred device,
* they will need to filter out the device that
* lvm is preferring.
*
* The dev_subsystem calls check if the major number
* of the dev is part of a subsystem like DM/MD/DRBD.
* A dev that's part of a subsystem is preferred over a
* duplicate of that dev that is not part of a
* subsystem.
*
* The has_holders calls check if the device is being
* used by another, and prefers one that's being used.
*
* FIXME: why do we prefer a device without holders
* over a device with holders? We should understand
* the reason for that choice.
*
* FIXME: there may be other reasons to prefer one
* device over another:
*
* . are there other use/open counts we could check
* beyond the holders?
*
* . check if either is bad/usable and prefer
* the good one?
*
* . prefer the one with smaller minor number?
* Might avoid disturbing things due to a new
* transient duplicate?
*/
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid,
@@ -1727,166 +1576,54 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
lvmcache_del_bas(info);
} else {
if (existing->dev != dev) {
int old_in_subsystem = 0;
int new_in_subsystem = 0;
int old_is_dm = 0;
int new_is_dm = 0;
int old_has_holders = 0;
int new_has_holders = 0;
/*
* Here are different devices with the same pvid:
* duplicates. See comment above.
*/
/*
* This flag tells the process_each_pv code to search
* the devices list for duplicates, so that devices
* can be processed together with their duplicates
* (while processing the VG, rather than reporting
* pv->dev under the VG, and its duplicate outside
* the VG context.)
*/
_found_duplicate_pvs = 1;
/*
* The new dev may not have pvid set.
* The process_each_pv code needs to have the pvid
* set in each device to detect that the devices
* are duplicates.
*/
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
/*
* Now decide if we are going to ignore the new
* device, or replace the existing/old device in
* lvmcache with the new one.
*/
old_in_subsystem = dev_subsystem_part_major(dt, existing->dev);
new_in_subsystem = dev_subsystem_part_major(dt, dev);
old_is_dm = dm_is_dm_major(MAJOR(existing->dev->dev));
new_is_dm = dm_is_dm_major(MAJOR(dev->dev));
old_has_holders = dm_device_has_holders(MAJOR(existing->dev->dev), MINOR(existing->dev->dev));
new_has_holders = dm_device_has_holders(MAJOR(dev->dev), MINOR(dev->dev));
if (old_has_holders && new_has_holders) {
/*
* This is not a selection of old or new, but
* just a warning to be aware of.
*/
log_warn("WARNING: duplicate PV %s is being used from both devices %s and %s",
pvid_s,
dev_name(existing->dev),
dev_name(dev));
}
if (existing->vginfo->preferred_duplicates) {
/*
* The preferred duplicate devs have already
* been chosen during a previous populating of
* lvmcache, so just use the existing preferences.
*/
log_verbose("Found duplicate PV %s: using existing dev %s",
pvid_s,
dev_name(existing->dev));
/* Is the existing entry a duplicate pvid e.g. md ? */
if (dev_subsystem_part_major(dt, existing->dev) &&
!dev_subsystem_part_major(dt, dev)) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s - using %s %s",
pvid, dev_name(dev),
dev_subsystem_name(dt, existing->dev),
dev_name(existing->dev));
return NULL;
} else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
!dm_is_dm_major(MAJOR(dev->dev))) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s - using dm %s",
pvid, dev_name(dev),
dev_name(existing->dev));
return NULL;
} else if (!dev_subsystem_part_major(dt, existing->dev) &&
dev_subsystem_part_major(dt, dev))
log_very_verbose("Duplicate PV %s on %s - "
"using %s %s", pvid,
dev_name(existing->dev),
dev_subsystem_name(dt, existing->dev),
dev_name(dev));
else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) &&
dm_is_dm_major(MAJOR(dev->dev)))
log_very_verbose("Duplicate PV %s on %s - "
"using dm %s", pvid,
dev_name(existing->dev),
dev_name(dev));
/* FIXME If both dm, check dependencies */
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
//dm_is_dm_major(MAJOR(dev->dev)))
//
else if (!strcmp(pvid_s, existing->dev->pvid)) {
log_error("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(existing->dev),
dev_name(dev));
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
_found_duplicate_pvs = 1;
return NULL;
}
if (old_in_subsystem && !new_in_subsystem) {
/* Use old, ignore new. */
log_warn("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(existing->dev),
dev_name(dev));
log_warn("Using duplicate PV %s from subsystem %s, ignoring %s",
dev_name(existing->dev),
dev_subsystem_name(dt, existing->dev),
dev_name(dev));
return NULL;
} else if (!old_in_subsystem && new_in_subsystem) {
/* Use new, replace old. */
log_warn("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(dev),
dev_name(existing->dev));
log_warn("Using duplicate PV %s from subsystem %s, replacing %s",
dev_name(dev),
dev_subsystem_name(dt, dev),
dev_name(existing->dev));
} else if (old_has_holders && !new_has_holders) {
/* Use new, replace old. */
/* FIXME: why choose the one without olders? */
log_warn("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(dev),
dev_name(existing->dev));
log_warn("Using duplicate PV %s without holders, replacing %s",
dev_name(dev),
dev_name(existing->dev));
} else if (!old_has_holders && new_has_holders) {
/* Use old, ignore new. */
log_warn("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(existing->dev),
dev_name(dev));
log_warn("Using duplicate PV %s without holders, ignoring %s",
dev_name(existing->dev),
dev_name(dev));
return NULL;
} else if (old_is_dm && new_is_dm) {
/* Use new, replace old. */
/* FIXME: why choose the new instead of the old? */
log_warn("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(dev),
dev_name(existing->dev));
log_warn("Using duplicate PV %s which is last seen, replacing %s",
dev_name(dev),
dev_name(existing->dev));
} else if (!strcmp(pvid_s, existing->dev->pvid)) {
/* No criteria to use for preferring old or new. */
/* FIXME: why choose the new instead of the old? */
/* FIXME: a transient duplicate would be a reason
* to select the old instead of the new. */
log_warn("Found duplicate PV %s: using %s not %s",
pvid_s,
dev_name(dev),
dev_name(existing->dev));
log_warn("Using duplicate PV %s which is last seen, replacing %s",
dev_name(dev),
dev_name(existing->dev));
}
} else {
/*
* The new dev is the same as the existing dev.
*
* FIXME: Why can't we just return NULL here if the
* device already exists? Things don't seem to work
* if we do that for some reason.
*/
log_verbose("Found same device %s with same pvid %s",
dev_name(existing->dev), pvid_s);
}
/*
* This happens when running pvcreate on an existing PV.
*/
if (strcmp(pvid_s, existing->dev->pvid)) {
log_verbose("Replacing dev %s pvid %s with dev %s pvid %s",
dev_name(existing->dev), existing->dev->pvid,
dev_name(dev), pvid_s);
}
/*
* Switch over to new preferred device.
*/
if (strcmp(pvid_s, existing->dev->pvid))
log_debug_cache("Updating pvid cache to %s (%s) from %s (%s)",
pvid_s, dev_name(dev),
existing->dev->pvid, dev_name(existing->dev));
/* Switch over to new preferred device */
existing->dev = dev;
info = existing;
/* Has labeller changed? */
@@ -2336,8 +2073,7 @@ int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
vgsummary->vgname = vginfo->vgname;
vgsummary->creation_host = vginfo->creation_host;
vgsummary->vgstatus = vginfo->status;
/* vginfo->vgid has 1 extra byte then vgsummary->vgid */
memcpy(&vgsummary->vgid, vginfo->vgid, sizeof(vgsummary->vgid));
memcpy((char *)&vgsummary->vgid, vginfo->vgid, sizeof(vginfo->vgid));
return 1;
}
@@ -2345,16 +2081,3 @@ int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
return 0;
}
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
{
struct lvmcache_vginfo *vginfo;
dm_list_iterate_items(vginfo, &_vginfos) {
if (vginfo->lock_type && !strcmp(vginfo->lock_type, "sanlock"))
return 1;
}
return 0;
}

19
lib/cache/lvmcache.h vendored
View File

@@ -39,23 +39,11 @@ struct disk_locn;
struct lvmcache_vginfo;
/*
* vgsummary represents a summary of the VG that is read
* without a lock. The info does not come through vg_read(),
* but through reading mdas. It provides information about
* the VG that is needed to lock the VG and then read it fully
* with vg_read(), after which the VG summary should be checked
* against the full VG metadata to verify it was correct (since
* it was read without a lock.)
*
* Once read, vgsummary information is saved in lvmcache_vginfo.
*/
struct lvmcache_vgsummary {
const char *vgname;
struct id vgid;
uint64_t vgstatus;
char *creation_host;
const char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
};
@@ -119,9 +107,6 @@ struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd,
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
int include_internal);
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct dm_list *vgnameids);
/* Returns list of struct dm_str_list containing pool-allocated copy of pvids */
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
const char *vgid);
@@ -186,8 +171,4 @@ void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
int lvmcache_found_duplicate_pvs(void);
void lvmcache_set_preferred_duplicates(const char *vgid);
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
#endif

637
lib/cache/lvmetad.c vendored
View File

@@ -22,7 +22,6 @@
#include "format-text.h" // TODO for disk_locn, used as a DA representation
#include "crc.h"
#include "lvm-signal.h"
#include "lvmlockd.h"
#define SCAN_TIMEOUT_SECONDS 80
#define MAX_RESCANS 10 /* Maximum number of times to scan all PVs and retry if the daemon returns a token mismatch error */
@@ -35,13 +34,12 @@ static char *_lvmetad_token = NULL;
static const char *_lvmetad_socket = NULL;
static struct cmd_context *_lvmetad_cmd = NULL;
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
void lvmetad_disconnect(void)
{
if (_lvmetad_connected)
daemon_close(_lvmetad);
_lvmetad_connected = 0;
_lvmetad_cmd = NULL;
}
void lvmetad_init(struct cmd_context *cmd)
@@ -49,10 +47,6 @@ void lvmetad_init(struct cmd_context *cmd)
if (!_lvmetad_use && !access(getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE, F_OK))
log_warn("WARNING: lvmetad is running but disabled."
" Restart lvmetad before enabling it!");
if (_lvmetad_connected)
log_debug(INTERNAL_ERROR "Refreshing lvmetad global handle while connection with the daemon is active");
_lvmetad_cmd = cmd;
}
@@ -148,7 +142,7 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
static daemon_reply _lvmetad_send(const char *id, ...)
{
va_list ap;
daemon_reply repl = { 0 };
daemon_reply repl;
daemon_request req;
unsigned num_rescans = 0;
unsigned total_usecs_waited = 0;
@@ -158,10 +152,8 @@ static daemon_reply _lvmetad_send(const char *id, ...)
retry:
req = daemon_request_make(id);
if (_lvmetad_token && !daemon_request_extend(req, "token = %s", _lvmetad_token, NULL)) {
repl.error = ENOMEM;
return repl;
}
if (_lvmetad_token)
daemon_request_extend(req, "token = %s", _lvmetad_token, NULL);
va_start(ap, id);
daemon_request_extend_v(req, ap);
@@ -273,12 +265,11 @@ static int _read_mda(struct lvmcache_info *info,
return 0;
}
static int _pv_populate_lvmcache(struct cmd_context *cmd,
struct dm_config_node *cn,
struct format_type *fmt, dev_t fallback)
static struct lvmcache_info *_pv_populate_lvmcache(struct cmd_context *cmd,
struct dm_config_node *cn,
struct format_type *fmt, dev_t fallback)
{
struct device *dev, *dev_alternate, *dev_alternate_cache = NULL;
struct label *label;
struct device *dev, *dev_alternate;
struct id pvid, vgid;
char mda_id[32];
char da_id[32];
@@ -287,7 +278,7 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
struct dm_config_node *alt_devices = dm_config_find_node(cn->child, "devices_alternate");
struct dm_config_value *alt_device = NULL;
uint64_t offset, size;
struct lvmcache_info *info, *info_alternate;
struct lvmcache_info *info;
const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL),
*vgid_txt = dm_config_find_str(cn->child, "vgid", NULL),
*vgname = dm_config_find_str(cn->child, "vgname", NULL),
@@ -301,7 +292,7 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
if (!fmt) {
log_error("PV %s not recognised. Is the device missing?", pvid_txt);
return 0;
return NULL;
}
dev = dev_cache_get_by_devt(devt, cmd->filter);
@@ -310,17 +301,17 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
if (!dev) {
log_warn("WARNING: Device for PV %s not found or rejected by a filter.", pvid_txt);
return 0;
return NULL;
}
if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) {
log_error("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
return 0;
return NULL;
}
if (vgid_txt) {
if (!id_read_format(&vgid, vgid_txt))
return_0;
return_NULL;
} else
strcpy((char*)&vgid, fmt->orphan_vg_name);
@@ -329,7 +320,7 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
if (!(info = lvmcache_add(fmt->labeller, (const char *)&pvid, dev,
vgname, (const char *)&vgid, 0)))
return_0;
return_NULL;
lvmcache_get_label(info)->sector = label_sector;
lvmcache_get_label(info)->dev = dev;
@@ -375,54 +366,21 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
while (alt_device) {
dev_alternate = dev_cache_get_by_devt(alt_device->v.i, cmd->filter);
if (dev_alternate) {
if ((info_alternate = lvmcache_add(fmt->labeller, (const char *)&pvid, dev_alternate,
vgname, (const char *)&vgid, 0))) {
dev_alternate_cache = dev_alternate;
info = info_alternate;
lvmcache_get_label(info)->dev = dev_alternate;
}
} else {
if (dev_alternate)
lvmcache_add(fmt->labeller, (const char *)&pvid, dev_alternate,
vgname, (const char *)&vgid, 0);
else
log_warn("Duplicate of PV %s dev %s exists on unknown device %"PRId64 ":%" PRId64,
pvid_txt, dev_name(dev), MAJOR(alt_device->v.i), MINOR(alt_device->v.i));
}
alt_device = alt_device->next;
}
/*
* Update lvmcache with the info about the alternate device by
* reading its label, which should update lvmcache.
*/
if (dev_alternate_cache) {
if (!label_read(dev_alternate_cache, &label, 0)) {
log_warn("No PV label found on duplicate device %s.", dev_name(dev_alternate_cache));
}
}
lvmcache_set_preferred_duplicates((const char *)&vgid);
return 1;
}
static int _pv_update_struct_pv(struct physical_volume *pv, struct format_instance *fid)
{
struct lvmcache_info *info;
if ((info = lvmcache_info_from_pvid((const char *)&pv->id, 0))) {
pv->label_sector = lvmcache_get_label(info)->sector;
pv->dev = lvmcache_device(info);
if (!pv->dev)
pv->status |= MISSING_PV;
if (!lvmcache_fid_add_mdas_pv(info, fid))
return_0;
pv->fid = fid;
} else
pv->status |= MISSING_PV; /* probably missing */
return 1;
return info;
}
struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
{
struct volume_group *vg = NULL;
struct volume_group *vg2 = NULL;
daemon_reply reply;
int found;
char uuid[64];
@@ -434,6 +392,7 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
struct format_type *fmt;
struct dm_config_node *pvcn;
struct pv_list *pvl;
struct lvmcache_info *info;
if (!lvmetad_active())
return NULL;
@@ -484,38 +443,22 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
if ((pvcn = dm_config_find_node(top, "metadata/outdated_pvs")))
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
top->key = name;
if (!(vg = import_vg_from_lvmetad_config_tree(reply.cft, fid)))
if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
goto_out;
/*
* locking may have detected a newer vg version and
* invalidated the cached vg.
*/
if (dm_config_find_node(reply.cft->root, "vg_invalid")) {
log_debug_lvmetad("Update invalid lvmetad cache for VG %s", vgname);
vg2 = lvmetad_pvscan_vg(cmd, vg);
release_vg(vg);
vg = vg2;
fid = vg->fid;
}
dm_list_iterate_items(pvl, &vg->pvs) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
}
}
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
}
if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
pvl->pv->label_sector = lvmcache_get_label(info)->sector;
pvl->pv->dev = lvmcache_device(info);
if (!pvl->pv->dev)
pvl->pv->status |= MISSING_PV;
if (!lvmcache_fid_add_mdas_pv(info, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
}
} else
pvl->pv->status |= MISSING_PV; /* probably missing */
}
lvmcache_update_vg(vg, 0);
@@ -714,56 +657,6 @@ int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
return 1;
}
int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids)
{
struct vgnameid_list *vgnl;
struct id vgid;
const char *vgid_txt;
const char *vg_name;
daemon_reply reply;
struct dm_config_node *cn;
log_debug_lvmetad("Asking lvmetad for complete list of known VG ids/names");
reply = _lvmetad_send("vg_list", NULL);
if (!_lvmetad_handle_reply(reply, "list VGs", "", NULL)) {
daemon_reply_destroy(reply);
return_0;
}
if ((cn = dm_config_find_node(reply.cft->root, "volume_groups"))) {
for (cn = cn->child; cn; cn = cn->sib) {
vgid_txt = cn->key;
if (!id_read_format(&vgid, vgid_txt)) {
stack;
continue;
}
if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {
log_error("vgnameid_list allocation failed.");
return 0;
}
if (!(vg_name = dm_config_find_str(cn->child, "name", NULL))) {
log_error("vg_list no name found.");
return 0;
}
vgnl->vgid = dm_pool_strdup(cmd->mem, (char *)&vgid);
vgnl->vg_name = dm_pool_strdup(cmd->mem, vg_name);
if (!vgnl->vgid || !vgnl->vg_name) {
log_error("vgnameid_list member allocation failed.");
return 0;
}
dm_list_add(vgnameids, &vgnl->list);
}
}
daemon_reply_destroy(reply);
return 1;
}
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
{
struct volume_group *tmp;
@@ -952,51 +845,6 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
/*
* pvscan --cache does not perform any lvmlockd locking, and
* pvscan --cache -aay skips autoactivation in lockd VGs.
*
* pvscan --cache populates lvmetad with VG metadata from disk.
* No lvmlockd locking is needed. It is expected that lockd VG
* metadata that is read by pvscan and populated in lvmetad may
* be immediately stale due to changes to the VG from other hosts
* during or after this pvscan. This is normal and not a problem.
* When a subsequent lvm command uses the VG, it will lock the VG
* with lvmlockd, read the VG from lvmetad, and update the cached
* copy from disk if necessary.
*
* pvscan --cache -aay does not activate LVs in lockd VGs because
* activation requires locking, and a lock-start operation is needed
* on a lockd VG before any locking can be performed in it.
*
* An equivalent of pvscan --cache -aay for lockd VGs is:
* 1. pvscan --cache
* 2. vgchange --lock-start
* 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
*
* [We could eventually add support for autoactivating lockd VGs
* using pvscan by incorporating the lock start step (which can
* take a long time), but there may be a better option than
* continuing to overload pvscan.]
*
* Stages of starting a lockd VG:
*
* . pvscan --cache populates lockd VGs in lvmetad without locks,
* and this initial cached copy may quickly become stale.
*
* . vgchange --lock-start VG reads the VG without the VG lock
* because no locks are available until the locking is started.
* It only uses the VG name and lock_type from the VG metadata,
* and then only uses it to start the VG lockspace in lvmlockd.
*
* . Further lvm commands, e.g. activation, can then lock the VG
* with lvmlockd and use current VG metdata.
*/
if (handler && vg && is_lockd_type(vg->lock_type)) {
log_debug_lvmetad("Skip pvscan activation for lockd type VG %s", vg->name);
handler = NULL;
}
if (result && handler) {
status = daemon_reply_str(reply, "status", "<missing>");
vgname = daemon_reply_str(reply, "vgname", "<missing>");
@@ -1064,8 +912,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
struct _lvmetad_pvscan_baton *b = baton;
struct volume_group *this;
if (!(this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
return 1;
this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1);
/* FIXME Also ensure contents match etc. */
if (!b->vg || this->seqno > b->vg->seqno)
@@ -1076,100 +923,6 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
return 1;
}
/*
* The lock manager may detect that the vg cached in lvmetad is out of date,
* due to something like an lvcreate from another host.
* This is limited to changes that only affect the vg (not global state like
* orphan PVs), so we only need to reread mdas on the vg's existing pvs.
*/
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
{
struct volume_group *vg_ret = NULL;
struct dm_config_tree *vgmeta_ret = NULL;
struct dm_config_tree *vgmeta;
struct pv_list *pvl;
struct lvmcache_info *info;
struct format_instance *fid;
struct format_instance_ctx fic = { .type = 0 };
struct _lvmetad_pvscan_baton baton;
dm_list_iterate_items(pvl, &vg->pvs) {
/* missing pv */
if (!pvl->pv->dev)
continue;
if (!(info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
return NULL;
}
baton.vg = NULL;
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!baton.fid)
return NULL;
if (baton.fid->fmt->features & FMT_OBSOLETE) {
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
baton.fid->fmt->name, dev_name(pvl->pv->dev));
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
return NULL;
}
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
if (!baton.vg) {
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
return NULL;
}
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
log_error("VG export to config tree failed");
release_vg(baton.vg);
return NULL;
}
if (!vgmeta_ret) {
vgmeta_ret = vgmeta;
} else {
if (!compare_config(vgmeta_ret->root, vgmeta->root)) {
log_error("VG metadata comparison failed");
dm_config_destroy(vgmeta);
dm_config_destroy(vgmeta_ret);
release_vg(baton.vg);
return NULL;
}
dm_config_destroy(vgmeta);
}
release_vg(baton.vg);
}
if (vgmeta_ret) {
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
log_error("VG import from config tree failed");
lvmcache_fmt(info)->ops->destroy_instance(fid);
goto out;
}
/*
* Update lvmetad with the newly read version of the VG.
* The "precommitted" name is a misnomer in this case,
* but that is the field which lvmetad_vg_update() uses
* to send the metadata cft to lvmetad.
*/
vg_ret->cft_precommitted = vgmeta_ret;
if (!lvmetad_vg_update(vg_ret))
log_error("Failed to update lvmetad with new VG meta");
vg_ret->cft_precommitted = NULL;
dm_config_destroy(vgmeta_ret);
}
out:
return vg_ret;
}
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
activation_handler handler, int ignore_obsolete)
{
@@ -1319,327 +1072,3 @@ int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handl
{
return _lvmetad_pvscan_all_devs(cmd, handler, 1);
}
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg)
{
char uuid[64];
daemon_reply reply;
int result;
if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
return_0;
reply = _lvmetad_send("vg_clear_outdated_pvs", "vgid = %s", uuid, NULL);
result = _lvmetad_handle_reply(reply, "clear the list of outdated PVs", vg->name, NULL);
daemon_reply_destroy(reply);
return result;
}
/*
* Records the state of cached PVs in lvmetad so we can look for changes
* after rescanning.
*/
struct pv_cache_list {
struct dm_list list;
dev_t devt;
struct id pvid;
const char *vgid;
unsigned found : 1;
unsigned update_udev : 1;
};
/*
* Get the list of PVs known to lvmetad.
*/
static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *pvc_list)
{
daemon_reply reply;
struct dm_config_node *cn;
struct pv_cache_list *pvcl;
const char *pvid_txt;
const char *vgid;
if (!lvmetad_active())
return 1;
log_debug_lvmetad("Asking lvmetad for complete list of known PVs");
reply = _lvmetad_send("pv_list", NULL);
if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) {
log_error("lvmetad message failed.");
daemon_reply_destroy(reply);
return_0;
}
if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes"))) {
for (cn = cn->child; cn; cn = cn->sib) {
if (!(pvcl = dm_pool_zalloc(cmd->mem, sizeof(*pvcl)))) {
log_error("pv_cache_list allocation failed.");
return 0;
}
pvid_txt = cn->key;
if (!id_read_format(&pvcl->pvid, pvid_txt)) {
stack;
continue;
}
pvcl->devt = dm_config_find_int(cn->child, "device", 0);
if ((vgid = dm_config_find_str(cn->child, "vgid", NULL)))
pvcl->vgid = dm_pool_strdup(cmd->mem, vgid);
dm_list_add(pvc_list, &pvcl->list);
}
}
daemon_reply_destroy(reply);
return 1;
}
/*
* Opening the device RDWR should trigger a udev db update.
* FIXME: is there a better way to update the udev db than
* doing an open/close of the device? - For example writing
* "change" to /sys/block/<device>/uevent?
*/
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
{
struct device *dev;
log_debug_devs("device %d:%d open to update udev",
(int)MAJOR(devt), (int)MINOR(devt));
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
log_error("_update_pv_in_udev no dev found");
return;
}
if (!dev_open(dev)) {
stack;
return;
}
if (!dev_close(dev))
stack;
}
/*
* Compare before and after PV lists from before/after rescanning,
* and update udev db for changes.
*
* For PVs that have changed pvid or vgid in lvmetad from rescanning,
* there may be information in the udev database to update, so open
* these devices to trigger a udev update.
*
* "before" refers to the list of pvs from lvmetad before rescanning
* "after" refers to the list of pvs from lvmetad after rescanning
*
* Comparing both lists, we can see which PVs changed (pvid or vgid),
* and trigger a udev db update for those.
*/
static void _update_changed_pvs_in_udev(struct cmd_context *cmd,
struct dm_list *pvc_before,
struct dm_list *pvc_after)
{
struct pv_cache_list *before;
struct pv_cache_list *after;
char id_before[ID_LEN + 1] __attribute__((aligned(8)));
char id_after[ID_LEN + 1] __attribute__((aligned(8)));
int found;
dm_list_iterate_items(before, pvc_before) {
found = 0;
dm_list_iterate_items(after, pvc_after) {
if (after->found)
continue;
if (before->devt != after->devt)
continue;
if (!id_equal(&before->pvid, &after->pvid)) {
memset(id_before, 0, sizeof(id_before));
memset(id_after, 0, sizeof(id_after));
strncpy(&id_before[0], (char *) &before->pvid, sizeof(id_before) - 1);
strncpy(&id_after[0], (char *) &after->pvid, sizeof(id_after) - 1);
log_debug_devs("device %d:%d changed pvid from %s to %s",
(int)MAJOR(before->devt), (int)MINOR(before->devt),
id_before, id_after);
before->update_udev = 1;
} else if ((before->vgid && !after->vgid) ||
(after->vgid && !before->vgid) ||
(before->vgid && after->vgid && strcmp(before->vgid, after->vgid))) {
log_debug_devs("device %d:%d changed vg from %s to %s",
(int)MAJOR(before->devt), (int)MINOR(before->devt),
before->vgid ?: "none", after->vgid ?: "none");
before->update_udev = 1;
}
after->found = 1;
before->found = 1;
found = 1;
break;
}
if (!found) {
memset(id_before, 0, sizeof(id_before));
strncpy(&id_before[0], (char *) &before->pvid, sizeof(id_before) - 1);
log_debug_devs("device %d:%d pvid %s vg %s is gone",
(int)MAJOR(before->devt), (int)MINOR(before->devt),
id_before, before->vgid ? before->vgid : "none");
before->update_udev = 1;
}
}
dm_list_iterate_items(before, pvc_before) {
if (before->update_udev)
_update_pv_in_udev(cmd, before->devt);
}
dm_list_iterate_items(after, pvc_after) {
if (after->update_udev)
_update_pv_in_udev(cmd, after->devt);
}
}
/*
* Before this command was run, some external entity may have
* invalidated lvmetad's cache of global information, e.g. lvmlockd.
*
* The global information includes things like a new VG, a
* VG that was removed, the assignment of a PV to a VG;
* any change that is not isolated within a single VG.
*
* The external entity, like a lock manager, would invalidate
* the lvmetad global cache if it detected that the global
* information had been changed on disk by something other
* than a local lvm command, e.g. an lvm command on another
* host with access to the same devices. (How it detects
* the change is specific to lock manager or other entity.)
*
* The effect is that metadata on disk is newer than the metadata
* in the local lvmetad daemon, and the local lvmetad's cache
* should be updated from disk before this command uses it.
*
* So, using this function, a command checks if lvmetad's global
* cache is valid. If so, it does nothing. If not, it rescans
* devices to update the lvmetad cache, then it notifies lvmetad
* that it's cache is valid again (consistent with what's on disk.)
* This command can then go ahead and use the newly refreshed metadata.
*
* 1. Check if the lvmetad global cache is invalid.
* 2. If so, reread metadata from all devices and update the lvmetad cache.
* 3. Tell lvmetad that the global cache is now valid.
*/
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
{
struct dm_list pvc_before; /* pv_cache_list */
struct dm_list pvc_after; /* pv_cache_list */
daemon_reply reply;
int global_invalid;
dm_list_init(&pvc_before);
dm_list_init(&pvc_after);
if (!lvmlockd_use()) {
log_error(INTERNAL_ERROR "validate global cache without lvmlockd");
return;
}
if (!lvmetad_used())
return;
log_debug_lvmetad("Validating global lvmetad cache");
if (force)
goto do_scan;
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
NULL);
if (reply.error) {
log_error("lvmetad_validate_global_cache get_global_info error %d", reply.error);
goto do_scan;
}
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
log_error("lvmetad_validate_global_cache get_global_info not ok");
goto do_scan;
}
global_invalid = daemon_reply_int(reply, "global_invalid", -1);
daemon_reply_destroy(reply);
if (!global_invalid) {
/* cache is valid */
return;
}
do_scan:
/*
* Save the current state of pvs from lvmetad so after devices are
* scanned, we can compare to the new state to see if pvs changed.
*/
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
/*
* Update the local lvmetad cache so it correctly reflects any
* changes made on remote hosts.
*/
lvmetad_pvscan_all_devs(cmd, NULL);
/*
* Clear the global_invalid flag in lvmetad.
* Subsequent local commands that read global state
* from lvmetad will not see global_invalid until
* another host makes another global change.
*/
reply = daemon_send_simple(_lvmetad, "set_global_info",
"token = %s", "skip",
"global_invalid = %d", 0,
NULL);
if (reply.error)
log_error("lvmetad_validate_global_cache set_global_info error %d", reply.error);
if (strcmp(daemon_reply_str(reply, "response", ""), "OK"))
log_error("lvmetad_validate_global_cache set_global_info not ok");
daemon_reply_destroy(reply);
/*
* Populate this command's lvmcache structures from lvmetad.
*/
lvmcache_seed_infos_from_lvmetad(cmd);
/*
* Update the local udev database to reflect PV changes from
* other hosts.
*
* Compare the before and after PV lists, and if a PV's
* pvid or vgid has changed, then open that device to trigger
* a uevent to update the udev db.
*
* This has no direct benefit to lvm, but is just a best effort
* attempt to keep the udev db updated and reflecting current
* lvm information.
*
* FIXME: lvmcache_seed_infos_from_lvmetad() and _lvmetad_get_pv_cache_list()
* each get pv_list from lvmetad, and they could share a single pv_list reply.
*/
if (!dm_list_empty(&pvc_before)) {
_lvmetad_get_pv_cache_list(cmd, &pvc_after);
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
}
}

24
lib/cache/lvmetad.h vendored
View File

@@ -29,7 +29,8 @@ typedef int (*activation_handler) (struct cmd_context *cmd,
#ifdef LVMETAD_SUPPORT
/*
* Sets up a global handle for our process.
* Initialise the communication with lvmetad. Normally called by
* lvmcache_init. Sets up a global handle for our process.
*/
void lvmetad_init(struct cmd_context *);
@@ -58,9 +59,7 @@ int lvmetad_socket_present(void);
/*
* Check whether lvmetad is active (where active means both that it is running
* and that we have a working connection with it). It opens new connection
* with lvmetad in the process when lvmetad is supposed to be used and the
* connection is not open yet.
* and that we have a working connection with it).
*/
int lvmetad_active(void);
@@ -71,9 +70,8 @@ int lvmetad_active(void);
void lvmetad_connect_or_warn(void);
/*
* Drop connection to lvmetad. A subsequent lvmetad_connect_or_warn or
* lvmetad_active will re-establish the connection (possibly at a
* different socket path).
* Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish
* the connection (possibly at a different socket path).
*/
void lvmetad_disconnect(void);
@@ -144,12 +142,6 @@ int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *f
*/
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd);
/*
* Request a list of vgid/vgname pairs for all VGs known to lvmetad.
* Does not do vg_lookup's on each VG, and does not populate lvmcache.
*/
int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids);
/*
* Find a VG by its ID or its name in the lvmetad cache. Gives NULL if the VG is
* not found.
@@ -166,9 +158,6 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
# else /* LVMETAD_SUPPORT */
# define lvmetad_init(cmd) do { } while (0)
@@ -190,13 +179,10 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
# define lvmetad_pvscan_all_devs(cmd, handler) (0)
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
# define lvmetad_vg_clear_outdated_pvs(vg) (1)
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
# endif /* LVMETAD_SUPPORT */

View File

@@ -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,16 +66,20 @@ 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 */
/*
* Read in policy args:
@@ -100,9 +99,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 +127,24 @@ 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;
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);
/*
* 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) {
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 +157,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 +176,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;
@@ -354,16 +282,9 @@ static int _cache_add_target_line(struct dev_manager *dm,
struct dm_tree_node *node, uint64_t len,
uint32_t *pvmove_mirror_count __attribute__((unused)))
{
struct lv_segment *cache_pool_seg;
struct lv_segment *cache_pool_seg = first_seg(seg->pool_lv);
char *metadata_uuid, *data_uuid, *origin_uuid;
if (!seg->pool_lv || !seg_is_cache(seg)) {
log_error(INTERNAL_ERROR "Passed segment is not cache.");
return 0;
}
cache_pool_seg = first_seg(seg->pool_lv);
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
return_0;
@@ -378,9 +299,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 +361,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;
}

View File

@@ -30,7 +30,6 @@
#include "lvmcache.h"
#include "lvmetad.h"
#include "archiver.h"
#include "lvmpolld-client.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
@@ -245,10 +244,8 @@ static int _parse_debug_classes(struct cmd_context *cmd)
const struct dm_config_value *cv;
int debug_classes = 0;
if (!(cn = find_config_tree_array(cmd, log_debug_classes_CFG, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for log/debug_classes.");
return -1;
}
if (!(cn = find_config_tree_node(cmd, log_debug_classes_CFG, NULL)))
return DEFAULT_LOGGED_DEBUG_CLASSES;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
@@ -276,8 +273,6 @@ static int _parse_debug_classes(struct cmd_context *cmd)
debug_classes |= LOG_CLASS_CACHE;
else if (!strcasecmp(cv->v.str, "locking"))
debug_classes |= LOG_CLASS_LOCKING;
else if (!strcasecmp(cv->v.str, "lvmpolld"))
debug_classes |= LOG_CLASS_LVMPOLLD;
else
log_verbose("Unrecognised value for log/debug_classes: %s", cv->v.str);
}
@@ -415,57 +410,6 @@ static int _check_config(struct cmd_context *cmd)
return 1;
}
static const char *_set_time_format(struct cmd_context *cmd)
{
/* Compared to strftime, we do not allow "newline" character - the %n in format. */
static const char *allowed_format_chars = "aAbBcCdDeFGghHIjklmMpPrRsStTuUVwWxXyYzZ%";
static const char *allowed_alternative_format_chars_e = "cCxXyY";
static const char *allowed_alternative_format_chars_o = "deHImMSuUVwWy";
static const char *chars_to_check;
const char *tf = find_config_tree_str(cmd, report_time_format_CFG, NULL);
const char *p_fmt;
size_t i;
char c;
if (!*tf) {
log_error("Configured time format is empty string.");
goto bad;
} else {
p_fmt = tf;
while ((c = *p_fmt)) {
if (c == '%') {
c = *++p_fmt;
if (c == 'E') {
c = *++p_fmt;
chars_to_check = allowed_alternative_format_chars_e;
} else if (c == 'O') {
c = *++p_fmt;
chars_to_check = allowed_alternative_format_chars_o;
} else
chars_to_check = allowed_format_chars;
for (i = 0; chars_to_check[i]; i++) {
if (c == chars_to_check[i])
break;
}
if (!chars_to_check[i])
goto_bad;
}
else if (isprint(c))
p_fmt++;
else {
log_error("Configured time format contains non-printable characters.");
goto bad;
}
}
}
return tf;
bad:
log_error("Invalid time format \"%s\" supplied.", tf);
return NULL;
}
int process_profilable_config(struct cmd_context *cmd)
{
if (!(cmd->default_settings.unit_factor =
@@ -479,8 +423,6 @@ int process_profilable_config(struct cmd_context *cmd)
cmd->report_binary_values_as_numeric = find_config_tree_bool(cmd, report_binary_values_as_numeric_CFG, NULL);
cmd->default_settings.suffix = find_config_tree_bool(cmd, global_suffix_CFG, NULL);
cmd->report_list_item_separator = find_config_tree_str(cmd, report_list_item_separator_CFG, NULL);
if (!(cmd->time_format = _set_time_format(cmd)))
return 0;
return 1;
}
@@ -532,6 +474,7 @@ static int _process_config(struct cmd_context *cmd)
const struct dm_config_node *cn;
const struct dm_config_value *cv;
int64_t pv_min_kb;
const char *lvmetad_socket;
int udev_disabled = 0;
char sysfs_dir[PATH_MAX];
@@ -652,7 +595,7 @@ static int _process_config(struct cmd_context *cmd)
}
}
if ((cn = find_config_tree_array(cmd, activation_mlock_filter_CFG, NULL)))
if ((cn = find_config_tree_node(cmd, activation_mlock_filter_CFG, NULL)))
for (cv = cn->v; cv; cv = cv->next)
if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
log_error("Ignoring invalid activation/mlock_filter entry in config file");
@@ -674,6 +617,30 @@ static int _process_config(struct cmd_context *cmd)
init_detect_internal_vg_cache_corruption
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
lvmetad_disconnect();
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
if (!lvmetad_socket)
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
/* TODO?
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
DEFAULT_RUN_DIR "/lvmetad.socket");
*/
lvmetad_set_socket(lvmetad_socket);
cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL);
lvmetad_set_token(cn ? cn->v : NULL);
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
"Clustered environment not supported by lvmetad yet.");
lvmetad_set_active(NULL, 0);
} else
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
lvmetad_init(cmd);
if (!_init_system_id(cmd))
return_0;
@@ -983,9 +950,15 @@ static int _init_dev_cache(struct cmd_context *cmd)
init_obtain_device_list_from_udev(device_list_from_udev);
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
return_0;
if (!(cn = find_config_tree_node(cmd, devices_scan_CFG, NULL))) {
if (!dev_cache_add_dir("/dev")) {
log_error("Failed to add /dev to internal "
"device cache");
return 0;
}
log_verbose("device/scan not in config file: "
"Defaulting to /dev");
return 1;
}
for (cv = cn->v; cv; cv = cv->next) {
@@ -1023,7 +996,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
}
}
if (!(cn = find_config_tree_array(cmd, devices_loopfiles_CFG, NULL)))
if (!(cn = find_config_tree_node(cmd, devices_loopfiles_CFG, NULL)))
return 1;
for (cv = cn->v; cv; cv = cv->next) {
@@ -1161,7 +1134,7 @@ bad:
* md component filter -> fw raid filter
*
*/
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
{
const char *dev_cache;
struct dev_filter *filter = NULL, *filter_components[2] = {0};
@@ -1169,11 +1142,6 @@ int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
const struct dm_config_node *cn;
struct timespec ts, cts;
if (!cmd->initialized.connections) {
log_error(INTERNAL_ERROR "connections must be initialized before filters");
return 0;
}
cmd->dump_filter = 0;
cmd->lvmetad_filter = _init_lvmetad_filter_chain(cmd);
@@ -1203,7 +1171,7 @@ int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
}
/* filter component 1 */
if ((cn = find_config_tree_array(cmd, devices_filter_CFG, NULL))) {
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
if (!(filter_components[1] = regex_filter_create(cn->v)))
goto_bad;
/* we have two filter components - create composite filter */
@@ -1254,7 +1222,6 @@ int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
dev_cache);
}
cmd->initialized.filters = 1;
return 1;
bad:
if (!filter) {
@@ -1278,7 +1245,6 @@ bad:
if (cmd->lvmetad_filter)
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
cmd->initialized.filters = 0;
return 0;
}
@@ -1322,7 +1288,7 @@ static int _init_formats(struct cmd_context *cmd)
#ifdef HAVE_LIBDL
/* Load any formats in shared libs if not static */
if (!is_static() &&
(cn = find_config_tree_array(cmd, global_format_libraries_CFG, NULL))) {
(cn = find_config_tree_node(cmd, global_format_libraries_CFG, NULL))) {
const struct dm_config_value *cv;
struct format_type *(*init_format_fn) (struct cmd_context *);
@@ -1488,7 +1454,7 @@ static int _init_segtypes(struct cmd_context *cmd)
#ifdef HAVE_LIBDL
/* Load any formats in shared libs unless static */
if (!is_static() &&
(cn = find_config_tree_array(cmd, global_segment_libraries_CFG, NULL))) {
(cn = find_config_tree_node(cmd, global_segment_libraries_CFG, NULL))) {
const struct dm_config_value *cv;
int (*init_multiple_segtypes_fn) (struct cmd_context *,
@@ -1652,80 +1618,11 @@ static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *na
return 1;
}
static int _init_lvmetad(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
const char *lvmetad_socket;
lvmetad_disconnect();
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
if (!lvmetad_socket)
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
/* TODO?
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
DEFAULT_RUN_DIR "/lvmetad.socket");
*/
lvmetad_set_socket(lvmetad_socket);
cn = find_config_tree_array(cmd, devices_global_filter_CFG, NULL);
lvmetad_set_token(cn ? cn->v : NULL);
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
"Clustered environment not supported by lvmetad yet.");
lvmetad_set_active(NULL, 0);
} else
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
lvmetad_init(cmd);
return 1;
}
static int _init_lvmpolld(struct cmd_context *cmd)
{
const char *lvmpolld_socket;
lvmpolld_disconnect();
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
if (!lvmpolld_socket)
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
lvmpolld_set_socket(lvmpolld_socket);
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
return 1;
}
int init_connections(struct cmd_context *cmd)
{
if (!_init_lvmetad(cmd)) {
log_error("Failed to initialize lvmetad connection.");
goto bad;
}
if (!_init_lvmpolld(cmd)) {
log_error("Failed to initialize lvmpolld connection.");
goto bad;
}
cmd->initialized.connections = 1;
return 1;
bad:
cmd->initialized.connections = 0;
return 0;
}
/* Entry point */
struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir,
unsigned set_buffering,
unsigned threaded,
unsigned set_connections,
unsigned set_filters)
unsigned threaded)
{
struct cmd_context *cmd;
FILE *new_stream;
@@ -1863,12 +1760,15 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
goto_out;
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
find_config_tree_array(cmd, devices_types_CFG, NULL))))
find_config_tree_node(cmd, devices_types_CFG, NULL))))
goto_out;
if (!_init_dev_cache(cmd))
goto_out;
if (!_init_filters(cmd, 1))
goto_out;
memlock_init(cmd);
if (!_init_formats(cmd))
@@ -1887,18 +1787,12 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
_init_globals(cmd);
if (set_connections && !init_connections(cmd))
return_0;
if (set_filters && !init_filters(cmd, 1))
goto_out;
cmd->default_settings.cache_vgmetadata = 1;
cmd->current_settings = cmd->default_settings;
cmd->initialized.config = 1;
cmd->config_initialized = 1;
out:
if (!cmd->initialized.config) {
if (!cmd->config_initialized) {
destroy_toolcontext(cmd);
cmd = NULL;
}
@@ -1970,19 +1864,14 @@ static void _destroy_filters(struct cmd_context *cmd)
cmd->full_filter->destroy(cmd->full_filter);
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
}
cmd->initialized.filters = 0;
}
int refresh_filters(struct cmd_context *cmd)
{
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
if (!cmd->initialized.filters)
/* if filters not initialized, there's nothing to refresh */
return 1;
_destroy_filters(cmd);
if (!(r = init_filters(cmd, 0)))
if (!(r = _init_filters(cmd, 0)))
stack;
/*
@@ -2011,6 +1900,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
_destroy_filters(cmd);
if (!dev_cache_exit())
stack;
@@ -2028,7 +1918,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
_destroy_config(cmd);
cmd->initialized.config = 0;
cmd->config_initialized = 0;
cmd->hosttags = 0;
@@ -2085,12 +1975,15 @@ int refresh_toolcontext(struct cmd_context *cmd)
return_0;
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
find_config_tree_array(cmd, devices_types_CFG, NULL))))
find_config_tree_node(cmd, devices_types_CFG, NULL))))
return_0;
if (!_init_dev_cache(cmd))
return_0;
if (!_init_filters(cmd, 0))
return_0;
if (!_init_formats(cmd))
return_0;
@@ -2103,13 +1996,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
if (!_init_backup(cmd))
return_0;
cmd->initialized.config = 1;
if (cmd->initialized.connections && !init_connections(cmd))
return_0;
if (!refresh_filters(cmd))
return_0;
cmd->config_initialized = 1;
reset_lvm_errno(1);
return 1;
@@ -2178,7 +2065,6 @@ void destroy_toolcontext(struct cmd_context *cmd)
lvmetad_release_token();
lvmetad_disconnect();
lvmpolld_disconnect();
release_log_memory();
activation_exit();

View File

@@ -60,59 +60,29 @@ struct config_tree_list {
struct dm_config_tree *cft;
};
struct cmd_context_initialized_parts {
unsigned config:1; /* used to reinitialize config if previous init was not successful */
unsigned filters:1;
unsigned connections:1;
};
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
struct cmd_context {
/*
* Memory handlers.
*/
struct dm_pool *libmem; /* for permanent config data */
struct dm_pool *mem; /* transient: cleared between each command */
struct dm_pool *libmem; /* For permanent config data */
struct dm_pool *mem; /* Transient: Cleared between each command */
/*
* Command line and arguments.
*/
const struct format_type *fmt; /* Current format to use by default */
struct format_type *fmt_backup; /* Format to use for backups */
struct dm_list formats; /* Available formats */
struct dm_list segtypes; /* Available segment types */
const char *system_id;
const char *hostname;
const char *kernel_vsn;
unsigned rand_seed;
char *linebuffer;
const char *cmd_line;
struct command *command;
char **argv;
struct arg_values *arg_values;
struct dm_list arg_value_groups;
/*
* Format handlers.
*/
const struct format_type *fmt; /* current format to use by default */
struct format_type *fmt_backup; /* format to use for backups */
struct dm_list formats; /* available formats */
struct dm_list segtypes; /* available segment types */
/*
* Machine and system identification.
*/
const char *system_id;
const char *hostname;
const char *kernel_vsn;
/*
* Device identification.
*/
struct dev_types *dev_types; /* recognized extra device types. */
/*
* Initialization state.
*/
struct cmd_context_initialized_parts initialized;
/*
* Switches.
*/
unsigned is_long_lived:1; /* optimises persistent_filter handling */
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
unsigned handles_missing_pvs:1;
unsigned handles_unknown_segments:1;
unsigned use_linear_target:1;
@@ -123,72 +93,59 @@ struct cmd_context {
unsigned report_binary_values_as_numeric:1;
unsigned metadata_read_only:1;
unsigned ignore_clustered_vgs:1;
unsigned threaded:1; /* set if running within a thread e.g. clvmd */
unsigned independent_metadata_areas:1; /* active formats have MDAs outside PVs */
unsigned threaded:1; /* Set if running within a thread e.g. clvmd */
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
unsigned unknown_system_id:1;
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
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;
unsigned include_foreign_vgs:1;
unsigned include_active_foreign_vgs:1;
unsigned error_foreign_vgs:1;
struct dev_types *dev_types;
/*
* Filtering.
* Use of filters depends on whether lvmetad is used or not:
*
* - if lvmetad is used:
* - cmd->lvmetad_filter used when scanning devices for lvmetad
* - cmd->filter used when processing lvmetad responses
* - cmd->full_filter used for remaining situations
*
* - if lvmetad is not used:
* - cmd->lvmetad_filter is NULL
* - cmd->filter == cmd->full_filter used for all situations
*
*/
struct dev_filter *lvmetad_filter; /* pre-lvmetad filter chain */
struct dev_filter *filter; /* post-lvmetad filter chain */
struct dev_filter *full_filter; /* lvmetad_filter + filter */
int dump_filter; /* Dump filter when exiting? */
struct dev_filter *lvmetad_filter;
struct dev_filter *filter;
struct dev_filter *full_filter;
int dump_filter; /* Dump filter when exiting? */
/*
* Configuration.
*/
struct dm_list config_files; /* master lvm config + any existing tag configs */
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
struct config_info default_settings; /* selected settings with original default/configured value which can be changed during cmd processing */
struct config_info current_settings; /* may contain changed values compared to default_settings */
struct dm_list config_files; /* master lvm config + any existing tag configs */
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
int config_initialized; /* used to reinitialize config if previous init was not successful */
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
/* selected settings with original default/configured value which can be changed during cmd processing */
struct config_info default_settings;
/* may contain changed values compared to default_settings */
struct config_info current_settings;
/*
* Archives and backups.
*/
struct archive_params *archive_params;
struct backup_params *backup_params;
const char *stripe_filler;
/*
* Host tags.
*/
struct dm_list tags; /* list of defined tags */
/* List of defined tags */
struct dm_list tags;
const char *report_list_item_separator;
int hosttags;
/*
* Paths.
*/
const char *lib_dir; /* cache value global/library_dir */
const char *lib_dir; /* Cache value global/library_dir */
char system_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
/*
* Buffers.
*/
char display_buffer[NAME_LEN * 10]; /* ring buffer for upto 10 longest vg/lv names */
unsigned display_lvname_idx; /* index to ring buffer */
char *linebuffer;
/*
* Others - unsorted.
*/
const char *report_list_item_separator;
const char *time_format;
unsigned rand_seed;
};
/*
@@ -198,17 +155,13 @@ struct cmd_context {
struct cmd_context *create_toolcontext(unsigned is_long_lived,
const char *system_dir,
unsigned set_buffering,
unsigned threaded,
unsigned set_connections,
unsigned set_filters);
unsigned threaded);
void destroy_toolcontext(struct cmd_context *cmd);
int refresh_toolcontext(struct cmd_context *cmd);
int refresh_filters(struct cmd_context *cmd);
int process_profilable_config(struct cmd_context *cmd);
int config_files_changed(struct cmd_context *cmd);
int init_lvmcache_orphans(struct cmd_context *cmd);
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
int init_connections(struct cmd_context *cmd);
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);

View File

@@ -65,11 +65,11 @@ struct config_source {
* Map each ID to respective definition of the configuration item.
*/
static struct cfg_def_item _cfg_def_items[CFG_COUNT + 1] = {
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, {0}, deprecated_since_version, deprecation_comment, comment},
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, {.v_UNCONFIGURED = unconfigured_value}, deprecated_since_version, deprecation_comment, comment},
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, {.v_UNCONFIGURED = unconfigured_value}, deprecated_since_version, deprecation_comment, comment},
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
#define cfg_section(id, name, parent, flags, since_version, unconfigured_path, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, unconfigured_path, comment},
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_path, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, unconfigured_path, comment},
#define cfg_runtime(id, name, parent, flags, type, since_version, unconfigured_path, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, unconfigured_path, comment},
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_path, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, unconfigured_path, comment},
#define cfg_array_runtime(id, name, parent, flags, types, since_version, unconfigured_path, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, unconfigured_path, comment},
#include "config_settings.h"
#undef cfg_section
#undef cfg
@@ -581,11 +581,8 @@ int config_file_read(struct dm_config_tree *cft)
if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
return_0;
if (!dev_open_readonly_buffered(cf->dev)) {
dev_destroy_file(cf->dev);
cf->dev = NULL;
if (!dev_open_readonly_buffered(cf->dev))
return_0;
}
}
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
@@ -607,7 +604,6 @@ struct timespec config_file_timestamp(struct dm_config_tree *cft)
}
#define cfg_def_get_item_p(id) (&_cfg_def_items[id])
#define cfg_def_get_default_unconfigured_value_hint(cmd,item) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_unconfigured_value.fn_UNCONFIGURED(cmd) : item->default_unconfigured_value.v_UNCONFIGURED)
#define cfg_def_get_default_value_hint(cmd,item,type,profile) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_value.fn_##type(cmd,profile) : item->default_value.v_##type)
#define cfg_def_get_default_value(cmd,item,type,profile) (item->flags & CFG_DEFAULT_UNDEFINED ? 0 : cfg_def_get_default_value_hint(cmd,item,type,profile))
@@ -669,28 +665,22 @@ static void _log_type_error(const char *path, cfg_def_type_t actual,
actual_type_name, expected_type_name);
}
static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
struct dm_config_tree *cft,
const cfg_def_item_t *def,
uint32_t format_flags)
static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
const cfg_def_item_t *def)
{
const char *def_enc_value;
char *enc_value, *token, *p, *r;
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
def_enc_value = cfg_def_get_default_value(cmd, def, CFG_TYPE_ARRAY, NULL);
if (!def_enc_value) {
if (!def->default_value.v_CFG_TYPE_STRING) {
if (!(array = dm_config_create_value(cft))) {
log_error("Failed to create default empty array for %s.", def->name);
return NULL;
}
array->type = DM_CFG_EMPTY_ARRAY;
dm_config_value_set_format_flags(array, format_flags);
return array;
}
if (!(p = token = enc_value = dm_strdup(def_enc_value))) {
if (!(p = token = enc_value = dm_strdup(def->default_value.v_CFG_TYPE_STRING))) {
log_error("_get_def_array_values: dm_strdup failed");
return NULL;
}
@@ -719,9 +709,6 @@ static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
dm_free(enc_value);
return NULL;
}
dm_config_value_set_format_flags(v, format_flags);
if (oldv)
oldv->next = v;
if (!array)
@@ -838,12 +825,6 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
float f;
const char *str;
if ((handle->ignoreunsupported && (def->flags & CFG_UNSUPPORTED)) ||
(handle->ignoreadvanced && (def->flags & CFG_ADVANCED))) {
diff = 0;
goto out;
}
/* if default value is undefined, the value used differs from default */
if (def->flags & CFG_DEFAULT_UNDEFINED) {
diff = 1;
@@ -851,7 +832,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
}
if (!v_def && (def->type & CFG_TYPE_ARRAY)) {
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cmd, handle->cft, def, 0)))
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cft, def)))
return_0;
do {
/* iterate over each element of the array and check its value */
@@ -1043,14 +1024,9 @@ static int _config_def_check_tree(struct cft_check_handle *handle,
size_t buf_size, struct dm_config_node *root)
{
struct dm_config_node *cn;
cfg_def_item_t *def;
int valid, r = 1;
size_t len;
def = cfg_def_get_item_p(root->id);
if (def->flags & CFG_SECTION_NO_CHECK)
return 1;
for (cn = root->child; cn; cn = cn->sib) {
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
buf_size, cn)) && !cn->v) {
@@ -1372,106 +1348,6 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
return b;
}
static struct dm_config_node *_get_array_def_node(struct cmd_context *cmd,
cfg_def_item_t *def,
struct profile *profile)
{
struct dm_config_node *cn;
if (def->flags & CFG_DEFAULT_UNDEFINED)
return NULL;
if (!(cn = dm_config_create_node(cmd->cft, def->name))) {
log_error("Failed to create default array node for %s.", def->name);
return NULL;
}
if (!(cn->v = _get_def_array_values(cmd, cmd->cft, def, 0))) {
dm_pool_free(cmd->cft->mem, cn);
return_NULL;
}
return cn;
}
struct _config_array_out_handle {
struct dm_pool *mem;
char *str;
};
static int _config_array_line(const struct dm_config_node *cn, const char *line, void *baton)
{
struct _config_array_out_handle *handle = (struct _config_array_out_handle *) baton;
if (!(handle->str = dm_pool_strdup(handle->mem, line))) {
log_error("_config_array_line: dm_pool_strdup failed");
return 0;
}
return 1;
}
static void _log_array_value_used(struct dm_pool *mem, const struct dm_config_node *cn,
const char *path, int default_used)
{
struct _config_array_out_handle out_handle = { 0 };
struct dm_config_node_out_spec out_spec = { 0 };
uint32_t old_format_flags;
out_handle.mem = mem;
out_spec.line_fn = _config_array_line;
old_format_flags = dm_config_value_get_format_flags(cn->v);
dm_config_value_set_format_flags(cn->v,
DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES |
DM_CONFIG_VALUE_FMT_COMMON_ARRAY);
if (!dm_config_write_one_node_out(cn, &out_spec, &out_handle)) {
log_error("_log_array_value_used: failed to write node value");
out_handle.mem = NULL;
}
if (default_used)
log_very_verbose("%s not found in config: defaulting to %s",
path, out_handle.mem ? out_handle.str : "<unknown>");
else
log_very_verbose("Setting %s to %s",
path, out_handle.mem ? out_handle.str : "<unknown>");
if (out_handle.mem)
dm_pool_free(out_handle.mem, out_handle.str);
dm_config_value_set_format_flags(cn->v, old_format_flags);
}
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
{
cfg_def_item_t *item = cfg_def_get_item_p(id);
char path[CFG_PATH_MAX_LEN];
int profile_applied;
const struct dm_config_node *cn = NULL, *cn_def = NULL;
profile_applied = _apply_local_profile(cmd, profile);
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
if (!(item->type & CFG_TYPE_ARRAY))
log_error(INTERNAL_ERROR "%s cfg tree element not declared as array.", path);
if (_config_disabled(cmd, item, path) ||
!(cn = find_config_tree_node(cmd, id, profile)))
cn_def = _get_array_def_node(cmd, item, profile);
if (cn)
_log_array_value_used(cmd->cft->mem, cn, path, 0);
else if (cn_def) {
_log_array_value_used(cmd->cft->mem, cn_def, path, 1);
cn = cn_def;
}
if (profile_applied)
remove_config_tree_by_source(cmd, profile->source);
return cn;
}
/* Insert cn2 after cn1 */
static void _insert_config_node(struct dm_config_node **cn1,
struct dm_config_node *cn2)
@@ -1642,25 +1518,6 @@ static int _copy_one_line(const char *comment, char *line, int *pos, int len)
return i;
}
static int _get_config_node_version(uint16_t version_enc, char *version)
{
if (dm_snprintf(version, 9, "%u.%u.%u",
(version_enc & 0xE000) >> 13,
(version_enc & 0x1E00) >> 9,
(version_enc & 0x1FF)) == -1) {
log_error("_get_config_node_version: couldn't create version string");
return 0;
}
return 1;
}
static int _def_node_is_deprecated(cfg_def_item_t *def, struct config_def_tree_spec *spec)
{
return def->deprecated_since_version &&
(spec->version >= def->deprecated_since_version);
}
static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, void *baton)
{
struct out_baton *out = baton;
@@ -1670,11 +1527,13 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
char path[CFG_PATH_MAX_LEN];
char commentline[MAX_COMMENT_LINE+1];
if (cn->id <= 0)
if (cn->id < 0)
return 1;
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
return 1;
if (!cn->id) {
log_error(INTERNAL_ERROR "Configuration node %s has invalid id.", cn->key);
return 0;
}
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
@@ -1682,33 +1541,21 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
cfg_def = cfg_def_get_item_p(cn->id);
if (out->tree_spec->withsummary || out->tree_spec->withcomments) {
if (out->tree_spec->withcomments || out->tree_spec->withfullcomments) {
_cfg_def_make_path(path, sizeof(path), cfg_def->id, cfg_def, 1);
fprintf(out->fp, "\n");
fprintf(out->fp, "%s# Configuration %s %s.\n", line, node_type_name, path);
if (out->tree_spec->withcomments &&
_def_node_is_deprecated(cfg_def, out->tree_spec))
fprintf(out->fp, "%s# %s", line, cfg_def->deprecation_comment);
if (cfg_def->comment) {
int pos = 0;
while (_copy_one_line(cfg_def->comment, commentline, &pos, strlen(cfg_def->comment))) {
if ((commentline[0] == '#') && (strlen(commentline) == 1)) {
if (!out->tree_spec->withspaces)
continue;
commentline[0] = '\0';
}
fprintf(out->fp, "%s# %s\n", line, commentline);
/* withsummary prints only the first comment line. */
if (!out->tree_spec->withcomments)
/* withcomments prints only the first comment line. */
if (!out->tree_spec->withfullcomments)
break;
}
}
if (_def_node_is_deprecated(cfg_def, out->tree_spec))
fprintf(out->fp, "%s# This configuration %s is deprecated.\n", line, node_type_name);
if (cfg_def->flags & CFG_ADVANCED)
fprintf(out->fp, "%s# This configuration %s is advanced.\n", line, node_type_name);
@@ -1720,101 +1567,34 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
if (cfg_def->flags & CFG_DEFAULT_UNDEFINED)
fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name);
if (cfg_def->flags & CFG_DEFAULT_COMMENTED)
fprintf(out->fp, "%s# This configuration %s has an automatic default value.\n", line, node_type_name);
if ((out->tree_spec->type == CFG_DEF_TREE_FULL) &&
(out->tree_spec->check_status[cn->id] & CFG_USED))
fprintf(out->fp, "%s# Value defined in existing configuration has been used for this setting.\n", line);
}
if (out->tree_spec->withversions) {
if (!_get_config_node_version(cfg_def->since_version, version))
return_0;
fprintf(out->fp, "%s# Available since version %s.\n", line, version);
if (_def_node_is_deprecated(cfg_def, out->tree_spec)) {
if (!_get_config_node_version(cfg_def->deprecated_since_version, version))
return_0;
fprintf(out->fp, "%s# Deprecated since version %s.\n", line, version);
if (dm_snprintf(version, 9, "%u.%u.%u",
(cfg_def->since_version & 0xE000) >> 13,
(cfg_def->since_version & 0x1E00) >> 9,
(cfg_def->since_version & 0x1FF)) == -1) {
log_error("_out_prefix_fn: couldn't create version string");
return 0;
}
fprintf(out->fp, "%s# Since version %s.\n", line, version);
}
return 1;
}
static int _should_print_cfg_with_undef_def_val(struct out_baton *out, cfg_def_item_t *cfg_def,
const struct dm_config_node *cn)
{
if (!(cfg_def->flags & CFG_DEFAULT_UNDEFINED))
return 1;
/* print it only if the value is directly defined in some config = it's used */
return out->tree_spec->check_status && (out->tree_spec->check_status[cn->id] & CFG_USED);
}
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
{
struct out_baton *out = baton;
struct cfg_def_item *cfg_def;
char config_path[CFG_PATH_MAX_LEN];
char summary[MAX_COMMENT_LINE+1];
char version[9];
int pos = 0;
size_t len;
char *space_prefix;
struct cfg_def_item *cfg_def = cfg_def_get_item_p(cn->id);
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
return 1;
cfg_def = cfg_def_get_item_p(cn->id);
if (out->tree_spec->type == CFG_DEF_TREE_LIST) {
/* List view with node paths and summary. */
if (cfg_def->type & CFG_TYPE_SECTION)
return 1;
if (!_cfg_def_make_path(config_path, CFG_PATH_MAX_LEN, cfg_def->id, cfg_def, 1))
return_0;
if (out->tree_spec->withversions && !_get_config_node_version(cfg_def->since_version, version))
return_0;
summary[0] = '\0';
if (out->tree_spec->withsummary && cfg_def->comment)
_copy_one_line(cfg_def->comment, summary, &pos, strlen(cfg_def->comment));
fprintf(out->fp, "%s%s%s%s%s%s%s\n", config_path,
*summary || out->tree_spec->withversions ? " - ": "",
*summary ? summary : "",
*summary ? " " : "",
out->tree_spec->withversions ? "[" : "",
out->tree_spec->withversions ? version : "",
out->tree_spec->withversions ? "]" : "");
return 1;
}
/* Usual tree view with nodes and their values. */
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
/* print with # at the front to comment out the line */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
if (space_prefix)
dm_pool_free(out->mem, space_prefix);
}
return 1;
}
/* print the line as it is */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
fprintf(out->fp, "%s\n", line);
fprintf(out->fp, "%s%s\n", (out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
(cfg_def->flags & CFG_DEFAULT_UNDEFINED) ? "#" : "", line);
return 1;
}
@@ -1882,31 +1662,20 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
{
struct dm_config_node *cn;
const char *str;
uint32_t format_flags = 0;
if (!(cn = dm_config_create_node(cft, def->name))) {
log_error("Failed to create default config setting node.");
return NULL;
}
if (!(def->type & CFG_TYPE_SECTION) && !(def->type & CFG_TYPE_ARRAY)) {
if (!(cn->v = dm_config_create_value(cft))) {
log_error("Failed to create default config setting node value.");
return NULL;
}
if (spec->withspaces)
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
if (!(def->type & CFG_TYPE_SECTION) && (!(cn->v = dm_config_create_value(cft)))) {
log_error("Failed to create default config setting node value.");
return NULL;
}
cn->id = def->id;
if (spec->unconfigured && def->default_unconfigured_value.v_UNCONFIGURED) {
cn->v->type = DM_CFG_STRING;
cn->v->v.str = cfg_def_get_default_unconfigured_value_hint(spec->cmd, def);
if (def->type != CFG_TYPE_STRING)
format_flags |= DM_CONFIG_VALUE_FMT_STRING_NO_QUOTES;
dm_config_value_set_format_flags(cn->v, format_flags);
} else if (!(def->type & CFG_TYPE_ARRAY)) {
if (!(def->type & CFG_TYPE_ARRAY)) {
switch (def->type) {
case CFG_TYPE_SECTION:
cn->v = NULL;
@@ -1918,8 +1687,6 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
case CFG_TYPE_INT:
cn->v->type = DM_CFG_INT;
cn->v->v.i = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_INT, NULL);
if (def->flags & CFG_FORMAT_INT_OCTAL)
format_flags |= DM_CONFIG_VALUE_FMT_INT_OCTAL;
break;
case CFG_TYPE_FLOAT:
cn->v->type = DM_CFG_FLOAT;
@@ -1930,19 +1697,17 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
if (!(str = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_STRING, NULL)))
str = "";
cn->v->v.str = str;
if (spec->unconfigured && def->unconfigured_path)
cn->v->v.str = def->unconfigured_path;
break;
default:
log_error(INTERNAL_ERROR "_add_def_node: unknown type");
return NULL;
break;
}
dm_config_value_set_format_flags(cn->v, format_flags);
} else {
if (spec->withspaces)
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_ARRAY;
cn->v = _get_def_array_values(spec->cmd, cft, def, format_flags);
}
} else
cn->v = _get_def_array_values(cft, def);
cn->child = NULL;
if (parent) {
@@ -1958,11 +1723,6 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
return cn;
}
static int _should_skip_deprecated_def_node(cfg_def_item_t *def, struct config_def_tree_spec *spec)
{
return spec->ignoredeprecated && _def_node_is_deprecated(def, spec);
}
static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_id, int id)
{
cfg_def_item_t *def = cfg_def_get_item_p(id);
@@ -1974,8 +1734,6 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
return 1;
switch (spec->type) {
case CFG_DEF_TREE_FULL:
/* fall through */
case CFG_DEF_TREE_MISSING:
if (!spec->check_status) {
log_error_once(INTERNAL_ERROR "couldn't determine missing "
@@ -1983,27 +1741,19 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
return 1;
}
if ((spec->check_status[id] & CFG_USED) ||
(def->flags & CFG_NAME_VARIABLE))
return 1;
if ((spec->type == CFG_DEF_TREE_MISSING) &&
((def->since_version > spec->version) ||
_should_skip_deprecated_def_node(def, spec)))
(def->flags & CFG_NAME_VARIABLE) ||
(def->since_version > spec->version))
return 1;
break;
case CFG_DEF_TREE_NEW:
if ((def->since_version != spec->version) ||
_should_skip_deprecated_def_node(def, spec))
if (def->since_version != spec->version)
return 1;
break;
case CFG_DEF_TREE_PROFILABLE:
/* fall through */
case CFG_DEF_TREE_PROFILABLE_CMD:
/* fall through */
case CFG_DEF_TREE_PROFILABLE_MDA:
if (!(def->flags & CFG_PROFILABLE) ||
(def->since_version > spec->version) ||
_should_skip_deprecated_def_node(def, spec))
(def->since_version > spec->version))
return 1;
flags = def->flags & ~CFG_PROFILABLE;
if (spec->type == CFG_DEF_TREE_PROFILABLE_CMD) {
@@ -2015,8 +1765,7 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
}
break;
default:
if ((def->since_version > spec->version) ||
_should_skip_deprecated_def_node(def, spec))
if (def->since_version > spec->version)
return 1;
break;
}
@@ -2055,7 +1804,7 @@ bad:
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
{
struct dm_config_tree *cft = NULL, *tmp_cft = NULL;
struct dm_config_tree *cft;
struct dm_config_node *root = NULL, *relay = NULL, *tmp;
int id;
@@ -2079,33 +1828,7 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
}
cft->root = root;
if (spec->type == CFG_DEF_TREE_FULL) {
if (!(tmp_cft = dm_config_create())) {
log_error("Failed to create temporary config tree while creating full tree.");
goto bad;
}
if (!(tmp_cft->root = dm_config_clone_node_with_mem(cft->mem, spec->current_cft->root, 1))) {
log_error("Failed to clone current config tree.");
goto bad;
}
if (!merge_config_tree(spec->cmd, cft, tmp_cft, CONFIG_MERGE_TYPE_RAW)) {
log_error("Failed to merge default and current config tree.");
goto bad;
}
dm_config_destroy(tmp_cft);
}
return cft;
bad:
if (cft)
dm_config_destroy(cft);
if (tmp_cft)
dm_config_destroy(tmp_cft);
return NULL;
}
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
@@ -2284,11 +2007,6 @@ const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct pr
return dm_pool_strdup(cmd->mem, buf);
}
const char *get_default_unconfigured_devices_cache_dir_CFG(struct cmd_context *cmd)
{
return "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@";
}
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile)
{
const char *cache_dir = NULL, *cache_file_prefix = NULL;
@@ -2323,24 +2041,6 @@ const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profil
return dm_pool_strdup(cmd->mem, buf);
}
const char *get_default_unconfigured_devices_cache_CFG(struct cmd_context *cmd)
{
const char *cache_file_prefix = NULL;
static char buf[PATH_MAX];
if (find_config_tree_node(cmd, devices_cache_file_prefix_CFG, NULL))
cache_file_prefix = find_config_tree_str_allow_empty(cmd, devices_cache_file_prefix_CFG, NULL);
if (dm_snprintf(buf, sizeof(buf), "%s/%s.cache",
get_default_unconfigured_devices_cache_dir_CFG(cmd),
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
log_error("Persistent cache filename too long.");
return NULL;
}
return dm_pool_strdup(cmd->mem, buf);
}
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile)
{
static char buf[PATH_MAX];
@@ -2354,11 +2054,6 @@ const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct pr
return dm_pool_strdup(cmd->mem, buf);
}
const char *get_default_unconfigured_backup_backup_dir_CFG(struct cmd_context *cmd)
{
return "@DEFAULT_SYS_DIR@/@DEFAULT_BACKUP_SUBDIR@";
}
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile)
{
static char buf[PATH_MAX];
@@ -2372,11 +2067,6 @@ const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct p
return dm_pool_strdup(cmd->mem, buf);
}
const char *get_default_unconfigured_backup_archive_dir_CFG(struct cmd_context *cmd)
{
return "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@";
}
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile)
{
static char buf[PATH_MAX];
@@ -2390,11 +2080,6 @@ const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct p
return dm_pool_strdup(cmd->mem, buf);
}
const char *get_default_unconfigured_config_profile_dir_CFG(struct cmd_context *cmd)
{
return "@DEFAULT_SYS_DIR@/@DEFAULT_PROFILE_SUBDIR@";
}
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile)
{
return find_config_tree_str(cmd, activation_mirror_device_fault_policy_CFG, profile);

View File

@@ -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.
@@ -72,7 +72,6 @@ typedef int (*t_fn_CFG_TYPE_INT) (struct cmd_context *cmd, struct profile *profi
typedef float (*t_fn_CFG_TYPE_FLOAT) (struct cmd_context *cmd, struct profile *profile);
typedef const char* (*t_fn_CFG_TYPE_STRING) (struct cmd_context *cmd, struct profile *profile);
typedef const char* (*t_fn_CFG_TYPE_ARRAY) (struct cmd_context *cmd, struct profile *profile);
typedef const char* (*t_fn_UNCONFIGURED) (struct cmd_context *cmd);
/* configuration definition item value (for item's default value) */
typedef union {
@@ -89,11 +88,6 @@ typedef union {
t_fn_CFG_TYPE_ARRAY fn_CFG_TYPE_ARRAY;
} cfg_def_value_t;
typedef union {
const char *v_UNCONFIGURED;
t_fn_UNCONFIGURED fn_UNCONFIGURED;
} cfg_def_unconfigured_value_t;
/* configuration definition item flags: */
@@ -113,62 +107,50 @@ typedef union {
#define CFG_PROFILABLE_METADATA 0x030
/* whether the default value is undefned */
#define CFG_DEFAULT_UNDEFINED 0x040
/* whether the default value is commented out on output */
#define CFG_DEFAULT_COMMENTED 0x080
/* whether the default value is calculated during run time */
#define CFG_DEFAULT_RUN_TIME 0x100
#define CFG_DEFAULT_RUN_TIME 0x080
/* whether the configuration setting is disabled (and hence defaults always used) */
#define CFG_DISABLED 0x200
/* whether to print integers in octal form (prefixed by "0") */
#define CFG_FORMAT_INT_OCTAL 0x400
/* whether to disable checks for the whole config section subtree */
#define CFG_SECTION_NO_CHECK 0x800
#define CFG_DISABLED 0x100
/* configuration definition item structure */
typedef struct cfg_def_item {
int id; /* ID of this item */
int parent; /* ID of parent item */
const char *name; /* name of the item in configuration tree */
int type; /* configuration item type (bits of cfg_def_type_t) */
cfg_def_value_t default_value; /* default value (only for settings) */
uint16_t flags; /* configuration item definition flags */
uint16_t since_version; /* version this item appeared in */
cfg_def_unconfigured_value_t default_unconfigured_value; /* default value in terms of @FOO@, pre-configured (only for settings) */
uint16_t deprecated_since_version; /* version since this item is deprecated */
const char *deprecation_comment; /* comment about reasons for deprecation and settings that supersede this one */
const char *comment; /* comment */
int id; /* ID of this item */
int parent; /* ID of parent item */
const char *name; /* name of the item in configuration tree */
int type; /* configuration item type (bits of cfg_def_type_t) */
cfg_def_value_t default_value; /* default value (only for settings) */
uint16_t flags; /* configuration item definition flags */
uint16_t since_version; /* version this item appeared in */
const char *unconfigured_path; /* path in terms of @FOO@, pre-configured */
const char *comment; /* brief comment */
} cfg_def_item_t;
/* configuration definition tree types */
typedef enum {
CFG_DEF_TREE_CURRENT, /* tree of nodes with values currently set in the config */
CFG_DEF_TREE_MISSING, /* tree of nodes missing in current config using default values */
CFG_DEF_TREE_FULL, /* CURRENT + MISSING, the tree actually used within execution */
CFG_DEF_TREE_COMPLETE, /* CURRENT + MISSING, the tree actually used within execution, not implemented yet */
CFG_DEF_TREE_DEFAULT, /* tree of all possible config nodes with default values */
CFG_DEF_TREE_NEW, /* tree of all new nodes that appeared in given version */
CFG_DEF_TREE_PROFILABLE, /* tree of all nodes that are customizable by profiles */
CFG_DEF_TREE_PROFILABLE_CMD, /* tree of all nodes that are customizable by command profiles (subset of PROFILABLE) */
CFG_DEF_TREE_PROFILABLE_MDA, /* tree of all nodes that are customizable by metadata profiles (subset of PROFILABLE) */
CFG_DEF_TREE_DIFF, /* tree of all nodes that differ from defaults */
CFG_DEF_TREE_LIST, /* list all nodes */
} cfg_def_tree_t;
/* configuration definition tree specification */
struct config_def_tree_spec {
struct cmd_context *cmd; /* command context (for run-time defaults */
struct dm_config_tree *current_cft; /* current config tree which is defined explicitly - defaults are not used */
cfg_def_tree_t type; /* tree type */
uint16_t version; /* tree at this LVM2 version */
struct cmd_context *cmd; /* command context (for run-time defaults */
cfg_def_tree_t type; /* tree type */
uint16_t version; /* tree at this LVM2 version */
unsigned ignoreadvanced:1; /* do not include advanced configs */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
unsigned ignoredeprecated:1; /* do not include deprecated configs */
unsigned ignorelocal:1; /* do not include the local section */
unsigned withsummary:1; /* include first line of comments - a summary */
unsigned withcomments:1; /* include all comment lines */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
unsigned ignorelocal:1; /* do not include the local section */
unsigned withcomments:1; /* include first line of comment */
unsigned withfullcomments:1; /* include all comment lines */
unsigned withversions:1; /* include versions */
unsigned withspaces:1; /* add more spaces in output for better readability */
unsigned unconfigured:1; /* use unconfigured path strings */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
};
@@ -183,11 +165,11 @@ struct config_def_tree_spec {
* Register ID for each possible item in the configuration tree.
*/
enum {
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) id,
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) id,
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) id,
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) id,
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) id,
#define cfg_section(id, name, parent, flags, since_version, unconfigured_path, comment) id,
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_path, comment) id,
#define cfg_runtime(id, name, parent, flags, type, since_version, unconfigured_path, comment) id,
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_path, comment) id,
#define cfg_array_runtime(id, name, parent, flags, types, since_version, unconfigured_path, comment) id,
#include "config_settings.h"
#undef cfg_section
#undef cfg
@@ -209,8 +191,6 @@ struct cft_check_handle {
unsigned skip_if_checked:1; /* skip the check if already done before - return last state */
unsigned suppress_messages:1; /* suppress messages during the check if config item is found invalid */
unsigned check_diff:1; /* check if the value used differs from default one */
unsigned ignoreadvanced:1; /* do not include advnced configs */
unsigned ignoreunsupported:1; /* do not include unsupported configs */
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
};
@@ -274,29 +254,18 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *profile);
float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *profile);
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile);
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile);
/*
* Functions for configuration settings for which the default
* value is evaluated at runtime based on command context.
*/
const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct profile *profile);
const char *get_default_unconfigured_devices_cache_dir_CFG(struct cmd_context *cmd);
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile);
const char *get_default_unconfigured_devices_cache_CFG(struct cmd_context *cmd);
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile);
const char *get_default_unconfigured_backup_backup_dir_CFG(struct cmd_context *cmd);
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile);
const char *get_default_unconfigured_backup_archive_dir_CFG(struct cmd_context *cmd);
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile);
const char *get_default_unconfigured_config_profile_dir_CFG(struct cmd_context *cmd);
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile);
#define get_default_unconfigured_activation_mirror_image_fault_policy_CFG NULL
int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
#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

File diff suppressed because it is too large Load Diff

View File

@@ -51,21 +51,16 @@
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
#define DEFAULT_WAIT_FOR_LOCKS 1
#define DEFAULT_LVMLOCKD_LOCK_RETRIES 3
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
#define DEFAULT_USE_MLOCKALL 0
#define DEFAULT_METADATA_READ_ONLY 0
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
#define DEFAULT_SANLOCK_LV_EXTEND_MB 256
#define DEFAULT_MIRRORLOG MIRROR_LOG_DISK
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
#define DEFAULT_RAID_MAX_IMAGES 253 /* limited by kernel failed devices bitfield in superblock and raid4/5/6 */
#define DEFAULT_RAID_FAULT_POLICY "warn"
#define DEFAULT_RAID_STRIPE_SIZE (64 * 2)
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
@@ -83,15 +78,12 @@
#ifdef THIN_CHECK_NEEDS_CHECK
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
# define DEFAULT_THIN_CHECK_OPTION2 "--clear-needs-check-flag"
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1 "#S" DEFAULT_THIN_CHECK_OPTION2
#else
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
# define DEFAULT_THIN_CHECK_OPTION2 ""
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1
#endif
#define DEFAULT_THIN_REPAIR_OPTION1 ""
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
#define DEFAULT_THIN_REPAIR_OPTIONS ""
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
@@ -103,27 +95,23 @@
#define DEFAULT_THIN_POOL_ZERO 1
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
#ifdef CACHE_CHECK_NEEDS_CHECK
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
# define DEFAULT_CACHE_CHECK_OPTION2 "--clear-needs-check-flag"
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1 "#S" DEFAULT_CACHE_CHECK_OPTION2
#else
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
# define DEFAULT_CACHE_CHECK_OPTION2 ""
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1
#endif
#define DEFAULT_CACHE_REPAIR_OPTION1 ""
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
#define DEFAULT_CACHE_CHECK_OPTION1 "-q"
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#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
#ifdef LVM1_FALLBACK
# define DEFAULT_FALLBACK_TO_LVM1 1
#else
# define DEFAULT_FALLBACK_TO_LVM1 0
#endif
#define DEFAULT_FORMAT "lvm2"
#define DEFAULT_STRIPESIZE 64 /* KB */
@@ -154,6 +142,10 @@
# define DEFAULT_LOG_FACILITY LOG_USER
#endif
#define DEFAULT_LOGGED_DEBUG_CLASSES (LOG_CLASS_MEM | LOG_CLASS_DEVS | \
LOG_CLASS_ACTIVATION | LOG_CLASS_ALLOC | LOG_CLASS_LVMETAD | \
LOG_CLASS_METADATA | LOG_CLASS_CACHE | LOG_CLASS_LOCKING)
#define DEFAULT_SYSLOG 1
#define DEFAULT_VERBOSE 0
#define DEFAULT_SILENT 0
@@ -199,19 +191,18 @@
#define DEFAULT_REP_QUOTED 1
#define DEFAULT_REP_SEPARATOR " "
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,data_copies,segtype,seg_size"
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
#define DEFAULT_DEVTYPES_COLS "devtype_name,devtype_max_partitions,devtype_description"
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,pool_lv,origin,data_percent,metadata_percent,move_pv,copy_percent,mirror_log,convert_lv,lv_uuid,lv_profile"
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid,vg_profile"
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,data_copies,segtype,stripesize,chunksize"
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"
#define DEFAULT_DEVTYPES_COLS_VERB "devtype_name,devtype_max_partitions,devtype_description"
@@ -229,6 +220,4 @@
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
#define DEFAULT_CY_LOCK_TYPE "sanlock"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -71,16 +71,6 @@ static void _dev_init(struct device *dev, int max_error_count)
dm_list_init(&dev->open_list);
}
void dev_destroy_file(struct device *dev)
{
if (!(dev->flags & DEV_ALLOCED))
return;
dm_free((void *) dm_list_item(dev->aliases.n, struct dm_str_list)->str);
dm_free(dev->aliases.n);
dm_free(dev);
}
struct device *dev_create_file(const char *filename, struct device *dev,
struct dm_str_list *alias, int use_malloc)
{
@@ -691,12 +681,10 @@ static int _init_preferred_names(struct cmd_context *cmd)
_cache.preferred_names_matcher = NULL;
if (!(cn = find_config_tree_array(cmd, devices_preferred_names_CFG, NULL)) ||
if (!(cn = find_config_tree_node(cmd, devices_preferred_names_CFG, NULL)) ||
cn->v->type == DM_CFG_EMPTY_ARRAY) {
log_very_verbose("devices/preferred_names %s: "
"using built-in preferences",
cn && cn->v->type == DM_CFG_EMPTY_ARRAY ? "is empty"
: "not found in config");
log_very_verbose("devices/preferred_names not found in config file: "
"using built-in preferences");
return 1;
}
@@ -955,7 +943,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
if (d)
dm_hash_remove(_cache.names, name);
log_sys_very_verbose("stat", name);
d = NULL;
return NULL;
}
if (d && (buf.st_rdev != d->dev)) {

View File

@@ -586,8 +586,12 @@ static void _close(struct device *dev)
log_debug_devs("Closed %s", dev_name(dev));
if (dev->flags & DEV_ALLOCED)
dev_destroy_file(dev);
if (dev->flags & DEV_ALLOCED) {
dm_free((void *) dm_list_item(dev->aliases.n, struct dm_str_list)->
str);
dm_free(dev->aliases.n);
dm_free(dev);
}
}
static int _dev_close(struct device *dev, int immediate)

View File

@@ -225,9 +225,6 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
{
if (MAJOR(dev->dev) == dt->device_mapper_major)
return "DM";
if (MAJOR(dev->dev) == dt->md_major)
return "MD";
@@ -433,7 +430,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
*/
if ((parts = dt->dev_type_array[major].max_partitions) > 1) {
if ((residue = minor % parts)) {
*result = MKDEV((dev_t)major, (dev_t)(minor - residue));
*result = MKDEV((dev_t)major, (minor - residue));
ret = 2;
} else {
*result = dev->dev;
@@ -510,7 +507,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
path, buffer);
goto out;
}
*result = MKDEV((dev_t)major, (dev_t)minor);
*result = MKDEV((dev_t)major, minor);
ret = 2;
out:
if (fp && fclose(fp))
@@ -528,14 +525,12 @@ static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
((flag_list & TYPE_DM_SNAPSHOT_COW) && !strcmp(type, "DM_snapshot_cow")));
}
#define MSG_FAILED_SIG_OFFSET "Failed to get offset of the %s signature on %s."
#define MSG_FAILED_SIG_LENGTH "Failed to get length of the %s signature on %s."
#define MSG_WIPING_SKIPPED " Wiping skipped."
static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
uint32_t types_to_exclude, uint32_t types_no_prompt,
int yes, force_t force)
{
static const char _msg_failed_offset[] = "Failed to get offset of the %s signature on %s.";
static const char _msg_failed_length[] = "Failed to get length of the %s signature on %s.";
static const char _msg_wiping[] = "Wiping %s signature on %s.";
const char *offset = NULL, *type = NULL, *magic = NULL,
*usage = NULL, *label = NULL, *uuid = NULL;
@@ -546,41 +541,21 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
if (_type_in_flag_list(type, types_to_exclude))
return 2;
if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) {
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_OFFSET, type, name);
return 0;
} else {
log_error("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
log_error(_msg_failed_offset, type, name);
return 0;
}
if (blkid_probe_lookup_value(probe, "SBMAGIC", &magic, &len)) {
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_LENGTH, type, name);
return 0;
} else {
log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
log_error(_msg_failed_length, type, name);
return 0;
}
} else if (!blkid_probe_lookup_value(probe, "PTTYPE", &type, NULL)) {
if (blkid_probe_lookup_value(probe, "PTMAGIC_OFFSET", &offset, NULL)) {
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_OFFSET, type, name);
return 0;
} else {
log_warn("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
log_error(_msg_failed_offset, type, name);
return 0;
}
if (blkid_probe_lookup_value(probe, "PTMAGIC", &magic, &len)) {
if (force < DONT_PROMPT) {
log_error(MSG_FAILED_SIG_LENGTH, type, name);
return 0;
} else {
log_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
log_error(_msg_failed_length, type, name);
return 0;
}
usage = "partition table";
} else

View File

@@ -123,7 +123,6 @@ void dev_flush(struct device *dev);
struct device *dev_create_file(const char *filename, struct device *dev,
struct dm_str_list *alias, int use_malloc);
void dev_destroy_file(struct device *dev);
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);

View File

@@ -24,6 +24,10 @@
#include <stdarg.h>
#define SIZE_BUF 128
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
static const struct {
alloc_policy_t alloc;
const char str[14]; /* must be changed when size extends 13 chars */
@@ -82,38 +86,6 @@ alloc_policy_t get_alloc_from_string(const char *str)
return ALLOC_INVALID;
}
const char *get_lock_type_string(lock_type_t lock_type)
{
switch (lock_type) {
case LOCK_TYPE_INVALID:
return "invalid";
case LOCK_TYPE_NONE:
return "none";
case LOCK_TYPE_CLVM:
return "clvm";
case LOCK_TYPE_DLM:
return "dlm";
case LOCK_TYPE_SANLOCK:
return "sanlock";
}
return "invalid";
}
lock_type_t get_lock_type_from_string(const char *str)
{
if (!str)
return LOCK_TYPE_NONE;
if (!strcmp(str, "none"))
return LOCK_TYPE_NONE;
if (!strcmp(str, "clvm"))
return LOCK_TYPE_CLVM;
if (!strcmp(str, "dlm"))
return LOCK_TYPE_DLM;
if (!strcmp(str, "sanlock"))
return LOCK_TYPE_SANLOCK;
return LOCK_TYPE_INVALID;
}
static const char *_percent_types[7] = { "NONE", "VG", "FREE", "LV", "PVS", "ORIGIN" };
const char *get_percent_string(percent_type_t def)
@@ -123,49 +95,168 @@ const char *get_percent_string(percent_type_t def)
const char *display_lvname(const struct logical_volume *lv)
{
char *name;
int r;
if ((lv->vg->cmd->display_lvname_idx + NAME_LEN) >= sizeof((lv->vg->cmd->display_buffer)))
lv->vg->cmd->display_lvname_idx = 0;
name = lv->vg->cmd->display_buffer + lv->vg->cmd->display_lvname_idx;
r = dm_snprintf(name, NAME_LEN, "%s/%s", lv->vg->name, lv->name);
if (r < 0) {
log_error("Full LV name \"%s/%s\" is too long.", lv->vg->name, lv->name);
return NULL;
}
lv->vg->cmd->display_lvname_idx += r + 1;
return name;
/* On allocation failure, just return the LV name. */
return lv_fullname_dup(lv->vg->cmd->mem, lv) ? : lv->name;
}
#define BASE_UNKNOWN 0
#define BASE_SHARED 1
#define BASE_1024 8
#define BASE_1000 15
#define BASE_SPECIAL 21
#define NUM_UNIT_PREFIXES 6
#define NUM_SPECIAL 3
/* Size supplied in sectors */
static const char *_display_size(const struct cmd_context *cmd,
uint64_t size, dm_size_suffix_t suffix_type)
uint64_t size, size_len_t sl)
{
return dm_size_to_string(cmd->mem, size, cmd->current_settings.unit_type,
cmd->si_unit_consistency,
cmd->current_settings.unit_factor,
cmd->current_settings.suffix,
suffix_type);
unsigned base = BASE_UNKNOWN;
unsigned s;
int suffix, precision;
uint64_t byte = UINT64_C(0);
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
const char * const size_str[][3] = {
/* BASE_UNKNOWN */
{" ", " ", " "}, /* [0] */
/* BASE_SHARED - Used if cmd->si_unit_consistency = 0 */
{" Exabyte", " EB", "E"}, /* [1] */
{" Petabyte", " PB", "P"}, /* [2] */
{" Terabyte", " TB", "T"}, /* [3] */
{" Gigabyte", " GB", "G"}, /* [4] */
{" Megabyte", " MB", "M"}, /* [5] */
{" Kilobyte", " KB", "K"}, /* [6] */
{" Byte ", " B", "B"}, /* [7] */
/* BASE_1024 - Used if cmd->si_unit_consistency = 1 */
{" Exbibyte", " EiB", "e"}, /* [8] */
{" Pebibyte", " PiB", "p"}, /* [9] */
{" Tebibyte", " TiB", "t"}, /* [10] */
{" Gibibyte", " GiB", "g"}, /* [11] */
{" Mebibyte", " MiB", "m"}, /* [12] */
{" Kibibyte", " KiB", "k"}, /* [13] */
{" Byte ", " B", "b"}, /* [14] */
/* BASE_1000 - Used if cmd->si_unit_consistency = 1 */
{" Exabyte", " EB", "E"}, /* [15] */
{" Petabyte", " PB", "P"}, /* [16] */
{" Terabyte", " TB", "T"}, /* [17] */
{" Gigabyte", " GB", "G"}, /* [18] */
{" Megabyte", " MB", "M"}, /* [19] */
{" Kilobyte", " kB", "K"}, /* [20] */
/* BASE_SPECIAL */
{" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */
{" Units ", " Un", "U"}, /* [22] */
{" Sectors ", " Se", "S"}, /* [23] */
};
if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) {
log_error("no memory for size display buffer");
return "";
}
suffix = cmd->current_settings.suffix;
if (!cmd->si_unit_consistency) {
/* Case-independent match */
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[BASE_SHARED + s][2]) {
base = BASE_SHARED;
break;
}
} else {
/* Case-dependent match for powers of 1000 */
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (cmd->current_settings.unit_type ==
*size_str[BASE_1000 + s][2]) {
base = BASE_1000;
break;
}
/* Case-dependent match for powers of 1024 */
if (base == BASE_UNKNOWN)
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
if (cmd->current_settings.unit_type ==
*size_str[BASE_1024 + s][2]) {
base = BASE_1024;
break;
}
}
if (base == BASE_UNKNOWN)
/* Check for special units - s, b or u */
for (s = 0; s < NUM_SPECIAL; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[BASE_SPECIAL + s][2]) {
base = BASE_SPECIAL;
break;
}
if (size == UINT64_C(0)) {
if (base == BASE_UNKNOWN)
s = 0;
sprintf(size_buf, "0%s", suffix ? size_str[base + s][sl] : "");
return size_buf;
}
size *= UINT64_C(512);
if (base != BASE_UNKNOWN)
byte = cmd->current_settings.unit_factor;
else {
/* Human-readable style */
if (cmd->current_settings.unit_type == 'H') {
units = UINT64_C(1000);
base = BASE_1000;
} else {
units = UINT64_C(1024);
base = BASE_1024;
}
if (!cmd->si_unit_consistency)
base = BASE_SHARED;
byte = units * units * units * units * units * units;
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
byte /= units;
suffix = 1;
}
/* FIXME Make precision configurable */
switch (toupper(*size_str[base + s][SIZE_UNIT])) {
case 'B':
case 'S':
precision = 0;
break;
default:
precision = 2;
}
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
(double) size / byte, suffix ? size_str[base + s][sl] : "");
return size_buf;
}
const char *display_size_long(const struct cmd_context *cmd, uint64_t size)
{
return _display_size(cmd, size, DM_SIZE_LONG);
return _display_size(cmd, size, SIZE_LONG);
}
const char *display_size_units(const struct cmd_context *cmd, uint64_t size)
{
return _display_size(cmd, size, DM_SIZE_UNIT);
return _display_size(cmd, size, SIZE_UNIT);
}
const char *display_size(const struct cmd_context *cmd, uint64_t size)
{
return _display_size(cmd, size, DM_SIZE_SHORT);
return _display_size(cmd, size, SIZE_SHORT);
}
void pvdisplay_colons(const struct physical_volume *pv)
@@ -383,7 +474,7 @@ int lvdisplay_full(struct cmd_context *cmd,
log_print("LV UUID %s", uuid);
log_print("LV Write Access %s", access_str);
log_print("LV Creation host, time %s, %s",
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv, 1));
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv));
if (lv_is_origin(lv)) {
log_print("LV snapshot status source of");

View File

@@ -64,9 +64,6 @@ const char *get_alloc_string(alloc_policy_t alloc);
char alloc_policy_char(alloc_policy_t alloc);
alloc_policy_t get_alloc_from_string(const char *str);
const char *get_lock_type_string(lock_type_t lock_type);
lock_type_t get_lock_type_from_string(const char *str);
const char *get_percent_string(percent_type_t def);
char yes_no_prompt(const char *prompt, ...) __attribute__ ((format(printf, 1, 2)));

View File

@@ -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 ||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
sizeof(EXPORTED_TAG) - 1)) {
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
@@ -180,7 +180,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
}
/* Is VG being imported? */
if (vg && !vg_is_exported(vg) && vg->lvm1_system_id && *vg->lvm1_system_id &&
if (vg && !vg_is_exported(vg) && *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, IMPORTED_TAG))
return_0;
@@ -192,7 +192,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
return_0;
/* Update internal system_id if we changed it */
if (vg && vg->lvm1_system_id &&
if (vg &&
(!*vg->lvm1_system_id ||
strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN);

View File

@@ -225,8 +225,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
while (le < lvm->lv->le_count) {
len = _area_length(lvm, le);
if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0, 0,
NULL, 1, len, 1, 0, 0, 0, NULL))) {
if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0,
NULL, 1, len, 0, 0, 0, NULL))) {
log_error("Failed to allocate linear segment.");
return 0;
}
@@ -298,9 +298,9 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
if (!(seg = alloc_lv_segment(segtype, lvm->lv,
lvm->stripes * first_area_le,
lvm->stripes * area_len,
0, 0, lvm->stripe_size, NULL,
0, lvm->stripe_size, NULL,
lvm->stripes,
area_len, 1, 0, 0, 0, NULL))) {
area_len, 0, 0, 0, NULL))) {
log_error("Failed to allocate striped segment.");
return 0;
}

View File

@@ -193,9 +193,9 @@ static int _add_stripe_seg(struct dm_pool *mem,
return_0;
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
area_len * usp->num_devs, 0, 0,
area_len * usp->num_devs, 0,
usp->striping, NULL, usp->num_devs,
area_len, 1, 0, 0, 0, NULL))) {
area_len, 0, 0, 0, NULL))) {
log_error("Unable to allocate striped lv_segment structure");
return 0;
}
@@ -233,8 +233,8 @@ static int _add_linear_seg(struct dm_pool *mem,
area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
area_len, 0, 0, usp->striping,
NULL, 1, area_len, 1,
area_len, 0, usp->striping,
NULL, 1, area_len,
POOL_PE_SIZE, 0, 0, NULL))) {
log_error("Unable to allocate linear lv_segment "
"structure");

View File

@@ -361,7 +361,6 @@ static int _print_header(struct cmd_context *cmd, struct formatter *f,
static int _print_flag_config(struct formatter *f, uint64_t status, int type)
{
char buffer[4096];
if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer)))
return_0;
outf(f, "status = %s", buffer);
@@ -373,61 +372,19 @@ static int _print_flag_config(struct formatter *f, uint64_t status, int type)
return 1;
}
static char *_alloc_printed_str_list(struct dm_list *list)
static int _out_tags(struct formatter *f, struct dm_list *tagsl)
{
struct dm_str_list *sl;
int first = 1;
size_t size = 0;
char *buffer, *buf;
char *tag_buffer;
dm_list_iterate_items(sl, list)
/* '"' + item + '"' + ',' + ' ' */
size += strlen(sl->str) + 4;
/* '[' + ']' + '\0' */
size += 3;
if (!(buffer = buf = dm_malloc(size))) {
log_error("Could not allocate memory for string list buffer.");
return NULL;
}
if (!emit_to_buffer(&buf, &size, "["))
goto_bad;
dm_list_iterate_items(sl, list) {
if (!first) {
if (!emit_to_buffer(&buf, &size, ", "))
goto_bad;
} else
first = 0;
if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str))
goto_bad;
}
if (!emit_to_buffer(&buf, &size, "]"))
goto_bad;
return buffer;
bad:
dm_free(buffer);
return_NULL;
}
static int _out_list(struct formatter *f, struct dm_list *list,
const char *list_name)
{
char *buffer;
if (!dm_list_empty(list)) {
if (!(buffer = _alloc_printed_str_list(list)))
if (!dm_list_empty(tagsl)) {
if (!(tag_buffer = alloc_printed_tags(tagsl)))
return_0;
if (!out_text(f, "%s = %s", list_name, buffer)) {
dm_free(buffer);
if (!out_text(f, "tags = %s", tag_buffer)) {
dm_free(tag_buffer);
return_0;
}
dm_free(buffer);
dm_free(tag_buffer);
}
return 1;
@@ -465,7 +422,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
if (!_print_flag_config(f, status, VG_FLAGS))
return_0;
if (!_out_list(f, &vg->tags, "tags"))
if (!_out_tags(f, &vg->tags))
return_0;
if (vg->system_id && *vg->system_id)
@@ -473,11 +430,8 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
else if (vg->lvm1_system_id && *vg->lvm1_system_id)
outf(f, "system_id = \"%s\"", vg->lvm1_system_id);
if (vg->lock_type) {
if (vg->lock_type)
outf(f, "lock_type = \"%s\"", vg->lock_type);
if (vg->lock_args)
outf(f, "lock_args = \"%s\"", vg->lock_args);
}
outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
vg->extent_size);
@@ -555,7 +509,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
if (!_print_flag_config(f, pv->status, PV_FLAGS))
return_0;
if (!_out_list(f, &pv->tags, "tags"))
if (!_out_tags(f, &pv->tags))
return_0;
outsize(f, pv->size, "dev_size = %" PRIu64, pv->size);
@@ -588,13 +542,10 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
outsize(f, (uint64_t) seg->len * vg->extent_size,
"extent_count = %u", seg->len);
if (seg->reshape_len)
outsize(f, (uint64_t) seg->reshape_len * vg->extent_size,
"reshape_count = %u", seg->reshape_len);
outnl(f);
outf(f, "type = \"%s\"", seg->segtype->name);
if (!_out_list(f, &seg->tags, "tags"))
if (!_out_tags(f, &seg->tags))
return_0;
if (seg->segtype->ops->text_export &&
@@ -637,18 +588,16 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
continue;
}
/* RAID devices are laid-out in metadata/data pairs (unless raid0 which is w/o metadata) */
PFLA("seg_lv(seg, %u)->name=%s", s, seg_lv(seg, s)->name);
/* RAID devices are laid-out in metadata/data pairs */
if (!lv_is_raid_image(seg_lv(seg, s)) ||
(seg->meta_areas && seg_metalv(seg, s) && !lv_is_raid_metadata(seg_metalv(seg, s)))) {
PFLA("image=%u, meta=%u", lv_is_raid_image(seg_lv(seg, s)), (seg->meta_areas && seg_metalv(seg, s) && lv_is_raid_metadata(seg_metalv(seg, s))) ? 1 : 0);
log_error("RAID segment of %s has non-RAID areas", display_lvname(seg->lv));
!lv_is_raid_metadata(seg_metalv(seg, s))) {
log_error("RAID segment has non-RAID areas");
return 0;
}
outf(f, "\"%s\", \"%s\"%s",
(seg->meta_areas && seg_metalv(seg, s)) ? seg_metalv(seg, s)->name : "-",
seg_lv(seg, s)->name, (s == seg->area_count - 1) ? "" : ",");
seg_metalv(seg, s)->name, seg_lv(seg, s)->name,
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_UNASSIGNED:
@@ -670,11 +619,6 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
time_t ts;
uint64_t status = lv->status;
#if 0
/* HM FIXME: workaround for empty metadata lvs with raid0 */
if (!dm_list_size(&lv->segments))
return 1;
#endif
outnl(f);
outf(f, "%s {", lv->name);
_inc_indent(f);
@@ -697,7 +641,7 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
if (!_print_flag_config(f, status, LV_FLAGS))
return_0;
if (!_out_list(f, &lv->tags, "tags"))
if (!_out_tags(f, &lv->tags))
return_0;
if (lv->timestamp) {
@@ -713,9 +657,6 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
lv->timestamp);
}
if (lv->lock_args)
outf(f, "lock_args = \"%s\"", lv->lock_args);
if (lv->alloc != ALLOC_INHERIT)
outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));

View File

@@ -61,17 +61,12 @@ static const struct flag _lv_flags[] = {
{LOCKED, "LOCKED", STATUS_FLAG},
{LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
{LV_REBUILD, "REBUILD", STATUS_FLAG},
{LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", STATUS_FLAG},
{LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", STATUS_FLAG},
{LV_RESHAPE_REMOVED, "RESHAPE_REMOVED", STATUS_FLAG},
{LV_DUPLICATED, "DUPLICATED", STATUS_FLAG},
{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
{LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG},
{LV_NOSCAN, NULL, 0},
{LV_TEMPORARY, NULL, 0},
{POOL_METADATA_SPARE, NULL, 0},
{LOCKD_SANLOCK_LV, NULL, 0},
{RAID, NULL, 0},
{RAID_META, NULL, 0},
{RAID_IMAGE, NULL, 0},
@@ -162,7 +157,7 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size)
if (status)
log_warn(INTERNAL_ERROR "Metadata inconsistency: "
"Not all flags successfully exported (0x%lx).", status);
"Not all flags successfully exported.");
return 1;
}

View File

@@ -453,9 +453,8 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
"not match expected name %s.", vgname);
bad:
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)) &&
!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
stack;
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)))
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
return NULL;
}
@@ -1331,7 +1330,6 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
struct _write_single_mda_baton baton;
unsigned mda_index;
PFL();
/* Add a new cache entry with PV info or update existing one. */
if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id,
pv->dev, pv->vg_name,
@@ -1605,9 +1603,9 @@ static int _text_pv_initialise(const struct format_type *fmt,
if (rp->extent_count)
pv->pe_count = rp->extent_count;
if ((pv->pe_start + pv->pe_count * (uint64_t)pv->pe_size - 1) > pv->size) {
if ((pv->pe_start + pv->pe_count * pv->pe_size - 1) > (pv->size << SECTOR_SHIFT)) {
log_error("Physical extents end beyond end of device %s.",
pv_dev_name(pv));
pv_dev_name(pv));
return 0;
}
@@ -2174,7 +2172,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
* LABEL_SCAN_SIZE.
*/
pe_end = pv->pe_count ? (pv->pe_start +
pv->pe_count * (uint64_t)pv->pe_size - 1) << SECTOR_SHIFT
pv->pe_count * pv->pe_size - 1) << SECTOR_SHIFT
: 0;
if (pe_start || pe_start_locked) {
@@ -2239,7 +2237,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
if (limit_applied)
log_very_verbose("Using limited metadata area size on %s "
"with value %" PRIu64 " (limited by %s of "
FMTu64 ").", pv_dev_name(pv),
"%" PRIu64 ").", pv_dev_name(pv),
mda_size, limit_name, limit);
if (mda_size) {
@@ -2493,7 +2491,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
goto bad;
}
if ((cn = find_config_tree_array(cmd, metadata_dirs_CFG, NULL))) {
if ((cn = find_config_tree_node(cmd, metadata_dirs_CFG, NULL))) {
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Invalid string in config file: "

View File

@@ -47,8 +47,7 @@ struct text_vg_version_ops {
int (*check_version) (const struct dm_config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
const struct dm_config_tree *cf,
unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions);
unsigned use_cached_pvs);
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
time_t *when, char **desc);
int (*read_vgname) (const struct format_type *fmt,
@@ -61,6 +60,9 @@ struct text_vg_version_ops *text_vg_vsn1_init(void);
int print_flags(uint64_t status, int type, char *buffer, size_t size);
int read_flags(uint64_t *status, int type, const struct dm_config_value *cv);
char *alloc_printed_tags(struct dm_list *tags);
int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
struct volume_group *text_vg_import_file(struct format_instance *fid,

View File

@@ -146,7 +146,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
if (!(*vsn)->check_version(cft))
continue;
if (!(vg = (*vsn)->read_vg(fid, cft, single_device, 0)))
if (!(vg = (*vsn)->read_vg(fid, cft, single_device)))
goto_out;
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
@@ -174,9 +174,8 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
when, desc);
}
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid,
unsigned allow_lvmetad_extensions)
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid)
{
struct volume_group *vg = NULL;
struct text_vg_version_ops **vsn;
@@ -191,7 +190,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
* The only path to this point uses cached vgmetadata,
* so it can use cached PV state too.
*/
if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
if (!(vg = (*vsn)->read_vg(fid, cft, 1)))
stack;
else if ((vg_missing = vg_missing_pv_count(vg))) {
log_verbose("There are %d physical volumes missing.",
@@ -204,15 +203,3 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
return vg;
}
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid)
{
return _import_vg_from_config_tree(cft, fid, 0);
}
struct volume_group *import_vg_from_lvmetad_config_tree(const struct dm_config_tree *cft,
struct format_instance *fid)
{
return _import_vg_from_config_tree(cft, fid, 1);
}

View File

@@ -20,13 +20,11 @@
#include "toolcontext.h"
#include "lvmcache.h"
#include "lvmetad.h"
#include "lvmlockd.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "segtype.h"
#include "text_import.h"
#include "defaults.h"
#include "str_list.h"
typedef int (*section_fn) (struct format_instance * fid,
struct volume_group * vg, const struct dm_config_node * pvn,
@@ -155,26 +153,6 @@ static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, i
return 1;
}
static int _read_str_list(struct dm_pool *mem, struct dm_list *list, const struct dm_config_value *cv)
{
if (cv->type == DM_CFG_EMPTY_ARRAY)
return 1;
while (cv) {
if (cv->type != DM_CFG_STRING) {
log_error("Found an item that is not a string");
return 0;
}
if (!str_list_add(mem, list, dm_pool_strdup(mem, cv->v.str)))
return_0;
cv = cv->next;
}
return 1;
}
static int _read_pv(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
@@ -189,8 +167,6 @@ static int _read_pv(struct format_instance *fid,
const struct dm_config_value *cv;
uint64_t size, ba_start;
int outdated = !strcmp(pvn->parent->key, "outdated_pvs");
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv))))
return_0;
@@ -236,7 +212,7 @@ static int _read_pv(struct format_instance *fid,
memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
if (!outdated && !_read_flag_config(pvn, &pv->status, PV_FLAGS)) {
if (!_read_flag_config(pvn, &pv->status, PV_FLAGS)) {
log_error("Couldn't read status flags for physical volume.");
return 0;
}
@@ -258,13 +234,13 @@ static int _read_pv(struct format_instance *fid,
return 0;
}
if (!outdated && !_read_uint64(pvn, "pe_start", &pv->pe_start)) {
if (!_read_uint64(pvn, "pe_start", &pv->pe_start)) {
log_error("Couldn't read extent start value (pe_start) "
"for physical volume.");
return 0;
}
if (!outdated && !_read_int32(pvn, "pe_count", &pv->pe_count)) {
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
log_error("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
@@ -275,7 +251,7 @@ static int _read_pv(struct format_instance *fid,
_read_uint64(pvn, "ba_start", &ba_start);
_read_uint64(pvn, "ba_size", &size);
if (ba_start && size) {
log_debug_metadata("Found bootloader area specification for PV %s "
log_debug("Found bootloader area specification for PV %s "
"in metadata: ba_start=%" PRIu64 ", ba_size=%" PRIu64 ".",
pv_dev_name(pv), ba_start, size);
pv->ba_start = ba_start;
@@ -291,7 +267,7 @@ static int _read_pv(struct format_instance *fid,
/* Optional tags */
if (dm_config_get_list(pvn, "tags", &cv) &&
!(_read_str_list(mem, &pv->tags, cv))) {
!(read_tags(mem, &pv->tags, cv))) {
log_error("Couldn't read tags for physical volume %s in %s.",
pv_dev_name(pv), vg->name);
return 0;
@@ -323,10 +299,7 @@ static int _read_pv(struct format_instance *fid,
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
if (outdated)
dm_list_add(&vg->pvs_outdated, &pvl->list);
else
add_pvl_to_vgs(vg, pvl);
add_pvl_to_vgs(vg, pvl);
return 1;
}
@@ -354,7 +327,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
struct lv_segment *seg;
const struct dm_config_node *sn_child = sn->child;
const struct dm_config_value *cv;
uint32_t area_extents, start_extent, extent_count, reshape_count, data_copies;
uint32_t start_extent, extent_count;
struct segment_type *segtype;
const char *segtype_str;
@@ -375,12 +348,6 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
return 0;
}
if (!_read_int32(sn_child, "reshape_count", &reshape_count))
reshape_count = 0;
if (!_read_int32(sn_child, "data_copies", &data_copies))
data_copies = 1;
segtype_str = "striped";
if (!dm_config_get_str(sn_child, "type", &segtype_str)) {
@@ -388,7 +355,6 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
return 0;
}
PFLA("lv=%s segtype_str=%s", lv->name, segtype_str);
if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_str)))
return_0;
@@ -396,35 +362,20 @@ PFLA("lv=%s segtype_str=%s", lv->name, segtype_str);
!segtype->ops->text_import_area_count(sn_child, &area_count))
return_0;
if (segtype_is_mirror(segtype) || segtype_is_raid1(segtype))
data_copies = area_count;
#if 0
if (!(seg = alloc_lv_segment(segtype, lv, start_extent,
extent_count, reshape_count, 0, 0, NULL, area_count,
extent_count, data_copies, 0, 0, 0, NULL))) {
#else
PFLA("lv=%s data_copies=%u", lv->name, data_copies);
area_extents = segtype->parity_devs ?
raid_rimage_extents(segtype, extent_count, area_count - segtype->parity_devs, data_copies) : extent_count;
PFLA("lv=%s area_extents=%u", lv->name, area_extents);
if (!(seg = alloc_lv_segment(segtype, lv, start_extent,
extent_count, reshape_count, 0, 0, NULL, area_count,
area_extents, data_copies, 0, 0, 0, NULL))) {
#endif
extent_count, 0, 0, NULL, area_count,
extent_count, 0, 0, 0, NULL))) {
log_error("Segment allocation failed");
return 0;
}
PFLA("lv=%s seg->len=%u seg->area_len=%u", lv->name, seg->len, seg->area_len);
if (seg->segtype->ops->text_import &&
!seg->segtype->ops->text_import(seg, sn_child, pv_hash))
return_0;
PFLA("lv=%s seg->len=%u seg->area_len=%u", lv->name, seg->len, seg->area_len);
/* Optional tags */
if (dm_config_get_list(sn_child, "tags", &cv) &&
!(_read_str_list(mem, &seg->tags, cv))) {
!(read_tags(mem, &seg->tags, cv))) {
log_error("Couldn't read tags for a segment of %s/%s.",
lv->vg->name, lv->name);
return 0;
@@ -434,7 +385,6 @@ PFLA("lv=%s seg->len=%u seg->area_len=%u", lv->name, seg->len, seg->area_len);
* Insert into correct part of segment list.
*/
_insert_segment(lv, seg);
PFLA("lv=%s seg->len=%u seg->area_len=%u", lv->name, seg->len, seg->area_len);
if (seg_is_mirror(seg))
lv->status |= MIRROR;
@@ -482,8 +432,7 @@ int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
}
if (cv->next->type != DM_CFG_INT) {
log_error("Bad offset in areas array for segment %s, seg->lv %s.",
seg_name, display_lvname(seg->lv));
log_error("Bad offset in areas array for segment %s.", seg_name);
return 0;
}
@@ -624,30 +573,6 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
return 0;
}
/*
* The LV lock_args string is generated in lvmlockd, and the content
* depends on the lock_type.
*
* lock_type dlm does not use LV lock_args, so the LV lock_args field
* is just set to "dlm".
*
* lock_type sanlock uses the LV lock_args field to save the
* location on disk of that LV's sanlock lock. The disk name is
* specified in the VG lock_args. The lock_args string begins
* with a version number, e.g. 1.0.0, followed by a colon, followed
* by a number. The number is the offset on disk where sanlock is
* told to find the LV's lock.
* e.g. lock_args = 1.0.0:70254592
* means that the lock is located at offset 70254592.
*
* The lvmlockd code for each specific lock manager also validates
* the lock_args before using it to access the lock manager.
*/
if (dm_config_get_str(lvn, "lock_args", &str)) {
if (!(lv->lock_args = dm_pool_strdup(mem, str)))
return_0;
}
lv->alloc = ALLOC_INHERIT;
if (dm_config_get_str(lvn, "allocation_policy", &str)) {
lv->alloc = get_alloc_from_string(str);
@@ -686,7 +611,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
/* Optional tags */
if (dm_config_get_list(lvn, "tags", &cv) &&
!(_read_str_list(mem, &lv->tags, cv))) {
!(read_tags(mem, &lv->tags, cv))) {
log_error("Couldn't read tags for logical volume %s/%s.",
vg->name, lv->name);
return 0;
@@ -701,9 +626,6 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
if (timestamp && !lv_set_creation(lv, hostname, timestamp))
return_0;
if (!lv_is_visible(lv) && strstr(lv->name, "_dup_"))
lv->status |= LV_DUPLICATED;
if (!lv_is_visible(lv) && strstr(lv->name, "_pmspare")) {
if (vg->pool_metadata_spare_lv) {
log_error("Couldn't use another pool metadata spare "
@@ -716,12 +638,6 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
vg->pool_metadata_spare_lv = lv;
}
if (!lv_is_visible(lv) && !strcmp(lv->name, LOCKD_SANLOCK_LV_NAME)) {
log_debug_metadata("Logical volume %s is sanlock lv.", lv->name);
lv->status |= LOCKD_SANLOCK_LV;
vg->sanlock_lv = lv;
}
return 1;
}
@@ -819,8 +735,7 @@ static int _read_sections(struct format_instance *fid,
static struct volume_group *_read_vg(struct format_instance *fid,
const struct dm_config_tree *cft,
unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions)
unsigned use_cached_pvs)
{
const struct dm_config_node *vgn;
const struct dm_config_value *cv;
@@ -874,32 +789,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
goto bad;
}
/*
* The VG lock_args string is generated in lvmlockd, and the content
* depends on the lock_type. lvmlockd begins the lock_args string
* with a version number, e.g. 1.0.0, followed by a colon, followed
* by a string that depends on the lock manager. The string after
* the colon is information needed to use the lock manager for the VG.
*
* For sanlock, the string is the name of the internal LV used to store
* sanlock locks. lvmlockd needs to know where the locks are located
* so it can pass that location to sanlock which needs to access the locks.
* e.g. lock_args = 1.0.0:lvmlock
* means that the locks are located on the the LV "lvmlock".
*
* For dlm, the string is the dlm cluster name. lvmlockd needs to use
* a dlm lockspace in this cluster to use the VG.
* e.g. lock_args = 1.0.0:foo
* means that the host needs to be a member of the cluster "foo".
*
* The lvmlockd code for each specific lock manager also validates
* the lock_args before using it to access the lock manager.
*/
if (dm_config_get_str(vgn, "lock_args", &str)) {
if (!(vg->lock_args = dm_pool_strdup(vg->vgmem, str)))
goto bad;
}
if (!_read_id(&vg->id, vgn, "id")) {
log_error("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
@@ -988,15 +877,9 @@ static struct volume_group *_read_vg(struct format_instance *fid,
goto bad;
}
if (allow_lvmetad_extensions)
_read_sections(fid, "outdated_pvs", _read_pv, vg,
vgn, pv_hash, lv_hash, 1, &scan_done_once);
else if (dm_config_has_node(vgn, "outdated_pvs"))
log_error(INTERNAL_ERROR "Unexpected outdated_pvs section in metadata of VG %s.", vg->name);
/* Optional tags */
if (dm_config_get_list(vgn, "tags", &cv) &&
!(_read_str_list(vg->vgmem, &vg->tags, cv))) {
!(read_tags(vg->vgmem, &vg->tags, cv))) {
log_error("Couldn't read tags for volume group %s.", vg->name);
goto bad;
}
@@ -1058,11 +941,6 @@ static void _read_desc(struct dm_pool *mem,
*when = u;
}
/*
* It would be more accurate to call this _read_vgsummary().
* It is used to read vgsummary information about a VG
* before locking and reading the VG via vg_read().
*/
static int _read_vgname(const struct format_type *fmt, const struct dm_config_tree *cft,
struct lvmcache_vgsummary *vgsummary)
{
@@ -1099,8 +977,6 @@ static int _read_vgname(const struct format_type *fmt, const struct dm_config_tr
return 0;
}
dm_config_get_str(vgn, "lock_type", &vgsummary->lock_type);
return 1;
}

82
lib/format_text/tags.c Normal file
View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "str_list.h"
#include "lvm-string.h"
char *alloc_printed_tags(struct dm_list *tagsl)
{
struct dm_str_list *sl;
int first = 1;
size_t size = 0;
char *buffer, *buf;
dm_list_iterate_items(sl, tagsl)
/* '"' + tag + '"' + ',' + ' ' */
size += strlen(sl->str) + 4;
/* '[' + ']' + '\0' */
size += 3;
if (!(buffer = buf = dm_malloc(size))) {
log_error("Could not allocate memory for tag list buffer.");
return NULL;
}
if (!emit_to_buffer(&buf, &size, "["))
goto_bad;
dm_list_iterate_items(sl, tagsl) {
if (!first) {
if (!emit_to_buffer(&buf, &size, ", "))
goto_bad;
} else
first = 0;
if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str))
goto_bad;
}
if (!emit_to_buffer(&buf, &size, "]"))
goto_bad;
return buffer;
bad:
dm_free(buffer);
return_NULL;
}
int read_tags(struct dm_pool *mem, struct dm_list *tagsl, const struct dm_config_value *cv)
{
if (cv->type == DM_CFG_EMPTY_ARRAY)
return 1;
while (cv) {
if (cv->type != DM_CFG_STRING) {
log_error("Found a tag that is not a string");
return 0;
}
if (!str_list_add(mem, tagsl, dm_pool_strdup(mem, cv->v.str)))
return_0;
cv = cv->next;
}
return 1;
}

View File

@@ -418,8 +418,8 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf,
if (!(ext_version = xlate32(pvhdr_ext->version)))
goto out;
log_debug_metadata("%s: PV header extension version %" PRIu32 " found",
dev_name(dev), ext_version);
log_debug("%s: PV header extension version %" PRIu32 " found",
dev_name(dev), ext_version);
/* Bootloader areas */
dlocn_xl = pvhdr_ext->bootloader_areas_xl;

View File

@@ -105,8 +105,7 @@ static void _update_lvmcache_orphan(struct lvmcache_info *info)
memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
if (!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
stack;
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
}
static struct labeller *_find_labeller(struct device *dev, char *buf,

View File

@@ -119,9 +119,8 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
switch (type) {
case 0:
init_no_locking(&_locking, cmd, suppress_messages);
log_warn_suppress(suppress_messages,
"WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
log_warn("WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
return 1;
case 1:

View File

@@ -195,10 +195,9 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define unlock_vg(cmd, vol) \
do { \
if (is_real_vg(vol) && !sync_dev_names(cmd)) \
stack; \
if (!lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL)) \
stack; \
if (is_real_vg(vol)) \
sync_dev_names(cmd); \
(void) lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL); \
} while (0)
#define unlock_and_release_vg(cmd, vg, vol) \
do { \

File diff suppressed because it is too large Load Diff

View File

@@ -1,246 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*/
#ifndef _LVMLOCKD_H
#define _LVMLOCKD_H
#include "config-util.h"
#include "daemon-client.h"
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
/* lockd_gl flags */
#define LDGL_UPDATE_NAMES 0x00000001
/* lockd_lv flags */
#define LDLV_MODE_NO_SH 0x00000001
#define LDLV_PERSISTENT 0x00000002
/* lvmlockd result flags */
#define LD_RF_NO_LOCKSPACES 0x00000001
#define LD_RF_NO_GL_LS 0x00000002
#define LD_RF_WARN_GL_REMOVED 0x00000004
#define LD_RF_DUP_GL_LS 0x00000008
#define LD_RF_INACTIVE_LS 0x00000010
#define LD_RF_ADD_LS_ERROR 0x00000020
/* lockd_state flags */
#define LDST_EX 0x00000001
#define LDST_SH 0x00000002
#define LDST_FAIL_REQUEST 0x00000004
#define LDST_FAIL_NOLS 0x00000008
#define LDST_FAIL_STARTING 0x00000010
#define LDST_FAIL_OTHER 0x00000020
#define LDST_FAIL (LDST_FAIL_REQUEST | LDST_FAIL_NOLS | LDST_FAIL_STARTING | LDST_FAIL_OTHER)
#ifdef LVMLOCKD_SUPPORT
/* lvmlockd connection and communication */
void lvmlockd_set_socket(const char *sock);
void lvmlockd_set_use(int use);
int lvmlockd_use(void);
void lvmlockd_init(struct cmd_context *cmd);
void lvmlockd_connect(void);
void lvmlockd_disconnect(void);
/* vgcreate/vgremove use init/free */
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count);
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg);
void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg);
/* vgrename */
int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg);
int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success);
/* start and stop the lockspace for a vg */
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg);
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
int lockd_start_wait(struct cmd_context *cmd);
/* locking */
int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type);
int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags);
int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
uint32_t flags, uint32_t *lockd_state);
int lockd_vg_update(struct volume_group *vg);
int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id,
const char *lock_args, const char *def_mode, uint32_t flags);
int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
const char *def_mode, uint32_t flags);
/* lvcreate/lvremove use init/free */
int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv,
struct lvcreate_params *lp);
int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char **lock_args);
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args);
const char *lockd_running_lock_type(struct cmd_context *cmd);
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
int lockd_lv_uses_lock(struct logical_volume *lv);
#else /* LVMLOCKD_SUPPORT */
static inline void lvmlockd_set_socket(const char *sock)
{
}
static inline void lvmlockd_set_use(int use)
{
}
static inline void lvmlockd_init(struct cmd_context *cmd)
{
}
static inline void lvmlockd_disconnect(void)
{
}
static inline void lvmlockd_connect(void)
{
}
static inline int lvmlockd_use(void)
{
return 0;
}
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count)
{
return 1;
}
static inline int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg)
{
return 1;
}
static inline void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg)
{
return;
}
static inline int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg)
{
return 1;
}
static inline int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success)
{
return 1;
}
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_start_wait(struct cmd_context *cmd)
{
return 0;
}
static inline int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type)
{
/*
* When lvm is built without lvmlockd support, creating a VG with
* a shared lock type should fail.
*/
if (is_lockd_type(vg_lock_type)) {
log_error("Using a shared lock type requires lvmlockd.");
return 0;
}
return 1;
}
static inline int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
{
return 1;
}
static inline int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
uint32_t flags, uint32_t *lockd_state)
{
*lockd_state = 0;
return 1;
}
static inline int lockd_vg_update(struct volume_group *vg)
{
return 1;
}
static inline int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id,
const char *lock_args, const char *def_mode, uint32_t flags)
{
return 1;
}
static inline int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
const char *def_mode, uint32_t flags)
{
return 1;
}
static inline int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, struct lvcreate_params *lp)
{
return 1;
}
static inline int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv, const char *lock_type, const char **lock_args)
{
return 1;
}
static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
const char *lv_name, struct id *lv_id, const char *lock_args)
{
return 1;
}
static inline const char *lockd_running_lock_type(struct cmd_context *cmd)
{
log_error("Using a shared lock type requires lvmlockd.");
return NULL;
}
static inline int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg)
{
return 0;
}
static inline int lockd_lv_uses_lock(struct logical_volume *lv)
{
return 0;
}
#endif /* LVMLOCKD_SUPPORT */
#endif /* _LVMLOCKD_H */

View File

@@ -36,7 +36,7 @@ static int _indent = 1;
static int _log_suppress = 0;
static char _msg_prefix[30] = " ";
static int _already_logging = 0;
static int _abort_on_internal_errors_config = 0;
static int _abort_on_internal_errors = 0;
static lvm2_log_fn_t _lvm2_log_fn = NULL;
@@ -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;
@@ -92,6 +92,9 @@ void init_log_file(const char *log_file, int append)
"%llu", &pid, &starttime) != 2) {
log_warn("WARNING: Cannot parse content of %s.", statfile);
} else {
if (fclose(st))
log_sys_debug("fclose", statfile);
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
"%s_%s_%d_%lld", log_file, env, pid, starttime) < 0) {
log_warn("WARNING: Debug log file path is too long for epoch.");
@@ -101,11 +104,7 @@ void init_log_file(const char *log_file, int append)
append = 1; /* force */
}
}
if (st && fclose(st))
log_sys_debug("fclose", statfile);
}
no_epoch:
if (!(_log_file = fopen(log_file, append ? "a" : "w"))) {
log_sys_error("fopen", log_file);
@@ -218,10 +217,9 @@ void init_indent(int indent)
_indent = indent;
}
/* If present, environment setting will override this. */
void init_abort_on_internal_errors(int fatal)
{
_abort_on_internal_errors_config = fatal;
_abort_on_internal_errors = fatal;
}
void reset_lvm_errno(int store_errmsg)
@@ -278,24 +276,10 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
size_t msglen;
const char *indent_spaces = "";
FILE *stream;
static int _abort_on_internal_errors_env_present = -1;
static int _abort_on_internal_errors_env = 0;
char *env_str;
level &= ~(_LOG_STDERR|_LOG_ONCE);
if (_abort_on_internal_errors_env_present < 0) {
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
_abort_on_internal_errors_env_present = 1;
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors_env = strcmp(env_str, "0");
} else
_abort_on_internal_errors_env_present = 0;
}
/* Use value from environment if present, otherwise use value from config. */
if (((_abort_on_internal_errors_env_present && _abort_on_internal_errors_env) ||
(!_abort_on_internal_errors_env_present && _abort_on_internal_errors_config)) &&
if (_abort_on_internal_errors &&
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1)) {
fatal_internal_error = 1;
/* Internal errors triggering abort cannot be suppressed. */
@@ -401,8 +385,6 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
default:
/* Typically only log_warn goes to stdout */
stream = (use_stderr || (level != _LOG_WARN)) ? stderr : stdout;
if (stream == stderr)
fflush(stdout);
fprintf(stream, "%s%s%s%s", buf, log_command_name(),
_msg_prefix, indent_spaces);
vfprintf(stream, trformat, ap);

View File

@@ -37,6 +37,8 @@
*
*/
#include <stdio.h> /* FILE */
#include <string.h> /* strerror() */
#include <errno.h>
#define EUNCLASSIFIED -1 /* Generic error code */
@@ -65,7 +67,6 @@
#define LOG_CLASS_METADATA 0x0020 /* "metadata" */
#define LOG_CLASS_CACHE 0x0040 /* "cache" */
#define LOG_CLASS_LOCKING 0x0080 /* "locking" */
#define LOG_CLASS_LVMPOLLD 0x0100 /* "lvmpolld" */
#define log_debug(x...) LOG_LINE(_LOG_DEBUG, x)
#define log_debug_mem(x...) LOG_LINE_WITH_CLASS(_LOG_DEBUG, LOG_CLASS_MEM, x)
@@ -76,7 +77,6 @@
#define log_debug_metadata(x...) LOG_LINE_WITH_CLASS(_LOG_DEBUG, LOG_CLASS_METADATA, x)
#define log_debug_cache(x...) LOG_LINE_WITH_CLASS(_LOG_DEBUG, LOG_CLASS_CACHE, x)
#define log_debug_locking(x...) LOG_LINE_WITH_CLASS(_LOG_DEBUG, LOG_CLASS_LOCKING, x)
#define log_debug_lvmpolld(x...) LOG_LINE_WITH_CLASS(_LOG_DEBUG, LOG_CLASS_LVMPOLLD, x)
#define log_info(x...) LOG_LINE(_LOG_INFO, x)
#define log_notice(x...) LOG_LINE(_LOG_NOTICE, x)

View File

@@ -1,356 +0,0 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "daemon-io.h"
#include "lvmpolld-client.h"
#include "lvmpolld-protocol.h"
#include "metadata-exported.h"
#include "polldaemon.h"
#include "toolcontext.h"
#include "lvm2cmd.h"
struct progress_info {
unsigned error:1;
unsigned finished:1;
int cmd_signal;
int cmd_retcode;
};
static int _lvmpolld_use;
static int _lvmpolld_connected;
static const char* _lvmpolld_socket;
static daemon_handle _lvmpolld = { .error = 0 };
static daemon_handle _lvmpolld_open(const char *socket)
{
daemon_info lvmpolld_info = {
.path = "lvmpolld",
.socket = socket ?: LVMPOLLD_SOCKET,
.protocol = LVMPOLLD_PROTOCOL,
.protocol_version = LVMPOLLD_PROTOCOL_VERSION
};
return daemon_open(lvmpolld_info);
}
void lvmpolld_set_active(int active)
{
_lvmpolld_use = active;
}
void lvmpolld_set_socket(const char *socket)
{
_lvmpolld_socket = socket;
}
static void _lvmpolld_connect_or_warn(void)
{
if (!_lvmpolld_connected && !_lvmpolld.error) {
_lvmpolld = _lvmpolld_open(_lvmpolld_socket);
if ( _lvmpolld.socket_fd >= 0 && !_lvmpolld.error) {
log_debug_lvmpolld("Sucessfully connected to lvmpolld on fd %d.", _lvmpolld.socket_fd);
_lvmpolld_connected = 1;
} else {
log_warn("WARNING: Failed to connect to lvmpolld. Proceeding with polling without using lvmpolld.");
log_warn("WARNING: Check global/use_lvmpolld in lvm.conf or the lvmpolld daemon state.");
}
}
}
int lvmpolld_use(void)
{
if (!_lvmpolld_use || !_lvmpolld_socket)
return 0;
_lvmpolld_connect_or_warn();
return _lvmpolld_connected;
}
void lvmpolld_disconnect(void)
{
if (_lvmpolld_connected) {
daemon_close(_lvmpolld);
_lvmpolld_connected = 0;
}
}
static void _explain_error_codes(int retcode)
{
switch (retcode) {
/* LVM2 return codes */
case LVM2_NO_SUCH_COMMAND:
log_error("LVM command run by lvmpolld responded with: 'No such command.'");
break;
case LVM2_INVALID_PARAMETERS:
log_error("LVM command run by lvmpolld failed due to invalid parameters.");
break;
case LVM2_PROCESSING_FAILED:
log_error("LVM command executed by lvmpolld failed.");
break;
/* lvmpolld specific return codes */
case LVMPD_RET_DUP_FAILED:
log_error("lvmpolld failed to duplicate file descriptors.");
/* fall through */
case LVMPD_RET_EXC_FAILED:
log_error("lvmpolld failed to exec() lvm binary.");
break;
default:
log_error("lvmpolld responded with unexpected return code.");
}
log_print_unless_silent("For more information see lvmpolld messages in syslog or lvmpolld log file.");
}
static void _process_error_response(daemon_reply rep)
{
if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_FAILED))
log_error("lvmpolld failed to process a request. The reason was: %s.",
daemon_reply_str(rep, "reason", "<empty>"));
else if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_EINVAL))
log_error("lvmpolld couldn't handle a request. "
"It might be due to daemon internal state. The reason was: %s.",
daemon_reply_str(rep, "reason", "<empty>"));
else
log_error("Unexpected response %s. The reason: %s.",
daemon_reply_str(rep, "response", "<empty>"),
daemon_reply_str(rep, "reason", "<empty>"));
log_print_unless_silent("For more information see lvmpolld messages in syslog or lvmpolld log file.");
}
static struct progress_info _request_progress_info(const char *uuid, unsigned abort_polling)
{
daemon_reply rep;
const char *e = getenv("LVM_SYSTEM_DIR");
struct progress_info ret = { .error = 1, .finished = 1 };
daemon_request req = daemon_request_make(LVMPD_REQ_PROGRESS);
if (!daemon_request_extend(req, LVMPD_PARM_LVID " = %s", uuid, NULL)) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
if (abort_polling &&
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)abort_polling, NULL)) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
if (e &&
!(daemon_request_extend(req, LVMPD_PARM_SYSDIR " = %s",
e, NULL))) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
rep = daemon_send(_lvmpolld, req);
if (rep.error) {
log_error("Failed to process request with error %s (errno: %d).",
strerror(rep.error), rep.error);
goto out_rep;
}
if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_IN_PROGRESS)) {
ret.finished = 0;
ret.error = 0;
} else if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_FINISHED)) {
if (!strcmp(daemon_reply_str(rep, "reason", ""), LVMPD_REAS_SIGNAL))
ret.cmd_signal = daemon_reply_int(rep, LVMPD_PARM_VALUE, 0);
else
ret.cmd_retcode = daemon_reply_int(rep, LVMPD_PARM_VALUE, -1);
ret.error = 0;
} else if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_NOT_FOUND)) {
log_verbose("No polling operation in progress regarding LV %s.", uuid);
ret.error = 0;
} else {
_process_error_response(rep);
stack;
}
out_rep:
daemon_reply_destroy(rep);
out_req:
daemon_request_destroy(req);
return ret;
}
/*
* interval in seconds long
* enough for more than a year
* of waiting
*/
#define INTERV_SIZE 10
static int _process_poll_init(const struct cmd_context *cmd, const char *poll_type,
const struct poll_operation_id *id, const struct daemon_parms *parms)
{
char *str;
daemon_reply rep;
daemon_request req;
const char *e = getenv("LVM_SYSTEM_DIR");
int r = 0;
str = dm_malloc(INTERV_SIZE * sizeof(char));
if (!str)
return r;
if (snprintf(str, INTERV_SIZE, "%u", parms->interval) >= INTERV_SIZE) {
log_warn("Interval string conversion got truncated.");
str[INTERV_SIZE - 1] = '\0';
}
req = daemon_request_make(poll_type);
if (!daemon_request_extend(req, LVMPD_PARM_LVID " = %s", id->uuid,
LVMPD_PARM_VGNAME " = %s", id->vg_name,
LVMPD_PARM_LVNAME " = %s", id->lv_name,
LVMPD_PARM_INTERVAL " = %s", str,
"cmdline = %s", cmd->cmd_line, /* FIXME: debug param only */
NULL)) {
log_error("Failed to create %s request.", poll_type);
goto out_req;
}
if (parms->aborting &&
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)(parms->aborting), NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
if (cmd->handles_missing_pvs &&
!(daemon_request_extend(req, LVMPD_PARM_HANDLE_MISSING_PVS " = %d",
(int64_t)(cmd->handles_missing_pvs), NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
if (e &&
!(daemon_request_extend(req, LVMPD_PARM_SYSDIR " = %s",
e, NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
rep = daemon_send(_lvmpolld, req);
if (rep.error) {
log_error("Failed to process request with error %s (errno: %d).",
strerror(rep.error), rep.error);
goto out_rep;
}
if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_OK))
r = 1;
else {
_process_error_response(rep);
stack;
}
out_rep:
daemon_reply_destroy(rep);
out_req:
daemon_request_destroy(req);
dm_free(str);
return r;
}
int lvmpolld_poll_init(const struct cmd_context *cmd, const struct poll_operation_id *id,
const struct daemon_parms *parms)
{
int r = 0;
if (!id->uuid) {
log_error(INTERNAL_ERROR "Use of lvmpolld requires uuid set");
return 0;
}
if (!id->vg_name) {
log_error(INTERNAL_ERROR "Use of lvmpolld requires vgname set");
return 0;
}
if (!id->lv_name) {
log_error(INTERNAL_ERROR "Use of lvmpolld requires lvname set");
return 0;
}
if (parms->lv_type & PVMOVE) {
log_debug_lvmpolld("Asking lvmpolld for pvmove%s on %s/%s.",
parms->aborting ? " abort" : "", id->vg_name, id->lv_name);
r = _process_poll_init(cmd, LVMPD_REQ_PVMOVE, id, parms);
} else if (parms->lv_type & CONVERTING) {
log_debug_lvmpolld("Asking lvmpolld for mirror conversion on %s/%s.",
id->vg_name, id->lv_name);
r = _process_poll_init(cmd, LVMPD_REQ_CONVERT, id, parms);
} else if (parms->lv_type & MERGING) {
if (parms->lv_type & SNAPSHOT) {
log_debug_lvmpolld("Asking lvmpolld for snapshot merge on %s/%s.",
id->vg_name, id->lv_name);
r = _process_poll_init(cmd, LVMPD_REQ_MERGE, id, parms);
}
else if (parms->lv_type & THIN_VOLUME) {
log_debug_lvmpolld("Asking lvmpolld for thin snapshot merge on %s/%s.",
id->vg_name, id->lv_name);
r = _process_poll_init(cmd, LVMPD_REQ_MERGE_THIN, id, parms);
}
else {
log_error(INTERNAL_ERROR "Unsupported poll operation.");
}
} else
log_error(INTERNAL_ERROR "Unsupported poll operation");
return r;
}
int lvmpolld_request_info(const struct poll_operation_id *id, const struct daemon_parms *parms, unsigned *finished)
{
struct progress_info info;
int ret = 0;
*finished = 1;
if (!id->uuid) {
log_error(INTERNAL_ERROR "use of lvmpolld requires uuid being set");
return 0;
}
log_debug_lvmpolld("Asking lvmpolld for progress status of an operation on %s/%s.",
id->vg_name, id->lv_name);
info = _request_progress_info(id->uuid, parms->aborting);
*finished = info.finished;
if (info.error)
return_0;
if (info.finished) {
if (info.cmd_signal)
log_error("Command executed by lvmpolld got terminated by signal (%d).",
info.cmd_signal);
else if (info.cmd_retcode)
_explain_error_codes(info.cmd_retcode);
else {
log_verbose("Polling finished successfully.");
ret = 1;
}
} else
ret = 1;
return ret;
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_CLIENT_H
#define _LVM_LVMPOLLD_CLIENT_H
# ifdef LVMPOLLD_SUPPORT
# include "daemon-client.h"
# define LVMPOLLD_SOCKET DEFAULT_RUN_DIR "/lvmpolld.socket"
struct cmd_context;
struct poll_operation_id;
struct daemon_parms;
void lvmpolld_disconnect(void);
int lvmpolld_poll_init(const struct cmd_context *cmd, const struct poll_operation_id *id,
const struct daemon_parms *parms);
int lvmpolld_request_info(const struct poll_operation_id *id, const struct daemon_parms *parms,
unsigned *finished);
int lvmpolld_use(void);
void lvmpolld_set_active(int active);
void lvmpolld_set_socket(const char *socket);
# else
# define lvmpolld_disconnect() do {} while (0)
# define lvmpolld_poll_init(cmd, id, parms) (0)
# define lvmpolld_request_info(id, parms, finished) (0)
# define lvmpolld_use() (0)
# define lvmpolld_set_active(active) do {} while (0)
# define lvmpolld_set_socket(socket) do {} while (0)
# endif /* LVMPOLLD_SUPPORT */
#endif /* _LVM_LVMPOLLD_CLIENT_H */

View File

@@ -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;
}
@@ -361,7 +322,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
dirty_blocks = status->cache->dirty_blocks;
dm_pool_destroy(status->mem);
if (dirty_blocks) {
log_print_unless_silent(FMTu64 " blocks must still be flushed.",
log_print_unless_silent("%" PRIu64 " blocks must still be flushed.",
dirty_blocks);
sleep(1);
}
@@ -434,105 +395,37 @@ 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);
}
static const char *_get_default_cache_policy(struct cmd_context *cmd)
{
const struct segment_type *segtype = get_segtype_from_string(cmd, "cache");
unsigned attr = ~0;
const char *def = NULL;
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)
def = "smq";
else if (attr & CACHE_FEATURE_POLICY_MQ)
def = "mq";
else {
log_error("Default cache policy is not available.");
return NULL;
}
log_debug_metadata("Detected default cache_policy \"%s\".", def);
return def;
}
int cache_set_policy(struct lv_segment *seg, const char *name,
const struct dm_config_tree *settings)
int lv_cache_setpolicy(struct logical_volume *lv, struct dm_config_tree *policy)
{
struct lv_segment *seg = first_seg(lv);
const char *name;
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);
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) {
if (!(seg->policy_name = find_config_tree_str(seg->lv->vg->cmd, allocation_cache_policy_CFG, NULL)) &&
!(seg->policy_name = _get_default_cache_policy(seg->lv->vg->cmd)))
return_0;
}
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;
if (!(new = dm_config_create()))
goto_out;
new->root = policy->root;
old->root = seg->policy_settings;
new->cascade = old;
if (!(tmp = policy = dm_config_flatten(new)))
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 (!cn->child)
break;
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 ((cn = dm_config_find_node(policy->root, "policy_settings")) &&
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
goto_out;
if ((name = dm_config_find_str(policy->root, "policy", NULL)) &&
!(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name)))
goto_out;
restart: /* remove any 'default" nodes */
cn = seg->policy_settings ? seg->policy_settings->child : NULL;
while (cn) {
@@ -546,13 +439,12 @@ restart: /* remove any 'default" nodes */
r = 1;
out:
if (tmp)
dm_config_destroy(tmp);
if (new)
dm_config_destroy(new);
if (old)
dm_config_destroy(old);
if (new)
dm_config_destroy(new);
if (tmp)
dm_config_destroy(tmp);
return r;
}

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