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

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
e58d38a322 commands: new method for defining commands 2016-09-02 14:24:42 -05:00
760 changed files with 23562 additions and 67826 deletions

View File

@@ -59,8 +59,6 @@ liblvm: lib
daemons: lib libdaemon tools
tools: lib libdaemon device-mapper
po: tools daemons
man: tools
all_man: tools
scripts: liblvm libdm
lib.device-mapper: include.device-mapper
@@ -100,7 +98,7 @@ CLEAN_DIRS += autom4te.cache
check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
$(MAKE) -C test $(@)
conf.generate man.generate: tools
conf.generate: tools
# how to use parenthesis in makefiles
leftparen:=(
@@ -130,9 +128,8 @@ rpm: dist
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
generate: conf.generate man.generate
generate: conf.generate
$(MAKE) -C conf generate
$(MAKE) -C man generate
all_man:
$(MAKE) -C man all_man

5
README
View File

@@ -6,12 +6,11 @@ Installation instructions are in INSTALL.
There is no warranty - see COPYING and COPYING.LIB.
Tarballs are available from:
ftp://sourceware.org/pub/lvm2/
ftp://sources.redhat.com/pub/lvm2/
The source code is stored in git:
https://sourceware.org/git/?p=lvm2.git
git clone git://sourceware.org/git/lvm2.git
http://git.fedorahosted.org/git/lvm2.git
git clone git://git.fedorahosted.org/git/lvm2.git
Mailing list for general discussion related to LVM2:
linux-lvm@redhat.com

View File

@@ -1 +1 @@
2.02.174(2)-git (2017-07-20)
2.02.165(2)-git (2016-08-15)

View File

@@ -1 +1 @@
1.02.143-git (2017-07-20)
1.02.134-git (2016-08-15)

248
WHATS_NEW
View File

@@ -1,249 +1,5 @@
Version 2.02.174 -
=================================
Fix check for 2nd mda at end of disk fits if using pvcreate --restorefile.
Use maximum metadataarea size that fits with pvcreate --restorefile.
Always clear cached bootloaderarea when wiping label e.g. in pvcreate.
Disallow --bootloaderareasize with pvcreate --restorefile.
Fix lvmlockd check for running lock managers during lock adoption.
Add --withgeneralpreamble and --withlocalpreamble to lvmconfig.
Improve makefiles' linking.
Fix some paths in generated makefiles to respected configured settings.
Add warning when creating thin-pool with zeroing and chunk size >= 512KiB.
Introduce exit code 4 EINIT_FAILED to replace -1 when initialisation fails.
Add synchronization points with udev during reshape of raid LVs.
Version 2.02.173 - 20th July 2017
=================================
Add synchronization points with udev during conversion of raid LVs.
Improve --size args validation and report more detailed error message.
Initialize debugging mutex before any debug message in clvmd.
Log error instead of warn when noticing connection problem with lvmetad.
Fix memory leak in lvmetad when working with duplicates.
Remove restrictions on reshaping open and clustered raid devices.
Add incompatible data_offset to raid metadata to fix reshape activation.
Accept 'lvm -h' and 'lvm --help' as well as 'lvm help' for help.
Suppress error message from accept() on clean lvmetad shutdown.
Tidy clvmd client list processing and fix segfaults.
Protect clvmd debug log messages with mutex and add client id.
Fix shellcheck reported issues for script files.
Version 2.02.172 - 28th June 2017
=================================
Add missing NULL to argv array when spliting cmdline arguments.
Add display_percent helper function for printing percent values.
lvconvert --repair handles failing raid legs (present but marked 'D'ead).
Do not lvdisplay --maps unset settings of cache pool.
Fix lvdisplay --maps for cache pool without policy settings.
Support aborting of flushing cache LV.
Reenable conversion of data and metadata thin-pool volumes to raid.
Improve raid status reporting with lvs.
No longer necessary to '--force' a repair for RAID1.
Linear to RAID1 upconverts now use "recover" sync action, not "resync".
Improve lvcreate --cachepool arg validation.
Limit maximum size of thin-pool for specific chunk size.
Print a warning about in-use PVs with no VG using them.
Disable automatic clearing of PVs that look like in-use orphans.
Cache format2 flag is now using segment name type field.
Support storing status flags via segtype name field.
Stop using '--yes' mode when fsadm runs without terminal.
Extend validation of filesystems resized by fsadm.
Enhance lvconvert automatic settings of possible (raid) LV types.
Allow lvchange to change properties on a thin pool data sub LV.
Fix lvcreate extent percentage calculation for mirrors.
Don't reinstate still-missing devices when correcting inconsistent metadata.
Properly handle subshell return codes in fsadm.
Disallow cachepool creation with policy cleaner and mode writeback.
Version 2.02.171 - 3rd May 2017
===============================
Fix memory warnings by using mempools for command definition processing.
Fix running commands from a script file.
Add pvcreate prompt when device size doesn't match setphysicalvolumesize.
lvconvert - preserve region size on raid1 image count changes
Adjust pvresize/pvcreate messages and prompt if underlying dev size differs.
raid - sanely handle insufficient space on takeover.
Fix configure --enable-notify-dbus status message.
Change configure option name prefix from --enable-lockd to --enable-lvmlockd.
lvcreate - raise mirror/raid default regionsize to 2MiB
Add missing configurable prefix to configuration file installation directory.
Version 2.02.170 - 13th April 2017
==================================
Introduce global/fsadm_executable to make fsadm path configurable.
Look for limited thin pool metadata size when using 16G metadata.
Add lvconvert pool creation rule disallowing options with poolmetadata.
Fix lvconvert when the same LV is incorrectly reused in options.
Fix lvconvert VG name validation in option values.
Fix missing lvmlockd LV locks in lvchange and lvconvert.
Fix dmeventd setup for lvchange --poll.
Fix use of --poll and --monitor with lvchange and vgchange.
Disallow lvconvert of hidden LV to a pool.
Ignore --partial option when not used for activation.
Allow --activationmode option with lvchange --refresh.
Better message on lvconvert --regionsize
Allow valid lvconvert --regionsize change
Add raid10 alias raid10_near
Handle insufficient PVs on lvconvert takeover
Fix SIGINT blocking to prevent corrupted metadata
Fix systemd unit existence check for lvmconf --services --startstopservices.
Check and use PATH_MAX buffers when creating vgrename device paths.
Version 2.02.169 - 28th March 2017
==================================
Automatically decide whether '-' in a man page is a hyphen or a minus sign.
Add build-time configuration command line to 'lvm version' output.
Handle known table line parameter order change in specific raid target vsns.
Conditionally reject raid convert to striped/raid0* after reshape.
Ensure raid6 upconversion restrictions.
Adjust mirror & raid dmeventd plugins for new lvconvert --repair behaviour.
Disable lvmetad when lvconvert --repair is run.
Remove obsolete lvmchange binary - convert to built-in command.
Show more information for cached volumes in lvdisplay [-m].
Add option for lvcreate/lvconvert --cachemetadataformat auto|1|2.
Support cache segment with configurable metadata format.
Add allocation/cache_metadata_format profilable settings.
Use function cache_set_params() for both lvcreate and lvconvert.
Skip rounding on cache chunk size boudary when create cache LV.
Improve cache_set_params support for chunk_size selection.
Fix metadata profile allocation/cache_[mode|policy] setting.
Fix missing support for using allocation/cache_pool_chunk_size setting.
Upstream git moved to https://sourceware.org/git/?p=lvm2
Support conversion of raid type, stripesize and number of disks
Reject writemostly/writebehind in lvchange during resynchronization.
Deactivate active origin first before removal for improved workflow.
Fix regression of accepting both --type and -m with lvresize. (2.02.158)
Add lvconvert --swapmetadata, new specific way to swap pool metadata LVs.
Add lvconvert --startpoll, new specific way to start polling conversions.
Add lvconvert --mergethin, new specific way to merge thin snapshots.
Add lvconvert --mergemirrors, new specific way to merge split mirrors.
Add lvconvert --mergesnapshot, new specific way to combine cow LVs.
Split up lvconvert code based on command definitions.
Split up lvchange code based on command definitions.
Generate help output and man pages from command definitions.
Verify all command line items against command definition.
Match every command run to one command definition.
Specify every allowed command definition/syntax in command-lines.in.
Add extra memory page when limiting pthread stack size in clvmd.
Support striped/raid0* <-> raid10_near conversions.
Support shrinking of RaidLVs.
Support region size changes on existing RaidLVs.
Avoid parallel usage of cpg_mcast_joined() in clvmd with corosync.
Support raid6_{ls,rs,la,ra}_6 segment types and conversions from/to it.
Support raid6_n_6 segment type and conversions from/to it.
Support raid5_n segment type and conversions from/to it.
Support new internal command _dmeventd_thin_command.
Introduce new dmeventd/thin_command configurable setting.
Use new default units 'r' for displaying sizes.
Also unmount mount point on top of MD device if using blkdeactivate -u.
Restore check preventing resize of cache type volumes (2.02.158).
Add missing udev sync when flushing dirty cache content.
vgchange -p accepts only uint32 numbers.
Report thin LV date for merged LV when the merge is in progress.
Detect if snapshot merge really started before polling for progress.
Checking LV for merging origin requires also it has merged snapshot.
Extend validation of metadata processing.
Enable usage of cached volumes as snapshot origin LV.
Fix displayed lv name when splitting snapshot (2.02.146).
Warn about command not making metadata backup just once per command.
Enable usage of cached volume as thin volume's external origin.
Support cache volume activation with -real layer.
Improve search of lock-holder for external origin and thin-pool.
Support status checking of cache volume used in layer.
Avoid shifting by one number of blocks when clearing dirty cache volume.
Extend metadata validation of external origin LV use count.
Fix dm table when the last user of active external origin is removed.
Improve reported lvs status for active external origin volume.
Fix table load for splitted RAID LV and require explicit activation.
Always active splitted RAID LV exclusively locally.
Do not use LV RAID status bit for segment status.
Check segtype directly instead of checking RAID in segment status.
Reusing exiting code for raid image removal.
Fix pvmove leaving -pvmove0 error device in clustered VG.
Avoid adding extra '_' at end of raid extracted images or metadata.
Optimize another _rmeta clearing code.
Fix deactivation of raid orphan devices for clustered VG.
Fix lvconvert raid1 to mirror table reload order.
Add internal function for separate mirror log preparation.
Fix segfault in lvmetad from missing NULL in daemon_reply_simple.
Simplify internal _info_run() and use _setup_task_run() for mknod.
Better API for internal function _setup_task_run.
Avoid using lv_has_target_type() call within lv_info_with_seg_status.
Simplify internal lv_info_with_seg_status API.
Decide which status is needed in one place for lv_info_with_seg_status.
Fix matching of LV segment when checking for it info status.
Report log_warn when status cannot be parsed.
Test segment type before accessing segment members when checking status.
Implement compatible target function for stripe segment.
Use status info to report merge failed and snapshot invalid lvs fields.
Version 2.02.168 - 30th November 2016
=====================================
Display correct sync_percent on large RaidLVs
lvmdbusd --blackboxsize <n> added, used to override default size of 16
Allow a transiently failed RaidLV to be refreshed
Use lv_update_and_reload() inside mirror code where it applies.
Preserve mirrored status for temporary layered mirrors.
Use transient raid check before repairing raid volume.
Implement transient status check for raid volumes.
Only log msg as debug if lvm2-lvmdbusd unit missing for D-Bus notification.
Avoid duplicated underscore in name of extracted LV image.
Missing stripe filler now could be also 'zero'.
lvconvert --repair accepts --interval and --background option.
More efficiently prepare _rmeta devices when creating a new raid LV.
Version 2.02.167 - 5th November 2016
====================================
Use log_error in regex and sysfs filter to describe reason of failure.
Fix blkdeactivate to deactivate dev stack if dev on top already unmounted.
Prevent non-synced raid1 repair unless --force
Prevent raid4 creation/conversion on non-supporting kernels
Add direct striped -> raid4 conversion
Fix raid4 parity image pair position on conversions from striped/raid0*
Fix a few unconverted return code values for some lvconvert error path.
Disable lvconvert of thin pool to raid while active.
Disable systemd service start rate limiting for lvm2-pvscan@.service.
Version 2.02.166 - 26th September 2016
======================================
Fix lvm2-activation-generator to read all LVM2 config sources. (2.02.155)
Fix lvchange-rebuild-raid.sh to cope with older target versions.
Use dm_config_parse_without_dup_node_check() to speedup metadata reading.
Fix lvconvert --repair regression
Fix reported origin lv field for cache volumes. (2.02.133)
Always specify snapshot cow LV for monitoring not internal LV. (2.02.165)
Fix lvchange --discard|--zero for active thin-pool.
Enforce 4MiB or 25% metadata free space for thin pool operations.
Fix lock-holder device for thin pool with inactive thin volumes.
Use --alloc normal for mirror logs even if the mimages were stricter.
Use O_DIRECT to gather metadata in lvmdump.
Ignore creation_time when checking for matching metadata for lvmetad.
Fix possible NULL pointer derefence when checking for monitoring.
Add lvmreport(7) man page.
Don't install lvmraid(7) man page when raid excluded. (2.02.165)
Report 0% as dirty (copy%) for cache without any used block.
Fix lvm2api reporting of cache data and metadata percent.
Restore reporting of metadata usage for cache volumes (2.02.155).
Support raid scrubbing on cache origin LV.
Version 2.02.165 - 7th September 2016
=====================================
Add lvmraid(7) man page.
Use udev db to check for mpath components before running pvscan for lvmetad.
Use lsblk -s and lsblk -O in lvmdump only if these options are supported.
Fix number of stripes shown in lvcreate raid10 message when too many.
Change lvmdbusd to use new lvm shell facilities.
Do not monitor cache-pool metadata when LV is just being cleared.
Add allocation/cache_pool_max_chunks to prevent misuse of cache target.
Give error not segfault in lvconvert --splitmirrors when PV lies outside LV.
Fix typo in report/columns_as_rows config option name recognition (2.02.99).
Avoid PV tags when checking allocation against parallel PVs.
Disallow mirror conversions of raid10 volumes.
Fix dmeventd unmonitoring when segment type (and dso) changes.
Don't allow lvconvert --repair on raid0 devices or attempt to monitor them.
No longer adjust incorrect number of raid stripes supplied to lvcreate.
Move lcm and gcd to lib/misc.
Fix vgsplit of external origins. (2.02.162)
Prohibit creation of RAID LVs unless VG extent size is at least the page size.
Version 2.02.165 -
===================================
Suppress some unnecessary --stripesize parameter warnings.
Fix 'pvmove -n name ...' to prohibit collocation of RAID SubLVs

View File

@@ -1,87 +1,5 @@
Version 1.02.143 -
=================================
Add --concise to dmsetup create for many devices with tables in one command.
Accept minor number without major in library when it knows dm major number.
Introduce single-line concise table output format: dmsetup table --concise
Version 1.02.142 - 20th July 2017
=================================
Create /dev/disk/by-part{uuid,label} and gpt-auto-root symlinks with udev.
Version 1.02.141 - 28th June 2017
=================================
Fix reusing of dm_task structure for status reading (used by dmeventd).
Add dm_percent_to_round_float for adjusted percentage rounding.
Reset array with dead rimage devices once raid gets in sync.
Drop unneeded --config option from raid dmeventd plugin.
dm_get_status_raid() handle better some incosistent md statuses.
Accept truncated files in calls to dm_stats_update_regions_from_fd().
Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
Version 1.02.140 - 3rd May 2017
===============================
Add missing configure --enable-dmfilemapd status message and fix --disable.
Version 1.02.139 - 13th April 2017
==================================
Fix assignment in _target_version() when dm task can't run.
Flush stdout on each iteration when using --count or --interval.
Show detailed error message when execvp fails while starting dmfilemapd.
Fix segmentation fault when dmfilemapd is run with no arguments.
Numerous minor dmfilemapd fixes from coverity.
Version 1.02.138 - 28th March 2017
==================================
Support additional raid5/6 configurations.
Provide dm_tree_node_add_cache_target@base compatible symbol.
Support DM_CACHE_FEATURE_METADATA2, new cache metadata format 2.
Improve code to handle mode mask for cache nodes.
Cache status check for passthrough also require trailing space.
Add extra memory page when limiting pthread stack size in dmeventd.
Avoids immediate resume when preloaded device is smaller.
Do not suppress kernel key description in dmsetup table output for dm-crypt.
Support configurable command executed from dmeventd thin plugin.
Support new R|r human readable units output format.
Thin dmeventd plugin reacts faster on lvextend failure path with umount.
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
Do not try call callback when reverting activation on error path.
Fix file mapping for extents with physically adjacent extents in dmstats.
Validation vsnprintf result in runtime translate of dm_log (1.02.136).
Separate filemap extent allocation from region table in dmstats.
Fix segmentation fault when filemap region creation fails in dmstats.
Fix performance of region cleanup for failed filemap creation in dmstats.
Fix very slow region deletion with many regions in dmstats.
Version 1.02.137 - 30th November 2016
=====================================
Document raid status values.
Always exit dmsetup with success when asked to display help/version.
Version 1.02.136 - 5th November 2016
====================================
Log failure of raid device with log_error level.
Use dm_log_with_errno and translate runtime to dm_log only when needed.
Make log messages from dm and lvm library different from dmeventd.
Notice and Info messages are again logged from dmeventd and its plugins.
Dmeventd now also respects DM_ABORT_ON_INTERNAL_ERRORS as libdm based tool.
Report as non default dm logging also when logging with errno was changed.
Use log_level() macro to consistently decode message log level in dmeventd.
Still produce output when dmsetup dependency tree building finds dev missing.
Check and report pthread_sigmask() failure in dmeventd.
Check mem alloc fail in _canonicalize_field_ids().
Use unsigned math when checking more then 31 legs of raid.
Fix 'dmstats delete' with dmsetup older than v1.02.129
Fix stats walk segfault with dmsetup older than v1.02.129
Version 1.02.135 - 26th September 2016
======================================
Fix man entry for dmsetup status.
Introduce new dm_config_parse_without_dup_node_check().
Don't omit last entry in dmstats list --group.
Version 1.02.134 - 7th September 2016
=====================================
Improve explanation of udev fallback in libdevmapper.h.
Version 1.02.134 -
===================================
Version 1.02.133 - 10th August 2016
===================================

View File

@@ -61,174 +61,3 @@ AC_DEFUN([AC_TRY_LDFLAGS],
ifelse([$4], [], [:], [$4])
fi
])
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_GCC_BUILTIN(BUILTIN)
#
# DESCRIPTION
#
# This macro checks if the compiler supports one of GCC's built-in
# functions; many other compilers also provide those same built-ins.
#
# The BUILTIN parameter is the name of the built-in function.
#
# If BUILTIN is supported define HAVE_<BUILTIN>. Keep in mind that since
# builtins usually start with two underscores they will be copied over
# into the HAVE_<BUILTIN> definition (e.g. HAVE___BUILTIN_EXPECT for
# __builtin_expect()).
#
# The macro caches its result in the ax_cv_have_<BUILTIN> variable (e.g.
# ax_cv_have___builtin_expect).
#
# The macro currently supports the following built-in functions:
#
# __builtin_assume_aligned
# __builtin_bswap16
# __builtin_bswap32
# __builtin_bswap64
# __builtin_choose_expr
# __builtin___clear_cache
# __builtin_clrsb
# __builtin_clrsbl
# __builtin_clrsbll
# __builtin_clz
# __builtin_clzl
# __builtin_clzll
# __builtin_complex
# __builtin_constant_p
# __builtin_ctz
# __builtin_ctzl
# __builtin_ctzll
# __builtin_expect
# __builtin_ffs
# __builtin_ffsl
# __builtin_ffsll
# __builtin_fpclassify
# __builtin_huge_val
# __builtin_huge_valf
# __builtin_huge_vall
# __builtin_inf
# __builtin_infd128
# __builtin_infd32
# __builtin_infd64
# __builtin_inff
# __builtin_infl
# __builtin_isinf_sign
# __builtin_nan
# __builtin_nand128
# __builtin_nand32
# __builtin_nand64
# __builtin_nanf
# __builtin_nanl
# __builtin_nans
# __builtin_nansf
# __builtin_nansl
# __builtin_object_size
# __builtin_parity
# __builtin_parityl
# __builtin_parityll
# __builtin_popcount
# __builtin_popcountl
# __builtin_popcountll
# __builtin_powi
# __builtin_powif
# __builtin_powil
# __builtin_prefetch
# __builtin_trap
# __builtin_types_compatible_p
# __builtin_unreachable
#
# Unsuppored built-ins will be tested with an empty parameter set and the
# result of the check might be wrong or meaningless so use with care.
#
# LICENSE
#
# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 3
AC_DEFUN([AX_GCC_BUILTIN], [
AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1])
AC_CACHE_CHECK([for $1], [ac_var], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [
m4_case([$1],
[__builtin_assume_aligned], [$1("", 0)],
[__builtin_bswap16], [$1(0)],
[__builtin_bswap32], [$1(0)],
[__builtin_bswap64], [$1(0)],
[__builtin_choose_expr], [$1(0, 0, 0)],
[__builtin___clear_cache], [$1("", "")],
[__builtin_clrsb], [$1(0)],
[__builtin_clrsbl], [$1(0)],
[__builtin_clrsbll], [$1(0)],
[__builtin_clz], [$1(0)],
[__builtin_clzl], [$1(0)],
[__builtin_clzll], [$1(0)],
[__builtin_complex], [$1(0.0, 0.0)],
[__builtin_constant_p], [$1(0)],
[__builtin_ctz], [$1(0)],
[__builtin_ctzl], [$1(0)],
[__builtin_ctzll], [$1(0)],
[__builtin_expect], [$1(0, 0)],
[__builtin_ffs], [$1(0)],
[__builtin_ffsl], [$1(0)],
[__builtin_ffsll], [$1(0)],
[__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)],
[__builtin_huge_val], [$1()],
[__builtin_huge_valf], [$1()],
[__builtin_huge_vall], [$1()],
[__builtin_inf], [$1()],
[__builtin_infd128], [$1()],
[__builtin_infd32], [$1()],
[__builtin_infd64], [$1()],
[__builtin_inff], [$1()],
[__builtin_infl], [$1()],
[__builtin_isinf_sign], [$1(0.0)],
[__builtin_nan], [$1("")],
[__builtin_nand128], [$1("")],
[__builtin_nand32], [$1("")],
[__builtin_nand64], [$1("")],
[__builtin_nanf], [$1("")],
[__builtin_nanl], [$1("")],
[__builtin_nans], [$1("")],
[__builtin_nansf], [$1("")],
[__builtin_nansl], [$1("")],
[__builtin_object_size], [$1("", 0)],
[__builtin_parity], [$1(0)],
[__builtin_parityl], [$1(0)],
[__builtin_parityll], [$1(0)],
[__builtin_popcount], [$1(0)],
[__builtin_popcountl], [$1(0)],
[__builtin_popcountll], [$1(0)],
[__builtin_powi], [$1(0, 0)],
[__builtin_powif], [$1(0, 0)],
[__builtin_powil], [$1(0, 0)],
[__builtin_prefetch], [$1("")],
[__builtin_trap], [$1()],
[__builtin_types_compatible_p], [$1(int, int)],
[__builtin_unreachable], [$1()],
[m4_warn([syntax], [Unsupported built-in $1, the test may fail])
$1()]
)
])],
[AS_VAR_SET([ac_var], [yes])],
[AS_VAR_SET([ac_var], [no])])
])
AS_IF([test yes = AS_VAR_GET([ac_var])],
[AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1,
[Define to 1 if the system has the `$1' built-in function])], [])
AS_VAR_POPDEF([ac_var])
])

1
aclocal.m4 vendored
View File

@@ -536,5 +536,4 @@ AC_DEFUN([AM_RUN_LOG],
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
(exit $ac_status); }])
m4_include([acinclude.m4])

View File

@@ -32,8 +32,8 @@ include $(top_builddir)/make.tmpl
.PHONY: install_conf install_localconf install_profiles
generate:
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withgeneralpreamble --withcomments --ignorelocal --withspaces > example.conf.in
LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withlocalpreamble --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 --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
install_conf: $(CONFSRC)
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
@@ -48,8 +48,8 @@ install_localconf: $(CONFLOCAL)
fi
install_profiles: $(PROFILES)
$(INSTALL_DIR) $(profiledir)
$(INSTALL_DATA) $(PROFILES) $(profiledir)/
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
install_lvm2: install_conf install_localconf install_profiles

View File

@@ -9,6 +9,6 @@ allocation {
cache_mode = "writethrough"
cache_policy = "smq"
cache_settings {
# currently no settings for "smq" policy
# currently no settins for "smq" policy
}
}

View File

@@ -39,7 +39,7 @@ report {
list_item_separator=","
prefixes=0
quoted=1
columns_as_rows=0
colums_as_rows=0
binary_values_as_numeric=0
time_format="%Y-%m-%d %T %z"
devtypes_sort="devtype_name"

23
conf/example.conf.base Normal file
View File

@@ -0,0 +1,23 @@
# This is an example configuration file for the LVM2 system.
# It contains the default settings that would be used if there was no
# @DEFAULT_SYS_DIR@/lvm.conf file.
#
# 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.
#
# N.B. Take care that each setting only appears once if uncommenting
# example settings in this file.

View File

@@ -379,9 +379,8 @@ allocation {
# Configuration option allocation/raid_stripe_all_devices.
# Stripe across all PVs when RAID stripes are not specified.
# If enabled, all PVs in the VG or on the command line are used for
# raid0/4/5/6/10 when the command does not specify the number of
# stripes to use.
# If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10
# when the command does not specify the number of stripes to use.
# This was the default behaviour until release 2.02.162.
# This configuration option has an automatic default value.
# raid_stripe_all_devices = 0
@@ -390,17 +389,6 @@ allocation {
# Cache pool metadata and data will always use different PVs.
cache_pool_metadata_require_separate_pvs = 0
# Configuration option allocation/cache_metadata_format.
# Sets default metadata format for new cache.
#
# Accepted values:
# 0 Automatically detected best available format
# 1 Original format
# 2 Improved 2nd. generation format
#
# This configuration option has an automatic default value.
# cache_metadata_format = 0
# Configuration option allocation/cache_mode.
# The default cache mode used for new cache.
#
@@ -417,7 +405,7 @@ allocation {
# Configuration option allocation/cache_policy.
# The default cache policy used for new cache volume.
# Since kernel 4.2 the default policy is smq (Stochastic multiqueue),
# Since kernel 4.2 the default policy is smq (Stochastic multique),
# otherwise the older mq (Multiqueue) policy is selected.
# This configuration option does not have a default value defined.
@@ -440,12 +428,6 @@ allocation {
# 32KiB to 1GiB in multiples of 32.
# This configuration option does not have a default value defined.
# Configuration option allocation/cache_pool_max_chunks.
# The maximum number of chunks in a cache pool.
# For cache target v1.9 the recommended maximumm is 1000000 chunks.
# Using cache pool with more chunks may degrade cache performance.
# This configuration option does not have a default value defined.
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
# Thin pool metdata and data will always use different PVs.
thin_pool_metadata_require_separate_pvs = 0
@@ -677,7 +659,7 @@ global {
# Configuration option global/units.
# Default value for --units argument.
units = "r"
units = "h"
# Configuration option global/si_unit_consistency.
# Distinguish between powers of 1024 and 1000 bytes.
@@ -940,7 +922,7 @@ global {
use_lvmetad = @DEFAULT_USE_LVMETAD@
# Configuration option global/lvmetad_update_wait_time.
# Number of seconds a command will wait for lvmetad update to finish.
# The number of seconds a command will wait for lvmetad update to finish.
# After waiting for this period, a command will not use lvmetad, and
# will revert to disk scanning.
# This configuration option has an automatic default value.
@@ -1025,7 +1007,7 @@ global {
# Configuration option global/cache_disabled_features.
# Features to not use in the cache driver.
# This can be helpful for testing, or to avoid using a feature that is
# causing problems. Features include: policy_mq, policy_smq, metadata2.
# causing problems. Features include: policy_mq, policy_smq.
#
# Example
# cache_disabled_features = [ "policy_smq" ]
@@ -1070,12 +1052,6 @@ global {
# This configuration option has an automatic default value.
# cache_repair_options = [ "" ]
# Configuration option global/fsadm_executable.
# The full path to the fsadm command.
# LVM uses this command to help with lvresize -r operations.
# This configuration option has an automatic default value.
# fsadm_executable = "@FSADM_PATH@"
# Configuration option global/system_id_source.
# The method LVM uses to set the local system ID.
# Volume Groups can also be given a system ID (by vgcreate, vgchange,
@@ -1174,8 +1150,7 @@ activation {
# Configuration option activation/missing_stripe_filler.
# Method to fill missing stripes when activating an incomplete LV.
# Using 'error' will make inaccessible parts of the device return I/O
# errors on access. Using 'zero' will return success (and zero) on I/O
# You can instead use a device path, in which case,
# errors on access. You can instead use a device path, in which case,
# that device will be used in place of missing stripes. Using anything
# other than 'error' with mirrored or snapshotted volumes is likely to
# result in data corruption.
@@ -1295,10 +1270,9 @@ activation {
# Configuration option activation/raid_region_size.
# Size in KiB of each raid or mirror synchronization region.
# The clean/dirty state of data is tracked for each region.
# The value is rounded down to a power of two if necessary, and
# is ignored if it is not a multiple of the machine memory page size.
raid_region_size = 2048
# For raid or mirror segment types, this is the amount of data that is
# copied at once when initializing, or moved at once by pvmove.
raid_region_size = 512
# Configuration option activation/error_when_full.
# Return errors if a thin pool runs out of space.
@@ -1710,11 +1684,11 @@ activation {
# This configuration option has an automatic default value.
# quoted = 1
# Configuration option report/columns_as_rows.
# Configuration option report/colums_as_rows.
# Output each column as a row.
# If set, this also implies report/prefixes=1.
# This configuration option has an automatic default value.
# columns_as_rows = 0
# colums_as_rows = 0
# Configuration option report/binary_values_as_numeric.
# Use binary values 0 or 1 instead of descriptive literal values.
@@ -2068,15 +2042,6 @@ dmeventd {
# warning is repeated when 85%, 90% and 95% of the pool is filled.
thin_library = "libdevmapper-event-lvm2thin.so"
# Configuration option dmeventd/thin_command.
# The plugin runs command with each 5% increment when thin-pool data volume
# or metadata volume gets above 50%.
# Command which starts with 'lvm ' prefix is internal lvm command.
# You can write your own handler to customise behaviour in more details.
# User handler is specified with the full path starting with '/'.
# This configuration option has an automatic default value.
# thin_command = "lvm lvextend --use-policies"
# Configuration option dmeventd/executable.
# The full path to the dmeventd binary.
# This configuration option has an automatic default value.

19
conf/lvmlocal.conf.base Normal file
View File

@@ -0,0 +1,19 @@
# This is a local configuration file template for the LVM2 system
# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
#
# Refer to 'man lvm.conf' for information about the file layout.
#
# To put this file in a different directory and override
# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
# running the tools.
#
# The lvmlocal.conf file is normally expected to contain only the
# "local" section which contains settings that should not be shared or
# repeated among different hosts. (But if other sections are present,
# they *will* get processed. Settings in this file override equivalent
# ones in lvm.conf and are in turn overridden by ones in any enabled
# lvm_<tag>.conf files.)
#
# Please take care that each setting only appears once if uncommenting
# example settings in this file and never copy this file between hosts.

591
configure vendored
View File

@@ -660,7 +660,7 @@ SELINUX_PC
SELINUX_LIBS
REPLICATORS
READLINE_LIBS
RT_LIBS
RT_LIB
RAID
PYTHON3DIR
PYTHON2DIR
@@ -676,7 +676,6 @@ PTHREAD_LIBS
M_LIBS
POOL
PKGCONFIG
ODIRECT
OCFDIR
OCF
MIRRORS
@@ -699,11 +698,11 @@ HAVE_VALGRIND
HAVE_REALTIME
HAVE_LIBDL
BLKDEACTIVATE
FSADM_PATH
FSADM
ELDFLAGS
DM_LIB_PATCHLEVEL
DMEVENTD_PATH
DMEVENTD
DL_LIBS
DEVMAPPER
DEFAULT_USE_LVMLOCKD
@@ -736,7 +735,7 @@ CLDWHOLEARCHIVE
CLDNOWHOLEARCHIVE
CLDFLAGS
CACHE
BUILD_DMFILEMAPD
BUILD_NOTIFYDBUS
BUILD_LOCKDDLM
BUILD_LOCKDSANLOCK
BUILD_LVMLOCKD
@@ -819,14 +818,11 @@ THIN_CHECK_CMD
HAVE_FULL_RELRO
HAVE_PIE
POW_LIB
ALLOCA
LIBOBJS
SORT
WC
ALLOCA
CHMOD
CSCOPE_CMD
CFLOW_CMD
AR
RANLIB
MKDIR_P
SET_MAKE
@@ -953,15 +949,14 @@ enable_valgrind_pool
enable_devmapper
enable_lvmetad
enable_lvmpolld
enable_lvmlockd_sanlock
enable_lvmlockd_dlm
enable_lockd_sanlock
enable_lockd_dlm
enable_use_lvmlockd
with_lvmlockd_pidfile
enable_use_lvmetad
with_lvmetad_pidfile
enable_use_lvmpolld
with_lvmpolld_pidfile
enable_dmfilemapd
enable_notify_dbus
enable_blkid_wiping
enable_udev_systemd_background_jobs
@@ -1691,13 +1686,11 @@ Optional Features:
--disable-devmapper disable LVM2 device-mapper interaction
--enable-lvmetad enable the LVM Metadata Daemon
--enable-lvmpolld enable the LVM Polling Daemon
--enable-lvmlockd-sanlock
enable the LVM lock daemon using sanlock
--enable-lvmlockd-dlm enable the LVM lock daemon using dlm
--enable-lockd-sanlock enable the LVM lock daemon using sanlock
--enable-lockd-dlm enable the LVM lock daemon using dlm
--disable-use-lvmlockd disable usage of LVM lock daemon
--disable-use-lvmetad disable usage of LVM Metadata Daemon
--disable-use-lvmpolld disable usage of LVM Poll Daemon
--enable-dmfilemapd enable the dmstats filemap daemon
--enable-notify-dbus enable LVM notification using dbus
--disable-blkid_wiping disable libblkid detection of signatures when wiping
and use native code instead
@@ -3015,7 +3008,6 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
CONFIGURE_LINE="$0 $@"
ac_config_headers="$ac_config_headers include/configure.h"
@@ -3169,7 +3161,6 @@ fi
case "$host_os" in
linux*)
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
# equivalent to -rdynamic
ELDFLAGS="-Wl,--export-dynamic"
# FIXME Generate list and use --dynamic-list=.dlopen.sym
CLDWHOLEARCHIVE="-Wl,-whole-archive"
@@ -4948,98 +4939,6 @@ else
RANLIB="$ac_cv_prog_RANLIB"
fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
set dummy ${ac_tool_prefix}ar; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_AR+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$AR"; then
ac_cv_prog_AR="$AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_AR="${ac_tool_prefix}ar"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
AR=$ac_cv_prog_AR
if test -n "$AR"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
$as_echo "$AR" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
if test -z "$ac_cv_prog_AR"; then
ac_ct_AR=$AR
# Extract the first word of "ar", so it can be a program name with args.
set dummy ar; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_AR+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_AR"; then
ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_AR="ar"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
ac_ct_AR=$ac_cv_prog_ac_ct_AR
if test -n "$ac_ct_AR"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
$as_echo "$ac_ct_AR" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x$ac_ct_AR" = x; then
AR=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
AR=$ac_ct_AR
fi
else
AR="$ac_cv_prog_AR"
fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cflow", so it can be a program name with args.
set dummy ${ac_tool_prefix}cflow; ac_word=$2
@@ -5334,202 +5233,6 @@ else
CHMOD="$ac_cv_path_CHMOD"
fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}wc", so it can be a program name with args.
set dummy ${ac_tool_prefix}wc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_WC+:} false; then :
$as_echo_n "(cached) " >&6
else
case $WC in
[\\/]* | ?:[\\/]*)
ac_cv_path_WC="$WC" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_WC="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
WC=$ac_cv_path_WC
if test -n "$WC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $WC" >&5
$as_echo "$WC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
if test -z "$ac_cv_path_WC"; then
ac_pt_WC=$WC
# Extract the first word of "wc", so it can be a program name with args.
set dummy wc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_ac_pt_WC+:} false; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_WC in
[\\/]* | ?:[\\/]*)
ac_cv_path_ac_pt_WC="$ac_pt_WC" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_ac_pt_WC="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
ac_pt_WC=$ac_cv_path_ac_pt_WC
if test -n "$ac_pt_WC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_WC" >&5
$as_echo "$ac_pt_WC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x$ac_pt_WC" = x; then
WC=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
WC=$ac_pt_WC
fi
else
WC="$ac_cv_path_WC"
fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}sort", so it can be a program name with args.
set dummy ${ac_tool_prefix}sort; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_SORT+:} false; then :
$as_echo_n "(cached) " >&6
else
case $SORT in
[\\/]* | ?:[\\/]*)
ac_cv_path_SORT="$SORT" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_SORT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
SORT=$ac_cv_path_SORT
if test -n "$SORT"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SORT" >&5
$as_echo "$SORT" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
if test -z "$ac_cv_path_SORT"; then
ac_pt_SORT=$SORT
# Extract the first word of "sort", so it can be a program name with args.
set dummy sort; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_ac_pt_SORT+:} false; then :
$as_echo_n "(cached) " >&6
else
case $ac_pt_SORT in
[\\/]* | ?:[\\/]*)
ac_cv_path_ac_pt_SORT="$ac_pt_SORT" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_ac_pt_SORT="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
ac_pt_SORT=$ac_cv_path_ac_pt_SORT
if test -n "$ac_pt_SORT"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_SORT" >&5
$as_echo "$ac_pt_SORT" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x$ac_pt_SORT" = x; then
SORT=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
SORT=$ac_pt_SORT
fi
else
SORT="$ac_cv_path_SORT"
fi
################################################################################
ac_header_dirent=no
@@ -6172,7 +5875,7 @@ fi
done
for ac_header in termios.h sys/statvfs.h sys/timerfd.h sys/vfs.h linux/magic.h linux/fiemap.h
for ac_header in termios.h sys/statvfs.h sys/timerfd.h linux/magic.h linux/fiemap.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -6365,26 +6068,6 @@ _ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_blocks" "ac_cv_member_struct_stat_st_blocks" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_blocks" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_BLOCKS 1
_ACEOF
$as_echo "#define HAVE_ST_BLOCKS 1" >>confdefs.h
else
case " $LIBOBJS " in
*" fileblocks.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS fileblocks.$ac_objext"
;;
esac
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
if ${ac_cv_struct_tm+:} false; then :
@@ -6637,50 +6320,6 @@ _ACEOF
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_clz" >&5
$as_echo_n "checking for __builtin_clz... " >&6; }
if ${ax_cv_have___builtin_clz+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
__builtin_clz(0)
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ax_cv_have___builtin_clz=yes
else
ax_cv_have___builtin_clz=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_clz" >&5
$as_echo "$ax_cv_have___builtin_clz" >&6; }
if test yes = $ax_cv_have___builtin_clz; then :
cat >>confdefs.h <<_ACEOF
#define HAVE___BUILTIN_CLZ 1
_ACEOF
fi
################################################################################
for ac_func in ftruncate gethostname getpagesize gettimeofday localtime_r \
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
@@ -9349,11 +8988,6 @@ $as_echo "$as_me: WARNING: $CACHE_CHECK_CMD: Old version \"$CACHE_CHECK_VSN\" fo
CACHE_CHECK_VERSION_WARN=y
CACHE_CHECK_NEEDS_CHECK=no
fi
if test "$CACHE_CHECK_VSN_MINOR" -lt 7 ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $CACHE_CHECK_CMD: Old version \"$CACHE_CHECK_VSN\" does not support new cache format V2" >&5
$as_echo "$as_me: WARNING: $CACHE_CHECK_CMD: Old version \"$CACHE_CHECK_VSN\" does not support new cache format V2" >&2;}
CACHE_CHECK_VERSION_WARN=y
fi
fi
fi
# Empty means a config way to ignore cache dumping
@@ -9716,6 +9350,8 @@ _ACEOF
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable readline" >&5
$as_echo_n "checking whether to enable readline... " >&6; }
# Check whether --enable-readline was given.
if test "${enable_readline+set}" = set; then :
enableval=$enable_readline; READLINE=$enableval
@@ -9723,6 +9359,8 @@ else
READLINE=maybe
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $READLINE" >&5
$as_echo "$READLINE" >&6; }
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable realtime support" >&5
@@ -11867,11 +11505,11 @@ $as_echo "$BUILD_LVMPOLLD" >&6; }
################################################################################
BUILD_LVMLOCKD=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build lvmlockdsanlock" >&5
$as_echo_n "checking whether to build lvmlockdsanlock... " >&6; }
# Check whether --enable-lvmlockd-sanlock was given.
if test "${enable_lvmlockd_sanlock+set}" = set; then :
enableval=$enable_lvmlockd_sanlock; LOCKDSANLOCK=$enableval
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build lockdsanlock" >&5
$as_echo_n "checking whether to build lockdsanlock... " >&6; }
# Check whether --enable-lockd-sanlock was given.
if test "${enable_lockd_sanlock+set}" = set; then :
enableval=$enable_lockd_sanlock; LOCKDSANLOCK=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LOCKDSANLOCK" >&5
@@ -11958,11 +11596,11 @@ $as_echo "#define LOCKDSANLOCK_SUPPORT 1" >>confdefs.h
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build lvmlockddlm" >&5
$as_echo_n "checking whether to build lvmlockddlm... " >&6; }
# Check whether --enable-lvmlockd-dlm was given.
if test "${enable_lvmlockd_dlm+set}" = set; then :
enableval=$enable_lvmlockd_dlm; LOCKDDLM=$enableval
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build lockddlm" >&5
$as_echo_n "checking whether to build lockddlm... " >&6; }
# Check whether --enable-lockd-dlm was given.
if test "${enable_lockd_dlm+set}" = set; then :
enableval=$enable_lockd_dlm; LOCKDDLM=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LOCKDDLM" >&5
@@ -12193,55 +11831,28 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build dmfilemapd" >&5
$as_echo_n "checking whether to build dmfilemapd... " >&6; }
# Check whether --enable-dmfilemapd was given.
if test "${enable_dmfilemapd+set}" = set; then :
enableval=$enable_dmfilemapd; BUILD_DMFILEMAPD=$enableval
else
BUILD_DMFILEMAPD=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_DMFILEMAPD" >&5
$as_echo "$BUILD_DMFILEMAPD" >&6; }
$as_echo "#define DMFILEMAPD \$BUILD_DMFILEMAPD" >>confdefs.h
if test "$BUILD_DMFILEMAPD" = yes; then
ac_fn_c_check_header_mongrel "$LINENO" "linux/fiemap.h" "ac_cv_header_linux_fiemap_h" "$ac_includes_default"
if test "x$ac_cv_header_linux_fiemap_h" = xyes; then :
else
as_fn_error $? "--enable-dmfilemapd requires fiemap.h" "$LINENO" 5
fi
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build notifydbus" >&5
$as_echo_n "checking whether to build notifydbus... " >&6; }
# Check whether --enable-notify-dbus was given.
if test "${enable_notify_dbus+set}" = set; then :
enableval=$enable_notify_dbus; NOTIFYDBUS_SUPPORT=$enableval
else
NOTIFYDBUS_SUPPORT=no
enableval=$enable_notify_dbus; NOTIFYDBUS=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $NOTIFYDBUS_SUPPORT" >&5
$as_echo "$NOTIFYDBUS_SUPPORT" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $NOTIFYDBUS" >&5
$as_echo "$NOTIFYDBUS" >&6; }
if test "$NOTIFYDBUS_SUPPORT" = yes; then
BUILD_NOTIFYDBUS=$NOTIFYDBUS
if test "$BUILD_NOTIFYDBUS" = yes; then
$as_echo "#define NOTIFYDBUS_SUPPORT 1" >>confdefs.h
SYSTEMD_LIBS="-lsystemd"
LIBS="-lsystemd $LIBS"
fi
################################################################################
if test "$NOTIFYDBUS_SUPPORT" = yes; then
if test "$BUILD_NOTIFYDBUS" = yes; then
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for NOTIFY_DBUS" >&5
@@ -12317,6 +11928,8 @@ fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable libblkid detection of signatures when wiping" >&5
$as_echo_n "checking whether to enable libblkid detection of signatures when wiping... " >&6; }
# Check whether --enable-blkid_wiping was given.
if test "${enable_blkid_wiping+set}" = set; then :
enableval=$enable_blkid_wiping; BLKID_WIPING=$enableval
@@ -12324,8 +11937,9 @@ else
BLKID_WIPING=maybe
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BLKID_WIPING" >&5
$as_echo "$BLKID_WIPING" >&6; }
DEFAULT_USE_BLKID_WIPING=0
if test "$BLKID_WIPING" != no; then
pkg_config_init
@@ -12405,19 +12019,20 @@ else
BLKID_LIBS=$pkg_cv_BLKID_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
BLKID_WIPING=yes
BLKID_PC="blkid"
DEFAULT_USE_BLKID_WIPING=1
test "$BLKID_WIPING" = maybe && BLKID_WIPING=yes
fi
if test "$BLKID_WIPING" = yes; then
BLKID_PC="blkid"
DEFAULT_USE_BLKID_WIPING=1
$as_echo "#define BLKID_WIPING_SUPPORT 1" >>confdefs.h
else
DEFAULT_USE_BLKID_WIPING=0
fi
else
DEFAULT_USE_BLKID_WIPING=0
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable libblkid detection of signatures when wiping" >&5
$as_echo_n "checking whether to enable libblkid detection of signatures when wiping... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BLKID_WIPING" >&5
$as_echo "$BLKID_WIPING" >&6; }
cat >>confdefs.h <<_ACEOF
#define DEFAULT_USE_BLKID_WIPING $DEFAULT_USE_BLKID_WIPING
@@ -12425,6 +12040,8 @@ _ACEOF
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use udev-systemd protocol for jobs in background" >&5
$as_echo_n "checking whether to use udev-systemd protocol for jobs in background... " >&6; }
# Check whether --enable-udev-systemd-background-jobs was given.
if test "${enable_udev_systemd_background_jobs+set}" = set; then :
enableval=$enable_udev_systemd_background_jobs; UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval
@@ -12432,6 +12049,8 @@ else
UDEV_SYSTEMD_BACKGROUND_JOBS=maybe
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_SYSTEMD_BACKGROUND_JOBS" >&5
$as_echo "$UDEV_SYSTEMD_BACKGROUND_JOBS" >&6; }
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
pkg_config_init
@@ -12512,15 +12131,10 @@ else
SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
UDEV_SYSTEMD_BACKGROUND_JOBS=yes
test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe && UDEV_SYSTEMD_BACKGROUND_JOBS=yes
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use udev-systemd protocol for jobs in background" >&5
$as_echo_n "checking whether to use udev-systemd protocol for jobs in background... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_SYSTEMD_BACKGROUND_JOBS" >&5
$as_echo "$UDEV_SYSTEMD_BACKGROUND_JOBS" >&6; }
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable synchronisation with udev processing" >&5
$as_echo_n "checking whether to enable synchronisation with udev processing... " >&6; }
@@ -13916,15 +13530,15 @@ $as_echo "$BLKDEACTIVATE" >&6; }
$as_echo_n "checking whether to use dmeventd... " >&6; }
# Check whether --enable-dmeventd was given.
if test "${enable_dmeventd+set}" = set; then :
enableval=$enable_dmeventd; BUILD_DMEVENTD=$enableval
else
BUILD_DMEVENTD=no
enableval=$enable_dmeventd; DMEVENTD=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_DMEVENTD" >&5
$as_echo "$BUILD_DMEVENTD" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $DMEVENTD" >&5
$as_echo "$DMEVENTD" >&6; }
if test "$BUILD_DMEVENTD" = yes; then
BUILD_DMEVENTD=$DMEVENTD
if test "$DMEVENTD" = yes; then
if test "$MIRRORS" != internal; then
as_fn_error $? "--enable-dmeventd currently requires --with-mirrors=internal" "$LINENO" 5
fi
@@ -14315,24 +13929,8 @@ fi
fi
################################################################################
RT_LIBS=
HAVE_REALTIME=no
if test "$REALTIME" = yes; then
for ac_func in clock_gettime
do :
ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
if test "x$ac_cv_func_clock_gettime" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_CLOCK_GETTIME 1
_ACEOF
HAVE_REALTIME=yes
fi
done
if test "$HAVE_REALTIME" != yes; then :
# try again with -lrt
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
if ${ac_cv_lib_rt_clock_gettime+:} false; then :
$as_echo_n "(cached) " >&6
@@ -14369,15 +13967,18 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
RT_LIBS="-lrt"; HAVE_REALTIME=yes
HAVE_REALTIME=yes
else
HAVE_REALTIME=no
fi
fi
if test "$HAVE_REALTIME" = yes; then
$as_echo "#define HAVE_REALTIME 1" >>confdefs.h
LIBS="-lrt $LIBS"
RT_LIB="-lrt"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling realtime clock" >&5
$as_echo "$as_me: WARNING: Disabling realtime clock" >&2;}
@@ -14546,8 +14147,7 @@ if test "x$ac_cv_lib_readline_readline" = xyes; then :
$as_echo "#define READLINE_SUPPORT 1" >>confdefs.h
READLINE=yes
LIBS=$lvm_saved_libs
LIBS=$lvm_saved_libs
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_line_buffer in -lreadline" >&5
$as_echo_n "checking for rl_line_buffer in -lreadline... " >&6; }
if ${ac_cv_lib_readline_rl_line_buffer+:} false; then :
@@ -14867,10 +14467,6 @@ fi
done
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable readline" >&5
$as_echo_n "checking whether to enable readline... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $READLINE" >&5
$as_echo "$READLINE" >&6; }
if test "$BUILD_CMIRRORD" = yes; then
for ac_func in atexit
@@ -14889,15 +14485,13 @@ done
fi
if test "$BUILD_LVMLOCKD" = yes; then
if test "$HAVE_REALTIME" != yes; then :
as_fn_error $? "Realtime clock support is mandatory for lvmlockd." "$LINENO" 5
fi
for ac_func in strtoull
for ac_func in clock_gettime strtoull
do :
ac_fn_c_check_func "$LINENO" "strtoull" "ac_cv_func_strtoull"
if test "x$ac_cv_func_strtoull" = xyes; then :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRTOULL 1
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
else
@@ -15217,7 +14811,7 @@ done
fi
if test "$BUILD_DMEVENTD" = yes; then
if test "$DMEVENTD" = yes; then
for ac_header in arpa/inet.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default"
@@ -15286,23 +14880,6 @@ done
fi
if test "$BUILD_DMFILEMAPD" = yes; then
for ac_header in sys/inotify.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_inotify_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_SYS_INOTIFY_H 1
_ACEOF
else
hard_bailout
fi
done
fi
################################################################################
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}modprobe", so it can be a program name with args.
@@ -15431,14 +15008,6 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
FSADM_PATH="$lvm_exec_prefix/sbin/fsadm"
cat >>confdefs.h <<_ACEOF
#define FSADM_PATH "$FSADM_PATH"
_ACEOF
################################################################################
if test "$BUILD_DMEVENTD" = yes; then
@@ -15614,12 +15183,6 @@ LVM_MINOR=`echo "$VER" | $AWK -F '.' '{print $2}'`
LVM_PATCHLEVEL=`echo "$VER" | $AWK -F '[(.]' '{print $3}'`
LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
cat >>confdefs.h <<_ACEOF
#define LVM_CONFIGURE_LINE "$CONFIGURE_LINE"
_ACEOF
################################################################################
@@ -15775,13 +15338,11 @@ _ACEOF
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_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 scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_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 scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -16489,7 +16050,6 @@ do
"daemons/dmeventd/plugins/mirror/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/mirror/Makefile" ;;
"daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;;
"daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;;
"daemons/dmfilemapd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmfilemapd/Makefile" ;;
"daemons/lvmdbusd/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/Makefile" ;;
"daemons/lvmdbusd/path.py") CONFIG_FILES="$CONFIG_FILES daemons/lvmdbusd/path.py" ;;
"daemons/lvmetad/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmetad/Makefile" ;;
@@ -16549,7 +16109,6 @@ do
"scripts/lvm2_monitoring_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_systemd_red_hat.service" ;;
"scripts/lvm2_pvscan_systemd_red_hat@.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_pvscan_systemd_red_hat@.service" ;;
"scripts/lvm2_tmpfiles_red_hat.conf") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_tmpfiles_red_hat.conf" ;;
"scripts/lvmdump.sh") CONFIG_FILES="$CONFIG_FILES scripts/lvmdump.sh" ;;
"scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
"test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;;
@@ -17158,8 +16717,8 @@ $as_echo "$as_me: WARNING: Support for thin provisioning is limited since some t
fi
if test -n "$THIN_CHECK_VERSION_WARN"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You should also install latest thin_check vsn 0.7.0 (or later) for lvm2 thin provisioning" >&5
$as_echo "$as_me: WARNING: You should also install latest thin_check vsn 0.7.0 (or later) for lvm2 thin provisioning" >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning" >&5
$as_echo "$as_me: WARNING: You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning" >&2;}
fi
if test -n "$CACHE_CONFIGURE_WARN"; then :
@@ -17167,12 +16726,6 @@ if test -n "$CACHE_CONFIGURE_WARN"; then :
$as_echo "$as_me: WARNING: Support for cache is limited since some cache tools are missing!" >&2;}
fi
if test -n "$CACHE_CHECK_VERSION_WARN"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2" >&5
$as_echo "$as_me: WARNING: You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2" >&2;}
fi
if test "$ODIRECT" != yes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: O_DIRECT disabled: low-memory pvmove may lock up" >&5
$as_echo "$as_me: WARNING: O_DIRECT disabled: low-memory pvmove may lock up" >&2;}

View File

@@ -15,7 +15,6 @@ AC_PREREQ(2.69)
################################################################################
dnl -- Process this file with autoconf to produce a configure script.
AC_INIT
CONFIGURE_LINE="$0 $@"
AC_CONFIG_SRCDIR([lib/device/dev-cache.h])
AC_CONFIG_HEADERS([include/configure.h])
@@ -31,7 +30,6 @@ AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
case "$host_os" in
linux*)
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
# equivalent to -rdynamic
ELDFLAGS="-Wl,--export-dynamic"
# FIXME Generate list and use --dynamic-list=.dlopen.sym
CLDWHOLEARCHIVE="-Wl,-whole-archive"
@@ -85,12 +83,9 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_PROG_RANLIB
AC_CHECK_TOOL(AR, ar)
AC_PATH_TOOL(CFLOW_CMD, cflow)
AC_PATH_TOOL(CSCOPE_CMD, cscope)
AC_PATH_TOOL(CHMOD, chmod)
AC_PATH_TOOL(WC, wc)
AC_PATH_TOOL(SORT, sort)
################################################################################
dnl -- Check for header files.
@@ -108,7 +103,7 @@ AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
unistd.h], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h sys/vfs.h linux/magic.h linux/fiemap.h)
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h linux/magic.h linux/fiemap.h)
case "$host_os" in
linux*)
@@ -123,7 +118,6 @@ AC_C_CONST
AC_C_INLINE
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_TYPES([ptrdiff_t])
AC_STRUCT_ST_BLOCKS
AC_STRUCT_TM
AC_TYPE_OFF_T
AC_TYPE_PID_T
@@ -140,7 +134,6 @@ AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AX_GCC_BUILTIN([__builtin_clz])
################################################################################
dnl -- Check for functions
@@ -619,10 +612,6 @@ case "$CACHE" in
CACHE_CHECK_VERSION_WARN=y
CACHE_CHECK_NEEDS_CHECK=no
fi
if test "$CACHE_CHECK_VSN_MINOR" -lt 7 ; then
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" does not support new cache format V2])
CACHE_CHECK_VERSION_WARN=y
fi
fi
fi
# Empty means a config way to ignore cache dumping
@@ -676,9 +665,11 @@ AC_DEFINE_UNQUOTED([CACHE_RESTORE_CMD], ["$CACHE_RESTORE_CMD"],
################################################################################
dnl -- Disable readline
AC_MSG_CHECKING(whether to enable readline)
AC_ARG_ENABLE([readline],
AC_HELP_STRING([--disable-readline], [disable readline support]),
READLINE=$enableval, READLINE=maybe)
AC_MSG_RESULT($READLINE)
################################################################################
dnl -- Disable realtime clock support
@@ -1154,10 +1145,10 @@ AC_MSG_RESULT($BUILD_LVMPOLLD)
################################################################################
BUILD_LVMLOCKD=no
dnl -- Build lvmlockdsanlock
AC_MSG_CHECKING(whether to build lvmlockdsanlock)
AC_ARG_ENABLE(lvmlockd-sanlock,
AC_HELP_STRING([--enable-lvmlockd-sanlock],
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)
@@ -1172,10 +1163,10 @@ if test "$BUILD_LOCKDSANLOCK" = yes; then
fi
################################################################################
dnl -- Build lvmlockddlm
AC_MSG_CHECKING(whether to build lvmlockddlm)
AC_ARG_ENABLE(lvmlockd-dlm,
AC_HELP_STRING([--enable-lvmlockd-dlm],
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)
@@ -1277,80 +1268,75 @@ fi
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
[Use lvmpolld by default.])
################################################################################
dnl -- Check dmfilemapd
AC_MSG_CHECKING(whether to build dmfilemapd)
AC_ARG_ENABLE(dmfilemapd, AC_HELP_STRING([--enable-dmfilemapd],
[enable the dmstats filemap daemon]),
BUILD_DMFILEMAPD=$enableval, BUILD_DMFILEMAPD=no)
AC_MSG_RESULT($BUILD_DMFILEMAPD)
AC_DEFINE([DMFILEMAPD], $BUILD_DMFILEMAPD, [Define to 1 to enable the device-mapper filemap daemon.])
dnl -- dmfilemapd requires FIEMAP
if test "$BUILD_DMFILEMAPD" = yes; then
AC_CHECK_HEADER([linux/fiemap.h], , [AC_MSG_ERROR(--enable-dmfilemapd requires fiemap.h)])
fi
################################################################################
dnl -- Build notifydbus
AC_MSG_CHECKING(whether to build notifydbus)
AC_ARG_ENABLE(notify-dbus,
AC_HELP_STRING([--enable-notify-dbus],
[enable LVM notification using dbus]),
NOTIFYDBUS_SUPPORT=$enableval, NOTIFYDBUS_SUPPORT=no)
AC_MSG_RESULT($NOTIFYDBUS_SUPPORT)
NOTIFYDBUS=$enableval)
AC_MSG_RESULT($NOTIFYDBUS)
if test "$NOTIFYDBUS_SUPPORT" = yes; then
BUILD_NOTIFYDBUS=$NOTIFYDBUS
if test "$BUILD_NOTIFYDBUS" = yes; then
AC_DEFINE([NOTIFYDBUS_SUPPORT], 1, [Define to 1 to include code that uses dbus notification.])
SYSTEMD_LIBS="-lsystemd"
LIBS="-lsystemd $LIBS"
fi
################################################################################
dnl -- Look for dbus libraries
if test "$NOTIFYDBUS_SUPPORT" = yes; then
if test "$BUILD_NOTIFYDBUS" = yes; then
PKG_CHECK_MODULES(NOTIFY_DBUS, systemd >= 221, [HAVE_NOTIFY_DBUS=yes], $bailout)
fi
################################################################################
dnl -- Enable blkid wiping functionality
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
AC_ARG_ENABLE(blkid_wiping,
AC_HELP_STRING([--disable-blkid_wiping],
[disable libblkid detection of signatures when wiping and use native code instead]),
BLKID_WIPING=$enableval, BLKID_WIPING=maybe)
AC_MSG_RESULT($BLKID_WIPING)
DEFAULT_USE_BLKID_WIPING=0
if test "$BLKID_WIPING" != no; then
pkg_config_init
PKG_CHECK_MODULES(BLKID, blkid >= 2.24,
[ BLKID_WIPING=yes
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.])
], [if test "$BLKID_WIPING" = maybe; then
[test "$BLKID_WIPING" = maybe && BLKID_WIPING=yes],
[if test "$BLKID_WIPING" = maybe; then
BLKID_WIPING=no
else
AC_MSG_ERROR([bailing out... blkid library >= 2.24 is required])
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=0
fi
else
DEFAULT_USE_BLKID_WIPING=0
fi
AC_MSG_CHECKING([whether to enable libblkid detection of signatures when wiping])
AC_MSG_RESULT($BLKID_WIPING)
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
dnl -- Requires systemd version 205 at least (including support for systemd-run)
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
AC_ARG_ENABLE(udev-systemd-background-jobs,
AC_HELP_STRING([--disable-udev-systemd-background-jobs],
[disable udev-systemd protocol to instantiate a service for background job]),
UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval,
UDEV_SYSTEMD_BACKGROUND_JOBS=maybe)
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
pkg_config_init
PKG_CHECK_MODULES(SYSTEMD, systemd >= 205,
[UDEV_SYSTEMD_BACKGROUND_JOBS=yes],
[test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe && UDEV_SYSTEMD_BACKGROUND_JOBS=yes],
[if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe; then
UDEV_SYSTEMD_BACKGROUND_JOBS=no
else
@@ -1358,9 +1344,6 @@ if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
fi])
fi
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
################################################################################
dnl -- Enable udev synchronisation
AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
@@ -1581,11 +1564,13 @@ dnl -- enable dmeventd handling
AC_MSG_CHECKING(whether to use dmeventd)
AC_ARG_ENABLE(dmeventd, AC_HELP_STRING([--enable-dmeventd],
[enable the device-mapper event daemon]),
BUILD_DMEVENTD=$enableval, BUILD_DMEVENTD=no)
AC_MSG_RESULT($BUILD_DMEVENTD)
DMEVENTD=$enableval)
AC_MSG_RESULT($DMEVENTD)
BUILD_DMEVENTD=$DMEVENTD
dnl -- dmeventd currently requires internal mirror support
if test "$BUILD_DMEVENTD" = yes; then
if test "$DMEVENTD" = yes; then
if test "$MIRRORS" != internal; then
AC_MSG_ERROR([--enable-dmeventd currently requires --with-mirrors=internal])
fi
@@ -1669,16 +1654,13 @@ fi
################################################################################
dnl -- Check for realtime clock support
RT_LIBS=
HAVE_REALTIME=no
if test "$REALTIME" = yes; then
AC_CHECK_FUNCS([clock_gettime], HAVE_REALTIME=yes)
AS_IF([test "$HAVE_REALTIME" != yes], [ # try again with -lrt
AC_CHECK_LIB([rt], [clock_gettime], RT_LIBS="-lrt"; HAVE_REALTIME=yes)])
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
if test "$HAVE_REALTIME" = yes; then
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
LIBS="-lrt $LIBS"
RT_LIB="-lrt"
else
AC_MSG_WARN(Disabling realtime clock)
fi
@@ -1722,7 +1704,6 @@ Note: (n)curses also seems to work as a substitute for termcap. This was
AC_DEFINE([READLINE_SUPPORT], 1,
[Define to 1 to include the LVM readline shell.])
dnl -- Try only with -lreadline and check for different symbol
READLINE=yes
LIBS=$lvm_saved_libs
AC_CHECK_LIB([readline], [rl_line_buffer],
[ READLINE_LIBS="-lreadline" ], [
@@ -1829,16 +1810,13 @@ dnl -- Ensure additional headers required
if test "$READLINE" = yes; then
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
fi
AC_MSG_CHECKING(whether to enable readline)
AC_MSG_RESULT($READLINE)
if test "$BUILD_CMIRRORD" = yes; then
AC_CHECK_FUNCS(atexit,,hard_bailout)
fi
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])])
AC_CHECK_FUNCS(strtoull,,hard_bailout)
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
fi
if test "$BUILD_LVMPOLLD" = yes; then
@@ -1858,7 +1836,7 @@ if test "$CLUSTER" != none; then
AC_CHECK_FUNCS(socket,,hard_bailout)
fi
if test "$BUILD_DMEVENTD" = yes; then
if test "$DMEVENTD" = yes; then
AC_CHECK_HEADERS(arpa/inet.h,,hard_bailout)
fi
@@ -1874,10 +1852,6 @@ if test "$UDEV_SYNC" = yes; then
AC_CHECK_HEADERS(sys/ipc.h sys/sem.h,,hard_bailout)
fi
if test "$BUILD_DMFILEMAPD" = yes; then
AC_CHECK_HEADERS([sys/inotify.h],,hard_bailout)
fi
################################################################################
AC_PATH_TOOL(MODPROBE_CMD, modprobe)
@@ -1897,10 +1871,6 @@ test "$prefix" != NONE && clvmd_prefix=$prefix
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
FSADM_PATH="$lvm_exec_prefix/sbin/fsadm"
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
################################################################################
dnl -- dmeventd pidfile and executable path
if test "$BUILD_DMEVENTD" = yes; then
@@ -2009,8 +1979,6 @@ LVM_MINOR=`echo "$VER" | $AWK -F '.' '{print $2}'`
LVM_PATCHLEVEL=`echo "$VER" | $AWK -F '[[(.]]' '{print $3}'`
LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
AC_DEFINE_UNQUOTED(LVM_CONFIGURE_LINE, "$CONFIGURE_LINE", [configure command line used])
################################################################################
AC_SUBST(APPLIB)
AC_SUBST(AWK)
@@ -2023,7 +1991,7 @@ AC_SUBST(BUILD_LVMPOLLD)
AC_SUBST(BUILD_LVMLOCKD)
AC_SUBST(BUILD_LOCKDSANLOCK)
AC_SUBST(BUILD_LOCKDDLM)
AC_SUBST(BUILD_DMFILEMAPD)
AC_SUBST(BUILD_NOTIFYDBUS)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
@@ -2070,11 +2038,11 @@ 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_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
AC_SUBST(FSADM)
AC_SUBST(FSADM_PATH)
AC_SUBST(BLKDEACTIVATE)
AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_REALTIME)
@@ -2100,7 +2068,6 @@ AC_SUBST(MIRRORS)
AC_SUBST(MSGFMT)
AC_SUBST(OCF)
AC_SUBST(OCFDIR)
AC_SUBST(ODIRECT)
AC_SUBST(PKGCONFIG)
AC_SUBST(POOL)
AC_SUBST(M_LIBS)
@@ -2119,7 +2086,7 @@ AC_SUBST(PYTHON3DIR)
AC_SUBST(QUORUM_CFLAGS)
AC_SUBST(QUORUM_LIBS)
AC_SUBST(RAID)
AC_SUBST(RT_LIBS)
AC_SUBST(RT_LIB)
AC_SUBST(READLINE_LIBS)
AC_SUBST(REPLICATORS)
AC_SUBST(SACKPT_CFLAGS)
@@ -2128,7 +2095,6 @@ AC_SUBST(SALCK_CFLAGS)
AC_SUBST(SALCK_LIBS)
AC_SUBST(SELINUX_LIBS)
AC_SUBST(SELINUX_PC)
AC_SUBST(SYSTEMD_LIBS)
AC_SUBST(SNAPSHOTS)
AC_SUBST(STATICDIR)
AC_SUBST(STATIC_LINK)
@@ -2188,7 +2154,6 @@ daemons/dmeventd/plugins/raid/Makefile
daemons/dmeventd/plugins/mirror/Makefile
daemons/dmeventd/plugins/snapshot/Makefile
daemons/dmeventd/plugins/thin/Makefile
daemons/dmfilemapd/Makefile
daemons/lvmdbusd/Makefile
daemons/lvmdbusd/path.py
daemons/lvmetad/Makefile
@@ -2248,7 +2213,6 @@ scripts/lvm2_monitoring_init_red_hat
scripts/lvm2_monitoring_systemd_red_hat.service
scripts/lvm2_pvscan_systemd_red_hat@.service
scripts/lvm2_tmpfiles_red_hat.conf
scripts/lvmdump.sh
scripts/Makefile
test/Makefile
test/api/Makefile
@@ -2265,14 +2229,10 @@ AS_IF([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 latest thin_check vsn 0.7.0 (or later) for lvm2 thin provisioning])])
[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!])])
AS_IF([test -n "$CACHE_CHECK_VERSION_WARN"],
[AC_MSG_WARN([You should install latest cache_check vsn 0.7.0 to use lvm2 cache metadata format 2])])
AS_IF([test "$ODIRECT" != yes],
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])

View File

@@ -41,19 +41,6 @@ struct lv_segment *last_seg(const struct logical_volume *lv)
return ((struct lv_segment **)lv)[0];
}
const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile *profile)
{
return "STRING";
}
struct logical_volume *origin_from_cow(const struct logical_volume *lv)
{
if (lv)
return lv;
__coverity_panic__();
}
/* simple_memccpy() from glibc */
void *memccpy(void *dest, const void *src, int c, size_t n)
{
@@ -84,17 +71,6 @@ void model_FD_ZERO(void *fdset)
((long*)fdset)[i] = 0;
}
/* Resent Coverity reports quite weird errors... */
int *__errno_location(void)
{
}
const unsigned short **__ctype_b_loc (void)
{
}
/*
* Added extra pointer check to not need these models,
* for now just keep then in file

View File

@@ -41,19 +41,15 @@ ifeq ("@BUILD_LVMPOLLD@", "yes")
endif
ifeq ("@BUILD_LVMLOCKD@", "yes")
SUBDIRS += lvmlockd
SUBDIRS += lvmlockd
endif
ifeq ("@BUILD_LVMDBUSD@", "yes")
SUBDIRS += lvmdbusd
endif
ifeq ("@BUILD_DMFILEMAPD@", "yes")
SUBDIRS += dmfilemapd
SUBDIRS += lvmdbusd
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd
endif
include $(top_builddir)/make.tmpl

View File

@@ -31,9 +31,9 @@ SALCK_LIBS = @SALCK_LIBS@
SALCK_CFLAGS = @SALCK_CFLAGS@
SOURCES = \
clvmd-command.c\
clvmd.c\
lvm-functions.c\
clvmd-command.c \
clvmd.c \
lvm-functions.c \
refresh_clvmd.c
ifneq (,$(findstring cman,, "@CLVMD@,"))
@@ -72,17 +72,26 @@ endif
TARGETS = \
clvmd
LVMLIBS = $(LVMINTERNAL_LIBS)
ifeq ("@DMEVENTD@", "yes")
LVMLIBS += -ldevmapper-event
endif
include $(top_builddir)/make.tmpl
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS)
LVMLIBS += -ldevmapper
LIBS += $(PTHREAD_LIBS)
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
INSTALL_TARGETS = \
install_clvmd
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
-o clvmd $(OBJECTS) $(LMLIBS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o clvmd $(OBJECTS) \
$(LVMLIBS) $(LMLIBS) $(LIBS)
.PHONY: install_clvmd

View File

@@ -206,7 +206,7 @@ static int lock_vg(struct local_client *client)
lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
/* lock_flags = args[1]; */
lockname = &args[2];
DEBUGLOG("(%p) doing PRE command LOCK_VG '%s' at %x\n", client, lockname, lock_cmd);
DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
if (lock_mode == LCK_UNLOCK) {
if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
@@ -323,7 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
int lkid;
char *lockname;
DEBUGLOG("(%p) Client thread cleanup\n", client);
DEBUGLOG("Client thread cleanup (%p)\n", client);
if (!client->bits.localsock.private)
return;
@@ -332,7 +332,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("(%p) Cleanup: Unlocking lock %s %x\n", client, lockname, lkid);
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
(void) sync_unlock(lockname, lkid);
}

View File

@@ -532,7 +532,6 @@ static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
const char *errtext)
{
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
struct iovec iov[2];
cs_error_t err;
int target_node;
@@ -547,10 +546,7 @@ static int _cluster_send_message(const void *buf, int msglen, const char *csid,
iov[1].iov_base = (char *)buf;
iov[1].iov_len = msglen;
pthread_mutex_lock(&_mutex);
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
pthread_mutex_unlock(&_mutex);
return cs_to_errno(err);
}

View File

@@ -425,6 +425,8 @@ static void _add_up_node(const char *csid)
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
ninfo->state = NODE_CLVMD;
return;
}
/* Call a callback for each node, so the caller knows whether it's up or down */

View File

@@ -58,7 +58,6 @@
/* Head of the fd list. Also contains
the cluster_socket details */
static struct local_client local_client_head;
static int _local_client_count = 0;
static unsigned short global_xid = 0; /* Last transaction ID issued */
@@ -69,37 +68,6 @@ static unsigned max_csid_len;
static unsigned max_cluster_message;
static unsigned max_cluster_member_name_len;
static void _add_client(struct local_client *new_client, struct local_client *existing_client)
{
_local_client_count++;
DEBUGLOG("(%p) Adding listener for fd %d. (Now %d monitored fds.)\n", new_client, new_client->fd, _local_client_count);
new_client->next = existing_client->next;
existing_client->next = new_client;
}
int add_client(struct local_client *new_client)
{
_add_client(new_client, &local_client_head);
return 0;
}
/* Returns 0 if delfd is found and removed from list */
static int _del_client(struct local_client *delfd)
{
struct local_client *lastfd, *thisfd;
for (lastfd = &local_client_head; (thisfd = lastfd->next); lastfd = thisfd)
if (thisfd == delfd) {
DEBUGLOG("(%p) Removing listener for fd %d\n", thisfd, thisfd->fd);
lastfd->next = delfd->next;
_local_client_count--;
return 0;
}
return 1;
}
/* Structure of items on the LVM thread list */
struct lvm_thread_cmd {
struct dm_list list;
@@ -124,7 +92,6 @@ static const size_t STACK_SIZE = 128 * 1024;
static pthread_attr_t stack_attr;
static int lvm_thread_exit = 0;
static pthread_mutex_t lvm_thread_mutex;
static pthread_mutex_t _debuglog_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t lvm_thread_cond;
static pthread_barrier_t lvm_start_barrier;
static struct dm_list lvm_cmd_head;
@@ -251,17 +218,14 @@ void debuglog(const char *fmt, ...)
switch (clvmd_get_debug()) {
case DEBUG_STDERR:
pthread_mutex_lock(&_debuglog_mutex);
va_start(ap,fmt);
time(&P);
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
pthread_mutex_unlock(&_debuglog_mutex);
break;
case DEBUG_SYSLOG:
pthread_mutex_lock(&_debuglog_mutex);
if (!syslog_init) {
openlog("clvmd", LOG_PID, LOG_DAEMON);
syslog_init = 1;
@@ -270,7 +234,6 @@ void debuglog(const char *fmt, ...)
va_start(ap,fmt);
vsyslog(LOG_DEBUG, fmt, ap);
va_end(ap);
pthread_mutex_unlock(&_debuglog_mutex);
break;
case DEBUG_OFF:
break;
@@ -554,7 +517,7 @@ int main(int argc, char *argv[])
/* Initialise the LVM thread variables */
dm_list_init(&lvm_cmd_head);
if (pthread_attr_init(&stack_attr) ||
pthread_attr_setstacksize(&stack_attr, STACK_SIZE + getpagesize())) {
pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) {
log_sys_error("pthread_attr_init", "");
exit(1);
}
@@ -621,7 +584,6 @@ int main(int argc, char *argv[])
local_client_head.fd = clops->get_main_cluster_fd();
local_client_head.type = CLUSTER_MAIN_SOCK;
local_client_head.callback = clops->cluster_fd_callback;
_local_client_count++;
/* Add the local socket to the list */
if (!(newfd = dm_zalloc(sizeof(struct local_client)))) {
@@ -632,14 +594,14 @@ int main(int argc, char *argv[])
newfd->fd = local_sock;
newfd->type = LOCAL_RENDEZVOUS;
newfd->callback = local_rendezvous_callback;
(void) add_client(newfd);
newfd->next = local_client_head.next;
local_client_head.next = newfd;
/* This needs to be started after cluster initialisation
as it may need to take out locks */
DEBUGLOG("Starting LVM thread\n");
DEBUGLOG("(%p) Main cluster socket fd %d with local socket %d (%p)\n",
&local_client_head, local_client_head.fd, newfd->fd, newfd);
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
local_client_head.fd, &local_client_head, newfd->fd, newfd);
/* Don't let anyone else to do work until we are started */
if (pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params)) {
@@ -675,7 +637,6 @@ int main(int argc, char *argv[])
while ((delfd = local_client_head.next)) {
local_client_head.next = delfd->next;
_local_client_count--;
/* Failing cleanup_zombie leaks... */
if (delfd->type == LOCAL_SOCK && !cleanup_zombie(delfd))
cmd_client_cleanup(delfd); /* calls sync_unlock */
@@ -737,13 +698,13 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
pthread_mutex_init(&newfd->bits.localsock.mutex, NULL);
if (fcntl(client_fd, F_SETFD, 1))
DEBUGLOG("(%p) Setting CLOEXEC on client fd %d failed: %s\n", thisfd, client_fd, strerror(errno));
DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
newfd->fd = client_fd;
newfd->type = LOCAL_SOCK;
newfd->callback = local_sock_callback;
newfd->bits.localsock.all_success = 1;
DEBUGLOG("(%p) Got new connection on fd %d\n", newfd, newfd->fd);
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
*new_client = newfd;
}
return 1;
@@ -765,8 +726,8 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
if (len == sizeof(int))
memcpy(&status, buffer, sizeof(int));
DEBUGLOG("(%p) Read on pipe %d, %d bytes, status %d\n",
thisfd, thisfd->fd, len, status);
DEBUGLOG("Read on pipe %d, %d bytes, status %d\n",
thisfd->fd, len, status);
/* EOF on pipe or an error, close it */
if (len <= 0) {
@@ -789,11 +750,11 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
}
return -1;
} else {
DEBUGLOG("(%p) Background routine status was %d, sock_client %p\n",
thisfd, status, sock_client);
DEBUGLOG("Background routine status was %d, sock_client (%p)\n",
status, sock_client);
/* But has the client gone away ?? */
if (!sock_client) {
DEBUGLOG("(%p) Got pipe response for dead client, ignoring it\n", thisfd);
DEBUGLOG("Got pipe response for dead client, ignoring it\n");
} else {
/* If error then just return that code */
if (status)
@@ -833,7 +794,7 @@ static void timedout_callback(struct local_client *client, const char *csid,
return;
clops->name_from_csid(csid, nodename);
DEBUGLOG("(%p) Checking for a reply from %s\n", client, nodename);
DEBUGLOG("Checking for a reply from %s\n", nodename);
pthread_mutex_lock(&client->bits.localsock.mutex);
reply = client->bits.localsock.replies;
@@ -843,7 +804,7 @@ static void timedout_callback(struct local_client *client, const char *csid,
pthread_mutex_unlock(&client->bits.localsock.mutex);
if (!reply) {
DEBUGLOG("(%p) Node %s timed-out\n", client, nodename);
DEBUGLOG("Node %s timed-out\n", nodename);
add_reply_to_list(client, ETIMEDOUT, csid,
"Command timed out", 18);
}
@@ -858,7 +819,7 @@ static void timedout_callback(struct local_client *client, const char *csid,
*/
static void request_timed_out(struct local_client *client)
{
DEBUGLOG("(%p) Request timed-out. padding\n", client);
DEBUGLOG("Request timed-out. padding\n");
clops->cluster_do_node_callback(client, timedout_callback);
if (!client->bits.localsock.threadid)
@@ -892,11 +853,13 @@ static void main_loop(int cmd_timeout)
while (!quit) {
fd_set in;
int select_status;
struct local_client *thisfd, *nextfd;
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();
@@ -912,22 +875,21 @@ static void main_loop(int cmd_timeout)
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->next;
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
/* cleanup_zombie might have removed the next list element */
nextfd = thisfd->next;
(void) _del_client(thisfd);
DEBUGLOG("(%p) removeme set with %d monitored fds remaining\n", thisfd, _local_client_count);
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(thisfd, NULL, 0, NULL);
add_to_lvmqueue(free_fd, NULL, 0, NULL);
continue;
}
lastfd = thisfd;
if (thisfd->removeme)
continue;
@@ -977,15 +939,16 @@ static void main_loop(int cmd_timeout)
type == CLUSTER_INTERNAL)
goto closedown;
DEBUGLOG("(%p) ret == %d, errno = %d. removing client\n",
thisfd, ret, errno);
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
thisfd->removeme = 1;
continue;
}
/* New client...simply add it to the list */
if (newfd) {
_add_client(newfd, thisfd);
newfd->next = thisfd->next;
thisfd->next = newfd;
thisfd = newfd;
}
}
@@ -1003,8 +966,8 @@ static void main_loop(int cmd_timeout)
thisfd->bits.localsock.expected_replies !=
thisfd->bits.localsock.num_replies) {
/* Send timed out message + replies we already have */
DEBUGLOG("Request to client %p timed-out (send: %ld, now: %ld)\n",
thisfd, thisfd->bits.localsock.sent_time, the_time);
DEBUGLOG("Request timed-out (send: %ld, now: %ld)\n",
thisfd->bits.localsock.sent_time, the_time);
thisfd->bits.localsock.all_success = 0;
@@ -1216,8 +1179,8 @@ static int cleanup_zombie(struct local_client *thisfd)
if (!thisfd->bits.localsock.cleanup_needed)
return 0;
DEBUGLOG("(%p) EOF on local socket %d: inprogress=%d\n",
thisfd, thisfd->fd, thisfd->bits.localsock.in_progress);
DEBUGLOG("EOF on local socket: inprogress=%d\n",
thisfd->bits.localsock.in_progress);
if ((pipe_client = thisfd->bits.localsock.pipe_client))
pipe_client = pipe_client->bits.pipe.client;
@@ -1239,7 +1202,7 @@ static int cleanup_zombie(struct local_client *thisfd)
/* Kill the subthread & free resources */
if (thisfd->bits.localsock.threadid) {
DEBUGLOG("(%p) Waiting for pre&post thread\n", pipe_client);
DEBUGLOG("Waiting for pre&post thread (%p)\n", pipe_client);
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
thisfd->bits.localsock.state = PRE_COMMAND;
thisfd->bits.localsock.finished = 1;
@@ -1250,22 +1213,26 @@ static int cleanup_zombie(struct local_client *thisfd)
(void **) &status)))
log_sys_error("pthread_join", "");
DEBUGLOG("(%p) Joined pre&post thread\n", pipe_client);
DEBUGLOG("Joined pre&post thread\n");
thisfd->bits.localsock.threadid = 0;
/* Remove the pipe client */
if (thisfd->bits.localsock.pipe_client) {
struct local_client *delfd = thisfd->bits.localsock.pipe_client;
struct local_client *delfd;
struct local_client *lastfd;
(void) close(delfd->fd); /* Close pipe */
(void) close(thisfd->bits.localsock.pipe_client->fd); /* Close pipe */
(void) close(thisfd->bits.localsock.pipe);
/* Remove pipe client */
if (!_del_client(delfd)) {
dm_free(delfd);
thisfd->bits.localsock.pipe_client = NULL;
}
for (lastfd = &local_client_head; (delfd = lastfd->next); lastfd = delfd)
if (thisfd->bits.localsock.pipe_client == delfd) {
thisfd->bits.localsock.pipe_client = NULL;
lastfd->next = delfd->next;
dm_free(delfd);
break;
}
}
}
@@ -1296,7 +1263,7 @@ static int read_from_local_sock(struct local_client *thisfd)
if (len == -1 && errno == EINTR)
return 1;
DEBUGLOG("(%p) Read on local socket %d, len = %d\n", thisfd, thisfd->fd, len);
DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len);
if (len && verify_message(buffer, len) < 0) {
log_error("read_from_local_sock from %d len %d bad verify.",
@@ -1370,15 +1337,15 @@ static int read_from_local_sock(struct local_client *thisfd)
char *argptr = inheader->node + strlen(inheader->node) + 1;
while (missing_len > 0) {
DEBUGLOG("(%p) got %d bytes, need another %d (total %d)\n",
thisfd, argslen, missing_len, inheader->arglen);
DEBUGLOG("got %d bytes, need another %d (total %d)\n",
argslen, missing_len, inheader->arglen);
len = read(thisfd->fd, argptr + argslen, missing_len);
if (len == -1 && errno == EINTR)
continue;
if (len <= 0) {
/* EOF or error on socket */
DEBUGLOG("(%p) EOF on local socket\n", thisfd);
DEBUGLOG("EOF on local socket\n");
dm_free(thisfd->bits.localsock.cmd);
thisfd->bits.localsock.cmd = NULL;
return 0;
@@ -1406,7 +1373,7 @@ static int read_from_local_sock(struct local_client *thisfd)
.status = ENOENT
};
DEBUGLOG("(%p) Unknown node: '%s'\n", thisfd, inheader->node);
DEBUGLOG("Unknown node: '%s'\n", inheader->node);
send_message(&reply, sizeof(reply), our_csid, thisfd->fd,
"Error sending ENOENT reply to local user");
thisfd->bits.localsock.expected_replies = 0;
@@ -1432,7 +1399,7 @@ static int read_from_local_sock(struct local_client *thisfd)
.status = EBUSY
};
DEBUGLOG("(%p) Creating pipe failed: %s\n", thisfd, strerror(errno));
DEBUGLOG("Creating pipe failed: %s\n", strerror(errno));
send_message(&reply, sizeof(reply), our_csid, thisfd->fd,
"Error sending EBUSY reply to local user");
return len;
@@ -1452,7 +1419,7 @@ static int read_from_local_sock(struct local_client *thisfd)
return len;
}
DEBUGLOG("(%p) Creating pipe, [%d, %d]\n", thisfd, comms_pipe[0], comms_pipe[1]);
DEBUGLOG("Creating pipe, [%d, %d]\n", comms_pipe[0], comms_pipe[1]);
if (fcntl(comms_pipe[0], F_SETFD, 1))
DEBUGLOG("setting CLOEXEC on pipe[0] failed: %s\n", strerror(errno));
@@ -1463,8 +1430,8 @@ static int read_from_local_sock(struct local_client *thisfd)
newfd->type = THREAD_PIPE;
newfd->callback = local_pipe_callback;
newfd->bits.pipe.client = thisfd;
_add_client(newfd, thisfd);
newfd->next = thisfd->next;
thisfd->next = newfd;
/* Store a cross link to the pipe */
thisfd->bits.localsock.pipe_client = newfd;
@@ -1477,10 +1444,10 @@ 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("(%p) Creating pre&post thread for pipe fd %d\n", newfd, newfd->fd);
DEBUGLOG("Creating pre&post thread for pipe fd %d (%p)\n", newfd->fd, newfd);
status = pthread_create(&thisfd->bits.localsock.threadid,
&stack_attr, pre_and_post_thread, thisfd);
DEBUGLOG("(%p) Created pre&post thread, state = %d\n", newfd, status);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
return len;
}
@@ -1488,6 +1455,13 @@ static int read_from_local_sock(struct local_client *thisfd)
/* Add a file descriptor from the cluster or comms interface to
our list of FDs for select
*/
int add_client(struct local_client *new_client)
{
new_client->next = local_client_head.next;
local_client_head.next = new_client;
return 0;
}
/* Called when the pre-command has completed successfully - we
now execute the real command on all the requested nodes */
@@ -1498,8 +1472,8 @@ static int distribute_command(struct local_client *thisfd)
int len = thisfd->bits.localsock.cmd_len;
thisfd->xid = global_xid++;
DEBUGLOG("(%p) distribute command: XID = %d, flags=0x%x (%s%s)\n",
thisfd, thisfd->xid, inheader->flags,
DEBUGLOG("distribute command: XID = %d, flags=0x%x (%s%s)\n",
thisfd->xid, inheader->flags,
(inheader->flags & CLVMD_FLAG_LOCAL) ? "LOCAL" : "",
(inheader->flags & CLVMD_FLAG_REMOTE) ? "REMOTE" : "");
@@ -1521,7 +1495,7 @@ static int distribute_command(struct local_client *thisfd)
*/
add_to_lvmqueue(thisfd, inheader, len, NULL);
DEBUGLOG("(%p) Sending message to all cluster nodes\n", thisfd);
DEBUGLOG("Sending message to all cluster nodes\n");
inheader->xid = thisfd->xid;
send_message(inheader, len, NULL, -1,
"Error forwarding message to cluster");
@@ -1540,11 +1514,11 @@ static int distribute_command(struct local_client *thisfd)
/* Are we the requested node ?? */
if (memcmp(csid, our_csid, max_csid_len) == 0) {
DEBUGLOG("(%p) Doing command on local node only\n", thisfd);
DEBUGLOG("Doing command on local node only\n");
add_to_lvmqueue(thisfd, inheader, len, NULL);
} else {
DEBUGLOG("(%p) Sending message to single node: %s\n",
thisfd, inheader->node);
DEBUGLOG("Sending message to single node: %s\n",
inheader->node);
inheader->xid = thisfd->xid;
send_message(inheader, len, csid, -1,
"Error forwarding message to cluster node");
@@ -1555,7 +1529,7 @@ static int distribute_command(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.expected_replies = 1;
thisfd->bits.localsock.num_replies = 0;
DEBUGLOG("(%p) Doing command explicitly on local node only\n", thisfd);
DEBUGLOG("Doing command explicitly on local node only\n");
add_to_lvmqueue(thisfd, inheader, len, NULL);
}
@@ -1681,7 +1655,7 @@ static void add_reply_to_list(struct local_client *client, int status,
reply->status = status;
clops->name_from_csid(csid, reply->node);
DEBUGLOG("(%p) Reply from node %s: %d bytes\n", client, reply->node, len);
DEBUGLOG("Reply from node %s: %d bytes\n", reply->node, len);
if (len > 0) {
if (!(reply->replymsg = dm_malloc(len)))
@@ -1708,8 +1682,8 @@ static void add_reply_to_list(struct local_client *client, int status,
client->bits.localsock.state = POST_COMMAND;
pthread_cond_signal(&client->bits.localsock.cond);
}
DEBUGLOG("(%p) Got %d replies, expecting: %d\n",
client, client->bits.localsock.num_replies,
DEBUGLOG("Got %d replies, expecting: %d\n",
client->bits.localsock.num_replies,
client->bits.localsock.expected_replies);
}
pthread_mutex_unlock(&client->bits.localsock.mutex);
@@ -1724,7 +1698,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
sigset_t ss;
int pipe_fd = client->bits.localsock.pipe;
DEBUGLOG("(%p) Pre&post thread pipe fd %d\n", client, pipe_fd);
DEBUGLOG("Pre&post thread (%p), pipe fd %d\n", client, pipe_fd);
pthread_mutex_lock(&client->bits.localsock.mutex);
/* Ignore SIGUSR1 (handled by master process) but enable
@@ -1744,7 +1718,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
if ((status = do_pre_command(client)))
client->bits.localsock.all_success = 0;
DEBUGLOG("(%p) Pre&post thread writes status %d down to pipe fd %d\n",
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe fd %d\n",
client, status, pipe_fd);
/* Tell the parent process we have finished this bit */
@@ -1762,13 +1736,13 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
/* We may need to wait for the condition variable before running the post command */
if (client->bits.localsock.state != POST_COMMAND &&
!client->bits.localsock.finished) {
DEBUGLOG("(%p) Pre&post thread waiting to do post command, state = %d\n",
DEBUGLOG("Pre&post thread (%p) waiting to do post command, state = %d\n",
client, client->bits.localsock.state);
pthread_cond_wait(&client->bits.localsock.cond,
&client->bits.localsock.mutex);
}
DEBUGLOG("(%p) Pre&post thread got post command condition...\n", client);
DEBUGLOG("Pre&post thread (%p) got post command condition...\n", client);
/* POST function must always run, even if the client aborts */
status = 0;
@@ -1782,15 +1756,15 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
next_pre:
if (client->bits.localsock.state != PRE_COMMAND &&
!client->bits.localsock.finished) {
DEBUGLOG("(%p) Pre&post thread waiting for next pre command\n", client);
DEBUGLOG("Pre&post thread (%p) waiting for next pre command\n", client);
pthread_cond_wait(&client->bits.localsock.cond,
&client->bits.localsock.mutex);
}
DEBUGLOG("(%p) Pre&post thread got pre command condition...\n", client);
DEBUGLOG("Pre&post thread (%p) got pre command condition...\n", client);
}
pthread_mutex_unlock(&client->bits.localsock.mutex);
DEBUGLOG("(%p) Pre&post thread finished\n", client);
DEBUGLOG("Pre&post thread (%p) finished\n", client);
pthread_exit(NULL);
}
@@ -1808,8 +1782,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
if (!(replybuf = dm_malloc(max_cluster_message)))
return -1;
DEBUGLOG("(%p) process_local_command: %s msg=%p, msglen =%d\n",
client, decode_cmd(msg->cmd), msg, msglen);
DEBUGLOG("process_local_command: %s msg=%p, msglen =%d, client=%p\n",
decode_cmd(msg->cmd), msg, msglen, client);
/* If remote flag is set, just set a successful status code. */
if (msg->flags & CLVMD_FLAG_REMOTE)
@@ -1824,8 +1798,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
if (xid == client->xid)
add_reply_to_list(client, status, our_csid, replybuf, replylen);
else
DEBUGLOG("(%p) Local command took too long, discarding xid %d, current is %d\n",
client, xid, client->xid);
DEBUGLOG("Local command took too long, discarding xid %d, current is %d\n",
xid, client->xid);
dm_free(replybuf);
@@ -1867,7 +1841,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
char *ptr;
int message_len = 0;
DEBUGLOG("(%p) Send local reply\n", client);
DEBUGLOG("Send local reply\n");
/* Work out the total size of the reply */
while (thisreply) {
@@ -1884,7 +1858,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
/* Add in the size of our header */
message_len = message_len + sizeof(struct clvm_header);
if (!(replybuf = dm_malloc(message_len))) {
DEBUGLOG("(%p) Memory allocation fails\n", client);
DEBUGLOG("Memory allocation fails\n");
return;
}
@@ -2013,7 +1987,6 @@ static int send_message(void *buf, int msglen, const char *csid, int fd,
(void) nanosleep (&delay, &remtime);
continue;
}
DEBUGLOG("%s", errtext);
log_error("%s", errtext);
break;
}
@@ -2027,7 +2000,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("(%p) process_work_item: free\n", cmd->client);
DEBUGLOG("process_work_item: free %p\n", cmd->client);
cmd_client_cleanup(cmd->client);
pthread_mutex_destroy(&cmd->client->bits.localsock.mutex);
pthread_cond_destroy(&cmd->client->bits.localsock.cond);
@@ -2036,11 +2009,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
}
if (!cmd->remote) {
DEBUGLOG("(%p) process_work_item: local\n", cmd->client);
DEBUGLOG("process_work_item: local\n");
process_local_command(cmd->msg, cmd->msglen, cmd->client,
cmd->xid);
} else {
DEBUGLOG("(%p) process_work_item: remote\n", cmd->client);
DEBUGLOG("process_work_item: remote\n");
process_remote_command(cmd->msg, cmd->msglen, cmd->client->fd,
cmd->csid);
}
@@ -2134,8 +2107,8 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
} else
cmd->remote = 0;
DEBUGLOG("(%p) add_to_lvmqueue: cmd=%p, msg=%p, len=%d, csid=%p, xid=%d\n",
client, cmd, msg, msglen, csid, cmd->xid);
DEBUGLOG("add_to_lvmqueue: cmd=%p. client=%p, msg=%p, len=%d, csid=%p, xid=%d\n",
cmd, client, msg, msglen, csid, cmd->xid);
pthread_mutex_lock(&lvm_thread_mutex);
if (lvm_thread_exit) {
pthread_mutex_unlock(&lvm_thread_mutex);
@@ -2271,8 +2244,7 @@ static void check_all_callback(struct local_client *client, const char *csid,
If not, returns -1 and prints out a list of errant nodes */
static int check_all_clvmds_running(struct local_client *client)
{
DEBUGLOG("(%p) check_all_clvmds_running\n", client);
DEBUGLOG("check_all_clvmds_running\n");
return clops->cluster_do_node_callback(client, check_all_callback);
}
@@ -2311,11 +2283,13 @@ static void ntoh_clvm(struct clvm_header *hdr)
static void sigusr2_handler(int sig)
{
DEBUGLOG("SIGUSR2 received\n");
return;
}
static void sigterm_handler(int sig)
{
quit = 1;
return;
}
static void sighup_handler(int sig)

View File

@@ -29,7 +29,7 @@ include $(top_builddir)/make.tmpl
LIBS += -ldevmapper
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LDFLAGS += $(EXTRA_EXEC_LDFLAGS)
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \

View File

@@ -182,7 +182,7 @@ int cluster_send(struct clog_request *rq)
}
/*
* Once the request heads for the cluster, the luid loses
* Once the request heads for the cluster, the luid looses
* all its meaning.
*/
rq->u_rq.luid = 0;

View File

@@ -12,7 +12,6 @@
#include "logging.h"
#include "functions.h"
#include <sys/sysmacros.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -377,7 +376,7 @@ static int _clog_ctr(char *uuid, uint64_t luid,
uint32_t block_on_error = 0;
int disk_log;
char disk_path[PATH_MAX];
char disk_path[128];
int unlink_path = 0;
long page_size;
int pages;

View File

@@ -56,16 +56,18 @@ include $(top_builddir)/make.tmpl
all: device-mapper
device-mapper: $(TARGETS)
LIBS += -ldevmapper
LVMLIBS += -ldevmapper-event $(PTHREAD_LIBS)
CFLAGS_dmeventd.o += $(EXTRA_EXEC_CFLAGS)
LIBS += -ldevmapper $(PTHREAD_LIBS)
dmeventd: $(LIB_SHARED) dmeventd.o
$(CC) $(CFLAGS) -L. $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -L. -o $@ dmeventd.o \
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
dmeventd.static: $(LIB_STATIC) dmeventd.o $(interfacebuilddir)/libdevmapper.a
$(CC) $(CFLAGS) $(LDFLAGS) -static -L. -L$(interfacebuilddir) dmeventd.o \
-o $@ $(DL_LIBS) $(DMEVENT_LIBS) $(LIBS) $(STATIC_LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L. -L$(interfacebuilddir) -o $@ \
dmeventd.o $(DL_LIBS) $(LVMLIBS) $(LIBS) $(STATIC_LIBS)
ifeq ("@PKGCONFIG@", "yes")
INSTALL_LIB_TARGETS += install_pkgconfig

View File

@@ -99,28 +99,13 @@ static time_t _idle_since = 0;
static char **_initial_registrations = 0;
/* FIXME Make configurable at runtime */
/* All libdm messages */
__attribute__((format(printf, 5, 6)))
static void _libdm_log(int level, const char *file, int line,
int dm_errno_or_class, const char *format, ...)
{
va_list ap;
va_start(ap, format);
dm_event_log("#dm", level, file, line, dm_errno_or_class, format, ap);
va_end(ap);
}
/* All dmeventd messages */
#undef LOG_MESG
#define LOG_MESG(l, f, ln, e, x...) _dmeventd_log(l, f, ln, e, ## x)
__attribute__((format(printf, 5, 6)))
__attribute__((format(printf, 4, 5)))
static void _dmeventd_log(int level, const char *file, int line,
int dm_errno_or_class, const char *format, ...)
const char *format, ...)
{
va_list ap;
va_start(ap, format);
dm_event_log("dmeventd", level, file, line, dm_errno_or_class, format, ap);
dm_event_log("dm", level, file, line, 0, format, ap);
va_end(ap);
}
@@ -468,7 +453,7 @@ static int _pthread_create_smallstack(pthread_t *t, void *(*fun)(void *), void *
/*
* We use a smaller stack since it gets preallocated in its entirety
*/
pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE + getpagesize());
pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
/*
* If no-one will be waiting, we need to detach.
@@ -844,6 +829,17 @@ static void _print_sigset(const char *prefix, const sigset_t *sigset)
}
#endif
static sigset_t _unblock_sigalrm(void)
{
sigset_t set, old;
sigemptyset(&set);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &set, &old);
return old;
}
enum {
DM_WAIT_RETRY,
DM_WAIT_INTR,
@@ -853,7 +849,7 @@ enum {
/* Wait on a device until an event occurs. */
static int _event_wait(struct thread_status *thread)
{
sigset_t set, old;
sigset_t set;
int ret = DM_WAIT_RETRY;
struct dm_info info;
@@ -863,12 +859,7 @@ static int _event_wait(struct thread_status *thread)
* This is so that you can break out of waiting on an event,
* either for a timeout event, or to cancel the thread.
*/
sigemptyset(&set);
sigaddset(&set, SIGALRM);
if (pthread_sigmask(SIG_UNBLOCK, &set, &old) != 0) {
log_sys_error("pthread_sigmask", "unblock alarm");
return ret; /* What better */
}
set = _unblock_sigalrm();
if (dm_task_run(thread->wait_task)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
@@ -892,11 +883,10 @@ static int _event_wait(struct thread_status *thread)
}
}
if (pthread_sigmask(SIG_SETMASK, &old, NULL) != 0)
log_sys_error("pthread_sigmask", "block alarm");
pthread_sigmask(SIG_SETMASK, &set, NULL);
#ifdef DEBUG_SIGNALS
_print_sigset("dmeventd blocking ", &old);
_print_sigset("dmeventd blocking ", &set);
#endif
DEBUGLOG("Completed waitevent task for %s.", thread->device.name);
@@ -2206,7 +2196,7 @@ int main(int argc, char *argv[])
openlog("dmeventd", LOG_PID, LOG_DAEMON);
dm_event_log_set(_debug_level, _use_syslog);
dm_log_with_errno_init(_libdm_log);
dm_log_init(_dmeventd_log);
(void) dm_prepare_selinux_context(DMEVENTD_PIDFILE, S_IFREG);
if (dm_create_lockfile(DMEVENTD_PIDFILE) == 0)
@@ -2252,8 +2242,7 @@ int main(int argc, char *argv[])
"for %ld second(s), exiting.",
(long) (time(NULL) - _idle_since));
break;
}
if (idle_exit_timeout) {
} else if (idle_exit_timeout) {
now = time(NULL);
if (now < _idle_since)
_idle_since = now; /* clock change? */

View File

@@ -250,9 +250,10 @@ static int _daemon_read(struct dm_event_fifos *fifos,
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
log_error("Unable to read from event server.");
return 0;
else {
log_error("Unable to read from event server.");
return 0;
}
}
bytes += ret;
@@ -328,9 +329,10 @@ static int _daemon_write(struct dm_event_fifos *fifos,
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
log_error("Unable to talk to event daemon.");
return 0;
else {
log_error("Unable to talk to event daemon.");
return 0;
}
}
bytes += ret;
@@ -452,8 +454,7 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
if (close(fifos->client))
log_sys_debug("close", fifos->client_path);
return 1;
}
if (errno != ENXIO && errno != ENOENT) {
} else if (errno != ENXIO && errno != ENOENT) {
/* problem */
log_sys_error("open", fifos->client_path);
return 0;
@@ -864,38 +865,28 @@ void dm_event_log(const char *subsys, int level, const char *file,
int line, int dm_errno_or_class,
const char *format, va_list ap)
{
static int _abort_on_internal_errors = -1;
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
static time_t start = 0;
const char *indent = "";
FILE *stream = log_stderr(level) ? stderr : stdout;
FILE *stream = stdout;
int prio;
time_t now;
int log_with_debug = 0;
if (subsys[0] == '#') {
/* Subsystems starting with '#' are logged
* only when debugging is enabled. */
log_with_debug++;
subsys++;
}
switch (log_level(level)) {
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
case _LOG_DEBUG:
/* Never shown without -ddd */
if (_debug_level < 3)
return;
prio = LOG_DEBUG;
indent = " ";
break;
case _LOG_INFO:
if (log_with_debug && _debug_level < 2)
if (_debug_level < 2)
return;
prio = LOG_INFO;
indent = " ";
break;
case _LOG_NOTICE:
if (log_with_debug && _debug_level < 1)
if (_debug_level < 1)
return;
prio = LOG_NOTICE;
indent = " ";
@@ -921,13 +912,12 @@ void dm_event_log(const char *subsys, int level, const char *file,
if (!start)
start = now;
now -= start;
if (_debug_level)
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,
(_debug_level > 3) ? "" : indent);
if (_debug_level > 3)
fprintf(stream, "%28s:%4d %s", file, line, indent);
vfprintf(stream, _(format), ap);
@@ -936,15 +926,6 @@ void dm_event_log(const char *subsys, int level, const char *file,
}
pthread_mutex_unlock(&_log_mutex);
if (_abort_on_internal_errors < 0)
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors =
strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
if (_abort_on_internal_errors &&
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
abort();
}
#if 0 /* left out for now */

View File

@@ -32,7 +32,7 @@ static int _register_count = 0;
static struct dm_pool *_mem_pool = NULL;
static void *_lvm_handle = NULL;
DM_EVENT_LOG_FN("#lvm")
DM_EVENT_LOG_FN("lvm")
static void _lvm2_print_log(int level, const char *file, int line,
int dm_errno_or_class, const char *msg)
@@ -121,7 +121,6 @@ int dmeventd_lvm2_run(const char *cmdline)
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
const char *cmd, const char *device)
{
static char _internal_prefix[] = "_dmeventd_";
char *vg = NULL, *lv = NULL, *layer;
int r;
@@ -136,21 +135,6 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
(layer = strstr(lv, "_mlog")))
*layer = '\0';
if (!strncmp(cmd, _internal_prefix, sizeof(_internal_prefix) - 1)) {
dmeventd_lvm2_lock();
/* output of internal command passed via env var */
if (!dmeventd_lvm2_run(cmd))
cmd = NULL;
else if ((cmd = getenv(cmd)))
cmd = dm_pool_strdup(mem, cmd); /* copy with lock */
dmeventd_lvm2_unlock();
if (!cmd) {
log_error("Unable to find configured command.");
return 0;
}
}
r = dm_snprintf(buffer, size, "%s %s/%s", cmd, vg, lv);
dm_pool_free(mem, vg);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -25,6 +25,7 @@
struct dso_state {
struct dm_pool *mem;
char cmd_lvscan[512];
char cmd_lvconvert[512];
};
@@ -72,10 +73,8 @@ static int _get_mirror_event(struct dso_state *state, char *params)
unsigned i;
struct dm_status_mirror *ms;
if (!dm_get_status_mirror(state->mem, params, &ms)) {
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
}
if (!dm_get_status_mirror(state->mem, params, &ms))
goto_out;
/* Check for bad mirror devices */
for (i = 0; i < ms->dev_count; ++i)
@@ -96,19 +95,27 @@ static int _get_mirror_event(struct dso_state *state, char *params)
dm_pool_free(state->mem, ms);
return r;
out:
log_error("Unable to parse mirror status string.");
return ME_IGNORE;
}
static int _remove_failed_devices(const char *cmd_lvconvert, const char *device)
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
{
int r;
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
log_info("Re-scan of mirrored device failed.");
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(cmd_lvconvert)) {
log_error("Repair of mirrored device %s failed.", device);
return 0;
}
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
log_info("Repair of mirrored device %s finished successfully.", device);
log_info("Repair of mirrored device %s.",
(r) ? "finished successfully" : "failed");
return 1;
return r;
}
void process_event(struct dm_task *dmt,
@@ -146,7 +153,8 @@ void process_event(struct dm_task *dmt,
break;
case ME_FAILURE:
log_error("Device failure in %s.", device);
if (!_remove_failed_devices(state->cmd_lvconvert, device))
if (!_remove_failed_devices(state->cmd_lvscan,
state->cmd_lvconvert))
/* FIXME Why are all the error return codes unused? Get rid of them? */
log_error("Failed to remove faulty devices in %s.",
device);
@@ -160,7 +168,7 @@ void process_event(struct dm_task *dmt,
break;
default:
/* FIXME Provide value then! */
log_warn("WARNING: %s received unknown event.", device);
log_info("Unknown event received.");
}
} while (next);
}
@@ -176,10 +184,17 @@ int register_device(const char *device,
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
goto_bad;
/* CANNOT use --config as this disables cached content */
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --repair --use-policies", device))
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
"lvscan --cache", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --repair --use-policies", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
*user = state;
@@ -189,9 +204,6 @@ int register_device(const char *device,
bad:
log_error("Failed to monitor mirror %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -13,19 +13,14 @@
*/
#include "lib.h"
#include "defaults.h"
#include "dmeventd_lvm.h"
#include "libdevmapper-event.h"
/* Hold enough elements for the mximum number of RAID images */
#define RAID_DEVS_ELEMS ((DEFAULT_RAID_MAX_IMAGES + 63) / 64)
struct dso_state {
struct dm_pool *mem;
char cmd_lvscan[512];
char cmd_lvconvert[512];
uint64_t raid_devs[RAID_DEVS_ELEMS];
int failed;
int warned;
};
DM_EVENT_LOG_FN("raid")
@@ -36,70 +31,32 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
{
struct dm_status_raid *status;
const char *d;
int dead = 0, r = 1;
uint32_t dev;
if (!dm_get_status_raid(state->mem, params, &status)) {
log_error("Failed to process status line for %s.", device);
return 0;
}
d = status->dev_health;
while ((d = strchr(d, 'D'))) {
dev = (uint32_t)(d - status->dev_health);
if (!(state->raid_devs[dev / 64] & (UINT64_C(1) << (dev % 64)))) {
state->raid_devs[dev / 64] |= (UINT64_C(1) << (dev % 64));
log_warn("WARNING: Device #%u of %s array, %s, has failed.",
dev, status->raid_type, device);
}
d++;
dead = 1;
}
/*
* if we are converting from non-RAID to RAID (e.g. linear -> raid1)
* and too many original devices die, such that we cannot continue
* the "recover" operation, the sync action will go to "idle", the
* unsynced devs will remain at 'a', and the original devices will
* NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived.
*
* This is simply the way the kernel works...
*/
if (!strcmp(status->sync_action, "idle") &&
(status->dev_health[0] == 'a') &&
(status->insync_regions < status->total_regions)) {
log_error("Primary sources for new RAID, %s, have failed.",
device);
dead = 1; /* run it through LVM repair */
}
if (dead) {
if (status->insync_regions < status->total_regions) {
if (!state->warned) {
state->warned = 1;
log_warn("WARNING: waiting for resynchronization to finish "
"before initiating repair on RAID device %s.", device);
}
goto out; /* Not yet done syncing with accessible devices */
}
if ((d = strchr(status->dev_health, 'D'))) {
if (state->failed)
goto out; /* already reported */
log_error("Device #%d of %s array, %s, has failed.",
(int)(d - status->dev_health),
status->raid_type, device);
state->failed = 1;
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
/* if repair goes OK, report success even if lvscan has failed */
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
log_error("Repair of RAID device %s failed.", device);
r = 0;
log_info("Repair of RAID device %s failed.", device);
dm_pool_free(state->mem, status);
return 0;
}
} else {
state->failed = 0;
if (status->insync_regions == status->total_regions)
memset(&state->raid_devs, 0, sizeof(state->raid_devs));
log_info("%s array, %s, is %s in-sync.",
status->raid_type, device,
(status->insync_regions == status->total_regions) ? "now" : "not");
@@ -107,7 +64,7 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
out:
dm_pool_free(state->mem, status);
return r;
return 1;
}
void process_event(struct dm_task *dmt,
@@ -152,9 +109,14 @@ int register_device(const char *device,
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
goto_bad;
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --repair --use-policies", device))
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
"lvscan --cache", device) ||
!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
"lvconvert --config devices{ignore_suspended_devices=1} "
"--repair --use-policies", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
*user = state;
@@ -164,9 +126,6 @@ int register_device(const char *device,
bad:
log_error("Failed to monitor RAID %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -16,7 +16,6 @@
#include "dmeventd_lvm.h"
#include "libdevmapper-event.h"
#include <sys/sysmacros.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <pthread.h>
@@ -231,7 +230,7 @@ void process_event(struct dm_task *dmt,
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
device, dm_percent_to_round_float(percent, 2));
device, dm_percent_to_float(percent));
/* Try to extend the snapshot, in accord with user-set policies */
if (!_extend(state->cmd_lvextend))
@@ -254,8 +253,10 @@ int register_device(const char *device,
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
sizeof(state->cmd_lvextend),
"lvextend --use-policies", device))
"lvextend --use-policies", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
state->percent_check = CHECK_MINIMUM;
*user = state;
@@ -266,9 +267,6 @@ int register_device(const char *device,
bad:
log_error("Failed to monitor snapshot %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -18,6 +18,7 @@
#include <sys/wait.h>
#include <stdarg.h>
#include <pthread.h>
/* TODO - move this mountinfo code into library to be reusable */
#ifdef __linux__
@@ -39,120 +40,277 @@
#define UMOUNT_COMMAND "/bin/umount"
#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */
#define MAX_FAILS (10)
#define THIN_DEBUG 0
struct dso_state {
struct dm_pool *mem;
int metadata_percent_check;
int metadata_percent;
int data_percent_check;
int data_percent;
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
unsigned max_fails;
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
char *argv[3];
char *cmd_str;
char cmd_str[1024];
};
DM_EVENT_LOG_FN("thin")
#define UUID_PREFIX "LVM-"
static int _run_command(struct dso_state *state)
/* Figure out device UUID has LVM- prefix and is OPEN */
static int _has_unmountable_prefix(int major, int minor)
{
char val[3][36];
char *env[] = { val[0], val[1], val[2], NULL };
int i;
struct dm_task *dmt;
struct dm_info info;
const char *uuid;
int r = 0;
/* Mark for possible lvm2 command we are running from dmeventd
* lvm2 will not try to talk back to dmeventd while processing it */
(void) dm_snprintf(val[0], sizeof(val[0]), "LVM_RUN_BY_DMEVENTD=1");
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return_0;
if (state->data_percent) {
/* Prepare some known data to env vars for easy use */
(void) dm_snprintf(val[1], sizeof(val[1]), "DMEVENTD_THIN_POOL_DATA=%d",
state->data_percent / DM_PERCENT_1);
(void) dm_snprintf(val[2], sizeof(val[2]), "DMEVENTD_THIN_POOL_METADATA=%d",
state->metadata_percent / DM_PERCENT_1);
} else {
/* For an error event it's for a user to check status and decide */
env[1] = NULL;
log_debug("Error event processing.");
if (!dm_task_set_major_minor(dmt, major, minor, 1))
goto_out;
if (!dm_task_no_flush(dmt))
stack;
if (!dm_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info))
goto out;
if (!info.exists || !info.open_count)
goto out; /* Not open -> not mounted */
if (!(uuid = dm_task_get_uuid(dmt)))
goto out;
/* Check it's public mountable LV
* has prefix LVM- and UUID size is 68 chars */
if (memcmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) ||
strlen(uuid) != 68)
goto out;
#if THIN_DEBUG
log_debug("Found logical volume %s (%u:%u).", uuid, major, minor);
#endif
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/* Get dependencies for device, and try to find matching device */
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
{
struct dm_task *dmt;
const struct dm_deps *deps;
struct dm_info info;
int major, minor;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
return 0;
if (!dm_task_set_name(dmt, name))
goto out;
if (!dm_task_no_open_count(dmt))
goto out;
if (!dm_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info))
goto out;
if (!(deps = dm_task_get_deps(dmt)))
goto out;
if (!info.exists || deps->count != 1)
goto out;
major = (int) MAJOR(deps->device[0]);
minor = (int) MINOR(deps->device[0]);
if ((major != tp_major) || (minor != tp_minor))
goto out;
*dev_minor = info.minor;
if (!_has_unmountable_prefix(major, info.minor))
goto out;
#if THIN_DEBUG
{
char dev_name[PATH_MAX];
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
log_debug("Found %s (%u:%u) depends on %s.",
name, major, *dev_minor, dev_name);
}
#endif
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/* Get all active devices */
static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor)
{
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
int minor, r = 1;
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
return 0;
if (!dm_task_run(dmt)) {
r = 0;
goto out;
}
log_verbose("Executing command: %s", state->cmd_str);
if (!(names = dm_task_get_names(dmt))) {
r = 0;
goto out;
}
/* TODO:
* Support parallel run of 'task' and it's waitpid maintainence
* ATM we can't handle signaling of SIGALRM
* as signalling is not allowed while 'process_event()' is running
*/
if (!(state->pid = fork())) {
/* child */
(void) close(0);
for (i = 3; i < 255; ++i) (void) close(i);
execve(state->argv[0], state->argv, env);
_exit(errno);
} else if (state->pid == -1) {
log_error("Can't fork command %s.", state->cmd_str);
state->fails = 1;
return 0;
if (!names->dev)
goto out;
do {
names = (struct dm_names *)((char *) names + next);
if (_has_deps(names->name, tp_major, tp_minor, &minor))
dm_bit_set(bs, minor);
next = names->next;
} while (next);
out:
dm_task_destroy(dmt);
return r;
}
static int _run(const char *cmd, ...)
{
va_list ap;
int argc = 1; /* for argv[0], i.e. cmd */
int i = 0;
const char **argv;
pid_t pid = fork();
int status;
if (pid == 0) { /* child */
va_start(ap, cmd);
while (va_arg(ap, const char *))
++argc;
va_end(ap);
/* + 1 for the terminating NULL */
argv = alloca(sizeof(const char *) * (argc + 1));
argv[0] = cmd;
va_start(ap, cmd);
while ((argv[++i] = va_arg(ap, const char *)));
va_end(ap);
execvp(cmd, (char **)argv);
log_sys_error("exec", cmd);
exit(127);
}
if (pid > 0) { /* parent */
if (waitpid(pid, &status, 0) != pid)
return 0; /* waitpid failed */
if (!WIFEXITED(status) || WEXITSTATUS(status))
return 0; /* the child failed */
}
if (pid < 0)
return 0; /* fork failed */
return 1; /* all good */
}
struct mountinfo_s {
const char *device;
struct dm_info info;
dm_bitset_t minors; /* Bitset for active thin pool minors */
};
static int _umount_device(char *buffer, unsigned major, unsigned minor,
char *target, void *cb_data)
{
struct mountinfo_s *data = cb_data;
char *words[10];
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
if (dm_split_words(buffer, DM_ARRAY_SIZE(words), 0, words) < DM_ARRAY_SIZE(words))
words[9] = NULL; /* just don't show device name */
log_info("Unmounting thin %s (%d:%d) of thin-pool %s (%u:%u) from mount point \"%s\".",
words[9] ? : "", major, minor, data->device,
data->info.major, data->info.minor,
target);
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
log_error("Failed to lazy umount thin %s (%d:%d) from %s: %s.",
words[9], major, minor, target, strerror(errno));
}
return 1;
}
/*
* Find all thin pool LV users and try to umount them.
* TODO: work with read-only thin pool support
*/
static void _umount(struct dm_task *dmt)
{
/* TODO: Convert to use hash to reduce memory usage */
static const size_t MINORS = (1U << 20); /* 20 bit */
struct mountinfo_s data = { NULL };
if (!dm_task_get_info(dmt, &data.info))
return;
data.device = dm_task_get_name(dmt);
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
goto out;
}
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
log_error("Failed to detect mounted volumes for %s.", data.device);
goto out;
}
if (!dm_mountinfo_read(_umount_device, &data)) {
log_error("Could not parse mountinfo file.");
goto out;
}
out:
if (data.minors)
dm_bitset_destroy(data.minors);
}
static int _use_policy(struct dm_task *dmt, struct dso_state *state)
{
#if THIN_DEBUG
log_debug("dmeventd executes: %s.", state->cmd_str);
log_info("dmeventd executes: %s.", state->cmd_str);
#endif
if (state->argv[0])
return _run_command(state);
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
log_error("Failed command for %s.", dm_task_get_name(dmt));
state->fails = 1;
log_error("Failed to extend thin pool %s.",
dm_task_get_name(dmt));
state->fails++;
return 0;
}
state->fails = 0;
return 1;
}
/* Check if executed command has finished
* Only 1 command may run */
static int _wait_for_pid(struct dso_state *state)
{
int status = 0;
if (state->pid == -1)
return 1;
if (!waitpid(state->pid, &status, WNOHANG))
return 0;
/* Wait for finish */
if (WIFEXITED(status)) {
log_verbose("Child %d exited with status %d.",
state->pid, WEXITSTATUS(status));
state->fails = WEXITSTATUS(status) ? 1 : 0;
} else {
if (WIFSIGNALED(status))
log_verbose("Child %d was terminated with status %d.",
state->pid, WTERMSIG(status));
state->fails = 1;
}
state->pid = -1;
return 1;
}
@@ -161,6 +319,7 @@ void process_event(struct dm_task *dmt,
void **user)
{
const char *device = dm_task_get_name(dmt);
int percent;
struct dso_state *state = *user;
struct dm_status_thin_pool *tps = NULL;
void *next = NULL;
@@ -168,48 +327,25 @@ void process_event(struct dm_task *dmt,
char *target_type = NULL;
char *params;
int needs_policy = 0;
struct dm_task *new_dmt = NULL;
int needs_umount = 0;
#if THIN_DEBUG
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
dm_percent_to_round_float(state->data_percent_check, 2),
dm_percent_to_round_float(state->metadata_percent_check, 2));
dm_percent_to_float(state->data_percent_check),
dm_percent_to_float(state->metadata_percent_check));
#endif
if (!_wait_for_pid(state)) {
log_warn("WARNING: Skipping event, child %d is still running (%s).",
state->pid, state->cmd_str);
return;
}
#if 0
/* No longer monitoring, waiting for remove */
if (!state->meta_percent_check && !state->data_percent_check)
return;
#endif
if (event & DM_EVENT_DEVICE_ERROR) {
/* Error -> no need to check and do instant resize */
state->data_percent = state->metadata_percent = 0;
if (_use_policy(dmt, state))
goto out;
stack;
/*
* Rather update oldish status
* since after 'command' processing
* percentage info could have changed a lot.
* If we would get above UMOUNT_THRESH
* we would wait for next sigalarm.
*/
if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
goto_out;
if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
goto_out;
/* Non-blocking status read */
if (!dm_task_no_flush(new_dmt))
log_warn("WARNING: Can't set no_flush for dm status.");
if (!dm_task_run(new_dmt))
goto_out;
dmt = new_dmt;
}
dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
@@ -221,6 +357,7 @@ void process_event(struct dm_task *dmt,
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
log_error("Failed to parse status.");
needs_umount = 1;
goto out;
}
@@ -235,110 +372,67 @@ void process_event(struct dm_task *dmt,
if (state->known_metadata_size != tps->total_metadata_blocks) {
state->metadata_percent_check = CHECK_MINIMUM;
state->known_metadata_size = tps->total_metadata_blocks;
state->fails = 0;
}
if (state->known_data_size != tps->total_data_blocks) {
state->data_percent_check = CHECK_MINIMUM;
state->known_data_size = tps->total_data_blocks;
state->fails = 0;
}
/*
* Trigger action when threshold boundary is exceeded.
* Report 80% threshold warning when it's used above 80%.
* Only 100% is exception as it cannot be surpased so policy
* action is called for: >50%, >55% ... >95%, 100%
*/
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if ((state->metadata_percent > WARNING_THRESH) &&
(state->metadata_percent > state->metadata_percent_check))
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_round_float(state->metadata_percent, 2));
if (state->metadata_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->metadata_percent > state->metadata_percent_check)
needs_policy = 1;
state->metadata_percent_check = (state->metadata_percent / CHECK_STEP + 1) * CHECK_STEP;
if (state->metadata_percent_check == DM_PERCENT_100)
state->metadata_percent_check--; /* Can't get bigger then 100% */
} else
state->metadata_percent_check = CHECK_MINIMUM;
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if (percent >= state->metadata_percent_check) {
/*
* Usage has raised more than CHECK_STEP since the last
* time. Run actions.
*/
state->metadata_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if ((state->data_percent > WARNING_THRESH) &&
(state->data_percent > state->data_percent_check))
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_round_float(state->data_percent, 2));
if (state->data_percent > CHECK_MINIMUM) {
/* Run action when usage raised more than CHECK_STEP since the last time */
if (state->data_percent > state->data_percent_check)
needs_policy = 1;
state->data_percent_check = (state->data_percent / CHECK_STEP + 1) * CHECK_STEP;
if (state->data_percent_check == DM_PERCENT_100)
state->data_percent_check--; /* Can't get bigger then 100% */
} else
state->data_percent_check = CHECK_MINIMUM;
/* FIXME: extension of metadata needs to be written! */
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_float(percent));
needs_policy = 1;
/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
* Avoids too high number of error retries, yet shows some status messages in log regularly.
* i.e. PV could have been pvmoved and VG/LV was locked for a while...
*/
if (state->fails) {
if (state->fails++ <= state->max_fails) {
log_debug("Postponing frequently failing policy (%u <= %u).",
state->fails - 1, state->max_fails);
return;
}
if (state->max_fails < MAX_FAILS)
state->max_fails <<= 1;
state->fails = needs_policy = 1; /* Retry failing command */
} else
state->max_fails = 1; /* Reset on success */
if (percent >= UMOUNT_THRESH)
needs_umount = 1;
}
if (needs_policy)
_use_policy(dmt, state);
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if (percent >= state->data_percent_check) {
/*
* Usage has raised more than CHECK_STEP since
* the last time. Run actions.
*/
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_float(percent));
needs_policy = 1;
if (percent >= UMOUNT_THRESH)
needs_umount = 1;
}
if (needs_policy &&
_use_policy(dmt, state))
needs_umount = 0; /* No umount when command was successful */
out:
if (needs_umount) {
_umount(dmt);
/* Until something changes, do not retry any more actions */
state->data_percent_check = state->metadata_percent_check = (DM_PERCENT_1 * 101);
}
if (tps)
dm_pool_free(state->mem, tps);
if (new_dmt)
dm_task_destroy(new_dmt);
}
/* Handle SIGCHLD for a thread */
static void _sig_child(int signum __attribute__((unused)))
{
/* empty SIG_IGN */;
}
/* Setup handler for SIGCHLD when executing external command
* to get quick 'waitpid()' reaction
* It will interrupt syscall just like SIGALRM and
* invoke process_event().
*/
static void _init_thread_signals(struct dso_state *state)
{
struct sigaction act = { .sa_handler = _sig_child };
sigset_t my_sigset;
sigemptyset(&my_sigset);
if (sigaction(SIGCHLD, &act, NULL))
log_warn("WARNING: Failed to set SIGCHLD action.");
else if (sigaddset(&my_sigset, SIGCHLD))
log_warn("WARNING: Failed to add SIGCHLD to set.");
else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
log_warn("WARNING: Failed to unblock SIGCHLD.");
else
state->restore_sigset = 1;
}
static void _restore_thread_signals(struct dso_state *state)
{
if (state->restore_sigset &&
pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
log_warn("WARNING: Failed to block SIGCHLD.");
if (state->fails >= MAX_FAILS) {
log_warn("WARNING: Dropping monitoring of %s. "
"lvm2 command fails too often (%u times in raw).",
device, state->fails);
pthread_kill(pthread_self(), SIGALRM);
}
}
int register_device(const char *device,
@@ -348,55 +442,27 @@ int register_device(const char *device,
void **user)
{
struct dso_state *state;
char *str;
char cmd_str[PATH_MAX + 128 + 2]; /* cmd ' ' vg/lv \0 */
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
goto_bad;
if (!dmeventd_lvm2_command(state->mem, cmd_str, sizeof(cmd_str),
"_dmeventd_thin_command", device))
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
sizeof(state->cmd_str),
"lvextend --use-policies",
device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
if (strncmp(cmd_str, "lvm ", 4) == 0) {
if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str + 4))) {
log_error("Failed to copy lvm command.");
goto bad;
}
} else if (cmd_str[0] == '/') {
if (!(state->cmd_str = dm_pool_strdup(state->mem, cmd_str))) {
log_error("Failed to copy thin command.");
goto bad;
}
/* Find last space before 'vg/lv' */
if (!(str = strrchr(state->cmd_str, ' ')))
goto inval;
if (!(state->argv[0] = dm_pool_strndup(state->mem, state->cmd_str,
str - state->cmd_str))) {
log_error("Failed to copy command.");
goto bad;
}
state->argv[1] = str + 1; /* 1 argument - vg/lv */
_init_thread_signals(state);
} else /* Unuspported command format */
goto inval;
state->pid = -1;
state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent_check = CHECK_MINIMUM;
*user = state;
log_info("Monitoring thin pool %s.", device);
log_info("Monitoring thin %s.", device);
return 1;
inval:
log_error("Invalid command for monitoring: %s.", cmd_str);
bad:
log_error("Failed to monitor thin pool %s.", device);
if (state)
dmeventd_lvm2_exit_with_pool(state);
log_error("Failed to monitor thin %s.", device);
return 0;
}
@@ -408,31 +474,9 @@ int unregister_device(const char *device,
void **user)
{
struct dso_state *state = *user;
int i;
for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
if (i == 0)
/* Give it 2 seconds, then try to terminate & kill it */
log_verbose("Child %d still not finished (%s) waiting.",
state->pid, state->cmd_str);
else if (i == 3) {
log_warn("WARNING: Terminating child %d.", state->pid);
kill(state->pid, SIGINT);
kill(state->pid, SIGTERM);
} else if (i == 5) {
log_warn("WARNING: Killing child %d.", state->pid);
kill(state->pid, SIGKILL);
}
sleep(1);
}
if (state->pid != -1)
log_warn("WARNING: Cannot kill child %d!", state->pid);
_restore_thread_signals(state);
dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);
log_info("No longer monitoring thin %s.", device);
return 1;
}

View File

@@ -1 +0,0 @@
dmfilemapd

View File

@@ -1,66 +0,0 @@
#
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = dmfilemapd.c
TARGETS = dmfilemapd
.PHONY: install_dmfilemapd install_dmfilemapd_static
INSTALL_DMFILEMAPD_TARGETS = install_dmfilemapd_dynamic
CLEAN_TARGETS = dmfilemapd.static
CFLOW_LIST = $(SOURCES)
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
CFLOW_TARGET = dmfilemapd
include $(top_builddir)/make.tmpl
all: device-mapper
device-mapper: $(TARGETS)
CFLAGS_dmfilemapd.o += $(EXTRA_EXEC_CFLAGS)
LIBS += -ldevmapper
dmfilemapd: $(LIB_SHARED) dmfilemapd.o
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS)
dmfilemapd.static: $(LIB_STATIC) dmfilemapd.o $(interfacebuilddir)/libdevmapper.a
$(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -static -L$(interfacebuilddir) \
-o $@ dmfilemapd.o $(DL_LIBS) $(LIBS) $(STATIC_LIBS)
ifneq ("$(CFLOW_CMD)", "")
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
-include $(top_builddir)/libdm/libdevmapper.cflow
-include $(top_builddir)/lib/liblvm-internal.cflow
-include $(top_builddir)/lib/liblvm2cmd.cflow
-include $(top_builddir)/daemons/dmfilemapd/$(LIB_NAME).cflow
endif
install_dmfilemapd_dynamic: dmfilemapd
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_dmfilemapd_static: dmfilemapd.static
$(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
install_dmfilemapd: $(INSTALL_DMFILEMAPD_TARGETS)
install: install_dmfilemapd
install_device-mapper: install_dmfilemapd

View File

@@ -1,834 +0,0 @@
/*
* Copyright (C) 2016 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* It includes tree drawing code based on pstree: http://psmisc.sourceforge.net/
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tool.h"
#include "dm-logging.h"
#include "defaults.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/inotify.h>
#include <dirent.h>
#include <ctype.h>
#ifdef __linux__
# include "kdev_t.h"
#else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
#endif
/* limit to two updates/sec */
#define FILEMAPD_WAIT_USECS 500000
/* how long to wait for unlinked files */
#define FILEMAPD_NOFILE_WAIT_USECS 100000
#define FILEMAPD_NOFILE_WAIT_TRIES 10
struct filemap_monitor {
dm_filemapd_mode_t mode;
const char *program_id;
uint64_t group_id;
char *path;
int fd;
int inotify_fd;
int inotify_watch_fd;
/* monitoring heuristics */
int64_t blocks; /* allocated blocks, from stat.st_blocks */
uint64_t nr_regions;
int deleted;
};
static int _foreground;
static int _verbose;
const char *const _usage = "dmfilemapd <fd> <group_id> <abs_path> <mode> "
"[<foreground>[<log_level>]]";
/*
* Daemon logging. By default, all messages are thrown away: messages
* are only written to the terminal if the daemon is run in the foreground.
*/
__attribute__((format(printf, 5, 0)))
static void _dmfilemapd_log_line(int level,
const char *file __attribute__((unused)),
int line __attribute__((unused)),
int dm_errno_or_class,
const char *f, va_list ap)
{
static int _abort_on_internal_errors = -1;
FILE *out = log_stderr(level) ? stderr : stdout;
level = log_level(level);
if (level <= _LOG_WARN || _verbose) {
if (level < _LOG_WARN)
out = stderr;
vfprintf(out, f, ap);
fputc('\n', out);
}
if (_abort_on_internal_errors < 0)
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
_abort_on_internal_errors =
strcmp(getenv("DM_ABORT_ON_INTERNAL_ERRORS") ? : "0", "0");
if (_abort_on_internal_errors &&
!strncmp(f, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1))
abort();
}
__attribute__((format(printf, 5, 6)))
static void _dmfilemapd_log_with_errno(int level,
const char *file, int line,
int dm_errno_or_class,
const char *f, ...)
{
va_list ap;
va_start(ap, f);
_dmfilemapd_log_line(level, file, line, dm_errno_or_class, f, ap);
va_end(ap);
}
/*
* Only used for reporting errors before daemonise().
*/
__attribute__((format(printf, 1, 2)))
static void _early_log(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
}
static void _setup_logging(void)
{
dm_log_init_verbose(_verbose - 1);
dm_log_with_errno_init(_dmfilemapd_log_with_errno);
}
#define PROC_FD_DELETED_STR "(deleted)"
/*
* Scan the /proc/<pid>/fd directory for pid and check for an fd
* symlink whose contents match path.
*/
static int _is_open_in_pid(pid_t pid, const char *path)
{
char deleted_path[PATH_MAX + sizeof(PROC_FD_DELETED_STR)];
struct dirent *pid_dp = NULL;
char path_buf[PATH_MAX];
char link_buf[PATH_MAX];
DIR *pid_d = NULL;
ssize_t len;
if (pid == getpid())
return 0;
if (dm_snprintf(path_buf, sizeof(path_buf),
DEFAULT_PROC_DIR "%d/fd", pid) < 0) {
log_error("Could not format pid path.");
return 0;
}
/*
* Test for the kernel 'file (deleted)' form when scanning.
*/
if (dm_snprintf(deleted_path, sizeof(deleted_path), "%s %s",
path, PROC_FD_DELETED_STR) < 0) {
log_error("Could not format check path.");
return 0;
}
pid_d = opendir(path_buf);
if (!pid_d) {
log_error("Could not open proc path: %s.", path_buf);
return 0;
}
while ((pid_dp = readdir(pid_d)) != NULL) {
if (pid_dp->d_name[0] == '.')
continue;
if ((len = readlinkat(dirfd(pid_d), pid_dp->d_name, link_buf,
sizeof(link_buf))) < 0) {
log_error("readlink failed for " DEFAULT_PROC_DIR
"/%d/fd/.", pid);
goto bad;
}
link_buf[len] = '\0';
if (!strcmp(deleted_path, link_buf)) {
if (closedir(pid_d))
log_sys_error("closedir", path_buf);
return 1;
}
}
bad:
if (closedir(pid_d))
log_sys_error("closedir", path_buf);
return 0;
}
/*
* Attempt to determine whether a file is open by any process by
* scanning symbolic links in /proc/<pid>/fd.
*
* This is a heuristic since it cannot guarantee to detect brief
* access in all cases: a process that opens and then closes the
* file rapidly may never be seen by the scan.
*
* The method will also give false-positives if a process exists
* that has a deleted file open that had the same path, but a
* different inode number, to the file being monitored.
*
* For this reason the daemon only uses _is_open() for unlinked
* files when the mode is DM_FILEMAPD_FOLLOW_INODE, since these
* files can no longer be newly opened by processes.
*
* In this situation !is_open(path) provides an indication that
* the daemon should shut down: the file has been unlinked from
* the file system and we appear to hold the final reference.
*/
static int _is_open(const char *path)
{
struct dirent *proc_dp = NULL;
DIR *proc_d = NULL;
pid_t pid;
proc_d = opendir(DEFAULT_PROC_DIR);
if (!proc_d)
return 0;
while ((proc_dp = readdir(proc_d)) != NULL) {
if (!isdigit(proc_dp->d_name[0]))
continue;
errno = 0;
pid = (pid_t) strtol(proc_dp->d_name, NULL, 10);
if (errno || !pid)
continue;
if (_is_open_in_pid(pid, path)) {
if (closedir(proc_d))
log_sys_error("closedir", DEFAULT_PROC_DIR);
return 1;
}
}
if (closedir(proc_d))
log_sys_error("closedir", DEFAULT_PROC_DIR);
return 0;
}
static void _filemap_monitor_wait(uint64_t usecs)
{
if (_verbose) {
if (usecs == FILEMAPD_WAIT_USECS)
log_very_verbose("Waiting for check interval");
if (usecs == FILEMAPD_NOFILE_WAIT_USECS)
log_very_verbose("Waiting for unlinked path");
}
usleep((useconds_t) usecs);
}
static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
{
char *endptr;
/* we don't care what is in argv[0]. */
argc--;
argv++;
if (argc < 5) {
_early_log("Wrong number of arguments.");
_early_log("usage: %s", _usage);
return 0;
}
/*
* We don't know the true nr_regions at daemon start time,
* and it is not worth a dm_stats_list()/group walk to count:
* we can assume that there is at least one region or the
* daemon would not have been started.
*
* A correct value will be obtained following the first update
* of the group's regions.
*/
fm->nr_regions = 1;
/* parse <fd> */
errno = 0;
fm->fd = (int) strtol(argv[0], &endptr, 10);
if (errno || *endptr) {
_early_log("Could not parse file descriptor: %s", argv[0]);
return 0;
}
argc--;
argv++;
/* parse <group_id> */
errno = 0;
fm->group_id = strtoull(argv[0], &endptr, 10);
if (*endptr || errno) {
_early_log("Could not parse group identifier: %s", argv[0]);
return 0;
}
argc--;
argv++;
/* parse <path> */
if (!argv[0] || !strlen(argv[0])) {
_early_log("Path argument is required.");
return 0;
}
if (*argv[0] != '/') {
_early_log("Path argument must specify an absolute path.");
return 0;
}
fm->path = dm_strdup(argv[0]);
if (!fm->path) {
_early_log("Could not allocate memory for path argument.");
return 0;
}
argc--;
argv++;
/* parse <mode> */
if (!argv[0] || !strlen(argv[0])) {
_early_log("Mode argument is required.");
return 0;
}
fm->mode = dm_filemapd_mode_from_string(argv[0]);
if (fm->mode == DM_FILEMAPD_FOLLOW_NONE)
return 0;
argc--;
argv++;
/* parse [<foreground>[<verbose>]] */
if (argc) {
errno = 0;
_foreground = (int) strtol(argv[0], &endptr, 10);
if (errno || *endptr) {
_early_log("Could not parse debug argument: %s.",
argv[0]);
return 0;
}
argc--;
argv++;
if (argc) {
errno = 0;
_verbose = (int) strtol(argv[0], &endptr, 10);
if (errno || *endptr) {
_early_log("Could not parse verbose "
"argument: %s", argv[0]);
return 0;
}
if (_verbose < 0 || _verbose > 3) {
_early_log("Verbose argument out of range: %d.",
_verbose);
return 0;
}
}
}
return 1;
}
static int _filemap_fd_update_blocks(struct filemap_monitor *fm)
{
struct stat buf;
if (fm->fd < 0) {
log_error("Filemap fd is not open.");
return 0;
}
if (fstat(fm->fd, &buf)) {
log_error("Failed to fstat filemap file descriptor.");
return 0;
}
fm->blocks = buf.st_blocks;
return 1;
}
static int _filemap_fd_check_changed(struct filemap_monitor *fm)
{
int64_t old_blocks;
old_blocks = fm->blocks;
if (!_filemap_fd_update_blocks(fm))
return -1;
return (fm->blocks != old_blocks);
}
static void _filemap_monitor_close_fd(struct filemap_monitor *fm)
{
if (close(fm->fd))
log_error("Error closing file descriptor.");
fm->fd = -1;
}
static void _filemap_monitor_end_notify(struct filemap_monitor *fm)
{
inotify_rm_watch(fm->inotify_fd, fm->inotify_watch_fd);
}
static int _filemap_monitor_set_notify(struct filemap_monitor *fm)
{
int inotify_fd, watch_fd;
/*
* Set IN_NONBLOCK since we do not want to block in event read()
* calls. Do not set IN_CLOEXEC as dmfilemapd is single-threaded
* and does not fork or exec.
*/
if ((inotify_fd = inotify_init1(IN_NONBLOCK)) < 0) {
log_sys_error("inotify_init1", "IN_NONBLOCK");
return 0;
}
if ((watch_fd = inotify_add_watch(inotify_fd, fm->path,
IN_MODIFY | IN_DELETE_SELF)) < 0) {
log_sys_error("inotify_add_watch", fm->path);
return 0;
}
fm->inotify_fd = inotify_fd;
fm->inotify_watch_fd = watch_fd;
return 1;
}
static int _filemap_monitor_reopen_fd(struct filemap_monitor *fm)
{
int tries = FILEMAPD_NOFILE_WAIT_TRIES;
/*
* In DM_FILEMAPD_FOLLOW_PATH mode, inotify watches must be
* re-established whenever the file at the watched path is
* changed.
*
* FIXME: stat file and skip if inode is unchanged.
*/
if (fm->fd > 0)
log_error("Filemap file descriptor already open.");
while ((fm->fd < 0) && --tries)
if (((fm->fd = open(fm->path, O_RDONLY)) < 0) && tries)
_filemap_monitor_wait(FILEMAPD_NOFILE_WAIT_USECS);
if (!tries && (fm->fd < 0)) {
log_error("Could not re-open file descriptor.");
return 0;
}
return _filemap_monitor_set_notify(fm);
}
static int _filemap_monitor_get_events(struct filemap_monitor *fm)
{
/* alignment as per man(7) inotify */
char buf[sizeof(struct inotify_event) + NAME_MAX + 1]
__attribute__ ((aligned(__alignof__(struct inotify_event))));
struct inotify_event *event;
int check = 0;
ssize_t len;
char *ptr;
/*
* Close the file descriptor for the file being monitored here
* when mode=path: this will allow the inode to be de-allocated,
* and an IN_DELETE_SELF event generated in the case that the
* daemon is holding the last open reference to the file.
*/
if (fm->mode == DM_FILEMAPD_FOLLOW_PATH) {
_filemap_monitor_end_notify(fm);
_filemap_monitor_close_fd(fm);
}
len = read(fm->inotify_fd, (void *) &buf, sizeof(buf));
/* no events to read? */
if (len < 0 && (errno == EAGAIN))
goto out;
/* interrupted by signal? */
if (len < 0 && (errno == EINTR))
goto out;
if (len < 0)
return -1;
if (!len)
goto out;
for (ptr = buf; ptr < buf + len; ptr += sizeof(*event) + event->len) {
event = (struct inotify_event *) ptr;
if (event->mask & IN_DELETE_SELF)
fm->deleted = 1;
if (event->mask & IN_MODIFY)
check = 1;
/*
* Event IN_IGNORED is generated when a file has been deleted
* and IN_DELETE_SELF generated, and indicates that the file
* watch has been automatically removed.
*
* This can only happen for the DM_FILEMAPD_FOLLOW_PATH mode,
* since inotify IN_DELETE events are generated at the time
* the inode is destroyed: DM_FILEMAPD_FOLLOW_INODE will hold
* the file descriptor open, meaning that the event will not
* be generated until after the daemon closes the file.
*
* The event is ignored here since inotify monitoring will
* be reestablished (or the daemon will terminate) following
* deletion of a DM_FILEMAPD_FOLLOW_PATH monitored file.
*/
if (event->mask & IN_IGNORED)
log_very_verbose("Inotify watch removed: IN_IGNORED "
"in event->mask");
}
out:
/*
* Re-open file descriptor if required and log disposition.
*/
if (fm->mode == DM_FILEMAPD_FOLLOW_PATH)
if (!_filemap_monitor_reopen_fd(fm))
return -1;
log_very_verbose("exiting _filemap_monitor_get_events() with "
"deleted=%d, check=%d", fm->deleted, check);
return check;
}
static void _filemap_monitor_destroy(struct filemap_monitor *fm)
{
if (fm->fd > 0) {
_filemap_monitor_end_notify(fm);
_filemap_monitor_close_fd(fm);
}
dm_free((void *) fm->program_id);
dm_free(fm->path);
}
static int _filemap_monitor_check_same_file(int fd1, int fd2)
{
struct stat buf1, buf2;
if ((fd1 < 0) || (fd2 < 0))
return 0;
if (fstat(fd1, &buf1)) {
log_error("Failed to fstat file descriptor %d", fd1);
return -1;
}
if (fstat(fd2, &buf2)) {
log_error("Failed to fstat file descriptor %d", fd2);
return -1;
}
return ((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino));
}
static int _filemap_monitor_check_file_unlinked(struct filemap_monitor *fm)
{
char path_buf[PATH_MAX];
char link_buf[PATH_MAX];
int same, fd;
ssize_t len;
fm->deleted = 0;
same = 0;
if ((fd = open(fm->path, O_RDONLY)) < 0)
goto check_unlinked;
same = _filemap_monitor_check_same_file(fm->fd, fd);
if (close(fd))
log_error("Error closing fd %d", fd);
if (same < 0)
return 0;
if (same)
return 1;
check_unlinked:
/*
* The file has been unlinked from its original location: test
* whether it is still reachable in the filesystem, or if it is
* unlinked and anonymous.
*/
if (dm_snprintf(path_buf, sizeof(path_buf), DEFAULT_PROC_DIR
"/%d/fd/%d", getpid(), fm->fd) < 0) {
log_error("Could not format pid path.");
return 0;
}
if ((len = readlink(path_buf, link_buf, sizeof(link_buf) - 1)) < 0) {
log_error("readlink failed for " DEFAULT_PROC_DIR "/%d/fd/%d.",
getpid(), fm->fd);
return 0;
}
link_buf[len] = '\0';
/*
* Try to re-open the file, from the path now reported in /proc/pid/fd.
*/
if ((fd = open(link_buf, O_RDONLY)) < 0)
fm->deleted = 1;
else
same = _filemap_monitor_check_same_file(fm->fd, fd);
if ((fd >= 0) && close(fd))
log_error("Error closing fd %d", fd);
if (same < 0)
return 0;
/* Should not happen with normal /proc. */
if ((fd > 0) && !same) {
log_error("File descriptor mismatch: %d and %s (read from %s) "
"are not the same file!", fm->fd, link_buf, path_buf);
return 0;
}
return 1;
}
static int _daemonise(struct filemap_monitor *fm)
{
pid_t pid = 0, sid;
int fd;
if (!(sid = setsid())) {
_early_log("setsid failed.");
return 0;
}
if ((pid = fork()) < 0) {
_early_log("Failed to fork daemon process.");
return 0;
}
if (pid > 0) {
if (_verbose)
_early_log("Started dmfilemapd with pid=%d", pid);
exit(0);
}
if (chdir("/")) {
_early_log("Failed to change directory.");
return 0;
}
if (!_verbose) {
if (close(STDIN_FILENO))
_early_log("Error closing stdin");
if (close(STDOUT_FILENO))
_early_log("Error closing stdout");
if (close(STDERR_FILENO))
_early_log("Error closing stderr");
if ((open("/dev/null", O_RDONLY) < 0) ||
(open("/dev/null", O_WRONLY) < 0) ||
(open("/dev/null", O_WRONLY) < 0)) {
_early_log("Error opening stdio streams.");
return 0;
}
}
/* TODO: Use libdaemon/server/daemon-server.c _daemonise() */
for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) {
if (fd == fm->fd)
continue;
(void) close(fd);
}
return 1;
}
static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm)
{
uint64_t *regions = NULL, *region, nr_regions = 0;
regions = dm_stats_update_regions_from_fd(dms, fm->fd, fm->group_id);
if (!regions) {
log_error("Failed to update filemap regions for group_id="
FMTu64 ".", fm->group_id);
return 0;
}
for (region = regions; *region != DM_STATS_REGIONS_ALL; region++)
nr_regions++;
if (!nr_regions)
log_warn("File contains no extents: exiting.");
if (nr_regions && (regions[0] != fm->group_id)) {
log_warn("group_id changed from " FMTu64 " to " FMTu64,
fm->group_id, regions[0]);
fm->group_id = regions[0];
}
dm_free(regions);
fm->nr_regions = nr_regions;
return 1;
}
static int _dmfilemapd(struct filemap_monitor *fm)
{
int running = 1, check = 0, open = 0;
const char *program_id;
struct dm_stats *dms;
/*
* The correct program_id is retrieved from the group leader
* following the call to dm_stats_list().
*/
if (!(dms = dm_stats_create(NULL)))
goto_bad;
if (!dm_stats_bind_from_fd(dms, fm->fd)) {
log_error("Could not bind dm_stats handle to file descriptor "
"%d", fm->fd);
goto bad;
}
if (!_filemap_monitor_set_notify(fm))
goto bad;
if (!_filemap_fd_update_blocks(fm))
goto bad;
if (!dm_stats_list(dms, DM_STATS_ALL_PROGRAMS)) {
log_error("Failed to list stats handle.");
goto bad;
}
/*
* Take the program_id for new regions (created by calls to
* dm_stats_update_regions_from_fd()) from the value used by
* the group leader.
*/
program_id = dm_stats_get_region_program_id(dms, fm->group_id);
if (program_id)
fm->program_id = dm_strdup(program_id);
else
fm->program_id = NULL;
dm_stats_set_program_id(dms, 1, program_id);
do {
if (!dm_stats_group_present(dms, fm->group_id)) {
log_info("Filemap group removed: exiting.");
running = 0;
continue;
}
if ((check = _filemap_monitor_get_events(fm)) < 0)
goto bad;
if (!check)
goto wait;
if ((check = _filemap_fd_check_changed(fm)) < 0)
goto bad;
if (check && !_update_regions(dms, fm))
goto bad;
running = !!fm->nr_regions;
if (!running)
continue;
wait:
_filemap_monitor_wait(FILEMAPD_WAIT_USECS);
/* mode=inode termination condions */
if (fm->mode == DM_FILEMAPD_FOLLOW_INODE) {
if (!_filemap_monitor_check_file_unlinked(fm))
goto bad;
if (fm->deleted && !(open = _is_open(fm->path))) {
log_info("File unlinked and closed: exiting.");
running = 0;
} else if (fm->deleted && open)
log_verbose("File unlinked and open: "
"continuing.");
}
if (!dm_stats_list(dms, NULL)) {
log_error("Failed to list stats handle.");
goto bad;
}
} while (running);
_filemap_monitor_destroy(fm);
dm_stats_destroy(dms);
return 0;
bad:
_filemap_monitor_destroy(fm);
dm_stats_destroy(dms);
log_error("Exiting");
return 1;
}
static const char * _mode_names[] = {
"inode",
"path"
};
/*
* dmfilemapd <fd> <group_id> <path> <mode> [<foreground>[<log_level>]]
*/
int main(int argc, char **argv)
{
struct filemap_monitor fm;
memset(&fm, 0, sizeof(fm));
if (!_parse_args(argc, argv, &fm)) {
dm_free(fm.path);
return 1;
}
_setup_logging();
log_info("Starting dmfilemapd with fd=%d, group_id=" FMTu64 " "
"mode=%s, path=%s", fm.fd, fm.group_id,
_mode_names[fm.mode], fm.path);
if (!_foreground && !_daemonise(&fm))
return 1;
return _dmfilemapd(&fm);
}

View File

@@ -1 +0,0 @@
path.py

View File

@@ -33,6 +33,7 @@ LVMDBUS_SRCDIR_FILES = \
manager.py \
objectmanager.py \
pv.py \
refresh.py \
request.py \
state.py \
udevwatch.py \

View File

@@ -8,7 +8,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
import dbus.service
from . import cfg
from .utils import get_properties, add_properties, get_object_property_diff, \
log_debug
@@ -38,7 +37,7 @@ class AutomatedProperties(dbus.service.Object):
props = {}
for i in self.interface():
props[i] = AutomatedProperties._get_all_prop(self, i)
props[i] = self.GetAll(i)
return self._ap_o_path, props
@@ -65,52 +64,31 @@ class AutomatedProperties(dbus.service.Object):
return self._ap_interface
@staticmethod
def _get_prop(obj, interface_name, property_name):
value = getattr(obj, property_name)
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
value = getattr(self, property_name)
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
log_debug('Get (%s), type (%s), value(%s)' %
(property_name, str(type(value)), str(value)))
return value
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v',
async_callbacks=('cb', 'cbe'))
def Get(self, interface_name, property_name, cb, cbe):
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
r = cfg.create_request_entry(
-1, AutomatedProperties._get_prop,
(self, interface_name, property_name),
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _get_all_prop(obj, interface_name):
if interface_name in obj.interface(True):
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
if interface_name in self.interface(True):
# Using introspection, lets build this dynamically
properties = get_properties(obj)
properties = get_properties(self)
if interface_name in properties:
return properties[interface_name][1]
return {}
raise dbus.exceptions.DBusException(
obj._ap_interface,
self._ap_interface,
'The object %s does not implement the %s interface'
% (obj.__class__, interface_name))
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}',
async_callbacks=('cb', 'cbe'))
def GetAll(self, interface_name, cb, cbe):
r = cfg.create_request_entry(
-1, AutomatedProperties._get_all_prop,
(self, interface_name),
cb, cbe, False)
cfg.worker_q.put(r)
% (self.__class__, interface_name))
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ssv')
@@ -180,7 +158,10 @@ class AutomatedProperties(dbus.service.Object):
cfg.om.lookup_update(self, new_id[0], new_id[1])
# Grab the properties values, then replace the state of the object
# and retrieve the new values.
# and retrieve the new values
# TODO: We need to add locking to prevent concurrent access to the
# properties so that a client is not accessing while we are
# replacing.
o_prop = get_properties(self)
self.state = new_state
n_prop = get_properties(self)

View File

@@ -7,15 +7,17 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
import subprocess
from . import cfg
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
add_no_notify
import os
import threading
import time
from .cmdhandler import options_to_cli_args
import dbus
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug
import traceback
_rlock = threading.RLock()
_thread_list = list()
def pv_move_lv_cmd(move_options, lv_full_name,
@@ -39,58 +41,15 @@ def lv_merge_cmd(merge_options, lv_full_name):
return cmd
def _move_merge(interface_name, command, job_state):
# We need to execute these command stand alone by forking & exec'ing
# the command always as we will be getting periodic output from them on
# the status of the long running operation.
command.insert(0, cfg.LVM_CMD)
def _move_merge(interface_name, cmd, job_state):
add(cmd, job_state)
# Instruct lvm to not register an event with us
command = add_no_notify(command)
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.blackbox.add(meta)
process = subprocess.Popen(command, stdout=subprocess.PIPE,
env=os.environ,
stderr=subprocess.PIPE, close_fds=True)
log_debug("Background process for %s is %d" %
(str(command), process.pid))
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
job_state.Percent = round(
float(percentage.strip()[:-1]), 1)
# While the move is in progress we need to periodically update
# the state to reflect where everything is at.
cfg.load()
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
with meta.lock:
meta.ended = time.time()
meta.ec = process.returncode
meta.stderr_txt = out[1]
if process.returncode == 0:
job_state.Percent = 100
else:
done = job_state.Wait(-1)
if not done:
ec, err_msg = job_state.GetError
raise dbus.exceptions.DBusException(
interface_name,
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
'Exit code %s, stderr = %s' % (str(ec), err_msg))
cfg.load()
return '/'
@@ -125,6 +84,8 @@ def move(interface_name, lv_name, pv_src_obj, pv_source_range,
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
# Generate the command line for this command, but don't
# execute it.
cmd = pv_move_lv_cmd(move_options,
lv_name,
pv_src.lvm_id,
@@ -149,14 +110,92 @@ def merge(interface_name, lv_uuid, lv_name, merge_options, job_state):
'LV with uuid %s and name %s not present!' % (lv_uuid, lv_name))
def _run_cmd(req):
log_debug(
"_run_cmd: Running method: %s with args %s" %
(str(req.method), str(req.arguments)))
req.run_cmd()
log_debug("_run_cmd: complete!")
def background_reaper():
while cfg.run.value != 0:
with _rlock:
num_threads = len(_thread_list) - 1
if num_threads >= 0:
for i in range(num_threads, -1, -1):
_thread_list[i].join(0)
if not _thread_list[i].is_alive():
log_debug("Removing thread: %s" % _thread_list[i].name)
_thread_list.pop(i)
time.sleep(3)
def cmd_runner(request):
t = threading.Thread(target=_run_cmd, args=(request,))
def background_execute(command, background_job):
# Wrap this whole operation in an exception handler, otherwise if we
# hit a code bug we will silently exit this thread without anyone being
# the wiser.
try:
process = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
lines_iterator = iter(process.stdout.readline, b"")
for line in lines_iterator:
line_str = line.decode("utf-8")
# Check to see if the line has the correct number of separators
try:
if line_str.count(':') == 2:
(device, ignore, percentage) = line_str.split(':')
background_job.Percent = \
round(float(percentage.strip()[:-1]), 1)
except ValueError:
log_error("Trying to parse percentage which failed for %s" %
line_str)
out = process.communicate()
if process.returncode == 0:
background_job.Percent = 100
background_job.set_result(process.returncode, out[1])
except Exception:
# In the unlikely event that we blow up, we need to unblock caller which
# is waiting on an answer.
st = traceback.format_exc()
error = "Exception in background thread: \n%s" % st
log_error(error)
background_job.set_result(1, error)
def add(command, reporting_job):
# Create the thread, get it running and then add it to the list
t = threading.Thread(
target=background_execute,
name="thread: " + ' '.join(command),
args=(command, reporting_job))
t.start()
with _rlock:
_thread_list.append(t)
def wait_thread(job, timeout, cb, cbe):
# We need to put the wait on it's own thread, so that we don't block the
# entire dbus queue processing thread
try:
cb(job.state.Wait(timeout))
except Exception as e:
cbe("Wait exception: %s" % str(e))
return 0
def add_wait(job, timeout, cb, cbe):
if timeout == 0:
# Users are basically polling, do not create thread
cb(job.Complete)
else:
t = threading.Thread(
target=wait_thread,
name="thread job.Wait: %s" % job.dbus_object_path(),
args=(job, timeout, cb, cbe)
)
t.start()
with _rlock:
_thread_list.append(t)

View File

@@ -11,8 +11,10 @@ import os
import multiprocessing
import queue
import itertools
from lvmdbusd import path
try:
from . import path
except SystemError:
import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
@@ -22,28 +24,24 @@ om = None
# This is the global bus connection
bus = None
# Command line args
args = None
# Set to true if we are depending on external events for updates
got_external_event = False
# Shared state variable across all processes
run = multiprocessing.Value('i', 1)
# If this is set to true, the current setup support lvm shell and we are
# running in that mode of operation
SHELL_IN_USE = None
# Debug
DEBUG = True
# Use lvm shell
USE_SHELL = False
# Lock used by pprint
stdout_lock = multiprocessing.Lock()
kick_q = multiprocessing.Queue()
worker_q = queue.Queue()
# Main event loop
loop = None
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv'
VG_INTERFACE = BASE_INTERFACE + '.Vg'
@@ -77,13 +75,9 @@ hidden_lv = itertools.count()
# Used to prevent circular imports...
load = None
event = None
# Global cached state
db = None
# lvm flight recorder
blackbox = None
# RequestEntry ctor
create_request_entry = None

View File

@@ -12,12 +12,15 @@ import time
import threading
from itertools import chain
import collections
import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
from . import cfg
from .utils import pv_dest_ranges, log_debug, log_error
from .lvm_shell_proxy import LVMShellProxy
except SystemError:
import cfg
from utils import pv_dest_ranges, log_debug, log_error
from lvm_shell_proxy import LVMShellProxy
try:
import simplejson as json
@@ -33,11 +36,14 @@ total_count = 0
# at the same time.
cmd_lock = threading.RLock()
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = None
class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.lock = threading.RLock()
self.start = start
self.ended = ended
self.cmd = cmd
@@ -46,30 +52,28 @@ class LvmExecutionMeta(object):
self.stderr_txt = stderr_txt
def __str__(self):
with self.lock:
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
def __init__(self, size=16):
self.queue = collections.deque(maxlen=size)
def __init__(self):
self.queue = collections.deque(maxlen=16)
def add(self, lvm_exec_meta):
self.queue.append(lvm_exec_meta)
def dump(self):
with cmd_lock:
if len(self.queue):
log_error("LVM dbus flight recorder START")
for c in self.queue:
log_error(str(c))
log_error("LVM dbus flight recorder END")
log_error("LVM dbus flight recorder START")
for c in self.queue:
log_error(str(c))
log_error("LVM dbus flight recorder END")
cfg.blackbox = LvmFlightRecorder()
@@ -95,10 +99,8 @@ def call_lvm(command, debug=False):
# Prepend the full lvm executable so that we can run different versions
# in different locations on the same box
command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True)
out = process.communicate()
stdout_text = bytes(out[0]).decode("utf-8")
@@ -107,48 +109,37 @@ def call_lvm(command, debug=False):
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
if process.returncode == 0:
if cfg.DEBUG and out[1] and len(out[1]) and 'help' not in command:
log_error('WARNING: lvm is out-putting text to STDERR on success!')
_debug_c(command, process.returncode, (stdout_text, stderr_text))
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
_t_call = call_lvm
return process.returncode, stdout_text, stderr_text
def _shell_cfg():
global _t_call
# noinspection PyBroadException
try:
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell
return True
except Exception:
_t_call = call_lvm
cfg.SHELL_IN_USE = None
log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
return False
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
if cfg.USE_SHELL:
_shell_cfg()
else:
_t_call = call_lvm
def set_execution(shell):
global _t_call
with cmd_lock:
# If the user requested lvm shell and we are currently setup that
# way, just return
if cfg.SHELL_IN_USE and shell:
return True
else:
if not shell and cfg.SHELL_IN_USE:
cfg.SHELL_IN_USE.exit_shell()
cfg.SHELL_IN_USE = None
_t_call = call_lvm
_t_call = None
if shell:
if cfg.args.use_json:
return _shell_cfg()
else:
return False
return True
log_debug('Using lvm shell!')
lvm_shell = LVMShellProxy()
_t_call = lvm_shell.call_lvm
else:
_t_call = call_lvm
def time_wrapper(command, debug=False):
@@ -228,10 +219,6 @@ def pv_remove(device, remove_options):
return call(cmd)
def _qt(tag_name):
return '@%s' % tag_name
def _tag(operation, what, add, rm, tag_options):
cmd = [operation]
cmd.extend(options_to_cli_args(tag_options))
@@ -242,11 +229,9 @@ def _tag(operation, what, add, rm, tag_options):
cmd.append(what)
if add:
cmd.extend(list(chain.from_iterable(
('--addtag', _qt(x)) for x in add)))
cmd.extend(list(chain.from_iterable(('--addtag', x) for x in add)))
if rm:
cmd.extend(list(chain.from_iterable(
('--deltag', _qt(x)) for x in rm)))
cmd.extend(list(chain.from_iterable(('--deltag', x) for x in rm)))
return call(cmd, False)
@@ -281,7 +266,7 @@ def vg_lv_create(vg_name, create_options, name, size_bytes, pv_dests):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name, '--yes'])
cmd.extend(['--name', name, vg_name])
pv_dest_ranges(cmd, pv_dests)
return call(cmd)
@@ -298,7 +283,20 @@ def vg_lv_snapshot(vg_name, snapshot_options, name, size_bytes):
return call(cmd)
def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
if not thin_pool:
cmd.extend(['--size', str(size_bytes) + 'B'])
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
@@ -307,19 +305,6 @@ def _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool):
else:
cmd.extend(['--thin', '--size', str(size_bytes) + 'B'])
cmd.extend(['--yes'])
return cmd
def vg_lv_create_linear(vg_name, create_options, name, size_bytes, thin_pool):
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
cmd.extend(['--name', name, vg_name])
return call(cmd)
def vg_lv_create_striped(vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool):
cmd = _vg_lv_create_common_cmd(create_options, size_bytes, thin_pool)
cmd.extend(['--stripes', str(num_stripes)])
if stripe_size_kb != 0:
@@ -344,7 +329,7 @@ def _vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
if stripe_size_kb != 0:
cmd.extend(['--stripesize', str(stripe_size_kb)])
cmd.extend(['--name', name, vg_name, '--yes'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
@@ -357,15 +342,14 @@ def vg_lv_create_raid(vg_name, create_options, name, raid_type, size_bytes,
size_bytes, num_stripes, stripe_size_kb)
def vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies):
def vg_lv_create_mirror(vg_name, create_options, name, size_bytes, num_copies):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--type', 'mirror'])
cmd.extend(['--mirrors', str(num_copies)])
cmd.extend(['--size', str(size_bytes) + 'B'])
cmd.extend(['--name', name, vg_name, '--yes'])
cmd.extend(['--name', name, vg_name])
return call(cmd)
@@ -419,7 +403,7 @@ def lv_lv_create(lv_full_name, create_options, name, size_bytes):
cmd = ['lvcreate']
cmd.extend(options_to_cli_args(create_options))
cmd.extend(['--virtualsize', str(size_bytes) + 'B', '-T'])
cmd.extend(['--name', name, lv_full_name, '--yes'])
cmd.extend(['--name', name, lv_full_name])
return call(cmd)
@@ -451,11 +435,8 @@ def supports_json():
cmd = ['help']
rc, out, err = call(cmd)
if rc == 0:
if cfg.SHELL_IN_USE:
if 'fullreport' in err:
return True
else:
if 'fullreport' in err:
return True
return False
@@ -464,7 +445,7 @@ def lvm_full_report_json():
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pv_missing']
'vg_uuid']
pv_seg_columns = ['pvseg_start', 'pvseg_size', 'segtype',
'pv_uuid', 'lv_uuid', 'pv_name']
@@ -480,9 +461,7 @@ def lvm_full_report_json():
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'lv_parent', 'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
'metadata_lv', 'lv_parent', 'lv_role', 'lv_layout']
lv_seg_columns = ['seg_pe_ranges', 'segtype', 'lv_uuid']
@@ -498,14 +477,7 @@ def lvm_full_report_json():
rc, out, err = call(cmd)
if rc == 0:
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
return json.loads(out)
return json.loads(out)
return None
@@ -519,7 +491,7 @@ def pv_retrieve_with_segs(device=None):
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype']
# Lvm has some issues where it returns failure when querying pvs when other
# operations are in process, see:
@@ -555,7 +527,7 @@ def pv_resize(device, size_bytes, create_options):
cmd.extend(options_to_cli_args(create_options))
if size_bytes != 0:
cmd.extend(['--yes', '--setphysicalvolumesize', str(size_bytes) + 'B'])
cmd.extend(['--setphysicalvolumesize', str(size_bytes) + 'B'])
cmd.extend([device])
return call(cmd)
@@ -620,10 +592,10 @@ def vg_reduce(vg_name, missing, pv_devices, reduce_options):
cmd = ['vgreduce']
cmd.extend(options_to_cli_args(reduce_options))
if len(pv_devices) == 0:
cmd.append('--all')
if missing:
cmd.append('--removemissing')
elif len(pv_devices) == 0:
cmd.append('--all')
cmd.append(vg_name)
cmd.extend(pv_devices)
@@ -732,9 +704,7 @@ def lv_retrieve_with_segments():
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
'lv_role', 'lv_layout']
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
rc, out, err = call(cmd)
@@ -751,4 +721,4 @@ if __name__ == '__main__':
pv_data = pv_retrieve_with_segs()
for p in pv_data:
print(str(p))
log_debug(str(p))

View File

@@ -11,157 +11,20 @@ from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
from .utils import MThreadRunner, log_debug, log_error
import threading
import queue
import traceback
def _main_thread_load(refresh=True, emit_signal=True):
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True):
num_total_changes = 0
num_total_changes += load_pvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(
refresh=refresh,
emit_signal=emit_signal,
cache_refresh=False)[1]
return num_total_changes
def load(refresh=True, emit_signal=True, cache_refresh=True, log=True,
need_main_thread=True):
# Go through and load all the PVs, VGs and LVs
if cache_refresh:
cfg.db.refresh(log)
if need_main_thread:
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
else:
rc = _main_thread_load(refresh, emit_signal)
num_total_changes += load_pvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_vgs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
num_total_changes += load_lvs(refresh=refresh, emit_signal=emit_signal,
cache_refresh=False)[1]
return rc
# Even though lvm can handle multiple changes concurrently it really doesn't
# make sense to make a 1-1 fetch of data for each change of lvm because when
# we fetch the data once all previous changes are reflected.
class StateUpdate(object):
class UpdateRequest(object):
def __init__(self, refresh, emit_signal, cache_refresh, log,
need_main_thread):
self.is_done = False
self.refresh = refresh
self.emit_signal = emit_signal
self.cache_refresh = cache_refresh
self.log = log
self.need_main_thread = need_main_thread
self.result = None
self.cond = threading.Condition(threading.Lock())
def done(self):
with self.cond:
if not self.is_done:
self.cond.wait()
return self.result
def set_result(self, result):
with self.cond:
self.result = result
self.is_done = True
self.cond.notify_all()
@staticmethod
def update_thread(obj):
queued_requests = []
while cfg.run.value != 0:
# noinspection PyBroadException
try:
refresh = True
emit_signal = True
cache_refresh = True
log = True
need_main_thread = True
with obj.lock:
wait = not obj.deferred
obj.deferred = False
if len(queued_requests) == 0 and wait:
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
# check if any others
try:
while True:
queued_requests.append(obj.queue.get(False))
except queue.Empty:
pass
if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green')
# We have what we can, run the update with the needed options
for i in queued_requests:
if not i.refresh:
refresh = False
if not i.emit_signal:
emit_signal = False
if not i.cache_refresh:
cache_refresh = False
if not i.log:
log = False
if not i.need_main_thread:
need_main_thread = False
num_changes = load(refresh, emit_signal, cache_refresh, log,
need_main_thread)
# Update is done, let everyone know!
for i in queued_requests:
i.set_result(num_changes)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads and they never
# wake up if we get an exception
queued_requests = []
except queue.Empty:
pass
except Exception:
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
cfg.blackbox.dump()
def __init__(self):
self.lock = threading.RLock()
self.queue = queue.Queue()
self.deferred = False
# Do initial load
load(refresh=False, emit_signal=False, need_main_thread=False)
self.thread = threading.Thread(target=StateUpdate.update_thread,
args=(self,))
def load(self, refresh=True, emit_signal=True, cache_refresh=True,
log=True, need_main_thread=True):
# Place this request on the queue and wait for it to be completed
req = StateUpdate.UpdateRequest(refresh, emit_signal, cache_refresh,
log, need_main_thread)
self.queue.put(req)
return req.done()
def event(self):
with self.lock:
self.deferred = True
return num_total_changes

View File

@@ -8,55 +8,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from .utils import job_obj_path_generate, mt_async_result, mt_run_no_wait
from .utils import job_obj_path_generate
from . import cfg
from .cfg import JOB_INTERFACE
import dbus
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
# Class that handles a client waiting for something to be complete. We either
# get a timeout or the operation is done.
class WaitingClient(object):
# A timeout occurred
@staticmethod
def _timeout(wc):
with wc.rlock:
if wc.in_use:
wc.in_use = False
# Remove ourselves from waiting client
wc.job_state.remove_waiting_client(wc)
wc.timer_id = -1
mt_async_result(wc.cb, wc.job_state.Complete)
wc.job_state = None
def __init__(self, job_state, tmo, cb, cbe):
self.rlock = threading.RLock()
self.job_state = job_state
self.cb = cb
self.cbe = cbe
self.in_use = True # Indicates if object is in play
self.timer_id = -1
if tmo > 0:
self.timer_id = GLib.timeout_add_seconds(
tmo, WaitingClient._timeout, self)
# The job finished before the timer popped and we are being notified that
# it's done
def notify(self):
with self.rlock:
if self.in_use:
self.in_use = False
# Clear timer
if self.timer_id != -1:
GLib.source_remove(self.timer_id)
self.timer_id = -1
mt_async_result(self.cb, self.job_state.Complete)
self.job_state = None
from . import background
# noinspection PyPep8Naming
@@ -67,9 +24,9 @@ class JobState(object):
self._percent = 0
self._complete = False
self._request = request
self._cond = threading.Condition(self.rlock)
self._ec = 0
self._stderr = ''
self._waiting_clients = []
# This is an lvm command that is just taking too long and doesn't
# support background operation
@@ -92,6 +49,8 @@ class JobState(object):
with self.rlock:
if self._request:
self._complete = self._request.is_done()
if self._complete:
self._percent = 100
return self._complete
@@ -99,8 +58,7 @@ class JobState(object):
def Complete(self, value):
with self.rlock:
self._complete = value
self._percent = 100
self.notify_waiting_clients()
self._cond.notify_all()
@property
def GetError(self):
@@ -114,10 +72,29 @@ class JobState(object):
else:
return (-1, 'Job is not complete!')
def set_result(self, ec, msg):
with self.rlock:
self.Complete = True
self._ec = ec
self._stderr = msg
def dtor(self):
with self.rlock:
self._request = None
def Wait(self, timeout):
try:
with self._cond:
# Check to see if we are done, before we wait
if not self.Complete:
if timeout != -1:
self._cond.wait(timeout)
else:
self._cond.wait()
return self.Complete
except RuntimeError:
return False
@property
def Result(self):
with self.rlock:
@@ -125,40 +102,10 @@ class JobState(object):
return self._request.result()
return '/'
def add_waiting_client(self, client):
with self.rlock:
# Avoid race condition where it goes complete before we get added
# to the list of waiting clients
if self.Complete:
client.notify()
else:
self._waiting_clients.append(client)
def remove_waiting_client(self, client):
# If a waiting client timer pops before the job is done we will allow
# the client to remove themselves from the list. As we have a lock
# here and a lock in the waiting client too, and they can be obtained
# in different orders, a dead lock can occur.
# As this remove is really optional, we will try to acquire the lock
# and remove. If we are unsuccessful it's not fatal, we just delay
# the time when the objects can be garbage collected by python
if self.rlock.acquire(False):
try:
self._waiting_clients.remove(client)
finally:
self.rlock.release()
def notify_waiting_clients(self):
with self.rlock:
for c in self._waiting_clients:
c.notify()
self._waiting_clients = []
# noinspection PyPep8Naming
class Job(AutomatedProperties):
_Percent_meta = ('d', JOB_INTERFACE)
_Percent_meta = ('y', JOB_INTERFACE)
_Complete_meta = ('b', JOB_INTERFACE)
_Result_meta = ('o', JOB_INTERFACE)
_GetError_meta = ('(is)', JOB_INTERFACE)
@@ -174,25 +121,26 @@ class Job(AutomatedProperties):
@property
def Percent(self):
return dbus.Double(float(self.state.Percent))
return self.state.Percent
@Percent.setter
def Percent(self, value):
self.state.Percent = value
@property
def Complete(self):
return dbus.Boolean(self.state.Complete)
@staticmethod
def _signal_complete(obj):
obj.PropertiesChanged(
JOB_INTERFACE, dict(Complete=dbus.Boolean(obj.state.Complete)), [])
return self.state.Complete
@Complete.setter
def Complete(self, value):
self.state.Complete = value
mt_run_no_wait(Job._signal_complete, self)
@property
def GetError(self):
return dbus.Struct(self.state.GetError, signature="(is)")
return self.state.GetError
def set_result(self, ec, msg):
self.state.set_result(ec, msg)
@dbus.service.method(dbus_interface=JOB_INTERFACE)
def Remove(self):
@@ -208,15 +156,11 @@ class Job(AutomatedProperties):
out_signature='b',
async_callbacks=('cb', 'cbe'))
def Wait(self, timeout, cb, cbe):
if timeout == 0 or self.state.Complete:
cb(dbus.Boolean(self.state.Complete))
else:
self.state.add_waiting_client(
WaitingClient(self.state, timeout, cb, cbe))
background.add_wait(self, timeout, cb, cbe)
@property
def Result(self):
return dbus.ObjectPath(self.state.Result)
return self.state.Result
@property
def lvm_id(self):

View File

@@ -21,7 +21,7 @@ from .utils import n, n32
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects
from .utils import round_size
from .job import JobState
@@ -81,14 +81,7 @@ def lvs_state_retrieve(selection, cache_refresh=True):
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
l['lv_layout']))
return rc
@@ -108,15 +101,9 @@ class LvState(State):
rc = []
for pv in sorted(cfg.db.lv_contained_pv(uuid)):
(pv_uuid, pv_name, pv_segs) = pv
pv_obj = cfg.om.get_object_path_by_uuid_lvm_id(pv_uuid, pv_name)
segs_decorate = []
for i in pv_segs:
segs_decorate.append((dbus.UInt64(i[0]),
dbus.UInt64(i[1]),
dbus.String(i[2])))
rc.append((dbus.ObjectPath(pv_obj), segs_decorate))
pv_obj = cfg.om.get_object_path_by_uuid_lvm_id(
pv_uuid, pv_name, gen_new=False)
rc.append((pv_obj, pv_segs))
return dbus.Array(rc, signature="(oa(tts))")
@@ -137,26 +124,25 @@ class LvState(State):
for l in cfg.db.hidden_lvs(self.Uuid):
full_name = "%s/%s" % (vg_name, l[1])
op = cfg.om.get_object_path_by_uuid_lvm_id(l[0], full_name)
op = cfg.om.get_object_path_by_uuid_lvm_id(
l[0], full_name, gen_new=False)
assert op
rc.append(dbus.ObjectPath(op))
rc.append(op)
return rc
def __init__(self, Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
data_lv, metadata_lv, segtypes, role, layout, SnapPercent,
MetaDataPercent, CopyPercent, SyncPercent, MetaDataSizeBytes,
move_pv, move_pv_uuid):
data_lv, metadata_lv, segtypes, role, layout):
utils.init_class_from_arguments(self)
# The segtypes is possibly an array with potentially dupes or a single
# value
self._segs = dbus.Array([], signature='s')
if not isinstance(segtypes, list):
self._segs.append(dbus.String(segtypes))
self._segs.append(segtypes)
else:
self._segs.extend([dbus.String(x) for x in set(segtypes)])
self._segs.extend(set(segtypes))
self.Vg = cfg.om.get_object_path_by_uuid_lvm_id(
vg_uuid, vg_name, vg_obj_path_generate)
@@ -167,7 +153,8 @@ class LvState(State):
gen = utils.lv_object_path_method(Name, (Attr, layout, role))
self.PoolLv = cfg.om.get_object_path_by_uuid_lvm_id(
pool_lv_uuid, '%s/%s' % (vg_name, PoolLv), gen)
pool_lv_uuid, '%s/%s' % (vg_name, PoolLv),
gen)
else:
self.PoolLv = '/'
@@ -223,20 +210,13 @@ class LvState(State):
@utils.dbus_property(LV_COMMON_INTERFACE, 'Name', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Path', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SizeBytes', 't')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SegType', 'as')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Vg', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'OriginLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'PoolLv', 'o')
@utils.dbus_property(LV_COMMON_INTERFACE, 'Devices', "a(oa(tts))")
@utils.dbus_property(LV_COMMON_INTERFACE, 'HiddenLvs', "ao")
@utils.dbus_property(LV_COMMON_INTERFACE, 'Attr', 's')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SnapPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'DataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'MetaDataPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'CopyPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'SyncPercent', 'u')
@utils.dbus_property(LV_COMMON_INTERFACE, 'MetaDataSizeBytes', 't')
class LvCommon(AutomatedProperties):
_Tags_meta = ("as", LV_COMMON_INTERFACE)
_Roles_meta = ("as", LV_COMMON_INTERFACE)
@@ -252,45 +232,12 @@ class LvCommon(AutomatedProperties):
_FixedMinor_meta = ('b', LV_COMMON_INTERFACE)
_ZeroBlocks_meta = ('b', LV_COMMON_INTERFACE)
_SkipActivation_meta = ('b', LV_COMMON_INTERFACE)
_MovePv_meta = ('o', LV_COMMON_INTERFACE)
def _get_move_pv(self):
path = None
# It's likely that the move_pv is empty
if self.state.move_pv_uuid and self.state.move_pv:
path = cfg.om.get_object_path_by_uuid_lvm_id(
self.state.move_pv_uuid, self.state.move_pv)
if not path:
path = '/'
return path
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, object_path, object_state):
super(LvCommon, self).__init__(object_path, lvs_state_retrieve)
self.set_interface(LV_COMMON_INTERFACE)
self.state = object_state
self._move_pv = self._get_move_pv()
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@staticmethod
def validate_dbus_object(lv_uuid, lv_name):
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if not dbo:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return dbo
@property
def VolumeType(self):
@@ -305,16 +252,14 @@ class LvCommon(AutomatedProperties):
'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
'e': 'raid or pool metadata or pool metadata spare',
'-': 'Unspecified'}
return dbus.Struct((self.state.Attr[0], type_map[self.state.Attr[0]]),
signature="as")
return (self.state.Attr[0], type_map[self.state.Attr[0]])
@property
def Permissions(self):
type_map = {'w': 'writable', 'r': 'read-only',
'R': 'Read-only activation of non-read-only volume',
'-': 'Unspecified'}
return dbus.Struct((self.state.Attr[1], type_map[self.state.Attr[1]]),
signature="(ss)")
return (self.state.Attr[1], type_map[self.state.Attr[1]])
@property
def AllocationPolicy(self):
@@ -323,12 +268,11 @@ class LvCommon(AutomatedProperties):
'i': 'inherited', 'I': 'inherited locked',
'l': 'cling', 'L': 'cling locked',
'n': 'normal', 'N': 'normal locked', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[2], type_map[self.state.Attr[2]]),
signature="(ss)")
return (self.state.Attr[2], type_map[self.state.Attr[2]])
@property
def FixedMinor(self):
return dbus.Boolean(self.state.Attr[3] == 'm')
return self.state.Attr[3] == 'm'
@property
def State(self):
@@ -339,32 +283,29 @@ class LvCommon(AutomatedProperties):
'd': 'mapped device present without tables',
'i': 'mapped device present with inactive table',
'X': 'unknown', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[4], type_map[self.state.Attr[4]]),
signature="(ss)")
return (self.state.Attr[4], type_map[self.state.Attr[4]])
@property
def TargetType(self):
type_map = {'C': 'Cache', 'm': 'mirror', 'r': 'raid',
's': 'snapshot', 't': 'thin', 'u': 'unknown',
'v': 'virtual', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[6], type_map[self.state.Attr[6]]),
signature="(ss)")
return (self.state.Attr[6], type_map[self.state.Attr[6]])
@property
def ZeroBlocks(self):
return dbus.Boolean(self.state.Attr[7] == 'z')
return self.state.Attr[7] == 'z'
@property
def Health(self):
type_map = {'p': 'partial', 'r': 'refresh',
'm': 'mismatches', 'w': 'writemostly',
'X': 'X unknown', '-': 'Unspecified'}
return dbus.Struct((self.state.Attr[8], type_map[self.state.Attr[8]]),
signature="(ss)")
return (self.state.Attr[8], type_map[self.state.Attr[8]])
@property
def SkipActivation(self):
return dbus.Boolean(self.state.Attr[9] == 'k')
return self.state.Attr[9] == 'k'
def vg_name_lookup(self):
return self.state.vg_name_lookup()
@@ -390,19 +331,22 @@ class LvCommon(AutomatedProperties):
@property
def IsThinVolume(self):
return dbus.Boolean(self.state.Attr[0] == 'V')
return self.state.Attr[0] == 'V'
@property
def IsThinPool(self):
return dbus.Boolean(self.state.Attr[0] == 't')
return self.state.Attr[0] == 't'
@property
def Active(self):
return dbus.Boolean(self.state.active == "active")
return self.state.active == "active"
@property
def MovePv(self):
return dbus.ObjectPath(self._move_pv)
@dbus.service.method(
dbus_interface=LV_COMMON_INTERFACE,
in_signature='ia{sv}',
out_signature='o')
def _Future(self, tmo, open_options):
raise dbus.exceptions.DBusException(LV_COMMON_INTERFACE, 'Do not use!')
# noinspection PyPep8Naming
@@ -428,10 +372,25 @@ class Lv(LvCommon):
@staticmethod
def _remove(lv_uuid, lv_name, remove_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Remove the LV, if successful then remove from the model
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
LvCommon.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Remove the LV, if successful then remove from the model
rc, out, err = cmdhandler.lv_remove(lv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
@@ -449,11 +408,24 @@ class Lv(LvCommon):
@staticmethod
def _rename(lv_uuid, lv_name, new_name, rename_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Rename the logical volume
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
rename_options)
LvCommon.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
if dbo:
# Rename the logical volume
rc, out, err = cmdhandler.lv_rename(lv_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return '/'
@dbus.service.method(
@@ -487,27 +459,44 @@ class Lv(LvCommon):
pv_dests_and_ranges, move_options, job_state), cb, cbe, False,
job_state)
background.cmd_runner(r)
cfg.worker_q.put(r)
@staticmethod
def _snap_shot(lv_uuid, lv_name, name, optional_size,
snapshot_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# If you specify a size you get a 'thick' snapshot even if
# it is a thin lv
if not dbo.IsThinVolume:
if optional_size == 0:
space = dbo.SizeBytes / 80
remainder = space % 512
optional_size = space + 512 - remainder
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
rc, out, err = cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)
LvCommon.handle_execute(rc, out, err)
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
if dbo:
# If you specify a size you get a 'thick' snapshot even if
# it is a thin lv
if not dbo.IsThinVolume:
if optional_size == 0:
space = dbo.SizeBytes / 80
remainder = space % 512
optional_size = space + 512 - remainder
rc, out, err = cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size)
if rc == 0:
return_path = '/'
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
return_path = l.dbus_object_path()
# Refresh self and all included PVs
cfg.load(cache_refresh=False)
return return_path
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -530,24 +519,38 @@ class Lv(LvCommon):
resize_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# If we have PVs, verify them
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'PV Destination (%s) not found' % pr[0])
if dbo:
# If we have PVs, verify them
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
size_change = new_size_bytes - dbo.SizeBytes
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
pv_dests, resize_options)
LvCommon.handle_execute(rc, out, err)
return "/"
size_change = new_size_bytes - dbo.SizeBytes
rc, out, err = cmdhandler.lv_resize(dbo.lvm_id, size_change,
pv_dests, resize_options)
if rc == 0:
# Refresh what's changed
cfg.load()
return "/"
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -580,11 +583,23 @@ class Lv(LvCommon):
def _lv_activate_deactivate(uuid, lv_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(uuid, lv_name)
rc, out, err = cmdhandler.activate_deactivate(
'lvchange', lv_name, activate, control_flags, options)
LvCommon.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, lv_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'lvchange', lv_name, activate, control_flags, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -616,11 +631,25 @@ class Lv(LvCommon):
@staticmethod
def _add_rm_tags(uuid, lv_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
LvCommon.validate_dbus_object(uuid, lv_name)
rc, out, err = cmdhandler.lv_tag(
lv_name, tags_add, tags_del, tag_options)
LvCommon.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, lv_name)
if dbo:
rc, out, err = cmdhandler.lv_tag(
lv_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(uuid, lv_name))
@dbus.service.method(
dbus_interface=LV_INTERFACE,
@@ -669,22 +698,37 @@ class LvThinPool(Lv):
@property
def DataLv(self):
return dbus.ObjectPath(self._data_lv)
return self._data_lv
@property
def MetaDataLv(self):
return dbus.ObjectPath(self._metadata_lv)
return self._metadata_lv
@staticmethod
def _lv_create(lv_uuid, lv_name, name, size_bytes, create_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
rc, out, err = cmdhandler.lv_lv_create(
lv_name, create_options, name, size_bytes)
LvCommon.handle_execute(rc, out, err)
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
lv_created = '/'
if dbo:
rc, out, err = cmdhandler.lv_lv_create(
lv_name, create_options, name, size_bytes)
if rc == 0:
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
lvs = load_lvs([full_name], emit_signal=True)[0]
for l in lvs:
lv_created = l.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return lv_created
@dbus.service.method(
dbus_interface=THIN_POOL_INTERFACE,
@@ -713,21 +757,22 @@ class LvCachePool(Lv):
@property
def DataLv(self):
return dbus.ObjectPath(self._data_lv)
return self._data_lv
@property
def MetaDataLv(self):
return dbus.ObjectPath(self._metadata_lv)
return self._metadata_lv
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if lv_to_cache:
if dbo and lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
@@ -735,18 +780,27 @@ class LvCachePool(Lv):
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
mt_remove_dbus_objects((dbo, lv_to_cache))
cfg.om.remove_object(dbo, emit_signal=True)
cfg.om.remove_object(lv_to_cache, emit_signal=True)
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
msg = ""
if not dbo:
dbo += 'CachePool LV with uuid %s and name %s not present!' % \
(lv_uuid, lv_name)
if not lv_to_cache:
dbo += 'LV to cache with object path %s not present!' % \
(lv_object_path)
raise dbus.exceptions.DBusException(LV_INTERFACE, msg)
return lv_converted
@dbus.service.method(
@@ -772,30 +826,37 @@ class LvCacheLv(Lv):
@property
def CachePool(self):
return dbus.ObjectPath(self.state.PoolLv)
return self.state.PoolLv
@staticmethod
def _detach_lv(lv_uuid, lv_name, detach_options, destroy_cache):
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(lv_uuid, lv_name)
# Get current cache name
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
if dbo:
rc, out, err = cmdhandler.lv_detach_cache(
dbo.lv_full_name(), detach_options, destroy_cache)
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
mt_remove_dbus_objects((cache_pool, dbo))
cfg.load()
# Get current cache name
cache_pool = cfg.om.get_object_by_path(dbo.CachePool)
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
rc, out, err = cmdhandler.lv_detach_cache(
dbo.lv_full_name(), detach_options, destroy_cache)
if rc == 0:
# The cache pool gets removed as hidden and put back to
# visible, so lets delete
cfg.om.remove_object(cache_pool, emit_signal=True)
cfg.om.remove_object(dbo, emit_signal=True)
cfg.load()
uncached_lv_path = cfg.om.get_object_path_by_lvm_id(lv_name)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
'LV with uuid %s and name %s not present!' %
(lv_uuid, lv_name))
return uncached_lv_path
@dbus.service.method(
@@ -829,4 +890,4 @@ class LvSnapShot(Lv):
(SNAPSHOT_INTERFACE, self.Uuid, self.lvm_id,
merge_options, job_state), cb, cbe, False,
job_state)
background.cmd_runner(r)
cfg.worker_q.put(r)

View File

@@ -14,22 +14,17 @@
import subprocess
import shlex
from fcntl import fcntl, F_GETFL, F_SETFL
import os
from os import O_NONBLOCK
import traceback
import sys
import tempfile
import time
import select
import copy
import re
try:
import simplejson as json
except ImportError:
import json
from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error, add_no_notify
from .cfg import LVM_CMD
from .utils import log_debug, log_error
except:
from cfg import LVM_CMD
from utils import log_debug, log_error
SHELL_PROMPT = "lvm> "
@@ -42,81 +37,43 @@ def _quote_arg(arg):
class LVMShellProxy(object):
@staticmethod
def _read(stream):
tmp = stream.read()
if tmp:
return tmp.decode("utf-8")
return ''
# Read until we get prompt back and a result
# @param: no_output Caller expects no output to report FD
# Returns stdout, report, stderr (report is JSON!)
def _read_until_prompt(self, no_output=False):
def _read_until_prompt(self):
prev_ec = None
stdout = ""
report = ""
stderr = ""
keep_reading = True
extra_passes = 3
report_json = {}
prev_report_len = 0
# Try reading from all FDs to prevent one from filling up and causing
# a hang. Keep reading until we get the prompt back and the report
# FD does not contain valid JSON
while keep_reading:
while not stdout.endswith(SHELL_PROMPT):
try:
rd_fd = [
self.lvm_shell.stdout.fileno(),
self.report_stream.fileno(),
self.lvm_shell.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
for r in ready[0]:
if r == self.lvm_shell.stdout.fileno():
stdout += LVMShellProxy._read(self.lvm_shell.stdout)
elif r == self.report_stream.fileno():
report += LVMShellProxy._read(self.report_stream)
elif r == self.lvm_shell.stderr.fileno():
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
# Check to see if the lvm process died on us
if self.lvm_shell.poll():
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
if stdout.endswith(SHELL_PROMPT):
if no_output:
keep_reading = False
else:
cur_report_len = len(report)
if cur_report_len != 0:
# Only bother to parse if we have more data
if prev_report_len != cur_report_len:
prev_report_len = cur_report_len
# Parse the JSON if it's good we are done,
# if not we will try to read some more.
try:
report_json = json.loads(report)
keep_reading = False
except ValueError:
pass
if keep_reading:
extra_passes -= 1
if extra_passes <= 0:
if len(report):
raise ValueError("Invalid json: %s" %
report)
else:
raise ValueError(
"lvm returned no JSON output!")
except IOError as ioe:
log_debug(str(ioe))
tmp = self.lvm_shell.stdout.read()
if tmp:
stdout += tmp.decode("utf-8")
except IOError:
# nothing written yet
pass
return stdout, report_json, stderr
# strip the prompt from the STDOUT before returning and grab the exit
# code if it's available
m = self.re.match(stdout)
if m:
prev_ec = int(m.group(2))
strip_idx = -1 * len(m.group(1))
else:
strip_idx = -1 * len(SHELL_PROMPT)
return stdout[:strip_idx], prev_ec
def _read_line(self):
while True:
try:
tmp = self.lvm_shell.stdout.readline()
if tmp:
return tmp.decode("utf-8")
except IOError:
pass
def _discard_echo(self, expected):
line = ""
while line != expected:
# GNU readline inserts some interesting characters at times...
line += self._read_line().replace(' \r', '')
def _write_cmd(self, cmd):
cmd_bytes = bytes(cmd, "utf-8")
@@ -124,90 +81,39 @@ class LVMShellProxy(object):
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
@staticmethod
def _make_non_block(stream):
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def _lvm_echos(self):
echo = False
cmd = "version\n"
self._write_cmd(cmd)
line = self._read_line()
if line == cmd:
echo = True
self._read_until_prompt()
return echo
def __init__(self):
# Create a temp directory
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
try:
# Lets create fifo for the report output
os.mkfifo(tmp_file, 0o600)
except FileExistsError:
pass
# We have to open non-blocking as the other side isn't open until
# we actually fork the process.
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
# Setup the environment for using our own socket for reporting
local_env = copy.deepcopy(os.environ)
local_env["LVM_REPORT_FD"] = "32"
local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# Disable the abort logic if lvm logs too much, which easily happens
# when utilizing the lvm shell.
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
self.re = re.compile(".*(\[(-?[0-9]+)\] lvm> $)", re.DOTALL)
# run the lvm shell
self.lvm_shell = subprocess.Popen(
[LVM_CMD + " 32>%s" % tmp_file],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
stderr=subprocess.PIPE, close_fds=True, shell=True)
[LVM_CMD], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
flags = fcntl(self.lvm_shell.stdout, F_GETFL)
fcntl(self.lvm_shell.stdout, F_SETFL, flags | O_NONBLOCK)
flags = fcntl(self.lvm_shell.stderr, F_GETFL)
fcntl(self.lvm_shell.stderr, F_SETFL, flags | O_NONBLOCK)
try:
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
# wait for the first prompt
self._read_until_prompt()
# wait for the first prompt
errors = self._read_until_prompt(no_output=True)[2]
if errors and len(errors):
raise RuntimeError(errors)
except:
raise
finally:
# These will get deleted when the FD count goes to zero so we
# can be sure to clean up correctly no matter how we finish
os.unlink(tmp_file)
os.rmdir(tmp_dir)
def get_error_msg(self):
# We got an error, lets go fetch the error message
self._write_cmd('lastlog\n')
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return 'No error reason provided! (missing "log" section)'
# Check to see if the version of LVM we are using is running with
# gnu readline which will echo our writes from stdin to stdout
self.echo = self._lvm_echos()
def call_lvm(self, argv, debug=False):
rc = 1
error_msg = ""
if self.lvm_shell.poll():
raise Exception(
self.lvm_shell.returncode,
"Underlying lvm shell process is not present!")
argv = add_no_notify(argv)
# create the command string
cmd = " ".join(_quote_arg(arg) for arg in argv)
cmd += "\n"
@@ -215,34 +121,46 @@ class LVMShellProxy(object):
# run the command by writing it to the shell's STDIN
self._write_cmd(cmd)
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
# If lvm is utilizing gnu readline, it echos stdin to stdout
if self.echo:
self._discard_echo(cmd)
# Parse the report to see what happened
if 'log' in report_json:
if report_json['log'][-1:][0]['log_ret_code'] == '1':
rc = 0
# read everything from the STDOUT to the next prompt
stdout, exit_code = self._read_until_prompt()
# read everything from STDERR if there's something (we waited for the
# prompt on STDOUT so there should be all or nothing at this point on
# STDERR)
stderr = None
try:
t_error = self.lvm_shell.stderr.read()
if t_error:
stderr = t_error.decode("utf-8")
except IOError:
# nothing on STDERR
pass
if exit_code is not None:
rc = exit_code
else:
# LVM does write to stderr even when it did complete successfully,
# so without having the exit code in the prompt we can never be
# sure.
if stderr:
rc = 1
else:
error_msg = self.get_error_msg()
rc = 0
if debug or rc != 0:
log_error(('CMD: %s' % cmd))
log_error(("EC = %d" % rc))
log_error(("ERROR_MSG=\n %s\n" % error_msg))
log_error(("STDOUT=\n %s\n" % stdout))
log_error(("STDERR=\n %s\n" % stderr))
return rc, report_json, error_msg
def exit_shell(self):
try:
self._write_cmd('exit\n')
except Exception as e:
log_error(str(e))
return (rc, stdout, stderr)
def __del__(self):
try:
self.lvm_shell.terminate()
except:
pass
self.lvm_shell.terminate()
if __name__ == "__main__":
@@ -252,18 +170,15 @@ if __name__ == "__main__":
while in_line:
in_line = input("lvm> ")
if in_line:
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
print(("RC: %d" % ret))
ret, out, err, = shell.call_lvm(in_line.split())
print(("RET: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception:
traceback.print_exc(file=sys.stdout)
finally:
print()

View File

@@ -15,12 +15,16 @@ import pprint as prettyprint
import os
import sys
from lvmdbusd import cmdhandler
from lvmdbusd.utils import log_debug, log_error
try:
from . import cmdhandler
from .utils import log_debug, log_error
except SystemError:
import cmdhandler
from utils import log_debug
class DataStore(object):
def __init__(self, usejson=True):
def __init__(self, usejson=None):
self.pvs = {}
self.vgs = {}
self.lvs = {}
@@ -38,7 +42,7 @@ class DataStore(object):
# self.refresh()
self.num_refreshes = 0
if usejson:
if usejson is None:
self.json = cmdhandler.supports_json()
else:
self.json = usejson
@@ -68,20 +72,6 @@ class DataStore(object):
else:
table[key] = record
@staticmethod
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
for p in c_pvs.values():
# Capture which PVs are associated with which VG
if p['vg_uuid'] not in c_pvs_in_vgs:
c_pvs_in_vgs[p['vg_uuid']] = []
if p['vg_name']:
c_pvs_in_vgs[p['vg_uuid']].append(
(p['pv_name'], p['pv_uuid']))
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
@@ -95,7 +85,18 @@ class DataStore(object):
c_pvs, p['pv_uuid'], p,
['pvseg_start', 'pvseg_size', 'segtype'])
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
for p in c_pvs.values():
# Capture which PVs are associated with which VG
if p['vg_uuid'] not in c_pvs_in_vgs:
c_pvs_in_vgs[p['vg_uuid']] = []
if p['vg_name']:
c_pvs_in_vgs[p['vg_uuid']].append(
(p['pv_name'], p['pv_uuid']))
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
@@ -135,7 +136,17 @@ class DataStore(object):
i['pvseg_size'] = i['pv_pe_count']
i['segtype'] = 'free'
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
for p in c_pvs.values():
# Capture which PVs are associated with which VG
if p['vg_uuid'] not in c_pvs_in_vgs:
c_pvs_in_vgs[p['vg_uuid']] = []
if p['vg_name']:
c_pvs_in_vgs[p['vg_uuid']].append(
(p['pv_name'], p['pv_uuid']))
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
return c_pvs, c_lookup, c_pvs_in_vgs
@@ -426,12 +437,6 @@ class DataStore(object):
rc.append(self.pvs[self.pv_path_to_uuid[s]])
return rc
def pv_missing(self, pv_uuid):
if pv_uuid in self.pvs:
if self.pvs[pv_uuid]['pv_missing'] == '':
return False
return True
def fetch_vgs(self, vg_name):
if not vg_name:
return self.vgs.values()
@@ -515,7 +520,6 @@ if __name__ == "__main__":
print("PVS")
for v in ds.pvs.values():
pp.pprint(v)
print('PV missing is %s' % ds.pv_missing(v['pv_uuid']))
print("VGS")
for v in ds.vgs.values():

View File

@@ -10,7 +10,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from lvmdbusd import main
import lvmdbusd
if __name__ == '__main__':
sys.exit(main())
sys.exit(lvmdbusd.main())

View File

@@ -10,27 +10,25 @@
from . import cfg
from . import objectmanager
from . import utils
from .cfg import BUS_NAME, BASE_INTERFACE, BASE_OBJ_PATH, MANAGER_OBJ_PATH
from .cfg import BASE_INTERFACE, BASE_OBJ_PATH, MANAGER_OBJ_PATH
import threading
from . import cmdhandler
import time
import signal
import dbus
import dbus.mainloop.glib
from . import lvmdb
# noinspection PyUnresolvedReferences
from gi.repository import GLib
from .fetch import StateUpdate
from .fetch import load
from .manager import Manager
from .background import background_reaper
import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error
from .utils import log_debug
import argparse
import os
import sys
from .cmdhandler import LvmFlightRecorder
from .request import RequestEntry
from .refresh import handle_external_event, event_complete
class Lvm(objectmanager.ObjectManager):
@@ -38,16 +36,54 @@ class Lvm(objectmanager.ObjectManager):
super(Lvm, self).__init__(object_path, BASE_INTERFACE)
def _discard_pending_refreshes():
# We just handled a refresh, if we have any in the queue they can be
# removed because by definition they are older than the refresh we just did.
# As we limit the number of refreshes getting into the queue
# we should only ever have one to remove.
requests = []
while not cfg.worker_q.empty():
try:
r = cfg.worker_q.get(block=False)
if r.method != handle_external_event:
requests.append(r)
else:
# Make sure we make this event complete even though it didn't
# run, otherwise no other events will get processed
event_complete()
break
except queue.Empty:
break
# Any requests we removed, but did not discard need to be re-queued
for r in requests:
cfg.worker_q.put(r)
def process_request():
while cfg.run.value != 0:
# noinspection PyBroadException
try:
req = cfg.worker_q.get(True, 5)
start = cfg.db.num_refreshes
log_debug(
"Running method: %s with args %s" %
(str(req.method), str(req.arguments)))
req.run_cmd()
log_debug("Method complete ")
end = cfg.db.num_refreshes
num_refreshes = end - start
if num_refreshes > 0:
_discard_pending_refreshes()
if num_refreshes > 1:
log_debug(
"Inspect method %s for too many refreshes" %
(str(req.method)))
log_debug("Complete ")
except queue.Empty:
pass
except Exception:
@@ -55,63 +91,34 @@ def process_request():
utils.log_error("process_request exception: \n%s" % st)
def check_bb_size(value):
v = int(value)
if v < 0:
raise argparse.ArgumentTypeError(
"positive integers only ('%s' invalid)" % value)
return v
def main():
start = time.time()
# Add simple command line handling
parser = argparse.ArgumentParser()
parser.add_argument(
"--udev", action='store_true',
help="Use udev for updating state",
default=False,
dest='use_udev')
parser.add_argument(
"--debug", action='store_true',
help="Dump debug messages", default=False,
dest='debug')
parser.add_argument(
"--nojson", action='store_false',
help="Do not use LVM JSON output (disables lvmshell)", default=True,
dest='use_json')
parser.add_argument(
"--lvmshell", action='store_true',
help="Use the lvm shell, not fork & exec lvm",
default=False,
dest='use_lvm_shell')
parser.add_argument(
"--blackboxsize",
help="Size of the black box flight recorder, 0 to disable",
default=10,
type=check_bb_size,
dest='bb_size')
parser.add_argument("--udev", action='store_true',
help="Use udev for updating state", default=False,
dest='use_udev')
parser.add_argument("--debug", action='store_true',
help="Dump debug messages", default=False,
dest='debug')
parser.add_argument("--nojson", action='store_false',
help="Do not use LVM JSON output", default=None,
dest='use_json')
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
# Ensure that we get consistent output for parsing stdout/stderr
os.environ["LC_ALL"] = "C"
cfg.args = parser.parse_args()
cfg.create_request_entry = RequestEntry
args = parser.parse_args()
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
if cfg.args.use_lvm_shell and not cfg.args.use_json:
log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
cfg.DEBUG = args.debug
# List of threads that we start up
thread_list = []
start = time.time()
# Install signal handlers
for s in [signal.SIGHUP, signal.SIGINT]:
try:
@@ -122,59 +129,54 @@ def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
cmdhandler.set_execution(cfg.args.use_lvm_shell)
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
base_name = dbus.service.BusName(BASE_INTERFACE, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
cfg.db = lvmdb.DataStore(cfg.args.use_json)
cfg.load = load
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
cfg.db = lvmdb.DataStore(args.use_json)
# Start up thread to monitor pv moves
thread_list.append(
threading.Thread(target=background_reaper, name="pv_move_reaper"))
# Using a thread to process requests.
thread_list.append(threading.Thread(target=process_request))
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
cfg.load = updater.load
cfg.load(refresh=False, emit_signal=False)
cfg.loop = GLib.MainLoop()
for thread in thread_list:
thread.damon = True
thread.start()
# Add udev watching
if cfg.args.use_udev:
log_debug('Utilizing udev to trigger updates')
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
for process in thread_list:
process.damon = True
process.start()
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
'Service ready! total time= %.2f, lvm time= %.2f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
# Add udev watching
if args.use_udev:
log_debug('Utilizing udev to trigger updates')
udevwatch.add()
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
for thread in thread_list:
thread.join()
if args.use_udev:
udevwatch.remove()
for process in thread_list:
process.join()
except KeyboardInterrupt:
utils.handler(signal.SIGINT, None)
return 0

View File

@@ -6,6 +6,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .automatedproperties import AutomatedProperties
from . import utils
@@ -13,13 +14,14 @@ from .cfg import MANAGER_INTERFACE
import dbus
from . import cfg
from . import cmdhandler
from .fetch import load_pvs, load_vgs
from .request import RequestEntry
from . import udevwatch
from .refresh import event_add
# noinspection PyPep8Naming
class Manager(AutomatedProperties):
_Version_meta = ("s", MANAGER_INTERFACE)
_Version_meta = ("t", MANAGER_INTERFACE)
def __init__(self, object_path):
super(Manager, self).__init__(object_path)
@@ -27,31 +29,31 @@ class Manager(AutomatedProperties):
@property
def Version(self):
return dbus.String('1.0.0')
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return '1.0.0'
@staticmethod
def _pv_create(device, create_options):
# Check to see if we are already trying to create a PV for an existing
# PV
pv = cfg.om.get_object_path_by_uuid_lvm_id(device, device)
pv = cfg.om.get_object_path_by_uuid_lvm_id(
device, device, None, False)
if pv:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE, "PV %s Already exists!" % device)
MANAGER_INTERFACE, "PV Already exists!")
created_pv = []
rc, out, err = cmdhandler.pv_create(create_options, [device])
Manager.handle_execute(rc, out, err)
return cfg.om.get_object_path_by_lvm_id(device)
if rc == 0:
pvs = load_pvs([device], emit_signal=True)[0]
for p in pvs:
created_pv = p.dbus_object_path()
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_pv
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
@@ -78,8 +80,20 @@ class Manager(AutomatedProperties):
MANAGER_INTERFACE, 'object path = %s not found' % p)
rc, out, err = cmdhandler.vg_create(create_options, pv_devices, name)
Manager.handle_execute(rc, out, err)
return cfg.om.get_object_path_by_lvm_id(name)
created_vg = "/"
if rc == 0:
vgs = load_vgs([name], emit_signal=True)[0]
for v in vgs:
created_vg = v.dbus_object_path()
# Update the PVS
load_pvs(refresh=True, emit_signal=True, cache_refresh=False)
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
return created_vg
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
@@ -100,10 +114,6 @@ class Manager(AutomatedProperties):
# This is a diagnostic and should not be run in normal operation, so
# lets remove the log entries for refresh as it's implied.
# Run an internal diagnostic on the object manager look up tables
lc = cfg.om.validate_lookups()
rc = cfg.load(log=False)
if rc != 0:
@@ -111,7 +121,7 @@ class Manager(AutomatedProperties):
'bg_black', 'fg_light_red')
else:
utils.log_debug('Manager.Refresh - exit %d' % (rc))
return rc + lc
return rc
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
@@ -131,28 +141,11 @@ class Manager(AutomatedProperties):
r = RequestEntry(-1, Manager._refresh, (), cb, cbe, False)
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE)
def FlightRecorderDump(self):
"""
Dump the flight recorder to syslog
"""
cfg.blackbox.dump()
@staticmethod
def _lookup_by_lvm_id(key):
p = cfg.om.get_object_path_by_uuid_lvm_id(key, key)
if not p:
p = '/'
utils.log_debug('LookUpByLvmId: key = %s, result = %s' % (key, p))
return p
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def LookUpByLvmId(self, key, cb, cbe):
out_signature='o')
def LookUpByLvmId(self, key):
"""
Given a lvm id in one of the forms:
@@ -166,50 +159,29 @@ class Manager(AutomatedProperties):
:param key: The lookup value
:return: Return the object path. If object not found you will get '/'
"""
r = RequestEntry(-1, Manager._lookup_by_lvm_id, (key,), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _use_lvm_shell(yes_no):
return dbus.Boolean(cmdhandler.set_execution(yes_no))
p = cfg.om.get_object_path_by_uuid_lvm_id(
key, key, gen_new=False)
if p:
return p
return '/'
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='b', out_signature='b',
async_callbacks=('cb', 'cbe'))
def UseLvmShell(self, yes_no, cb, cbe):
in_signature='b')
def UseLvmShell(self, yes_no):
"""
Allow the client to enable/disable lvm shell, used for testing
:param yes_no:
:param cb: dbus python call back parameter, not client visible
:param cbe: dbus python error call back parameter, not client visible
:return: Boolean
:return: Nothing
"""
r = RequestEntry(-1, Manager._use_lvm_shell, (yes_no,), cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _external_event(command):
utils.log_debug("Processing _external_event= %s" % command,
'bg_black', 'fg_orange')
cfg.load()
cmdhandler.set_execution(yes_no)
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
utils.log_debug("ExternalEvent %s" % command)
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.got_external_event = True
r = RequestEntry(
-1, Manager._external_event, (command,), None, None, False)
cfg.worker_q.put(r)
event_add((command,))
return dbus.Int32(0)
@staticmethod
@@ -219,8 +191,15 @@ class Manager(AutomatedProperties):
activate, cache, device_path,
major_minor, scan_options)
Manager.handle_execute(rc, out, err)
return '/'
if rc == 0:
# This could potentially change the state quite a bit, so lets
# update everything to be safe
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
MANAGER_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@dbus.service.method(
dbus_interface=MANAGER_INTERFACE,

View File

@@ -12,9 +12,8 @@ import threading
import traceback
import dbus
import os
import copy
from . import cfg
from .utils import log_debug, pv_obj_path_generate, log_error
from .utils import log_debug
from .automatedproperties import AutomatedProperties
@@ -32,12 +31,14 @@ class ObjectManager(AutomatedProperties):
self._id_to_object_path = {}
self.rlock = threading.RLock()
@staticmethod
def _get_managed_objects(obj):
with obj.rlock:
@dbus.service.method(
dbus_interface="org.freedesktop.DBus.ObjectManager",
out_signature='a{oa{sa{sv}}}')
def GetManagedObjects(self):
with self.rlock:
rc = {}
try:
for k, v in list(obj._objects.items()):
for k, v in list(self._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
except Exception:
@@ -45,14 +46,6 @@ class ObjectManager(AutomatedProperties):
sys.exit(1)
return rc
@dbus.service.method(
dbus_interface="org.freedesktop.DBus.ObjectManager",
out_signature='a{oa{sa{sv}}}', async_callbacks=('cb', 'cbe'))
def GetManagedObjects(self, cb, cbe):
r = cfg.create_request_entry(-1, ObjectManager._get_managed_objects,
(self, ), cb, cbe, False)
cfg.worker_q.put(r)
def locked(self):
"""
If some external code need to run across a number of different
@@ -77,37 +70,12 @@ class ObjectManager(AutomatedProperties):
log_debug(('SIGNAL: InterfacesRemoved(%s, %s)' %
(str(object_path), str(interface_list))))
def validate_lookups(self):
with self.rlock:
tmp_lookups = copy.deepcopy(self._id_to_object_path)
# iterate over all we know, removing from the copy. If all is well
# we will have zero items left over
for path, md in self._objects.items():
obj, lvm_id, uuid = md
if lvm_id:
assert path == tmp_lookups[lvm_id]
del tmp_lookups[lvm_id]
if uuid:
assert path == tmp_lookups[uuid]
del tmp_lookups[uuid]
rc = len(tmp_lookups)
if rc:
# Error condition
log_error("_id_to_object_path has extraneous lookups!")
for key, path in tmp_lookups.items():
log_error("Key= %s, path= %s" % (key, path))
return rc
def _lookup_add(self, obj, path, lvm_id, uuid):
"""
Store information about what we added to the caches so that we
can remove it cleanly
:param obj: The dbus object we are storing
:param lvm_id: The lvm id for the asset
:param lvm_id: The user name for the asset
:param uuid: The uuid for the asset
:return:
"""
@@ -117,12 +85,7 @@ class ObjectManager(AutomatedProperties):
self._lookup_remove(path)
self._objects[path] = (obj, lvm_id, uuid)
# Make sure we have one or the other
assert lvm_id or uuid
if lvm_id:
self._id_to_object_path[lvm_id] = path
self._id_to_object_path[lvm_id] = path
if uuid:
self._id_to_object_path[uuid] = path
@@ -131,13 +94,8 @@ class ObjectManager(AutomatedProperties):
# Note: Only called internally, lock implied
if obj_path in self._objects:
(obj, lvm_id, uuid) = self._objects[obj_path]
if lvm_id in self._id_to_object_path:
del self._id_to_object_path[lvm_id]
if uuid in self._id_to_object_path:
del self._id_to_object_path[uuid]
del self._id_to_object_path[lvm_id]
del self._id_to_object_path[uuid]
del self._objects[obj_path]
def lookup_update(self, dbus_obj, new_uuid, new_lvm_id):
@@ -167,7 +125,7 @@ class ObjectManager(AutomatedProperties):
path, props = dbus_object.emit_data()
# print('Registering object path %s for %s' %
# (path, dbus_object.lvm_id))
# (path, dbus_object.lvm_id))
# We want fast access to the object by a number of different ways
# so we use multiple hashs with different keys
@@ -215,7 +173,7 @@ class ObjectManager(AutomatedProperties):
def get_object_by_uuid_lvm_id(self, uuid, lvm_id):
with self.rlock:
return self.get_object_by_path(
self.get_object_path_by_uuid_lvm_id(uuid, lvm_id))
self.get_object_path_by_uuid_lvm_id(uuid, lvm_id, None, False))
def get_object_by_lvm_id(self, lvm_id):
"""
@@ -223,9 +181,8 @@ class ObjectManager(AutomatedProperties):
:param lvm_id: The lvm identifier
"""
with self.rlock:
lookup_rc = self._id_lookup(lvm_id)
if lookup_rc:
return self.get_object_by_path(lookup_rc)
if lvm_id in self._id_to_object_path:
return self.get_object_by_path(self._id_to_object_path[lvm_id])
return None
def get_object_path_by_lvm_id(self, lvm_id):
@@ -235,9 +192,8 @@ class ObjectManager(AutomatedProperties):
:return: Object path or '/' if not found
"""
with self.rlock:
lookup_rc = self._id_lookup(lvm_id)
if lookup_rc:
return lookup_rc
if lvm_id in self._id_to_object_path:
return self._id_to_object_path[lvm_id]
return '/'
def _uuid_verify(self, path, uuid, lvm_id):
@@ -250,111 +206,78 @@ class ObjectManager(AutomatedProperties):
:return: None
"""
# This gets called when we found an object based on lvm_id, ensure
# uuid is correct too, as they can change. There is no durable
# non-changeable name in lvm
# uuid is correct too, as they can change
if lvm_id != uuid:
if uuid and uuid not in self._id_to_object_path:
if uuid not in self._id_to_object_path:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
def _lvm_id_verify(self, path, uuid, lvm_id):
def _return_lookup(self, uuid, lvm_identifier):
"""
Ensure lvm_id is present for a successful uuid lookup
NOTE: Internal call, assumes under object manager lock
:param path: Path to object we looked up
:param uuid: uuid used to find object
:param lvm_id: lvm_id to verify
:return: None
We found an identifier, so lets return the path to the found object
:param uuid: The lvm uuid
:param lvm_identifier: The lvm_id used to find object
:return:
"""
# This gets called when we found an object based on uuid, ensure
# lvm_id is correct too, as they can change. There is no durable
# non-changeable name in lvm
if lvm_id != uuid:
if lvm_id and lvm_id not in self._id_to_object_path:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
def _id_lookup(self, the_id):
path = None
if the_id:
# The _id_to_object_path contains hash keys for everything, so
# uuid and lvm_id
if the_id in self._id_to_object_path:
path = self._id_to_object_path[the_id]
else:
if "/" in the_id:
if the_id.startswith('/'):
# We could have a pv device path lookup that failed,
# lets try canonical form and try again.
canonical = os.path.realpath(the_id)
if canonical in self._id_to_object_path:
path = self._id_to_object_path[canonical]
else:
vg, lv = the_id.split("/", 1)
int_lvm_id = vg + "/" + ("[%s]" % lv)
if int_lvm_id in self._id_to_object_path:
path = self._id_to_object_path[int_lvm_id]
path = self._id_to_object_path[lvm_identifier]
self._uuid_verify(path, uuid, lvm_identifier)
return path
def get_object_path_by_uuid_lvm_id(self, uuid, lvm_id, path_create=None):
def get_object_path_by_uuid_lvm_id(self, uuid, lvm_id, path_create=None,
gen_new=True):
"""
For a given lvm asset return the dbus object path registered for it.
This method first looks up by uuid and then by lvm_id. You
can search by just one by setting uuid == lvm_id (uuid or lvm_id).
If the object is not found and path_create is a not None, the
path_create function will be called to create a new object path and
register it with the object manager for the specified uuid & lvm_id.
Note: If path create is not None, uuid and lvm_id cannot be equal
:param uuid: The uuid for the lvm object we are searching for
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
:param path_create: If not None, create the path using this function if
we fail to find the object by uuid or lvm_id.
:returns None if lvm asset not found and path_create == None otherwise
a valid dbus object path
For a given lvm asset return the dbus object registered to it. If the
object is not found and gen_new == True and path_create is a valid
function we will create a new path, register it and return it.
:param uuid: The uuid for the lvm object
:param lvm_id: The lvm name
:param path_create: If true create an object path if not found
:param gen_new: The function used to create the new path
"""
with self.rlock:
assert lvm_id
assert uuid
if path_create:
assert uuid != lvm_id
if gen_new:
assert path_create
# Check for Manager.LookUpByLvmId query, we cannot
# check/verify/update the uuid and lvm_id lookups so don't!
if uuid == lvm_id:
path = self._id_lookup(lvm_id)
path = None
if lvm_id in self._id_to_object_path:
self._return_lookup(uuid, lvm_id)
if "/" in lvm_id:
vg, lv = lvm_id.split("/", 1)
int_lvm_id = vg + "/" + ("[%s]" % lv)
if int_lvm_id in self._id_to_object_path:
self._return_lookup(uuid, int_lvm_id)
elif lvm_id.startswith('/'):
# We could have a pv device path lookup that failed,
# lets try canonical form and try again.
canonical = os.path.realpath(lvm_id)
if canonical in self._id_to_object_path:
self._return_lookup(uuid, canonical)
if uuid and uuid in self._id_to_object_path:
# If we get here it indicates that we found the object, but
# the lvm_id lookup failed. In the case of a rename, the uuid
# will be correct, but the lvm_id will be wrong and vise versa.
# If the lvm_id does not equal the uuid, lets fix up the table
# so that lookups will be handled correctly.
path = self._id_to_object_path[uuid]
# In some cases we are looking up by one or the other, don't
# update when they are the same.
if uuid != lvm_id:
obj = self.get_object_by_path(path)
self._lookup_add(obj, path, lvm_id, uuid)
else:
# We have a uuid and a lvm_id we can do sanity checks to ensure
# that they are consistent
if gen_new:
path = path_create()
self._lookup_add(None, path, lvm_id, uuid)
# If a PV is missing it's device path is '[unknown]' or some
# other text derivation of unknown. When we find that a PV is
# missing we will clear out the lvm_id as it's likely not unique
# and thus not useful and potentially harmful for lookups.
if path_create == pv_obj_path_generate and \
cfg.db.pv_missing(uuid):
lvm_id = None
# Lets check for the uuid first
path = self._id_lookup(uuid)
if path:
# Verify the lvm_id is sane
self._lvm_id_verify(path, uuid, lvm_id)
else:
# Unable to find by UUID, lets lookup by lvm_id
path = self._id_lookup(lvm_id)
if path:
# Verify the uuid is sane
self._uuid_verify(path, uuid, lvm_id)
else:
# We have exhausted all lookups, let's create if we can
if path_create:
path = path_create()
self._lookup_add(None, path, lvm_id, uuid)
# print('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
# (uuid, lvm_id, str(path_create), str(gen_new), path))
# pprint('get_object_path_by_lvm_id(%s, %s, %s, %s: return %s' %
# (uuid, lvm_id, str(path_create), str(gen_new), path))
return path

View File

@@ -55,6 +55,9 @@ class PvState(State):
return self.lvm_path
def _lv_object_list(self, vg_name):
# Note we are returning "a(oa(tts))"
rc = []
if vg_name:
for lv in sorted(cfg.db.pv_contained_lv(self.lvm_id)):
@@ -66,7 +69,7 @@ class PvState(State):
lv_uuid, full_name, path_create)
rc.append((lv_path, segs))
return rc
return dbus.Array(rc, signature="(oa(tts))")
# noinspection PyUnusedLocal,PyPep8Naming
def __init__(self, lvm_path, Uuid, Name,
@@ -135,30 +138,23 @@ class Pv(AutomatedProperties):
def _remove(pv_uuid, pv_name, remove_options):
# Remove the PV, if successful then remove from the model
# Make sure we have a dbus object representing it
Pv.validate_dbus_object(pv_uuid, pv_name)
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
Pv.handle_execute(rc, out, err)
return '/'
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@staticmethod
def validate_dbus_object(pv_uuid, pv_name):
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if not dbo:
if dbo:
rc, out, err = cmdhandler.pv_remove(pv_name, remove_options)
if rc == 0:
cfg.om.remove_object(dbo, True)
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return dbo
return '/'
@dbus.service.method(
dbus_interface=PV_INTERFACE,
@@ -175,11 +171,22 @@ class Pv(AutomatedProperties):
@staticmethod
def _resize(pv_uuid, pv_name, new_size_bytes, resize_options):
# Make sure we have a dbus object representing it
Pv.validate_dbus_object(pv_uuid, pv_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
if dbo:
rc, out, err = cmdhandler.pv_resize(pv_name, new_size_bytes,
resize_options)
Pv.handle_execute(rc, out, err)
if rc == 0:
dbo.refresh()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
@@ -197,10 +204,21 @@ class Pv(AutomatedProperties):
@staticmethod
def _allocation_enabled(pv_uuid, pv_name, yes_no, allocation_options):
# Make sure we have a dbus object representing it
Pv.validate_dbus_object(pv_uuid, pv_name)
rc, out, err = cmdhandler.pv_allocatable(
pv_name, yes_no, allocation_options)
Pv.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(pv_uuid, pv_name)
if dbo:
rc, out, err = cmdhandler.pv_allocatable(
pv_name, yes_no, allocation_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
PV_INTERFACE,
'PV with uuid %s and name %s not present!' %
(pv_uuid, pv_name))
return '/'
@dbus.service.method(
@@ -223,20 +241,26 @@ class Pv(AutomatedProperties):
@property
def PeSegments(self):
if len(self.state.pe_segments):
return dbus.Array(self.state.pe_segments, signature='(tt)')
return self.state.pe_segments
return dbus.Array([], '(tt)')
@property
def Exportable(self):
return dbus.Boolean(self.state.attr[1] == 'x')
if self.state.attr[1] == 'x':
return True
return False
@property
def Allocatable(self):
return dbus.Boolean(self.state.attr[0] == 'a')
if self.state.attr[0] == 'a':
return True
return False
@property
def Missing(self):
return dbus.Boolean(self.state.attr[2] == 'm')
if self.state.attr[2] == 'm':
return True
return False
def object_path(self):
return self._object_path
@@ -251,8 +275,8 @@ class Pv(AutomatedProperties):
@property
def Lv(self):
return dbus.Array(self.state.lv, signature="(oa(tts))")
return self.state.lv
@property
def Vg(self):
return dbus.ObjectPath(self.state.vg_path)
return self.state.vg_path

View File

@@ -0,0 +1,45 @@
# Copyright (C) 2015-2016 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
# 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, see <http://www.gnu.org/licenses/>.
# Try and minimize the refreshes we do.
import threading
from .request import RequestEntry
from . import cfg
from . import utils
_rlock = threading.RLock()
_count = 0
def handle_external_event(command):
utils.log_debug("External event: '%s'" % command)
event_complete()
cfg.load()
def event_add(params):
global _rlock
global _count
with _rlock:
if _count == 0:
_count += 1
r = RequestEntry(
-1, handle_external_event,
params, None, None, False)
cfg.worker_q.put(r)
def event_complete():
global _rlock
global _count
with _rlock:
if _count > 0:
_count -= 1
return _count

View File

@@ -13,12 +13,13 @@ from gi.repository import GLib
from .job import Job
from . import cfg
import traceback
from .utils import log_error, mt_async_result
from .utils import log_error
class RequestEntry(object):
def __init__(self, tmo, method, arguments, cb, cb_error,
return_tuple=True, job_state=None):
self.tmo = tmo
self.method = method
self.arguments = arguments
self.cb = cb
@@ -34,32 +35,25 @@ class RequestEntry(object):
self._return_tuple = return_tuple
self._job_state = job_state
if tmo < 0:
if self.tmo < 0:
# Client is willing to block forever
pass
elif tmo == 0:
self._return_job()
else:
# Note: using 990 instead of 1000 for second to ms conversion to
# account for overhead. Goal is to return just before the
# timeout amount has expired. Better to be a little early than
# late.
self.timer_id = GLib.timeout_add(
tmo * 990, RequestEntry._request_timeout, self)
self.timer_id = GLib.timeout_add_seconds(
tmo, RequestEntry._request_timeout, self)
@staticmethod
def _request_timeout(r):
"""
Method which gets called when the timer runs out!
:param r: RequestEntry which timed out
:return: Result of timer_expired
:return: Nothing
"""
return r.timer_expired()
r.timer_expired()
def _return_job(self):
# Return job is only called when we create a request object or when
# we pop a timer. In both cases we are running in the correct context
# and do not need to schedule the call back in main context.
self._job = Job(self, self._job_state)
cfg.om.register_object(self._job, True)
if self._return_tuple:
@@ -116,9 +110,9 @@ class RequestEntry(object):
if error_rc == 0:
if self.cb:
if self._return_tuple:
mt_async_result(self.cb, (result, '/'))
self.cb((result, '/'))
else:
mt_async_result(self.cb, result)
self.cb(result)
else:
if self.cb_error:
if not error_exception:
@@ -129,14 +123,15 @@ class RequestEntry(object):
else:
error_exception = Exception(error_msg)
mt_async_result(self.cb_error, error_exception)
self.cb_error(error_exception)
else:
# We have a job and it's complete, indicate that it's done.
# TODO: We need to signal the job is done too.
self._job.Complete = True
self._job = None
def register_error(self, error_rc, error_message, error_exception):
self._reg_ending('/', error_rc, error_message, error_exception)
self._reg_ending(None, error_rc, error_message, error_exception)
def register_result(self, result):
self._reg_ending(result)

View File

@@ -8,42 +8,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pyudev
import threading
from .refresh import event_add
from . import cfg
from .request import RequestEntry
from . import utils
observer = None
observer_lock = threading.RLock()
_udev_lock = threading.RLock()
_udev_count = 0
def udev_add():
global _udev_count
with _udev_lock:
if _udev_count == 0:
_udev_count += 1
# Place this on the queue so any other operations will sequence
# behind it
r = RequestEntry(
-1, _udev_event, (), None, None, False)
cfg.worker_q.put(r)
def udev_complete():
global _udev_count
with _udev_lock:
if _udev_count > 0:
_udev_count -= 1
def _udev_event():
utils.log_debug("Processing udev event")
udev_complete()
cfg.load()
# noinspection PyUnusedLocal
@@ -68,24 +36,19 @@ def filter_event(action, device):
refresh = True
if refresh:
udev_add()
event_add(('udev',))
def add():
with observer_lock:
global observer
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('block')
observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()
global observer
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('block')
observer = pyudev.MonitorObserver(monitor, filter_event)
observer.start()
def remove():
with observer_lock:
global observer
if observer:
observer.stop()
observer = None
return True
return False
global observer
observer.stop()
observer = None

View File

@@ -13,14 +13,15 @@ import inspect
import ctypes
import os
import string
import datetime
import dbus
from lvmdbusd import cfg
# noinspection PyUnresolvedReferences
from gi.repository import GLib
import threading
import dbus.service
import dbus.mainloop.glib
try:
from . import cfg
except SystemError:
import cfg
STDOUT_TTY = os.isatty(sys.stdout.fileno())
@@ -148,27 +149,17 @@ def add_properties(xml, interface, props):
:param props: Output from get_properties
:return: updated XML string
"""
root = Et.fromstring(xml)
if props:
root = Et.fromstring(xml)
interface_element = None
# Check to see if interface is present
for c in root:
# print c.attrib['name']
if c.attrib['name'] == interface:
interface_element = c
break
# Interface is not present, lets create it so we have something to
# attach the properties too
if interface_element is None:
interface_element = Et.Element("interface", name=interface)
root.append(interface_element)
# Add the properties
for p in props:
temp = '<property type="%s" name="%s" access="%s"/>\n' % \
(p['p_t'], p['p_name'], p['p_access'])
interface_element.append(Et.fromstring(temp))
for p in props:
temp = '<property type="%s" name="%s" access="%s"/>\n' % \
(p['p_t'], p['p_name'], p['p_access'])
c.append(Et.fromstring(temp))
return Et.tostring(root, encoding='utf8')
return xml
@@ -244,7 +235,7 @@ def parse_tags(tags):
if len(tags):
if ',' in tags:
return tags.split(',')
return dbus.Array(sorted([tags]), signature='s')
return sorted([tags])
return dbus.Array([], signature='s')
@@ -252,13 +243,7 @@ def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
if STDOUT_TTY:
msg = "%s: %d:%d - %s" % \
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
os.getpid(), tid, msg)
else:
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
@@ -273,7 +258,7 @@ def _common_log(msg, *attributes):
# @param msg Message to output to stdout
# @return None
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
if cfg.DEBUG:
_common_log(msg, *attributes)
@@ -497,100 +482,3 @@ def validate_tag(interface, tag):
raise dbus.exceptions.DBusException(
interface, 'tag (%s) contains invalid character, allowable set(%s)'
% (tag, _ALLOWABLE_TAG_CH))
def add_no_notify(cmdline):
"""
Given a command line to execute we will see if `--config` is present, if it
is we will add the global/notify_dbus=0 to it, otherwise we will append it
to the end of the list.
:param: cmdline: The command line to inspect
:type: cmdline: list
:return: cmdline with notify_dbus config option present
:rtype: list
"""
# Only after we have seen an external event will be disable lvm from sending
# us one when we call lvm
if cfg.got_external_event:
if 'help' in cmdline:
return cmdline
if '--config' in cmdline:
for i, arg in enumerate(cmdline):
if arg == '--config':
if len(cmdline) <= i+1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i+1] += " global/notify_dbus=0"
break
else:
cmdline.extend(['--config', 'global/notify_dbus=0'])
return cmdline
# The methods below which start with mt_* are used to execute the desired code
# on the the main thread of execution to alleviate any issues the dbus-python
# library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread!
def _async_result(call_back, results):
log_debug('Results = %s' % str(results))
call_back(results)
# Return result in main thread
def mt_async_result(call_back, results):
GLib.idle_add(_async_result, call_back, results)
# Take the supplied function and run it on the main thread and not wait for
# a result!
def mt_run_no_wait(function, param):
GLib.idle_add(function, param)
# Run the supplied function and arguments on the main thread and wait for them
# to complete while allowing the ability to get the return value too.
#
# Example:
# result = MThreadRunner(foo, arg1, arg2).done()
#
class MThreadRunner(object):
@staticmethod
def runner(obj):
# noinspection PyProtectedMember
obj._run()
with obj.cond:
obj.function_complete = True
obj.cond.notify_all()
def __init__(self, function, *args):
self.f = function
self.rc = None
self.args = args
self.function_complete = False
self.cond = threading.Condition(threading.Lock())
def done(self):
GLib.idle_add(MThreadRunner.runner, self)
with self.cond:
if not self.function_complete:
self.cond.wait()
return self.rc
def _run(self):
if len(self.args):
self.rc = self.f(*self.args)
else:
self.rc = self.f()
def _remove_objects(dbus_objects_rm):
for o in dbus_objects_rm:
cfg.om.remove_object(o, emit_signal=True)
# Remove dbus objects from main thread
def mt_remove_dbus_objects(objs):
MThreadRunner(_remove_objects, objs).done()

View File

@@ -19,7 +19,7 @@ from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects
from .utils import round_size
from .job import JobState
@@ -78,7 +78,7 @@ class VgState(State):
(pv_name, pv_uuid) = p
rc.append(cfg.om.get_object_path_by_uuid_lvm_id(
pv_uuid, pv_name, pv_obj_path_generate))
return rc
return dbus.Array(rc, signature='o')
def __init__(self, Uuid, Name, Fmt,
SizeBytes, FreeBytes, SysId, ExtentSizeBytes,
@@ -145,35 +145,29 @@ class Vg(AutomatedProperties):
@staticmethod
def fetch_new_lv(vg_name, lv_name):
return cfg.om.get_object_path_by_lvm_id("%s/%s" % (vg_name, lv_name))
@staticmethod
def handle_execute(rc, out, err):
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
@staticmethod
def validate_dbus_object(vg_uuid, vg_name):
dbo = cfg.om.get_object_by_uuid_lvm_id(vg_uuid, vg_name)
if not dbo:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(vg_uuid, vg_name))
return dbo
cfg.load()
return cfg.om.get_object_by_lvm_id("%s/%s" % (vg_name, lv_name))
@staticmethod
def _rename(uuid, vg_name, new_name, rename_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_rename(
vg_name, new_name, rename_options)
Vg.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_rename(vg_name, new_name,
rename_options)
if rc == 0:
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -190,10 +184,31 @@ class Vg(AutomatedProperties):
@staticmethod
def _remove(uuid, vg_name, remove_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
Vg.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
# Remove the VG, if successful then remove from the model
rc, out, err = cmdhandler.vg_remove(vg_name, remove_options)
if rc == 0:
# Remove the VG
cfg.om.remove_object(dbo, True)
# If an LV has hidden LVs, things can get quite involved,
# especially if it's the last thin pool to get removed, so
# lets refresh all
cfg.load()
else:
# Need to work on error handling, need consistent
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -208,9 +223,26 @@ class Vg(AutomatedProperties):
@staticmethod
def _change(uuid, vg_name, change_options):
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
Vg.handle_execute(rc, out, err)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_change(change_options, vg_name)
# To use an example with d-feet (Method input)
# {"activate": __import__('gi.repository.GLib', globals(),
# locals(), ['Variant']).Variant("s", "n")}
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
# TODO: This should be broken into a number of different methods
@@ -231,24 +263,34 @@ class Vg(AutomatedProperties):
@staticmethod
def _reduce(uuid, vg_name, missing, pv_object_paths, reduce_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
pv_devices = []
if dbo:
pv_devices = []
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
# If pv_object_paths is not empty, then get the device paths
if pv_object_paths and len(pv_object_paths) > 0:
for pv_op in pv_object_paths:
pv = cfg.om.get_object_by_path(pv_op)
if pv:
pv_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Object path not found = %s!' % pv_op)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
Vg.handle_execute(rc, out, err)
rc, out, err = cmdhandler.vg_reduce(vg_name, missing, pv_devices,
reduce_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -265,26 +307,36 @@ class Vg(AutomatedProperties):
@staticmethod
def _extend(uuid, vg_name, pv_object_paths, extend_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
extend_devices = []
if dbo:
extend_devices = []
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
for i in pv_object_paths:
pv = cfg.om.get_object_by_path(i)
if pv:
extend_devices.append(pv.lvm_id)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
if rc == 0:
cfg.load()
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV Object path not found = %s!' % i)
if len(extend_devices):
rc, out, err = cmdhandler.vg_extend(vg_name, extend_devices,
extend_options)
Vg.handle_execute(rc, out, err)
VG_INTERFACE, 'No pv_object_paths provided!')
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'No pv_object_paths provided!')
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return '/'
@dbus.service.method(
@@ -321,24 +373,33 @@ class Vg(AutomatedProperties):
create_options):
# Make sure we have a dbus object representing it
pv_dests = []
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
Vg.validate_dbus_object(uuid, vg_name)
if dbo:
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Destination (%s) not found' % pr[0])
if len(pv_dests_and_ranges):
for pr in pv_dests_and_ranges:
pv_dbus_obj = cfg.om.get_object_by_path(pr[0])
if not pv_dbus_obj:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'PV Destination (%s) not found' % pr[0])
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
pv_dests.append((pv_dbus_obj.lvm_id, pr[1], pr[2]))
rc, out, err = cmdhandler.vg_lv_create(
vg_name, create_options, name, size_bytes, pv_dests)
rc, out, err = cmdhandler.vg_lv_create(
vg_name, create_options, name, size_bytes, pv_dests)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
if rc == 0:
return Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -374,13 +435,25 @@ class Vg(AutomatedProperties):
def _lv_create_linear(uuid, vg_name, name, size_bytes,
thin_pool, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_linear(
vg_name, create_options, name, size_bytes, thin_pool)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_linear(
vg_name, create_options, name, size_bytes, thin_pool)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -400,12 +473,24 @@ class Vg(AutomatedProperties):
def _lv_create_striped(uuid, vg_name, name, size_bytes, num_stripes,
stripe_size_kb, thin_pool, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_striped(
vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_striped(
vg_name, create_options, name, size_bytes,
num_stripes, stripe_size_kb, thin_pool)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -428,11 +513,25 @@ class Vg(AutomatedProperties):
def _lv_create_mirror(uuid, vg_name, name, size_bytes,
num_copies, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_mirror(
vg_name, create_options, name, size_bytes, num_copies)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -453,12 +552,26 @@ class Vg(AutomatedProperties):
def _lv_create_raid(uuid, vg_name, name, raid_type, size_bytes,
num_stripes, stripe_size_kb, create_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.vg_lv_create_raid(
vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb)
Vg.handle_execute(rc, out, err)
return Vg.fetch_new_lv(vg_name, name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.vg_lv_create_raid(
vg_name, create_options, name, raid_type, size_bytes,
num_stripes, stripe_size_kb)
if rc == 0:
created_lv = Vg.fetch_new_lv(vg_name, name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
return created_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -479,27 +592,35 @@ class Vg(AutomatedProperties):
def _create_pool(uuid, vg_name, meta_data_lv, data_lv,
create_options, create_method):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
# Retrieve the full names for the metadata and data lv
md = cfg.om.get_object_by_path(meta_data_lv)
data = cfg.om.get_object_by_path(data_lv)
if md and data:
if dbo and md and data:
new_name = data.Name
rc, out, err = create_method(
md.lv_full_name(), data.lv_full_name(), create_options)
if rc == 0:
mt_remove_dbus_objects((md, data))
cfg.om.remove_object(md, emit_signal=True)
cfg.om.remove_object(data, emit_signal=True)
Vg.handle_execute(rc, out, err)
cache_pool_lv = Vg.fetch_new_lv(vg_name, new_name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
msg = ""
if not dbo:
msg += 'VG with uuid %s and name %s not present!' % \
(uuid, vg_name)
if not md:
msg += 'Meta data LV with object path %s not present!' % \
(meta_data_lv)
@@ -510,7 +631,7 @@ class Vg(AutomatedProperties):
raise dbus.exceptions.DBusException(VG_INTERFACE, msg)
return Vg.fetch_new_lv(vg_name, new_name)
return cache_pool_lv
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -544,21 +665,33 @@ class Vg(AutomatedProperties):
pv_devices = []
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
# Check for existence of pv object paths
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
if dbo:
# Check for existence of pv object paths
for p in pv_object_paths:
pv = cfg.om.get_object_by_path(p)
if pv:
pv_devices.append(pv.Name)
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV object path = %s not found' % p)
rc, out, err = cmdhandler.pv_tag(
pv_devices, tags_add, tags_del, tag_options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE, 'PV object path = %s not found' % p)
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
rc, out, err = cmdhandler.pv_tag(
pv_devices, tags_add, tags_del, tag_options)
Vg.handle_execute(rc, out, err)
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -596,12 +729,25 @@ class Vg(AutomatedProperties):
@staticmethod
def _vg_add_rm_tags(uuid, vg_name, tags_add, tags_del, tag_options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options)
Vg.handle_execute(rc, out, err)
return '/'
if dbo:
rc, out, err = cmdhandler.vg_tag(
vg_name, tags_add, tags_del, tag_options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -638,10 +784,23 @@ class Vg(AutomatedProperties):
@staticmethod
def _vg_change_set(uuid, vg_name, method, value, options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = method(vg_name, value, options)
Vg.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = method(vg_name, value, options)
if rc == 0:
dbo.refresh()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -681,7 +840,9 @@ class Vg(AutomatedProperties):
cfg.worker_q.put(r)
def _attribute(self, pos, ch):
return dbus.Boolean(self.state.attr[pos] == ch)
if self.state.attr[pos] == ch:
return True
return False
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -699,11 +860,23 @@ class Vg(AutomatedProperties):
def _vg_activate_deactivate(uuid, vg_name, activate, control_flags,
options):
# Make sure we have a dbus object representing it
Vg.validate_dbus_object(uuid, vg_name)
rc, out, err = cmdhandler.activate_deactivate(
'vgchange', vg_name, activate, control_flags, options)
Vg.handle_execute(rc, out, err)
return '/'
dbo = cfg.om.get_object_by_uuid_lvm_id(uuid, vg_name)
if dbo:
rc, out, err = cmdhandler.activate_deactivate(
'vgchange', vg_name, activate, control_flags, options)
if rc == 0:
cfg.load()
return '/'
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
VG_INTERFACE,
'VG with uuid %s and name %s not present!' %
(uuid, vg_name))
@dbus.service.method(
dbus_interface=VG_INTERFACE,
@@ -735,11 +908,11 @@ class Vg(AutomatedProperties):
@property
def Pvs(self):
return dbus.Array(self.state.Pvs, signature='o')
return self.state.Pvs
@property
def Lvs(self):
return dbus.Array(self.state.Lvs, signature='o')
return self.state.Lvs
@property
def lvm_id(self):

View File

@@ -16,7 +16,7 @@ top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmetad-core.c
SOURCES2 = lvmetactl.c
SOURCES2 = testclient.c
TARGETS = lvmetad lvmetactl
@@ -28,19 +28,22 @@ CFLOW_TARGET = lvmetad
include $(top_builddir)/make.tmpl
CFLAGS_lvmetactl.o += $(EXTRA_EXEC_CFLAGS)
CFLAGS_lvmetad-core.o += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS)
CLDFLAGS += -L$(top_builddir)/libdaemon/server
CFLAGS += $(EXTRA_EXEC_CFLAGS)
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) -ldaemonserver $(LIBS)
$(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 $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
CLEAN_TARGETS += lvmetactl.o

View File

@@ -25,7 +25,6 @@
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
#define LVMETAD_DISABLE_REASON_VGRESTORE "VGRESTORE"
#define LVMETAD_DISABLE_REASON_REPAIR "REPAIR"
struct volume_group;

View File

@@ -203,9 +203,8 @@ struct vg_info {
#define GLFL_DISABLE_REASON_LVM1 0x00000008
#define GLFL_DISABLE_REASON_DUPLICATES 0x00000010
#define GLFL_DISABLE_REASON_VGRESTORE 0x00000020
#define GLFL_DISABLE_REASON_REPAIR 0x00000040
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_REPAIR | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_VGRESTORE)
#define VGFL_INVALID 0x00000001
@@ -258,21 +257,6 @@ static void destroy_metadata_hashes(lvmetad_state *s)
dm_hash_iterate(n, s->pvid_to_pvmeta)
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
dm_hash_iterate(n, s->vgid_to_vgname)
dm_free(dm_hash_get_data(s->vgid_to_vgname, n));
dm_hash_iterate(n, s->vgname_to_vgid)
dm_free(dm_hash_get_data(s->vgname_to_vgid, n));
dm_hash_iterate(n, s->vgid_to_info)
dm_free(dm_hash_get_data(s->vgid_to_info, n));
dm_hash_iterate(n, s->device_to_pvid)
dm_free(dm_hash_get_data(s->device_to_pvid, n));
dm_hash_iterate(n, s->pvid_to_vgid)
dm_free(dm_hash_get_data(s->pvid_to_vgid, n));
dm_hash_destroy(s->pvid_to_pvmeta);
dm_hash_destroy(s->vgid_to_metadata);
dm_hash_destroy(s->vgid_to_vgname);
@@ -615,7 +599,7 @@ static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvi
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
if (!outdated_pvs) {
if (!(outdated_pvs = config_tree_from_string_without_dup_node_check("outdated_pvs/pv_list = []")) ||
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();
@@ -808,8 +792,7 @@ static int _update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
if ((mode == REMOVE_EMPTY) && vgid_old) {
/* This copies the vgid_old string, doesn't reference it. */
if ((dm_hash_lookup(to_check, vgid_old) != (void*) 1) &&
!dm_hash_insert(to_check, vgid_old, (void*) 1)) {
if (!dm_hash_insert(to_check, vgid_old, (void*) 1)) {
ERROR(s, "update_pvid_to_vgid out of memory for hash insert vgid_old %s", vgid_old);
goto abort_daemon;
}
@@ -885,13 +868,16 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
/* free the unmapped data */
if (info_lookup)
dm_free(info_lookup);
if (meta_lookup)
dm_config_destroy(meta_lookup);
if (name_lookup)
dm_free(name_lookup);
if (outdated_pvs_lookup)
dm_config_destroy(outdated_pvs_lookup);
dm_free(info_lookup);
dm_free(name_lookup);
dm_free(vgid_lookup);
if (vgid_lookup)
dm_free(vgid_lookup);
return 1;
}
@@ -1218,8 +1204,10 @@ static int _update_metadata_add_new(lvmetad_state *s, const char *new_name, cons
out:
out_free:
if (!new_name_dup || !new_vgid_dup || abort_daemon) {
dm_free(new_name_dup);
dm_free(new_vgid_dup);
if (new_name_dup)
dm_free(new_name_dup);
if (new_vgid_dup)
dm_free(new_vgid_dup);
ERROR(s, "lvmetad could not be updated and is aborting.");
exit(EXIT_FAILURE);
}
@@ -1261,8 +1249,8 @@ static int _update_metadata(lvmetad_state *s, const char *arg_name, const char *
const char *old_vgid = NULL;
const char *new_vgid = NULL;
const char *new_metadata_vgid;
int new_seq;
int old_seq = -1;
int new_seq = -1;
int needs_repair = 0;
int abort_daemon = 0;
int retval = 0;
@@ -1809,7 +1797,8 @@ static response pv_gone(lvmetad_state *s, request r)
}
dm_config_destroy(pvmeta);
dm_free(old_pvid);
if (old_pvid)
dm_free(old_pvid);
return daemon_reply_simple("OK", NULL );
}
@@ -1922,7 +1911,7 @@ static response pv_found(lvmetad_state *s, request r)
const char *arg_pvid = NULL;
const char *arg_pvid_lookup = NULL;
const char *new_pvid = NULL;
char *new_pvid_dup = NULL;
const char *new_pvid_dup = NULL;
const char *arg_name = NULL;
const char *arg_vgid = NULL;
const char *arg_vgid_lookup = NULL;
@@ -2085,7 +2074,7 @@ static response pv_found(lvmetad_state *s, request r)
if (!(new_pvid_dup = dm_strdup(new_pvid)))
goto nomem_free1;
if (!dm_hash_insert_binary(s->device_to_pvid, &new_device, sizeof(new_device), new_pvid_dup))
if (!dm_hash_insert_binary(s->device_to_pvid, &new_device, sizeof(new_device), (char *)new_pvid_dup))
goto nomem_free2;
if (!dm_hash_insert(s->pvid_to_pvmeta, new_pvid, new_pvmeta))
@@ -2121,8 +2110,6 @@ static response pv_found(lvmetad_state *s, request r)
DEBUGLOG(s, "pv_found ignore duplicate device %" PRIu64 " of existing PV for pvid %s",
arg_device, arg_pvid);
dm_config_destroy(new_pvmeta);
/* device_to_pvid no longer references prev_pvid_lookup */
dm_free((void*)prev_pvid_on_dev);
s->flags |= GLFL_DISABLE;
s->flags |= GLFL_DISABLE_REASON_DUPLICATES;
return reply_fail("Ignore duplicate PV");
@@ -2133,7 +2120,7 @@ static response pv_found(lvmetad_state *s, request r)
if (!(new_pvid_dup = dm_strdup(new_pvid)))
goto nomem_free1;
if (!dm_hash_insert_binary(s->device_to_pvid, &arg_device, sizeof(arg_device), new_pvid_dup))
if (!dm_hash_insert_binary(s->device_to_pvid, &arg_device, sizeof(arg_device), (char *)new_pvid_dup))
goto nomem_free2;
if (!dm_hash_insert(s->pvid_to_pvmeta, new_pvid, new_pvmeta))
@@ -2233,7 +2220,8 @@ static response pv_found(lvmetad_state *s, request r)
}
/* This was unhashed from device_to_pvid above. */
dm_free((void *)prev_pvid_on_dev);
if (prev_pvid_on_dev)
dm_free((void *)prev_pvid_on_dev);
return daemon_reply_simple("OK",
"status = %s", vg_status,
@@ -2245,7 +2233,7 @@ static response pv_found(lvmetad_state *s, request r)
NULL);
nomem_free2:
dm_free(new_pvid_dup);
dm_free((char *)new_pvid_dup);
nomem_free1:
dm_config_destroy(new_pvmeta);
nomem:
@@ -2367,8 +2355,6 @@ static response set_global_info(lvmetad_state *s, request r)
if ((reason = daemon_request_str(r, "disable_reason", NULL))) {
if (strstr(reason, LVMETAD_DISABLE_REASON_DIRECT))
reason_flags |= GLFL_DISABLE_REASON_DIRECT;
if (strstr(reason, LVMETAD_DISABLE_REASON_REPAIR))
reason_flags |= GLFL_DISABLE_REASON_REPAIR;
if (strstr(reason, LVMETAD_DISABLE_REASON_LVM1))
reason_flags |= GLFL_DISABLE_REASON_LVM1;
if (strstr(reason, LVMETAD_DISABLE_REASON_DUPLICATES))
@@ -2432,9 +2418,8 @@ static response get_global_info(lvmetad_state *s, request r)
pid = (int)daemon_request_int(r, "pid", 0);
if (s->flags & GLFL_DISABLE) {
snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s%s%s",
snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s%s",
(s->flags & GLFL_DISABLE_REASON_DIRECT) ? LVMETAD_DISABLE_REASON_DIRECT "," : "",
(s->flags & GLFL_DISABLE_REASON_REPAIR) ? LVMETAD_DISABLE_REASON_REPAIR "," : "",
(s->flags & GLFL_DISABLE_REASON_LVM1) ? LVMETAD_DISABLE_REASON_LVM1 "," : "",
(s->flags & GLFL_DISABLE_REASON_DUPLICATES) ? LVMETAD_DISABLE_REASON_DUPLICATES "," : "",
(s->flags & GLFL_DISABLE_REASON_VGRESTORE) ? LVMETAD_DISABLE_REASON_VGRESTORE "," : "");
@@ -2572,12 +2557,14 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
dm_hash_iterate(n, ht) {
const char *key = dm_hash_get_key(ht, n),
*val = dm_hash_get_data(ht, n);
buffer_append(buf, " ");
if (int_key)
(void) dm_asprintf(&append, " %d = \"%s\"\n", *(const int*)key, val);
(void) dm_asprintf(&append, "%d = \"%s\"", *(const int*)key, val);
else
(void) dm_asprintf(&append, " %s = \"%s\"\n", key, val);
(void) dm_asprintf(&append, "%s = \"%s\"", key, val);
if (append)
buffer_append(buf, append);
buffer_append(buf, "\n");
dm_free(append);
}
buffer_append(buf, "}\n");
@@ -2595,9 +2582,11 @@ static void _dump_info_version(struct buffer *buf, struct dm_hash_table *ht, con
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
(void) dm_asprintf(&append, " %s = %lld\n", key, (long long)info->external_version);
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);
}
@@ -2616,9 +2605,11 @@ static void _dump_info_flags(struct buffer *buf, struct dm_hash_table *ht, const
while (n) {
const char *key = dm_hash_get_key(ht, n);
info = dm_hash_get_data(ht, n);
(void) dm_asprintf(&append, " %s = %llx\n", key, (long long)info->flags);
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);
}
@@ -2754,8 +2745,7 @@ static response handler(daemon_state s, client_handle h, request r)
"expected = %s", state->token,
"received = %s", token,
"update_pid = " FMTd64, (int64_t)state->update_pid,
"reason = %s", "another command has populated the cache",
NULL);
"reason = %s", "another command has populated the cache");
}
DEBUGLOG(state, "token_update end len %d pid %d new token %s",
@@ -2788,8 +2778,7 @@ static response handler(daemon_state s, client_handle h, request r)
"expected = %s", state->token,
"received = %s", token,
"update_pid = " FMTd64, (int64_t)state->update_pid,
"reason = %s", "another command has populated the cache",
NULL);
"reason = %s", "another command has populated the cache");
}
/* If a pid doing update was cancelled, ignore its update messages. */
@@ -2804,8 +2793,7 @@ static response handler(daemon_state s, client_handle h, request r)
"expected = %s", state->token,
"received = %s", token,
"update_pid = " FMTd64, (int64_t)state->update_pid,
"reason = %s", "another command has populated the lvmetad cache",
NULL);
"reason = %s", "another command has populated the lvmetad cache");
}
pthread_mutex_unlock(&state->token_lock);

View File

@@ -19,12 +19,10 @@ SOURCES = lvmlockd-core.c
ifeq ("@BUILD_LOCKDSANLOCK@", "yes")
SOURCES += lvmlockd-sanlock.c
LOCK_LIBS += -lsanlock_client
endif
ifeq ("@BUILD_LOCKDDLM@", "yes")
SOURCES += lvmlockd-dlm.c
LOCK_LIBS += -ldlm_lt
endif
TARGETS = lvmlockd lvmlockctl
@@ -33,17 +31,29 @@ TARGETS = lvmlockd lvmlockctl
include $(top_builddir)/make.tmpl
CFLAGS += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(RT_LIBS) $(DAEMON_LIBS) -ldevmapper $(PTHREAD_LIBS)
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) $(LOCK_LIBS) -ldaemonserver $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
lvmlockctl: lvmlockctl.o $(top_builddir)/libdaemon/client/libdaemonclient.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmlockctl.o $(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)

View File

@@ -19,7 +19,6 @@
#include "lvm-version.h"
#include "lvmetad-client.h"
#include "lvmlockd-client.h"
#include "dm-ioctl.h" /* for DM_UUID_LEN */
/* #include <assert.h> */
#include <errno.h>
@@ -3304,6 +3303,7 @@ static int work_init_lv(struct action *act)
lm_type = ls->lm_type;
memcpy(vg_args, ls->vg_args, MAX_ARGS);
free_offset = ls->free_lock_offset;
ls->free_lock_offset = 0;
}
pthread_mutex_unlock(&lockspaces_mutex);
@@ -4431,7 +4431,7 @@ static void client_recv_action(struct client *cl)
return;
}
req.cft = config_tree_from_string_without_dup_node_check(req.buffer.mem);
req.cft = dm_config_from_string(req.buffer.mem);
if (!req.cft) {
log_error("client recv %u config_from_string error", cl->id);
buffer_destroy(&req.buffer);
@@ -4907,10 +4907,14 @@ static int get_lockd_vgs(struct list_head *vg_lockd)
continue;
for (lv_cn = md_cn->child; lv_cn; lv_cn = lv_cn->sib) {
snprintf(find_str_path, PATH_MAX, "%s/lock_type", lv_cn->key);
lock_type = dm_config_find_str(lv_cn, find_str_path, NULL);
if (!lock_type)
continue;
snprintf(find_str_path, PATH_MAX, "%s/lock_args", lv_cn->key);
lock_args = dm_config_find_str(lv_cn, find_str_path, NULL);
if (!lock_args)
continue;
snprintf(find_str_path, PATH_MAX, "%s/id", lv_cn->key);
lv_uuid = dm_config_find_str(lv_cn, find_str_path, NULL);
@@ -4956,7 +4960,7 @@ out:
return rv;
}
static char _dm_uuid[DM_UUID_LEN];
static char _dm_uuid[64];
static char *get_dm_uuid(char *dm_name)
{
@@ -5175,17 +5179,20 @@ static void adopt_locks(void)
* Get list of lockspaces from lock managers.
* Get list of VGs from lvmetad with a lockd type.
* Get list of active lockd type LVs from /dev.
*
* ECONNREFUSED means the lock manager is not running.
* This is expected for at least one of them.
*/
if (lm_support_dlm() && lm_is_running_dlm()) {
if (lm_support_dlm()) {
rv = lm_get_lockspaces_dlm(&ls_found);
if (rv < 0)
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
}
if (lm_support_sanlock() && lm_is_running_sanlock()) {
if (lm_support_sanlock()) {
rv = lm_get_lockspaces_sanlock(&ls_found);
if (rv < 0)
if ((rv < 0) && (rv != -ECONNREFUSED))
goto fail;
}
@@ -5262,7 +5269,7 @@ static void adopt_locks(void)
list_for_each_entry_safe(ls1, l1safe, &ls_found, list) {
/* The dlm global lockspace is special and doesn't match a VG. */
if ((ls1->lm_type == LD_LM_DLM) && !strcmp(ls1->name, gl_lsname_dlm)) {
if (!strcmp(ls1->name, gl_lsname_dlm)) {
list_del(&ls1->list);
free(ls1);
continue;

View File

@@ -224,10 +224,7 @@ static int lock_lv_offset_from_args(char *lv_args, uint64_t *lock_lv_offset)
if (rv < 0)
return rv;
errno = 0;
*lock_lv_offset = strtoull(offset_str, NULL, 10);
if (errno)
return -1;
return 0;
}
@@ -938,9 +935,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct sanlk_resourced rd;
uint64_t offset;
uint64_t start_offset;
int rv;
int round = 0;
if (daemon_test) {
*free_offset = (1048576 * LV_LOCK_BEGIN) + (1048576 * (daemon_test_lv_count + 1));
@@ -953,22 +948,9 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
rd.rs.num_disks = 1;
strncpy(rd.rs.disks[0].path, lms->ss.host_id_disk.path, SANLK_PATH_LEN-1);
if (ls->free_lock_offset)
offset = ls->free_lock_offset;
else
offset = lms->align_size * LV_LOCK_BEGIN;
start_offset = offset;
offset = lms->align_size * LV_LOCK_BEGIN;
while (1) {
if (offset >= start_offset && round) {
/* This indicates the all space are allocated. */
log_debug("S %s init_lv_san read back to start offset %llu",
ls->name, (unsigned long long)offset);
rv = -EMSGSIZE;
return rv;
}
rd.rs.disks[0].offset = offset;
memset(rd.rs.name, 0, SANLK_NAME_LEN);
@@ -978,14 +960,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t *free_offset)
/* This indicates the end of the device is reached. */
log_debug("S %s find_free_lock_san read limit offset %llu",
ls->name, (unsigned long long)offset);
/* remember the NO SPACE offset, if no free area left,
* search from this offset after extend */
*free_offset = offset;
offset = lms->align_size * LV_LOCK_BEGIN;
round = 1;
continue;
return -EMSGSIZE;
}
/*

View File

@@ -27,14 +27,18 @@ CFLOW_TARGET = lvmpolld
include $(top_builddir)/make.tmpl
CFLAGS += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_srcdir)/libdaemon/server
LDFLAGS += -L$(top_builddir)/libdaemon/server $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
LIBS += $(DAEMON_LIBS) -ldaemonserver -ldevmapper $(PTHREAD_LIBS)
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) $(LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
install_lvmpolld: lvmpolld
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)

View File

@@ -19,12 +19,10 @@
#define MIN_ARGV_SIZE 8
static const char *const polling_ops[] = {
[PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE,
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN
};
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)
{

View File

@@ -19,8 +19,6 @@
#include <fcntl.h>
#include <signal.h>
static const char LVM_SYSTEM_DIR[] = "LVM_SYSTEM_DIR=";
static char *_construct_full_lvname(const char *vgname, const char *lvname)
{
char *name;
@@ -54,7 +52,7 @@ static char *_construct_lvm_system_dir_env(const char *sysdir)
*env = '\0';
if (sysdir && dm_snprintf(env, l, "%s%s", LVM_SYSTEM_DIR, sysdir) < 0) {
if (sysdir && dm_snprintf(env, l, "LVM_SYSTEM_DIR=%s", sysdir) < 0) {
dm_free(env);
env = NULL;
}
@@ -261,8 +259,8 @@ static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdl
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\t%s\"%s\"\n", LVM_SYSTEM_DIR,
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + (sizeof(LVM_SYSTEM_DIR) - 1)) : "<undefined>")) > 0)
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);

View File

@@ -207,10 +207,6 @@ Optional feature arguments are:
block, then the cache block is invalidated.
To enable passthrough mode the cache must be clean.
metadata2 : use version 2 of the metadata. This stores the dirty bits
in a separate btree, which improves speed of shutting
down the cache.
A policy called 'default' is always registered. This is an alias for
the policy we currently think is giving best all round performance.
@@ -290,7 +286,7 @@ message, which takes an arbitrary number of cblock ranges. Each cblock
range's end value is "one past the end", meaning 5-10 expresses a range
of values from 5 to 9. Each cblock must be expressed as a decimal
value, in the future a variant message that takes cblock ranges
expressed in hexadecimal may be needed to better support efficient
expressed in hexidecimal may be needed to better support efficient
invalidation of larger caches. The cache must be in passthrough mode
when invalidate_cblocks is used.

View File

@@ -11,57 +11,23 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
<offset> [<#opt_params> <opt_params>]
<cipher>
Encryption cipher, encryption mode and Initial Vector (IV) generator.
The cipher specifications format is:
cipher[:keycount]-chainmode-ivmode[:ivopts]
Encryption cipher and an optional IV generation mode.
(In format cipher[:keycount]-chainmode-ivmode[:ivopts]).
Examples:
des
aes-cbc-essiv:sha256
aes-xts-plain64
serpent-xts-plain64
twofish-ecb
Cipher format also supports direct specification with kernel crypt API
format (selected by capi: prefix). The IV specification is the same
as for the first format type.
This format is mainly used for specification of authenticated modes.
The crypto API cipher specifications format is:
capi:cipher_api_spec-ivmode[:ivopts]
Examples:
capi:cbc(aes)-essiv:sha256
capi:xts(aes)-plain64
Examples of authenticated modes:
capi:gcm(aes)-random
capi:authenc(hmac(sha256),xts(aes))-random
capi:rfc7539(chacha20,poly1305)-random
The /proc/crypto contains a list of curently loaded crypto modes.
/proc/crypto contains supported crypto modes
<key>
Key used for encryption. It is encoded either as a hexadecimal number
or it can be passed as <key_string> prefixed with single colon
character (':') for keys residing in kernel keyring service.
Key used for encryption. It is encoded as a hexadecimal number.
You can only use key sizes that are valid for the selected cipher
in combination with the selected iv mode.
Note that for some iv modes the key string can contain additional
keys (for example IV seed) so the key contains more parts concatenated
into a single string.
<key_string>
The kernel keyring key is identified by string in following format:
<key_size>:<key_type>:<key_description>.
<key_size>
The encryption key size in bytes. The kernel key payload size must match
the value passed in <key_size>.
<key_type>
Either 'logon' or 'user' kernel key type.
<key_description>
The kernel keyring key description crypt target should look for
when loading key of <key_type>.
<keycount>
Multi-key compatibility mode. You can define <keycount> keys and
then sectors are encrypted according to their offsets (sector 0 uses key0;
@@ -110,32 +76,6 @@ submit_from_crypt_cpus
thread because it benefits CFQ to have writes submitted using the
same context.
integrity:<bytes>:<type>
The device requires additional <bytes> metadata per-sector stored
in per-bio integrity structure. This metadata must by provided
by underlying dm-integrity target.
The <type> can be "none" if metadata is used only for persistent IV.
For Authenticated Encryption with Additional Data (AEAD)
the <type> is "aead". An AEAD mode additionally calculates and verifies
integrity for the encrypted device. The additional space is then
used for storing authentication tag (and persistent IV if needed).
sector_size:<bytes>
Use <bytes> as the encryption unit instead of 512 bytes sectors.
This option can be in range 512 - 4096 bytes and must be power of two.
Virtual device will announce this size as a minimal IO and logical sector.
iv_large_sectors
IV generators will use sector number counted in <sector_size> units
instead of default 512 bytes sectors.
For example, if <sector_size> is 4096 bytes, plain64 IV for the second
sector will be 8 (without flag) and 1 if iv_large_sectors is present.
The <iv_offset> must be multiple of <sector_size> (in 512 bytes units)
if this flag is specified.
Example scripts
===============
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
@@ -145,13 +85,7 @@ https://gitlab.com/cryptsetup/cryptsetup
[[
#!/bin/sh
# Create a crypt device using dmsetup
dmsetup create crypt1 --table "0 `blockdev --getsz $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
]]
[[
#!/bin/sh
# Create a crypt device using dmsetup when encryption key is stored in keyring service
dmsetup create crypt2 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 :32:logon:my_prefix:my_key 0 $1 0"
dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
]]
[[

View File

@@ -16,12 +16,12 @@ Example scripts
[[
#!/bin/sh
# Create device delaying rw operation for 500ms
echo "0 `blockdev --getsz $1` delay $1 0 500" | dmsetup create delayed
echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed
]]
[[
#!/bin/sh
# Create device delaying only write operation for 500ms and
# splitting reads and writes to different devices $1 $2
echo "0 `blockdev --getsz $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
]]

View File

@@ -42,7 +42,7 @@ Optional feature parameters:
<direction>: Either 'r' to corrupt reads or 'w' to corrupt writes.
'w' is incompatible with drop_writes.
<value>: The value (from 0-255) to write.
<flags>: Perform the replacement only if bio->bi_opf has all the
<flags>: Perform the replacement only if bio->bi_rw has all the
selected flags set.
Examples:

View File

@@ -1,199 +0,0 @@
The dm-integrity target emulates a block device that has additional
per-sector tags that can be used for storing integrity information.
A general problem with storing integrity tags with every sector is that
writing the sector and the integrity tag must be atomic - i.e. in case of
crash, either both sector and integrity tag or none of them is written.
To guarantee write atomicity, the dm-integrity target uses journal, it
writes sector data and integrity tags into a journal, commits the journal
and then copies the data and integrity tags to their respective location.
The dm-integrity target can be used with the dm-crypt target - in this
situation the dm-crypt target creates the integrity data and passes them
to the dm-integrity target via bio_integrity_payload attached to the bio.
In this mode, the dm-crypt and dm-integrity targets provide authenticated
disk encryption - if the attacker modifies the encrypted device, an I/O
error is returned instead of random data.
The dm-integrity target can also be used as a standalone target, in this
mode it calculates and verifies the integrity tag internally. In this
mode, the dm-integrity target can be used to detect silent data
corruption on the disk or in the I/O path.
When loading the target for the first time, the kernel driver will format
the device. But it will only format the device if the superblock contains
zeroes. If the superblock is neither valid nor zeroed, the dm-integrity
target can't be loaded.
To use the target for the first time:
1. overwrite the superblock with zeroes
2. load the dm-integrity target with one-sector size, the kernel driver
will format the device
3. unload the dm-integrity target
4. read the "provided_data_sectors" value from the superblock
5. load the dm-integrity target with the the target size
"provided_data_sectors"
6. if you want to use dm-integrity with dm-crypt, load the dm-crypt target
with the size "provided_data_sectors"
Target arguments:
1. the underlying block device
2. the number of reserved sector at the beginning of the device - the
dm-integrity won't read of write these sectors
3. the size of the integrity tag (if "-" is used, the size is taken from
the internal-hash algorithm)
4. mode:
D - direct writes (without journal) - in this mode, journaling is
not used and data sectors and integrity tags are written
separately. In case of crash, it is possible that the data
and integrity tag doesn't match.
J - journaled writes - data and integrity tags are written to the
journal and atomicity is guaranteed. In case of crash,
either both data and tag or none of them are written. The
journaled mode degrades write throughput twice because the
data have to be written twice.
R - recovery mode - in this mode, journal is not replayed,
checksums are not checked and writes to the device are not
allowed. This mode is useful for data recovery if the
device cannot be activated in any of the other standard
modes.
5. the number of additional arguments
Additional arguments:
journal_sectors:number
The size of journal, this argument is used only if formatting the
device. If the device is already formatted, the value from the
superblock is used.
interleave_sectors:number
The number of interleaved sectors. This values is rounded down to
a power of two. If the device is already formatted, the value from
the superblock is used.
buffer_sectors:number
The number of sectors in one buffer. The value is rounded down to
a power of two.
The tag area is accessed using buffers, the buffer size is
configurable. The large buffer size means that the I/O size will
be larger, but there could be less I/Os issued.
journal_watermark:number
The journal watermark in percents. When the size of the journal
exceeds this watermark, the thread that flushes the journal will
be started.
commit_time:number
Commit time in milliseconds. When this time passes, the journal is
written. The journal is also written immediatelly if the FLUSH
request is received.
internal_hash:algorithm(:key) (the key is optional)
Use internal hash or crc.
When this argument is used, the dm-integrity target won't accept
integrity tags from the upper target, but it will automatically
generate and verify the integrity tags.
You can use a crc algorithm (such as crc32), then integrity target
will protect the data against accidental corruption.
You can also use a hmac algorithm (for example
"hmac(sha256):0123456789abcdef"), in this mode it will provide
cryptographic authentication of the data without encryption.
When this argument is not used, the integrity tags are accepted
from an upper layer target, such as dm-crypt. The upper layer
target should check the validity of the integrity tags.
journal_crypt:algorithm(:key) (the key is optional)
Encrypt the journal using given algorithm to make sure that the
attacker can't read the journal. You can use a block cipher here
(such as "cbc(aes)") or a stream cipher (for example "chacha20",
"salsa20", "ctr(aes)" or "ecb(arc4)").
The journal contains history of last writes to the block device,
an attacker reading the journal could see the last sector nubmers
that were written. From the sector numbers, the attacker can infer
the size of files that were written. To protect against this
situation, you can encrypt the journal.
journal_mac:algorithm(:key) (the key is optional)
Protect sector numbers in the journal from accidental or malicious
modification. To protect against accidental modification, use a
crc algorithm, to protect against malicious modification, use a
hmac algorithm with a key.
This option is not needed when using internal-hash because in this
mode, the integrity of journal entries is checked when replaying
the journal. Thus, modified sector number would be detected at
this stage.
block_size:number
The size of a data block in bytes. The larger the block size the
less overhead there is for per-block integrity metadata.
Supported values are 512, 1024, 2048 and 4096 bytes. If not
specified the default block size is 512 bytes.
The journal mode (D/J), buffer_sectors, journal_watermark, commit_time can
be changed when reloading the target (load an inactive table and swap the
tables with suspend and resume). The other arguments should not be changed
when reloading the target because the layout of disk data depend on them
and the reloaded target would be non-functional.
The layout of the formatted block device:
* reserved sectors (they are not used by this target, they can be used for
storing LUKS metadata or for other purpose), the size of the reserved
area is specified in the target arguments
* superblock (4kiB)
* magic string - identifies that the device was formatted
* version
* log2(interleave sectors)
* integrity tag size
* the number of journal sections
* provided data sectors - the number of sectors that this target
provides (i.e. the size of the device minus the size of all
metadata and padding). The user of this target should not send
bios that access data beyond the "provided data sectors" limit.
* flags - a flag is set if journal_mac is used
* journal
The journal is divided into sections, each section contains:
* metadata area (4kiB), it contains journal entries
every journal entry contains:
* logical sector (specifies where the data and tag should
be written)
* last 8 bytes of data
* integrity tag (the size is specified in the superblock)
every metadata sector ends with
* mac (8-bytes), all the macs in 8 metadata sectors form a
64-byte value. It is used to store hmac of sector
numbers in the journal section, to protect against a
possibility that the attacker tampers with sector
numbers in the journal.
* commit id
* data area (the size is variable; it depends on how many journal
entries fit into the metadata area)
every sector in the data area contains:
* data (504 bytes of data, the last 8 bytes are stored in
the journal entry)
* commit id
To test if the whole journal section was written correctly, every
512-byte sector of the journal ends with 8-byte commit id. If the
commit id matches on all sectors in a journal section, then it is
assumed that the section was written correctly. If the commit id
doesn't match, the section was written partially and it should not
be replayed.
* one or more runs of interleaved tags and data. Each run contains:
* tag area - it contains integrity tags. There is one tag for each
sector in the data area
* data area - it contains data sectors. The number of data sectors
in one run must be a power of two. log2 of this value is stored
in the superblock.

View File

@@ -16,15 +16,15 @@ Example scripts
[[
#!/bin/sh
# Create an identity mapping for a device
echo "0 `blockdev --getsz $1` linear $1 0" | dmsetup create identity
echo "0 `blockdev --getsize $1` linear $1 0" | dmsetup create identity
]]
[[
#!/bin/sh
# Join 2 devices together
size1=`blockdev --getsz $1`
size2=`blockdev --getsz $2`
size1=`blockdev --getsize $1`
size2=`blockdev --getsize $2`
echo "0 $size1 linear $1 0
$size1 $size2 linear $2 0" | dmsetup create joined
]]
@@ -44,7 +44,7 @@ if (!defined($dev)) {
die("Please specify a device.\n");
}
my $dev_size = `blockdev --getsz $dev`;
my $dev_size = `blockdev --getsize $dev`;
my $extents = int($dev_size / $extent_size) -
(($dev_size % $extent_size) ? 1 : 0);

View File

@@ -14,14 +14,14 @@ Log Ordering
We log things in order of completion once we are sure the write is no longer in
cache. This means that normal WRITE requests are not actually logged until the
next REQ_PREFLUSH request. This is to make it easier for userspace to replay
the log in a way that correlates to what is on disk and not what is in cache,
to make it easier to detect improper waiting/flushing.
next REQ_FLUSH request. This is to make it easier for userspace to replay the
log in a way that correlates to what is on disk and not what is in cache, to
make it easier to detect improper waiting/flushing.
This works by attaching all WRITE requests to a list once the write completes.
Once we see a REQ_PREFLUSH request we splice this list onto the request and once
Once we see a REQ_FLUSH request we splice this list onto the request and once
the FLUSH request completes we log all of the WRITEs and then the FLUSH. Only
completed WRITEs, at the time the REQ_PREFLUSH is issued, are added in order to
completed WRITEs, at the time the REQ_FLUSH is issued, are added in order to
simulate the worst case scenario with regard to power failures. Consider the
following example (W means write, C means complete):

View File

@@ -14,12 +14,8 @@ The target is named "raid" and it accepts the following parameters:
<#raid_devs> <metadata_dev0> <dev0> [.. <metadata_devN> <devN>]
<raid_type>:
raid0 RAID0 striping (no resilience)
raid1 RAID1 mirroring
raid4 RAID4 with dedicated last parity disk
raid5_n RAID5 with dedicated last parity disk supporting takeover
Same as raid4
-Transitory layout
raid4 RAID4 dedicated parity disk
raid5_la RAID5 left asymmetric
- rotating parity 0 with data continuation
raid5_ra RAID5 right asymmetric
@@ -34,19 +30,7 @@ The target is named "raid" and it accepts the following parameters:
- rotating parity N (right-to-left) with data restart
raid6_nc RAID6 N continue
- rotating parity N (right-to-left) with data continuation
raid6_n_6 RAID6 with dedicate parity disks
- parity and Q-syndrome on the last 2 disks;
layout for takeover from/to raid4/raid5_n
raid6_la_6 Same as "raid_la" plus dedicated last Q-syndrome disk
- layout for takeover from raid5_la from/to raid6
raid6_ra_6 Same as "raid5_ra" dedicated last Q-syndrome disk
- layout for takeover from raid5_ra from/to raid6
raid6_ls_6 Same as "raid5_ls" dedicated last Q-syndrome disk
- layout for takeover from raid5_ls from/to raid6
raid6_rs_6 Same as "raid5_rs" dedicated last Q-syndrome disk
- layout for takeover from raid5_rs from/to raid6
raid10 Various RAID10 inspired algorithms chosen by additional params
(see raid10_format and raid10_copies below)
- RAID10: Striped Mirrors (aka 'Striping on top of mirrors')
- RAID1E: Integrated Adjacent Stripe Mirroring
- RAID1E: Integrated Offset Stripe Mirroring
@@ -132,57 +116,10 @@ The target is named "raid" and it accepts the following parameters:
Here we see layouts closely akin to 'RAID1E - Integrated
Offset Stripe Mirroring'.
[delta_disks <N>]
The delta_disks option value (-251 < N < +251) triggers
device removal (negative value) or device addition (positive
value) to any reshape supporting raid levels 4/5/6 and 10.
RAID levels 4/5/6 allow for addition of devices (metadata
and data device tuple), raid10_near and raid10_offset only
allow for device addition. raid10_far does not support any
reshaping at all.
A minimum of devices have to be kept to enforce resilience,
which is 3 devices for raid4/5 and 4 devices for raid6.
[data_offset <sectors>]
This option value defines the offset into each data device
where the data starts. This is used to provide out-of-place
reshaping space to avoid writing over data whilst
changing the layout of stripes, hence an interruption/crash
may happen at any time without the risk of losing data.
E.g. when adding devices to an existing raid set during
forward reshaping, the out-of-place space will be allocated
at the beginning of each raid device. The kernel raid4/5/6/10
MD personalities supporting such device addition will read the data from
the existing first stripes (those with smaller number of stripes)
starting at data_offset to fill up a new stripe with the larger
number of stripes, calculate the redundancy blocks (CRC/Q-syndrome)
and write that new stripe to offset 0. Same will be applied to all
N-1 other new stripes. This out-of-place scheme is used to change
the RAID type (i.e. the allocation algorithm) as well, e.g.
changing from raid5_ls to raid5_n.
[journal_dev <dev>]
This option adds a journal device to raid4/5/6 raid sets and
uses it to close the 'write hole' caused by the non-atomic updates
to the component devices which can cause data loss during recovery.
The journal device is used as writethrough thus causing writes to
be throttled versus non-journaled raid4/5/6 sets.
Takeover/reshape is not possible with a raid4/5/6 journal device;
it has to be deconfigured before requesting these.
[journal_mode <mode>]
This option sets the caching mode on journaled raid4/5/6 raid sets
(see 'journal_dev <dev>' above) to 'writethrough' or 'writeback'.
If 'writeback' is selected the journal device has to be resilient
and must not suffer from the 'write hole' problem itself (e.g. use
raid1 or raid10) to avoid a single point of failure.
<#raid_devs>: The number of devices composing the array.
Each device consists of two entries. The first is the device
containing the metadata (if any); the second is the one containing the
data. A Maximum of 64 metadata/data device entries are supported
up to target version 1.8.0.
1.9.0 supports up to 253 which is enforced by the used MD kernel runtime.
data.
If a drive has failed or is missing at creation time, a '-' can be
given for both the metadata and data drives for a given position.
@@ -258,14 +195,6 @@ recovery. Here is a fuller description of the individual fields:
in RAID1/10 or wrong parity values found in RAID4/5/6.
This value is valid only after a "check" of the array
is performed. A healthy array has a 'mismatch_cnt' of 0.
<data_offset> The current data offset to the start of the user data on
each component device of a raid set (see the respective
raid parameter to support out-of-place reshaping).
<journal_char> 'A' - active write-through journal device.
'a' - active write-back journal device.
'D' - dead journal device.
'-' - no journal device.
Message Interface
-----------------
@@ -278,6 +207,7 @@ include:
"recover"- Initiate/continue a recover process.
"check" - Initiate a check (i.e. a "scrub") of the array.
"repair" - Initiate a repair of the array.
"reshape"- Currently unsupported (-EINVAL).
Discard Support
@@ -327,19 +257,3 @@ Version History
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
1.6.0 Add discard support (and devices_handle_discard_safely module param).
1.7.0 Add support for MD RAID0 mappings.
1.8.0 Explicitly check for compatible flags in the superblock metadata
and reject to start the raid set if any are set by a newer
target version, thus avoiding data corruption on a raid set
with a reshape in progress.
1.9.0 Add support for RAID level takeover/reshape/region size
and set size reduction.
1.9.1 Fix activation of existing RAID 4/10 mapped devices
1.9.2 Don't emit '- -' on the status table line in case the constructor
fails reading a superblock. Correctly emit 'maj:min1 maj:min2' and
'D' on the status line. If '- -' is passed into the constructor, emit
'- -' on the table line and '-' as the status line health character.
1.10.0 Add support for raid4/5/6 journal device
1.10.1 Fix data corruption on reshape request
1.11.0 Fix table line argument order
(wrong raid10_copies/raid10_format sequence)
1.11.1 Add raid4/5/6 journal write-back support via journal_mode option

View File

@@ -37,9 +37,9 @@ if (!$num_devs) {
die("Specify at least one device\n");
}
$min_dev_size = `blockdev --getsz $devs[0]`;
$min_dev_size = `blockdev --getsize $devs[0]`;
for ($i = 1; $i < $num_devs; $i++) {
my $this_size = `blockdev --getsz $devs[$i]`;
my $this_size = `blockdev --getsize $devs[$i]`;
$min_dev_size = ($min_dev_size < $this_size) ?
$min_dev_size : $this_size;
}

View File

@@ -123,7 +123,7 @@ Assume that you have volumes vg1/switch0 vg1/switch1 vg1/switch2 with
the same size.
Create a switch device with 64kB region size:
dmsetup create switch --table "0 `blockdev --getsz /dev/vg1/switch0`
dmsetup create switch --table "0 `blockdev --getsize /dev/vg1/switch0`
switch 3 128 0 /dev/vg1/switch0 0 /dev/vg1/switch1 0 /dev/vg1/switch2 0"
Set mappings for the first 7 entries to point to devices switch0, switch1,

View File

@@ -1,144 +0,0 @@
dm-zoned
========
The dm-zoned device mapper target exposes a zoned block device (ZBC and
ZAC compliant devices) as a regular block device without any write
pattern constraints. In effect, it implements a drive-managed zoned
block device which hides from the user (a file system or an application
doing raw block device accesses) the sequential write constraints of
host-managed zoned block devices and can mitigate the potential
device-side performance degradation due to excessive random writes on
host-aware zoned block devices.
For a more detailed description of the zoned block device models and
their constraints see (for SCSI devices):
http://www.t10.org/drafts.htm#ZBC_Family
and (for ATA devices):
http://www.t13.org/Documents/UploadedDocuments/docs2015/di537r05-Zoned_Device_ATA_Command_Set_ZAC.pdf
The dm-zoned implementation is simple and minimizes system overhead (CPU
and memory usage as well as storage capacity loss). For a 10TB
host-managed disk with 256 MB zones, dm-zoned memory usage per disk
instance is at most 4.5 MB and as little as 5 zones will be used
internally for storing metadata and performaing reclaim operations.
dm-zoned target devices are formatted and checked using the dmzadm
utility available at:
https://github.com/hgst/dm-zoned-tools
Algorithm
=========
dm-zoned implements an on-disk buffering scheme to handle non-sequential
write accesses to the sequential zones of a zoned block device.
Conventional zones are used for caching as well as for storing internal
metadata.
The zones of the device are separated into 2 types:
1) Metadata zones: these are conventional zones used to store metadata.
Metadata zones are not reported as useable capacity to the user.
2) Data zones: all remaining zones, the vast majority of which will be
sequential zones used exclusively to store user data. The conventional
zones of the device may be used also for buffering user random writes.
Data in these zones may be directly mapped to the conventional zone, but
later moved to a sequential zone so that the conventional zone can be
reused for buffering incoming random writes.
dm-zoned exposes a logical device with a sector size of 4096 bytes,
irrespective of the physical sector size of the backend zoned block
device being used. This allows reducing the amount of metadata needed to
manage valid blocks (blocks written).
The on-disk metadata format is as follows:
1) The first block of the first conventional zone found contains the
super block which describes the on disk amount and position of metadata
blocks.
2) Following the super block, a set of blocks is used to describe the
mapping of the logical device blocks. The mapping is done per chunk of
blocks, with the chunk size equal to the zoned block device size. The
mapping table is indexed by chunk number and each mapping entry
indicates the zone number of the device storing the chunk of data. Each
mapping entry may also indicate if the zone number of a conventional
zone used to buffer random modification to the data zone.
3) A set of blocks used to store bitmaps indicating the validity of
blocks in the data zones follows the mapping table. A valid block is
defined as a block that was written and not discarded. For a buffered
data chunk, a block is always valid only in the data zone mapping the
chunk or in the buffer zone of the chunk.
For a logical chunk mapped to a conventional zone, all write operations
are processed by directly writing to the zone. If the mapping zone is a
sequential zone, the write operation is processed directly only if the
write offset within the logical chunk is equal to the write pointer
offset within of the sequential data zone (i.e. the write operation is
aligned on the zone write pointer). Otherwise, write operations are
processed indirectly using a buffer zone. In that case, an unused
conventional zone is allocated and assigned to the chunk being
accessed. Writing a block to the buffer zone of a chunk will
automatically invalidate the same block in the sequential zone mapping
the chunk. If all blocks of the sequential zone become invalid, the zone
is freed and the chunk buffer zone becomes the primary zone mapping the
chunk, resulting in native random write performance similar to a regular
block device.
Read operations are processed according to the block validity
information provided by the bitmaps. Valid blocks are read either from
the sequential zone mapping a chunk, or if the chunk is buffered, from
the buffer zone assigned. If the accessed chunk has no mapping, or the
accessed blocks are invalid, the read buffer is zeroed and the read
operation terminated.
After some time, the limited number of convnetional zones available may
be exhausted (all used to map chunks or buffer sequential zones) and
unaligned writes to unbuffered chunks become impossible. To avoid this
situation, a reclaim process regularly scans used conventional zones and
tries to reclaim the least recently used zones by copying the valid
blocks of the buffer zone to a free sequential zone. Once the copy
completes, the chunk mapping is updated to point to the sequential zone
and the buffer zone freed for reuse.
Metadata Protection
===================
To protect metadata against corruption in case of sudden power loss or
system crash, 2 sets of metadata zones are used. One set, the primary
set, is used as the main metadata region, while the secondary set is
used as a staging area. Modified metadata is first written to the
secondary set and validated by updating the super block in the secondary
set, a generation counter is used to indicate that this set contains the
newest metadata. Once this operation completes, in place of metadata
block updates can be done in the primary metadata set. This ensures that
one of the set is always consistent (all modifications committed or none
at all). Flush operations are used as a commit point. Upon reception of
a flush request, metadata modification activity is temporarily blocked
(for both incoming BIO processing and reclaim process) and all dirty
metadata blocks are staged and updated. Normal operation is then
resumed. Flushing metadata thus only temporarily delays write and
discard requests. Read requests can be processed concurrently while
metadata flush is being executed.
Usage
=====
A zoned block device must first be formatted using the dmzadm tool. This
will analyze the device zone configuration, determine where to place the
metadata sets on the device and initialize the metadata sets.
Ex:
dmzadm --format /dev/sdxx
For a formatted device, the target can be created normally with the
dmsetup utility. The only parameter that dm-zoned requires is the
underlying zoned block device name. Ex:
echo "0 `blockdev --getsize ${dev}` zoned ${dev}" | dmsetup create dmz-`basename ${dev}`

View File

@@ -50,7 +50,6 @@
@top_srcdir@/lib/misc/lvm-file.h
@top_srcdir@/lib/misc/lvm-flock.h
@top_srcdir@/lib/misc/lvm-globals.h
@top_srcdir@/lib/misc/lvm-maths.h
@top_srcdir@/lib/misc/lvm-percent.h
@top_srcdir@/lib/misc/lvm-signal.h
@top_srcdir@/lib/misc/lvm-string.h

View File

@@ -127,9 +127,6 @@
/* Path to dmeventd pidfile. */
#undef DMEVENTD_PIDFILE
/* Define to 1 to enable the device-mapper filemap daemon. */
#undef DMFILEMAPD
/* Define to enable compat protocol */
#undef DM_COMPAT
@@ -148,9 +145,6 @@
/* Library version */
#undef DM_LIB_VERSION
/* Path to fsadm binary. */
#undef FSADM_PATH
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
@@ -347,9 +341,6 @@
/* Define to 1 if the system has the type `ptrdiff_t'. */
#undef HAVE_PTRDIFF_T
/* Define to 1 if the compiler has the `__builtin_clz` builtin. */
#undef HAVE___BUILTIN_CLZ
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
@@ -494,9 +485,6 @@
/* Define to 1 if you have the <sys/file.h> header file. */
#undef HAVE_SYS_FILE_H
/* Define to 1 if you have the <sys/inotify.h> header file. */
#undef HAVE_SYS_INOTIFY_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
@@ -632,9 +620,6 @@
/* Define to 1 to include code that uses lvmpolld. */
#undef LVMPOLLD_SUPPORT
/* configure command line used */
#undef LVM_CONFIGURE_LINE
/* Path to lvm binary. */
#undef LVM_PATH

View File

@@ -48,10 +48,6 @@ ifeq ("@CACHE@", "shared")
SUBDIRS += cache_segtype
endif
ifeq ("@CLUSTER@", "shared")
SUBDIRS += locking
endif
SOURCES =\
activate/activate.c \
cache/lvmcache.c \
@@ -116,7 +112,6 @@ SOURCES =\
misc/lvm-file.c \
misc/lvm-flock.c \
misc/lvm-globals.c \
misc/lvm-maths.c \
misc/lvm-signal.c \
misc/lvm-string.c \
misc/lvm-wrappers.c \
@@ -153,6 +148,10 @@ ifeq ("@CLUSTER@", "internal")
SOURCES += locking/cluster_locking.c
endif
ifeq ("@CLUSTER@", "shared")
SUBDIRS += locking
endif
ifeq ("@SNAPSHOTS@", "internal")
SOURCES += snapshot/snapshot.c
endif
@@ -204,6 +203,11 @@ ifeq ("@BUILD_LVMLOCKD@", "yes")
locking/lvmlockd.c
endif
ifeq ("@DMEVENTD@", "yes")
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
LIBS += -ldevmapper-event
endif
LIB_NAME = liblvm-internal
LIB_STATIC = $(LIB_NAME).a
@@ -224,10 +228,10 @@ endif
CFLOW_LIST = $(SOURCES)
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
PROGS_CFLAGS = $(BLKID_CFLAGS) $(UDEV_CFLAGS)
include $(top_builddir)/make.tmpl
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
$(SUBDIRS): $(LIB_STATIC)
CLEAN_TARGETS += misc/configure.h misc/lvm-version.h

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -150,15 +150,15 @@ static int _lv_passes_volumes_filter(struct cmd_context *cmd, const struct logic
|| str_list_match_list(&cmd->tags,
&lv->vg->tags, NULL))
return 1;
continue;
else
continue;
}
/* If supplied tag matches LV or VG tag, activate */
if (str_list_match_item(&lv->tags, str) ||
str_list_match_item(&lv->vg->tags, str))
return 1;
continue;
else
continue;
}
/* If supplied name is vgname[/lvname] */
@@ -272,18 +272,10 @@ int lv_raid_percent(const struct logical_volume *lv, dm_percent_t *percent)
{
return 0;
}
int lv_raid_data_offset(const struct logical_volume *lv, uint64_t *data_offset)
{
return 0;
}
int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
{
return 0;
}
int lv_raid_dev_count(const struct logical_volume *lv, uint32_t *dev_cnt)
{
return 0;
}
int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt)
{
return 0;
@@ -366,10 +358,6 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
{
return 1;
}
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
{
return 1;
}
int pv_uses_vg(struct physical_volume *pv,
struct volume_group *vg)
{
@@ -382,11 +370,6 @@ void activation_exit(void)
{
}
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
{
return 1;
}
int lv_is_active(const struct logical_volume *lv)
{
return 0;
@@ -667,10 +650,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
&maj, &min, &patchlevel);
}
/*
* When '*info' is NULL, returns 1 only when LV is active.
* When '*info' != NULL, returns 1 when info structure is populated.
*/
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
int use_layer, struct lvinfo *info,
const struct lv_segment *seg,
@@ -704,6 +683,32 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
if (seg_status) {
/* TODO: for now it's mess with seg_status */
seg_status->seg = seg;
if (lv_is_merging_cow(lv)) {
if (lv_has_target_type(cmd->mem, origin_from_cow(lv), NULL, TARGET_NAME_SNAPSHOT_MERGE)) {
/*
* When the snapshot-merge has not yet started, query COW LVs as is.
* When merge is in progress, query merging origin LV instead.
* COW volume is already mapped as error target in this case.
*/
lv = origin_from_cow(lv);
seg_status->seg = first_seg(lv);
log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
display_lvname(lv));
}
} else if (!use_layer && lv_is_origin(lv) && !lv_is_external_origin(lv)) {
/*
* Query status for 'layered' (-real) device most of the time,
* only when snapshot merge started, query its progress.
* TODO: single LV may need couple status to be exposed at once....
* but this needs more logical background
*/
if (!lv_is_merging_origin(lv) ||
!lv_has_target_type(cmd->mem, origin_from_cow(lv), NULL, TARGET_NAME_SNAPSHOT_MERGE))
use_layer = 1;
} else if (lv_is_cow(lv)) {
/* Hadle fictional lvm2 snapshot and query snapshotX volume */
seg_status->seg = find_snapshot(lv);
}
}
if (!dev_manager_info(cmd, lv,
@@ -757,102 +762,44 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
}
/*
* Returns 1 if lv_with_info_and_seg_status info structure populated,
* Returns 1 if lv_seg_status structure populated,
* else 0 on failure or if device not active locally.
*
* When seg_status parsing had troubles it will set type to SEG_STATUS_UNKNOWN.
*
* Using usually one ioctl to obtain info and status.
* More complex segment do collect info from one device,
* but status from another device.
*
* TODO: further improve with more statuses (i.e. snapshot's origin/merge)
*/
int lv_info_with_seg_status(struct cmd_context *cmd,
const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
int use_layer, struct lv_seg_status *lv_seg_status)
{
const struct logical_volume *olv, *lv = status->lv = lv_seg->lv;
if (!activation())
return 0;
if (lv_is_used_cache_pool(lv)) {
/* INFO is not set as cache-pool cannot be active.
* STATUS is collected from cache LV */
if (!(lv_seg = get_only_segment_using_this_lv(lv)))
return_0;
(void) _lv_info(cmd, lv_seg->lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
}
return _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, lv_seg_status, 0, 0);
}
if (lv_is_thin_pool(lv)) {
/* Always collect status for '-tpool' */
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0) &&
(status->seg_status.type == SEG_STATUS_THIN_POOL)) {
/* There is -tpool device, but query 'active' state of 'fake' thin-pool */
if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0) &&
!status->seg_status.thin_pool->needs_check)
status->info.exists = 0; /* So pool LV is not active */
}
return 1;
}
/*
* Returns 1 if lv_with_info_and_seg_status structure populated,
* else 0 on failure or if device not active locally.
*
* This is the same as calling lv_info and lv_status,
* but* it's done in one go with one ioctl if possible! ]
*/
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_segment *lv_seg, int use_layer,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
{
if (!activation())
return 0;
if (lv_is_external_origin(lv)) {
if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL,
with_open_count, with_read_ahead))
return_0;
if (lv == lv_seg->lv)
return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
with_open_count, with_read_ahead);
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
}
if (lv_is_origin(lv)) {
/* Query segment status for 'layered' (-real) device most of the time,
* only for merging snapshot, query its progress.
* TODO: single LV may need couple status to be exposed at once....
* but this needs more logical background
*/
/* Show INFO for actual origin and grab status for merging origin */
if (!_lv_info(cmd, lv, 0, &status->info, lv_seg,
lv_is_merging_origin(lv) ? &status->seg_status : NULL,
with_open_count, with_read_ahead))
return_0;
if (status->info.exists &&
(status->seg_status.type != SEG_STATUS_SNAPSHOT)) /* Not merging */
/* Grab STATUS from layered -real */
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
}
if (lv_is_cow(lv)) {
if (lv_is_merging_cow(lv)) {
olv = origin_from_cow(lv);
if (!_lv_info(cmd, olv, 0, &status->info, first_seg(olv), &status->seg_status,
with_open_count, with_read_ahead))
return_0;
if (status->seg_status.type == SEG_STATUS_SNAPSHOT) {
log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
display_lvname(lv));
/*
* When merge is in progress, query merging origin LV instead.
* COW volume is already mapped as error target in this case.
*/
return 1;
}
/* Merge not yet started, still a snapshot... */
}
/* Hadle fictional lvm2 snapshot and query snapshotX volume */
lv_seg = find_snapshot(lv);
}
return _lv_info(cmd, lv, 0, &status->info, lv_seg, &status->seg_status,
with_open_count, with_read_ahead);
/*
* If the info is requested for an LV and segment
* status for segment that belong to another LV,
* we need to acquire info and status separately!
*/
return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
_lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
}
#define OPEN_COUNT_CHECK_RETRIES 25
@@ -998,30 +945,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_data_offset(const struct logical_volume *lv, uint64_t *data_offset)
{
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;
dev_manager_destroy(dm);
return r;
}
int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
{
int r;
@@ -1051,32 +974,6 @@ int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health)
return r;
}
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_mismatch_count(const struct logical_volume *lv, uint64_t *cnt)
{
struct dev_manager *dm;
@@ -1239,7 +1136,7 @@ int lv_cache_status(const struct logical_volume *cache_lv,
return 0;
}
if (!lv_info(cache_lv->vg->cmd, cache_lv, 1, NULL, 0, 0)) {
if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0)) {
log_error("Cannot check status for locally inactive cache volume %s.",
display_lvname(cache_lv));
return 0;
@@ -1592,26 +1489,6 @@ out:
return r || l;
}
/*
* Check if "raid4" @segtype is supported by kernel.
*
* if segment type is not raid4, return 1.
*/
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype)
{
unsigned attrs;
if (segtype_is_raid4(segtype) &&
(!segtype->ops->target_present ||
!segtype->ops->target_present(cmd, NULL, &attrs) ||
!(attrs & RAID_FEATURE_RAID4))) {
log_error("RAID module does not support RAID4.");
return 0;
}
return 1;
}
int lv_is_active(const struct logical_volume *lv)
{
return _lv_is_active(lv, NULL, NULL, NULL);
@@ -1671,7 +1548,7 @@ static struct dm_event_handler *_create_dm_event_handler(struct cmd_context *cmd
if (dm_event_handler_set_dmeventd_path(dmevh, find_config_tree_str(cmd, dmeventd_executable_CFG, NULL)))
goto_bad;
if (dso && dm_event_handler_set_dso(dmevh, dso))
if (dm_event_handler_set_dso(dmevh, dso))
goto_bad;
if (dm_event_handler_set_uuid(dmevh, dmuuid))
@@ -1715,39 +1592,6 @@ static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_vo
return build_dm_uuid(cmd->mem, lv, layer);
}
static int _device_registered_with_dmeventd(struct cmd_context *cmd, const struct logical_volume *lv, int *pending, const char **dso)
{
char *uuid;
enum dm_event_mask evmask = 0;
struct dm_event_handler *dmevh;
*pending = 0;
if (!(uuid = _build_target_uuid(cmd, lv)))
return_0;
if (!(dmevh = _create_dm_event_handler(cmd, uuid, NULL, 0, DM_EVENT_ALL_ERRORS)))
return_0;
if (dm_event_get_registered_device(dmevh, 0)) {
dm_event_handler_destroy(dmevh);
return 0;
}
evmask = dm_event_handler_get_event_mask(dmevh);
if (evmask & DM_EVENT_REGISTRATION_PENDING) {
*pending = 1;
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
}
if (dso && (*dso = dm_event_handler_get_dso(dmevh)) && !(*dso = dm_pool_strdup(cmd->mem, *dso)))
log_error("Failed to duplicate dso name.");
dm_event_handler_destroy(dmevh);
return evmask;
}
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
const struct logical_volume *lv, int *pending)
{
@@ -1806,7 +1650,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
if (!r)
return_0;
log_very_verbose("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", uuid);
return 1;
}
@@ -1830,8 +1674,6 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
uint32_t s;
static const struct lv_activate_opts zlaopts = { 0 };
struct lvinfo info;
const char *dso = NULL;
int new_unmonitor;
if (!laopts)
laopts = &zlaopts;
@@ -1846,26 +1688,6 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
if (monitor && !dmeventd_monitor_mode())
return 1;
/*
* Activation of unused cache-pool activates metadata device as
* a public LV for clearing purpose.
* FIXME:
* As VG lock is held across whole operation unmonitored volume
* is usually OK since dmeventd couldn't do anything.
* However in case command would have crashed, such LV is
* left unmonitored and may potentially require dmeventd.
*/
if (lv_is_cache_pool_data(lv) || lv_is_cache_pool_metadata(lv)) {
if (!(seg = find_pool_seg(first_seg(lv))))
return_0;
if (!lv_is_used_cache_pool(seg->lv)) {
log_debug_activation("Skipping %smonitor of %s.%s",
(monitor) ? "" : "un", display_lvname(lv),
(monitor) ? " Cache pool activation for clearing only." : "");
return 1;
}
}
/*
* Allow to unmonitor thin pool via explicit pool unmonitor
* or unmonitor before the last thin pool user deactivation
@@ -1900,8 +1722,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
/*
* In case this LV is a snapshot origin, we instead monitor
* each of its respective snapshots. The origin itself may
* also need to be monitored if it is a mirror, for example,
* so fall through to process it afterwards.
* also need to be monitored if it is a mirror, for example.
*/
if (!laopts->origin_only && lv_is_origin(lv))
dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
@@ -1960,68 +1781,55 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
!seg->segtype->ops->target_monitored) /* doesn't support registration */
continue;
if (!monitor)
/* When unmonitoring, obtain existing dso being used. */
monitored = _device_registered_with_dmeventd(cmd, seg_is_snapshot(seg) ? seg->cow : seg->lv, &pending, &dso);
else
monitored = seg->segtype->ops->target_monitored(seg, &pending);
monitored = seg->segtype->ops->target_monitored(seg, &pending);
/* FIXME: We should really try again if pending */
monitored = (pending) ? 0 : monitored;
monitor_fn = NULL;
new_unmonitor = 0;
if (monitor) {
if (monitored)
log_verbose("%s already monitored.", display_lvname(lv));
else if (seg->segtype->ops->target_monitor_events) {
log_verbose("Monitoring %s%s", display_lvname(lv), test_mode() ? " [Test mode: skipping this]" : "");
else if (seg->segtype->ops->target_monitor_events)
monitor_fn = seg->segtype->ops->target_monitor_events;
}
} else {
if (!monitored)
log_verbose("%s already not monitored.", display_lvname(lv));
else if (dso && *dso) {
/*
* Divert unmonitor away from code that depends on the new segment
* type instead of the existing one if it's changing.
*/
log_verbose("Not monitoring %s with %s%s", display_lvname(lv), dso, test_mode() ? " [Test mode: skipping this]" : "");
new_unmonitor = 1;
}
else if (seg->segtype->ops->target_unmonitor_events)
monitor_fn = seg->segtype->ops->target_unmonitor_events;
}
/* Do [un]monitor */
if (!monitor_fn)
continue;
log_verbose("%sonitoring %s%s", monitor ? "M" : "Not m", display_lvname(lv),
test_mode() ? " [Test mode: skipping this]" : "");
/* FIXME Test mode should really continue a bit further. */
if (test_mode())
continue;
if (new_unmonitor) {
if (!target_register_events(cmd, dso, seg_is_snapshot(seg) ? seg->cow : lv, 0, 0, 10)) {
log_error("%s: segment unmonitoring failed.",
display_lvname(lv));
return 0;
}
} else if (monitor_fn) {
/* FIXME specify events */
if (!monitor_fn(seg, 0)) {
log_error("%s: %s segment monitoring function failed.",
display_lvname(lv), lvseg_name(seg));
return 0;
}
} else
continue;
/* FIXME specify events */
if (!monitor_fn(seg, 0)) {
log_error("%s: %s segment monitoring function failed.",
display_lvname(lv), seg->segtype->name);
return 0;
}
/* Check [un]monitor results */
/* Try a couple times if pending, but not forever... */
for (i = 0;; i++) {
for (i = 0; i < 40; i++) {
pending = 0;
monitored = seg->segtype->ops->target_monitored(seg, &pending);
if (!pending || i >= 40)
if (pending ||
(!monitored && monitor) ||
(monitored && !monitor))
log_very_verbose("%s %smonitoring still pending: waiting...",
display_lvname(lv), monitor ? "" : "un");
else
break;
log_very_verbose("%s %smonitoring still pending: waiting...",
display_lvname(lv), monitor ? "" : "un");
usleep(10000 * i);
}
@@ -2641,77 +2449,6 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return r;
}
/* Remove any existing, closed mapped device by @name */
static int _remove_dm_dev_by_name(const char *name)
{
int r = 0;
struct dm_task *dmt;
struct dm_info info;
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return_0;
/* Check, if the device exists. */
if (dm_task_set_name(dmt, name) && dm_task_run(dmt) && dm_task_get_info(dmt, &info)) {
dm_task_destroy(dmt);
/* Ignore non-existing or open dm devices */
if (!info.exists || info.open_count)
return 1;
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
return_0;
if (dm_task_set_name(dmt, name))
r = dm_task_run(dmt);
}
dm_task_destroy(dmt);
return r;
}
/* Work all segments of @lv removing any existing, closed "*-missing_N_0" sub devices. */
static int _lv_remove_any_missing_subdevs(struct logical_volume *lv)
{
if (lv) {
uint32_t seg_no = 0;
char name[257];
struct lv_segment *seg;
dm_list_iterate_items(seg, &lv->segments) {
if (seg->area_count != 1)
return_0;
if (dm_snprintf(name, sizeof(name), "%s-%s-missing_%u_0", seg->lv->vg->name, seg->lv->name, seg_no) < 0)
return 0;
if (!_remove_dm_dev_by_name(name))
return 0;
seg_no++;
}
}
return 1;
}
/* Remove any "*-missing_*" sub devices added by the activation layer for an rmate/rimage missing PV mapping */
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
{
uint32_t s;
struct lv_segment *seg = first_seg(lv);
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_lv(seg, s)))
return 0;
if (seg->meta_areas && seg_metatype(seg, s) == AREA_LV &&
!_lv_remove_any_missing_subdevs(seg_metalv(seg, s)))
return 0;
}
return 1;
}
/*
* Does PV use VG somewhere in its construction?
* Returns 1 on failure.

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -54,12 +54,11 @@ struct lv_seg_status {
};
struct lv_with_info_and_seg_status {
const struct logical_volume *lv; /* input */
int info_ok;
const struct logical_volume *lv; /* output */
struct lvinfo info; /* output */
int seg_part_of_lv; /* output */
struct lv_seg_status seg_status; /* output, see lv_seg_status */
/* TODO: add extra status for snapshot origin */
struct lv_seg_status seg_status; /* input/output, see lv_seg_status */
};
struct lv_activate_opts {
@@ -100,7 +99,6 @@ int target_present(struct cmd_context *cmd, const char *target_name,
int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype);
int lvm_dm_prefix_check(int major, int minor, const char *prefix);
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
struct dm_list *modules);
@@ -124,8 +122,6 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv);
/*
* Returns 1 if info structure has been populated, else 0 on failure.
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
@@ -135,6 +131,13 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_la
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
struct lvinfo *info, int with_open_count, int with_read_ahead);
/*
* Returns 1 if lv_seg_status structure has been populated,
* else 0 on failure or if device not active locally.
*/
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
int use_layer, struct lv_seg_status *lv_seg_status);
/*
* Returns 1 if lv_info_and_seg_status structure has been populated,
* else 0 on failure or if device not active locally.
@@ -142,8 +145,8 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
* lv_info_with_seg_status is the same as calling lv_info and then lv_status,
* but this fn tries to do that with one ioctl if possible.
*/
int lv_info_with_seg_status(struct cmd_context *cmd,
const struct lv_segment *lv_seg,
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_segment *lv_seg, int use_layer,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead);
@@ -168,13 +171,11 @@ 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_data_offset(const struct logical_volume *lv, uint64_t *data_offset);
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);
int lv_raid_message(const struct logical_volume *lv, const char *msg);
int lv_cache_status(const struct logical_volume *cache_lv,
int lv_cache_status(const struct logical_volume *lv,
struct lv_status_cache **status);
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
dm_percent_t *percent);
@@ -202,12 +203,12 @@ int lv_has_target_type(struct dm_pool *mem, const struct logical_volume *lv,
const char *layer, const char *target_type);
int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume *lv,
const struct lv_activate_opts *laopts, int monitor);
const struct lv_activate_opts *laopts, int do_reg);
#ifdef DMEVENTD
# include "libdevmapper-event.h"
char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath);
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *libpath,
const struct logical_volume *lv, int *pending);
int target_register_events(struct cmd_context *cmd, const char *dso, const struct logical_volume *lv,
int evmask __attribute__((unused)), int set, int timeout);

File diff suppressed because it is too large Load Diff

View File

@@ -186,11 +186,11 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
!stat(lv_path, &buf)) {
if (buf_lp.st_rdev == buf.st_rdev)
return 1;
log_warn("Symlink %s that should have been "
"created by udev does not have "
"correct target. Falling back to "
"direct link creation", lv_path);
else
log_warn("Symlink %s that should have been "
"created by udev does not have "
"correct target. Falling back to "
"direct link creation", lv_path);
} else
log_warn("Symlink %s that should have been "
"created by udev could not be checked "
@@ -239,9 +239,7 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
return 1;
log_sys_error("lstat", lv_path);
return 0;
}
if (dm_udev_get_sync_support() && udev_checking() && check_udev)
} else if (dm_udev_get_sync_support() && udev_checking() && check_udev)
log_warn("The link %s should have been removed by udev "
"but it is still present. Falling back to "
"direct link removal.", lv_path);
@@ -480,9 +478,9 @@ int fs_rename_lv(const struct logical_volume *lv, const char *dev,
_fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name,
lv->name, dev, "", lv->vg->cmd->current_settings.udev_rules));
}
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
dev, old_lvname, lv->vg->cmd->current_settings.udev_rules);
else
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
dev, old_lvname, lv->vg->cmd->current_settings.udev_rules);
}
void fs_unlock(void)

15
lib/cache/lvmcache.c vendored
View File

@@ -858,7 +858,7 @@ static void _choose_preferred_devs(struct cmd_context *cmd,
struct dm_list *add_cache_devs)
{
char uuid[64] __attribute__((aligned(8)));
const char *reason;
const char *reason = "none";
struct dm_list altdevs;
struct dm_list new_unused;
struct dev_types *dt = cmd->dev_types;
@@ -1275,7 +1275,7 @@ struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname
/* Build config tree from vgmetadata, if not yet cached */
if (!vginfo->cft &&
!(vginfo->cft =
config_tree_from_string_without_dup_node_check(vginfo->vgmetadata)))
dm_config_from_string(vginfo->vgmetadata)))
goto_bad;
if (!(vg = import_vg_from_config_tree(vginfo->cft, fid)))
@@ -1600,6 +1600,8 @@ void lvmcache_del(struct lvmcache_info *info)
info->label->labeller->ops->destroy_label(info->label->labeller,
info->label);
dm_free(info);
return;
}
/*
@@ -1896,7 +1898,8 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
info->vginfo->creation_host))
goto set_lock_type;
dm_free(info->vginfo->creation_host);
if (info->vginfo->creation_host)
dm_free(info->vginfo->creation_host);
if (!(info->vginfo->creation_host = dm_strdup(creation_host))) {
log_error("cache creation host alloc failed for %s.",
@@ -1915,7 +1918,8 @@ set_lock_type:
if (info->vginfo->lock_type && !strcmp(lock_type, info->vginfo->lock_type))
goto set_system_id;
dm_free(info->vginfo->lock_type);
if (info->vginfo->lock_type)
dm_free(info->vginfo->lock_type);
if (!(info->vginfo->lock_type = dm_strdup(lock_type))) {
log_error("cache lock_type alloc failed for %s", lock_type);
@@ -1933,7 +1937,8 @@ set_system_id:
if (info->vginfo->system_id && !strcmp(system_id, info->vginfo->system_id))
goto out;
dm_free(info->vginfo->system_id);
if (info->vginfo->system_id)
dm_free(info->vginfo->system_id);
if (!(info->vginfo->system_id = dm_strdup(system_id))) {
log_error("cache system_id alloc failed for %s", system_id);

View File

@@ -181,7 +181,7 @@ int lvmcache_foreach_ba(struct lvmcache_info *info,
int (*fun)(struct disk_locn *, void *),
void *baton);
int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo,
int lvmcache_foreach_pv(struct lvmcache_vginfo *vg,
int (*fun)(struct lvmcache_info *, void *), void * baton);
uint64_t lvmcache_device_size(struct lvmcache_info *info);

61
lib/cache/lvmetad.c vendored
View File

@@ -66,7 +66,7 @@ static int _log_debug_inequality(const char *name, struct dm_config_node *a, str
log_debug_lvmetad("VG %s metadata inequality at %s / %s: %s / %s",
name, a->key, b->key, av->v.str, bv->v.str);
else if (a->v->type == DM_CFG_INT && b->v->type == DM_CFG_INT)
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTd64 " / " FMTd64,
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTi64 " / " FMTi64,
name, a->key, b->key, av->v.i, bv->v.i);
else
log_debug_lvmetad("VG %s metadata inequality at %s / %s: type %d / type %d",
@@ -145,14 +145,13 @@ int lvmetad_connect(struct cmd_context *cmd)
_lvmetad_use = 1;
_lvmetad_cmd = cmd;
return 1;
} else {
log_debug_lvmetad("Failed to connect to lvmetad: %s", strerror(_lvmetad.error));
_lvmetad_connected = 0;
_lvmetad_use = 0;
_lvmetad_cmd = NULL;
return 0;
}
log_debug_lvmetad("Failed to connect to lvmetad: %s", strerror(_lvmetad.error));
_lvmetad_connected = 0;
_lvmetad_use = 0;
_lvmetad_cmd = NULL;
return 0;
}
int lvmetad_used(void)
@@ -663,7 +662,7 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
}
if (reply.error) {
log_error("lvmetad cannot be used due to error: %s", strerror(reply.error));
log_warn("WARNING: lvmetad cannot be used due to error: %s", strerror(reply.error));
goto fail;
}
@@ -1305,7 +1304,7 @@ int lvmetad_vg_remove_pending(struct volume_group *vg)
reply = _lvmetad_send(vg->cmd, "set_vg_info",
"name = %s", vg->name,
"uuid = %s", uuid,
"version = %"PRId64, (int64_t)0,
"version = %d", 0,
NULL);
if (!_lvmetad_handle_reply(reply, "set_vg_info", vg->name, NULL)) {
@@ -1919,44 +1918,15 @@ scan_more:
vgmeta_ret = vgmeta;
save_dev = devl->dev;
} else {
struct dm_config_node *meta1 = vgmeta_ret->root;
struct dm_config_node *meta2 = vgmeta->root;
struct dm_config_node *sib1 = meta1->sib;
struct dm_config_node *sib2 = meta2->sib;
/*
* Do not compare the extraneous data that
* export_vg_to_config_tree() inserts next to the
* actual VG metadata. This includes creation_time
* which may not match since it is generated separately
* for each call to create the config tree.
*
* We're saving the sibling pointer and restoring it
* after the compare because we're unsure if anything
* later might want it.
*
* FIXME: make it clearer what we're doing here, e.g.
* pass a parameter to export_vg_to_config_tree()
* telling it to skip the extraneous data, or something.
* It's very non-obvious that setting sib=NULL does that.
*/
meta1->sib = NULL;
meta2->sib = NULL;
if (compare_config(meta1, meta2)) {
if (compare_config(vgmeta_ret->root, vgmeta->root)) {
log_error("VG %s metadata comparison failed for device %s vs %s",
vg->name, dev_name(devl->dev), save_dev ? dev_name(save_dev) : "none");
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
meta1->sib = sib1;
meta2->sib = sib2;
dm_config_destroy(vgmeta);
dm_config_destroy(vgmeta_ret);
release_vg(baton.vg);
return NULL;
}
meta1->sib = sib1;
meta2->sib = sib2;
dm_config_destroy(vgmeta);
}
@@ -2062,8 +2032,7 @@ scan_more:
dm_config_destroy(vgmeta_ret);
}
out:
if (vg_ret)
log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
return vg_ret;
}
@@ -2082,11 +2051,6 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
return 0;
}
if (udev_dev_is_mpath_component(dev)) {
log_debug("Ignore multipath component for pvscan.");
return 1;
}
if (!label_read(dev, &label, 0)) {
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
if (!lvmetad_pv_gone_by_dev(dev))
@@ -2875,9 +2839,6 @@ int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason)
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_DIRECT)) {
*reason = "the disable flag was set directly";
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_REPAIR)) {
*reason = "a repair command was run";
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_LVM1)) {
*reason = "LVM1 metadata was found";

View File

@@ -36,38 +36,6 @@ static unsigned _feature_mask;
log_error(t " segment %s of logical volume %s.", ## p, \
dm_config_parent_name(sn), seg->lv->name), 0;
static int _cache_out_line(const char *line, void *_f)
{
log_print(" Setting\t\t%s", line);
return 1;
}
static void _cache_display(const struct lv_segment *seg)
{
const struct dm_config_node *n;
const struct lv_segment *pool_seg =
seg_is_cache_pool(seg) ? seg : first_seg(seg->pool_lv);
log_print(" Chunk size\t\t%s",
display_size(seg->lv->vg->cmd, pool_seg->chunk_size));
if (pool_seg->cache_metadata_format != CACHE_METADATA_FORMAT_UNSELECTED)
log_print(" Metadata format\t%u", pool_seg->cache_metadata_format);
if (pool_seg->cache_mode != CACHE_MODE_UNSELECTED)
log_print(" Mode\t\t%s", get_cache_mode_name(pool_seg));
if (pool_seg->policy_name)
log_print(" Policy\t\t%s", pool_seg->policy_name);
if (pool_seg->policy_settings &&
(n = pool_seg->policy_settings->child))
dm_config_write_node(n, _cache_out_line, NULL);
log_print(" ");
}
/*
* When older metadata are loaded without newer settings,
* set then to default settings (the one that could have been
@@ -84,13 +52,7 @@ static void _fix_missing_defaults(struct lv_segment *cpool_seg)
cpool_seg->policy_name);
}
if (cpool_seg->cache_metadata_format == CACHE_METADATA_FORMAT_UNSELECTED) {
cpool_seg->cache_metadata_format = CACHE_METADATA_FORMAT_1;
log_verbose("Cache pool %s uses implicit metadata format %u.",
display_lvname(cpool_seg->lv), cpool_seg->cache_metadata_format);
}
if (cpool_seg->cache_mode == CACHE_MODE_UNSELECTED) {
if (cpool_seg->cache_mode == CACHE_MODE_UNDEFINED) {
cpool_seg->cache_mode = CACHE_MODE_WHEN_MISSING;
log_verbose("Cache pool %s is missing cache mode, using %s.",
display_lvname(cpool_seg->lv),
@@ -145,16 +107,6 @@ static int _cache_pool_text_import(struct lv_segment *seg,
return SEG_LOG_ERROR("Failed to duplicate policy in");
}
if (dm_config_has_node(sn, "metadata_format")) {
if (!dm_config_get_uint32(sn, "metadata_format", &seg->cache_metadata_format) ||
((seg->cache_metadata_format != CACHE_METADATA_FORMAT_1) &&
(seg->cache_metadata_format != CACHE_METADATA_FORMAT_2)))
return SEG_LOG_ERROR("Unknown cache metadata format %u number in",
seg->cache_metadata_format);
if (seg->cache_metadata_format == CACHE_METADATA_FORMAT_2)
seg->lv->status |= LV_METADATA_FORMAT;
}
/*
* Read in policy args:
* policy_settings {
@@ -212,31 +164,12 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
switch (seg->cache_metadata_format) {
case CACHE_METADATA_FORMAT_UNSELECTED:
/* Unselected format is not printed */
break;
case CACHE_METADATA_FORMAT_1:
/* If format 1 was already specified with cache pool, store it,
* otherwise format gets stored when LV is cached.
* NB: format 1 could be lost anytime, it's a default format.
* Older lvm2 tool can easily drop it.
*/
case CACHE_METADATA_FORMAT_2: /* more in future ? */
outf(f, "metadata_format = " FMTu32, seg->cache_metadata_format);
break;
default:
log_error(INTERNAL_ERROR "LV %s is using unknown cache metadada format %u.",
display_lvname(seg->lv), seg->cache_metadata_format);
return 0;
}
/*
* 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 (seg->cache_mode != CACHE_MODE_UNSELECTED) {
if (seg->cache_mode != CACHE_MODE_UNDEFINED) {
if (!(cache_mode = get_cache_mode_name(seg)))
return_0;
outf(f, "cache_mode = \"%s\"", cache_mode);
@@ -265,39 +198,6 @@ static void _destroy(struct segment_type *segtype)
}
#ifdef DEVMAPPER_SUPPORT
/*
* Parse and look for kernel symbol in /proc/kallsyms
* this could be our only change to figure out there is
* cache policy symbol already in the monolithic kernel
* where 'modprobe dm-cache-smq' will simply not work
*/
static int _lookup_kallsyms(const char *symbol)
{
static const char _syms[] = "/proc/kallsyms";
int ret = 0;
char *line = NULL;
size_t len;
FILE *s;
if (!(s = fopen(_syms, "r")))
log_sys_debug("fopen", _syms);
else {
while (getline(&line, &len, s) != -1)
if (strstr(line, symbol)) {
ret = 1; /* Found symbol */
log_debug("Found kernel symbol%s.", symbol); /* space is in symbol */
break;
}
free(line);
if (fclose(s))
log_sys_debug("fclose", _syms);
}
return ret;
}
static int _target_present(struct cmd_context *cmd,
const struct lv_segment *seg __attribute__((unused)),
unsigned *attributes __attribute__((unused)))
@@ -310,15 +210,13 @@ static int _target_present(struct cmd_context *cmd,
unsigned cache_alias;
const char feature[12];
const char module[12]; /* check dm-%s */
const char ksymbol[12]; /* check for kernel symbol */
const char *aliasing;
} _features[] = {
{ 1, 10, CACHE_FEATURE_METADATA2, 0, "metadata2" },
/* Assumption: cache >=1.9 always aliases MQ policy */
{ 1, 9, CACHE_FEATURE_POLICY_SMQ, CACHE_FEATURE_POLICY_MQ, "policy_smq", "cache-smq",
" smq_exit", " and aliases cache-mq" },
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, 0, "policy_smq", "cache-smq", " smq_exit" },
{ 1, 3, CACHE_FEATURE_POLICY_MQ, 0, "policy_mq", "cache-mq", " mq_init" },
" and aliases cache-mq" },
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, 0, "policy_smq", "cache-smq" },
{ 1, 3, CACHE_FEATURE_POLICY_MQ, 0, "policy_mq", "cache-mq" },
};
static const char _lvmconf[] = "global/cache_disabled_features";
static unsigned _attrs = 0;
@@ -352,20 +250,9 @@ static int _target_present(struct cmd_context *cmd,
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) {
if (_attrs & _features[i].cache_feature)
continue; /* already present */
if (!_features[i].module[0]) {
if ((maj > _features[i].maj) ||
(maj == _features[i].maj && min >= _features[i].min)) {
log_debug_activation("Cache supports %s.",
_features[i].feature);
_attrs |= _features[i].cache_feature;
}
continue;
}
if (((maj > _features[i].maj) ||
(maj == _features[i].maj && min >= _features[i].min)) &&
((_features[i].ksymbol[0] && _lookup_kallsyms(_features[i].ksymbol)) ||
module_present(cmd, _features[i].module))) {
module_present(cmd, _features[i].module)) {
log_debug_activation("Cache policy %s is available%s.",
_features[i].module,
_features[i].aliasing ? : "");
@@ -423,7 +310,6 @@ static int _modules_needed(struct dm_pool *mem,
#endif /* DEVMAPPER_SUPPORT */
static struct segtype_handler _cache_pool_ops = {
.display = _cache_display,
.text_import = _cache_pool_text_import,
.text_import_area_count = _cache_pool_text_import_area_count,
.text_export = _cache_pool_text_export,
@@ -513,7 +399,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
struct lv_segment *cache_pool_seg;
char *metadata_uuid, *data_uuid, *origin_uuid;
uint64_t feature_flags = 0;
unsigned attr;
if (!seg->pool_lv || !seg_is_cache(seg)) {
log_error(INTERNAL_ERROR "Passed segment is not cache.");
@@ -541,26 +426,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
break;
}
switch (cache_pool_seg->cache_metadata_format) {
case CACHE_METADATA_FORMAT_1: break;
case CACHE_METADATA_FORMAT_2:
if (!_target_present(cmd, NULL, &attr))
return_0;
if (!(attr & CACHE_FEATURE_METADATA2)) {
log_error("LV %s has metadata format %u unsuported by kernel.",
display_lvname(seg->lv), cache_pool_seg->cache_metadata_format);
return 0;
}
feature_flags |= DM_CACHE_FEATURE_METADATA2;
log_debug_activation("Using metadata2 format for %s.", display_lvname(seg->lv));
break;
default:
log_error(INTERNAL_ERROR "LV %s has unknown metadata format %u.",
display_lvname(seg->lv), cache_pool_seg->cache_metadata_format);
return 0;
}
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
return_0;
@@ -587,7 +452,6 @@ static int _cache_add_target_line(struct dev_manager *dm,
#endif /* DEVMAPPER_SUPPORT */
static struct segtype_handler _cache_ops = {
.display = _cache_display,
.text_import = _cache_text_import,
.text_import_area_count = _cache_text_import_area_count,
.text_export = _cache_text_export,

View File

@@ -192,9 +192,6 @@ static int _get_env_vars(struct cmd_context *cmd)
}
}
if (strcmp((getenv("LVM_RUN_BY_DMEVENTD") ? : "0"), "1") == 0)
init_run_by_dmeventd(cmd);
return 1;
}
@@ -474,12 +471,10 @@ bad:
int process_profilable_config(struct cmd_context *cmd)
{
const char *units;
if (!(cmd->default_settings.unit_factor =
dm_units_to_factor(units = find_config_tree_str(cmd, global_units_CFG, NULL),
dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL),
&cmd->default_settings.unit_type, 1, NULL))) {
log_error("Unrecognised configuration setting for global/units: %s", units);
log_error("Invalid units specification");
return 0;
}
@@ -645,8 +640,8 @@ static int _process_config(struct cmd_context *cmd)
if (!strcmp(cmd->stripe_filler, "/dev/ioerror") &&
stat(cmd->stripe_filler, &st))
cmd->stripe_filler = "error";
else if (strcmp(cmd->stripe_filler, "error") &&
strcmp(cmd->stripe_filler, "zero")) {
if (strcmp(cmd->stripe_filler, "error")) {
if (stat(cmd->stripe_filler, &st)) {
log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
"is invalid,", cmd->stripe_filler);
@@ -1002,7 +997,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
return 0;
return_0;
}
for (cv = cn->v; cv; cv = cv->next) {
@@ -1760,15 +1755,6 @@ bad:
return 0;
}
int init_run_by_dmeventd(struct cmd_context *cmd)
{
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
init_ignore_suspended_devices(1);
init_disable_dmeventd_monitoring(1); /* Lock settings */
return 0;
}
void destroy_config_context(struct cmd_context *cmd)
{
_destroy_config(cmd);
@@ -1801,27 +1787,10 @@ struct cmd_context *create_config_context(void)
goto_out;
dm_list_init(&cmd->config_files);
dm_list_init(&cmd->tags);
if (!_init_lvm_conf(cmd))
goto_out;
if (!_init_hostname(cmd))
goto_out;
if (!_init_tags(cmd, cmd->cft))
goto_out;
/* Load lvmlocal.conf */
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
goto_out;
if (!_init_tag_configs(cmd))
goto_out;
if (!(cmd->cft = _merge_config_files(cmd, cmd->cft)))
goto_out;
return cmd;
out:
if (cmd)
@@ -2011,6 +1980,7 @@ out:
cmd = NULL;
}
return cmd;
}

View File

@@ -88,20 +88,11 @@ struct cmd_context {
* Command line and arguments.
*/
const char *cmd_line;
const char *name; /* needed before cmd->command is set */
struct command_name *cname;
struct command *command;
char **argv;
struct arg_values *opt_arg_values;
struct arg_values *arg_values;
struct dm_list arg_value_groups;
/*
* Position args remaining after command name
* and --options are removed from original argc/argv.
*/
int position_argc;
char **position_argv;
/*
* Format handlers.
*/
@@ -242,7 +233,6 @@ 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);
int init_run_by_dmeventd(struct cmd_context *cmd);
/*
* A config context is a very light weight cmd struct that

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, 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},
#include "config_settings.h"
#undef cfg_section
#undef cfg
@@ -389,7 +389,7 @@ int override_config_tree_from_string(struct cmd_context *cmd,
!config_force_check(cmd, CONFIG_STRING, cft_new)) {
log_error("Ignoring invalid configuration string.");
dm_config_destroy(cft_new);
return 0;
return_0;
}
if (!(cs = dm_pool_zalloc(cft_new->mem, sizeof(struct config_source)))) {
@@ -481,8 +481,7 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
if (profile->source == CONFIG_PROFILE_COMMAND)
return _override_config_tree_from_command_profile(cmd, profile);
if (profile->source == CONFIG_PROFILE_METADATA)
else if (profile->source == CONFIG_PROFILE_METADATA)
return _override_config_tree_from_metadata_profile(cmd, profile);
log_error(INTERNAL_ERROR "override_config_tree_from_profile: incorrect profile source type");
@@ -497,7 +496,7 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int checksum_only, int no_dup_node_check)
int checksum_only)
{
char *fb, *fe;
int r = 0;
@@ -548,13 +547,8 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
if (!checksum_only) {
fe = fb + size + size2;
if (no_dup_node_check) {
if (!dm_config_parse_without_dup_node_check(cft, fb, fe))
goto_out;
} else {
if (!dm_config_parse(cft, fb, fe))
goto_out;
}
if (!dm_config_parse(cft, fb, fe))
goto_out;
}
r = 1;
@@ -602,7 +596,7 @@ int config_file_read(struct dm_config_tree *cft)
}
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0, 0, 0);
(checksum_fn_t) NULL, 0, 0);
if (!cf->keep_open) {
if (!dev_close(cf->dev))
@@ -620,9 +614,9 @@ 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))
#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))
static int _cfg_def_make_path(char *buf, size_t buf_size, int id, cfg_def_item_t *item, int xlate)
{
@@ -743,16 +737,14 @@ static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
switch (toupper(token[0])) {
case 'I':
case 'B':
errno = 0;
v->v.i = strtoll(token + 1, &r, 10);
if (errno || *r)
if (*r)
goto bad;
v->type = DM_CFG_INT;
break;
case 'F':
errno = 0;
v->v.f = strtod(token + 1, &r);
if (errno || *r)
if (*r)
goto bad;
v->type = DM_CFG_FLOAT;
break;
@@ -1880,12 +1872,6 @@ int config_write(struct dm_config_tree *cft,
}
log_verbose("Dumping configuration to %s", file);
if (tree_spec->withgeneralpreamble)
fprintf(baton.fp, CFG_PREAMBLE_GENERAL);
if (tree_spec->withlocalpreamble)
fprintf(baton.fp, CFG_PREAMBLE_LOCAL);
if (!argc) {
if (!dm_config_write_node_out(cft->root, &_out_spec, &baton)) {
log_error("Failure while writing to %s", file);
@@ -2451,13 +2437,21 @@ const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_cont
int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile)
{
const char *str;
uint32_t chunk_size;
int chunk_size_calc_method;
if (!get_default_allocation_thin_pool_chunk_size(cmd, profile, &chunk_size,
&chunk_size_calc_method)) {
stack; /* Ignore this error, never happens... */
if (!(str = find_config_tree_str(cmd, allocation_thin_pool_chunk_size_policy_CFG, profile))) {
log_error(INTERNAL_ERROR "Cannot find configuration.");
return 0;
}
if (!strcasecmp(str, "generic"))
chunk_size = DEFAULT_THIN_POOL_CHUNK_SIZE * 2;
else if (!strcasecmp(str, "performance"))
chunk_size = DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE * 2;
else {
log_error("Thin pool chunk size calculation policy \"%s\" is unrecognised.", str);
return 0;
}
return (int) chunk_size;
@@ -2467,25 +2461,3 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
{
return DEFAULT_CACHE_POOL_CHUNK_SIZE * 2;
}
uint64_t get_default_allocation_cache_pool_max_chunks_CFG(struct cmd_context *cmd, struct profile *profile)
{
static int _warn_max_chunks = 0;
/*
* TODO: In future may depend on the cache target version,
* newer targets may scale better.
*/
uint64_t default_max_chunks = DEFAULT_CACHE_POOL_MAX_CHUNKS;
uint64_t max_chunks = find_config_tree_int(cmd, allocation_cache_pool_max_chunks_CFG, profile);
if (!max_chunks)
max_chunks = default_max_chunks;
else if (max_chunks > default_max_chunks)
/* Still warn the user when the value is tweaked above recommended level */
/* Maybe drop to log_verbose... */
log_warn_suppress(_warn_max_chunks++, "WARNING: Configured cache_pool_max_chunks value "
FMTu64 " is higher then recommended " FMTu64 ".",
max_chunks, default_max_chunks);
return max_chunks;
}

View File

@@ -141,7 +141,6 @@ typedef struct cfg_def_item {
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 */
const char *file_premable; /* comment text to use at the start of the file */
} cfg_def_item_t;
/* configuration definition tree types */
@@ -174,8 +173,6 @@ struct config_def_tree_spec {
unsigned withversions:1; /* include versions */
unsigned withspaces:1; /* add more spaces in output for better readability */
unsigned unconfigured:1; /* use unconfigured path strings */
unsigned withgeneralpreamble:1; /* include preamble for a general config file */
unsigned withlocalpreamble:1; /* include preamble for a local config file */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
};
@@ -242,7 +239,7 @@ struct dm_config_tree *config_open(config_source_t source, const char *filename,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int skip_parse, int no_dup_node_check);
int skip_parse);
int config_file_read(struct dm_config_tree *cft);
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
struct cmd_context *cmd);
@@ -310,6 +307,5 @@ int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, st
#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
uint64_t get_default_allocation_cache_pool_max_chunks_CFG(struct cmd_context *cmd, struct profile *profile);
#endif

View File

@@ -121,30 +121,6 @@
cfg_section(root_CFG_SECTION, "(root)", root_CFG_SECTION, 0, vsn(0, 0, 0), 0, NULL, NULL)
#define CFG_PREAMBLE_GENERAL \
"# This is an example configuration file for the LVM2 system.\n" \
"# It contains the default settings that would be used if there was no\n" \
"# @DEFAULT_SYS_DIR@/lvm.conf file.\n" \
"#\n" \
"# Refer to 'man lvm.conf' for further information including the file layout.\n" \
"#\n" \
"# Refer to 'man lvm.conf' for information about how settings configured in\n" \
"# this file are combined with built-in values and command line options to\n" \
"# arrive at the final values used by LVM.\n" \
"#\n" \
"# Refer to 'man lvmconfig' for information about displaying the built-in\n" \
"# and configured values used by LVM.\n" \
"#\n" \
"# If a default value is set in this file (not commented out), then a\n" \
"# new version of LVM using this file will continue using that value,\n" \
"# even if the new version of LVM changes the built-in default value.\n" \
"#\n" \
"# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set\n" \
"# the environment variable LVM_SYSTEM_DIR before running the tools.\n" \
"#\n" \
"# N.B. Take care that each setting only appears once if uncommenting\n" \
"# example settings in this file.\n\n"
cfg_section(config_CFG_SECTION, "config", root_CFG_SECTION, 0, vsn(2, 2, 99), 0, NULL,
"How LVM configuration settings are handled.\n")
@@ -185,26 +161,6 @@ cfg_section(tags_CFG_SECTION, "tags", root_CFG_SECTION, CFG_DEFAULT_COMMENTED, v
cfg_section(local_CFG_SECTION, "local", root_CFG_SECTION, 0, vsn(2, 2, 117), 0, NULL,
"LVM settings that are specific to the local host.\n")
#define CFG_PREAMBLE_LOCAL \
"# This is a local configuration file template for the LVM2 system\n" \
"# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .\n" \
"#\n" \
"# Refer to 'man lvm.conf' for information about the file layout.\n" \
"#\n" \
"# To put this file in a different directory and override\n" \
"# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before\n" \
"# running the tools.\n" \
"#\n" \
"# The lvmlocal.conf file is normally expected to contain only the\n" \
"# \"local\" section which contains settings that should not be shared or\n" \
"# repeated among different hosts. (But if other sections are present,\n" \
"# they *will* get processed. Settings in this file override equivalent\n" \
"# ones in lvm.conf and are in turn overridden by ones in any enabled\n" \
"# lvm_<tag>.conf files.)\n" \
"#\n" \
"# Please take care that each setting only appears once if uncommenting\n" \
"# example settings in this file and never copy this file between hosts.\n\n"
cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), NULL, 0, NULL,
"If enabled, any LVM configuration mismatch is reported.\n"
"This implies checking that the configuration key is understood by\n"
@@ -513,28 +469,18 @@ cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separa
cfg(allocation_raid_stripe_all_devices_CFG, "raid_stripe_all_devices", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES, vsn(2, 2, 162), NULL, 0, NULL,
"Stripe across all PVs when RAID stripes are not specified.\n"
"If enabled, all PVs in the VG or on the command line are used for\n"
"raid0/4/5/6/10 when the command does not specify the number of\n"
"stripes to use.\n"
"If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10\n"
"when the command does not specify the number of stripes to use.\n"
"This was the default behaviour until release 2.02.162.\n")
cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
"Cache pool metadata and data will always use different PVs.\n")
cfg(allocation_cache_pool_cachemode_CFG, "cache_pool_cachemode", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 113), NULL, vsn(2, 2, 128),
cfg(allocation_cache_pool_cachemode_CFG, "cache_pool_cachemode", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 113), NULL, vsn(2, 2, 128),
"This has been replaced by the allocation/cache_mode setting.\n",
"Cache mode.\n")
cfg(allocation_cache_metadata_format_CFG, "cache_metadata_format", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_CACHE_METADATA_FORMAT, vsn(2, 2, 169), NULL, 0, NULL,
"Sets default metadata format for new cache.\n"
"#\n"
"Accepted values:\n"
" 0 Automatically detected best available format\n"
" 1 Original format\n"
" 2 Improved 2nd. generation format\n"
"#\n")
cfg(allocation_cache_mode_CFG, "cache_mode", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 128), NULL, 0, NULL,
cfg(allocation_cache_mode_CFG, "cache_mode", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_MODE, vsn(2, 2, 128), NULL, 0, NULL,
"The default cache mode used for new cache.\n"
"#\n"
"Accepted values:\n"
@@ -546,20 +492,20 @@ cfg(allocation_cache_mode_CFG, "cache_mode", allocation_CFG_SECTION, CFG_PROFILA
"#\n"
"This setting replaces allocation/cache_pool_cachemode.\n")
cfg(allocation_cache_policy_CFG, "cache_policy", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, 0, vsn(2, 2, 128), NULL, 0, NULL,
cfg(allocation_cache_policy_CFG, "cache_policy", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, 0, vsn(2, 2, 128), NULL, 0, NULL,
"The default cache policy used for new cache volume.\n"
"Since kernel 4.2 the default policy is smq (Stochastic multiqueue),\n"
"Since kernel 4.2 the default policy is smq (Stochastic multique),\n"
"otherwise the older mq (Multiqueue) policy is selected.\n")
cfg_section(allocation_cache_settings_CFG_SECTION, "cache_settings", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
cfg_section(allocation_cache_settings_CFG_SECTION, "cache_settings", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
"Settings for the cache policy.\n"
"See documentation for individual cache policies for more info.\n")
cfg_section(policy_settings_CFG_SUBSECTION, "policy_settings", allocation_cache_settings_CFG_SECTION, CFG_NAME_VARIABLE | CFG_SECTION_NO_CHECK | CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
cfg_section(policy_settings_CFG_SUBSECTION, "policy_settings", allocation_cache_settings_CFG_SECTION, CFG_NAME_VARIABLE | CFG_SECTION_NO_CHECK | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
"Replace this subsection name with a policy name.\n"
"Multiple subsections for different policies can be created.\n")
cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 106), 0, NULL,
cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 106), 0, NULL,
"The minimal chunk size in KiB for cache pool volumes.\n"
"Using a chunk_size that is too large can result in wasteful use of\n"
"the cache, where small reads and writes can cause large sections of\n"
@@ -570,11 +516,6 @@ cfg_runtime(allocation_cache_pool_chunk_size_CFG, "cache_pool_chunk_size", alloc
"on the smaller end of the spectrum. Supported values range from\n"
"32KiB to 1GiB in multiples of 32.\n")
cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, 0, vsn(2, 2, 165), NULL, 0, NULL,
"The maximum number of chunks in a cache pool.\n"
"For cache target v1.9 the recommended maximumm is 1000000 chunks.\n"
"Using cache pool with more chunks may degrade cache performance.\n")
cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
"Thin pool metdata and data will always use different PVs.\n")
@@ -979,7 +920,7 @@ cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL,
"devices/global_filter.\n")
cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMETAD_UPDATE_WAIT_TIME, vsn(2, 2, 151), NULL, 0, NULL,
"Number of seconds a command will wait for lvmetad update to finish.\n"
"The number of seconds a command will wait for lvmetad update to finish.\n"
"After waiting for this period, a command will not use lvmetad, and\n"
"will revert to disk scanning.\n")
@@ -1046,7 +987,7 @@ cfg_array(global_thin_disabled_features_CFG, "thin_disabled_features", global_CF
cfg_array(global_cache_disabled_features_CFG, "cache_disabled_features", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 128), NULL, 0, NULL,
"Features to not use in the cache driver.\n"
"This can be helpful for testing, or to avoid using a feature that is\n"
"causing problems. Features include: policy_mq, policy_smq, metadata2.\n"
"causing problems. Features include: policy_mq, policy_smq.\n"
"#\n"
"Example\n"
"cache_disabled_features = [ \"policy_smq\" ]\n"
@@ -1080,10 +1021,6 @@ cfg_array(global_cache_check_options_CFG, "cache_check_options", global_CFG_SECT
cfg_array(global_cache_repair_options_CFG, "cache_repair_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG, vsn(2, 2, 108), NULL, 0, NULL,
"List of options passed to the cache_repair command.\n")
cfg(global_fsadm_executable_CFG, "fsadm_executable", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_FSADM_PATH, vsn(2, 2, 170), "@FSADM_PATH@", 0, NULL,
"The full path to the fsadm command.\n"
"LVM uses this command to help with lvresize -r operations.\n")
cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SYSTEM_ID_SOURCE, vsn(2, 2, 117), NULL, 0, NULL,
"The method LVM uses to set the local system ID.\n"
"Volume Groups can also be given a system ID (by vgcreate, vgchange,\n"
@@ -1169,8 +1106,7 @@ cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECT
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
"Method to fill missing stripes when activating an incomplete LV.\n"
"Using 'error' will make inaccessible parts of the device return I/O\n"
"errors on access. Using 'zero' will return success (and zero) on I/O\n"
"You can instead use a device path, in which case,\n"
"errors on access. You can instead use a device path, in which case,\n"
"that device will be used in place of missing stripes. Using anything\n"
"other than 'error' with mirrored or snapshotted volumes is likely to\n"
"result in data corruption.\n")
@@ -1279,15 +1215,14 @@ cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activat
"read_only_volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n"
"#\n")
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
"This has been replaced by the activation/raid_region_size setting.\n",
"Size in KiB of each raid or mirror synchronization region.\n")
"Size in KiB of each copy operation when mirroring.\n")
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
"Size in KiB of each raid or mirror synchronization region.\n"
"The clean/dirty state of data is tracked for each region.\n"
"The value is rounded down to a power of two if necessary, and\n"
"is ignored if it is not a multiple of the machine memory page size.\n")
"For raid or mirror segment types, this is the amount of data that is\n"
"copied at once when initializing, or moved at once by pvmove.\n")
cfg(activation_error_when_full_CFG, "error_when_full", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ERROR_WHEN_FULL, vsn(2, 2, 115), NULL, 0, NULL,
"Return errors if a thin pool runs out of space.\n"
@@ -1636,7 +1571,7 @@ cfg(report_prefixes_CFG, "prefixes", report_CFG_SECTION, CFG_PROFILABLE | CFG_DE
cfg(report_quoted_CFG, "quoted", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_QUOTED, vsn(2, 2, 39), NULL, 0, NULL,
"Quote field values when using field name prefixes.\n")
cfg(report_columns_as_rows_CFG, "columns_as_rows", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COLUMNS_AS_ROWS, vsn(1, 0, 0), NULL, 0, NULL,
cfg(report_colums_as_rows_CFG, "colums_as_rows", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COLUMNS_AS_ROWS, vsn(1, 0, 0), NULL, 0, NULL,
"Output each column as a row.\n"
"If set, this also implies report/prefixes=1.\n")
@@ -1918,14 +1853,6 @@ cfg(dmeventd_thin_library_CFG, "thin_library", dmeventd_CFG_SECTION, 0, CFG_TYPE
"and emits a warning through syslog when the usage exceeds 80%. The\n"
"warning is repeated when 85%, 90% and 95% of the pool is filled.\n")
cfg(dmeventd_thin_command_CFG, "thin_command", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_THIN_COMMAND, vsn(2, 2, 169), NULL, 0, NULL,
"The plugin runs command with each 5% increment when thin-pool data volume\n"
"or metadata volume gets above 50%.\n"
"Command which starts with 'lvm ' prefix is internal lvm command.\n"
"You can write your own handler to customise behaviour in more details.\n"
"User handler is specified with the full path starting with '/'.\n")
/* TODO: systemd service handler */
cfg(dmeventd_executable_CFG, "executable", dmeventd_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_DMEVENTD_PATH, vsn(2, 2, 73), "@DMEVENTD_PATH@", 0, NULL,
"The full path to the dmeventd binary.\n")

View File

@@ -71,7 +71,7 @@
* FIXME: Increase these to 64 and further to the MD maximum
* once the SubLVs split and name shift got enhanced
*/
#define DEFAULT_RAID1_MAX_IMAGES 64
#define DEFAULT_RAID1_MAX_IMAGES 10
#define DEFAULT_RAID_MAX_IMAGES 64
#define DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES 0 /* Don't stripe across all devices if not -i/--stripes given */
@@ -81,7 +81,6 @@
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
#define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so"
#define DEFAULT_DMEVENTD_THIN_LIB "libdevmapper-event-lvm2thin.so"
#define DEFAULT_DMEVENTD_THIN_COMMAND "lvm lvextend --use-policies"
#define DEFAULT_DMEVENTD_MONITOR 1
#define DEFAULT_BACKGROUND_POLLING 1
@@ -104,9 +103,9 @@
#define DEFAULT_THIN_REPAIR_OPTION1 ""
#define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
#define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (DM_THIN_MAX_METADATA_SIZE / 2) /* KB */
#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
#define DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE (128 * 1024) /* KB */
#define DEFAULT_THIN_POOL_OPTIMAL_SIZE (128 * 1024 * 1024) /* KB */
#define DEFAULT_THIN_POOL_CHUNK_SIZE_POLICY "generic"
#define DEFAULT_THIN_POOL_CHUNK_SIZE 64 /* KB */
#define DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE 512 /* KB */
@@ -128,15 +127,11 @@
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
#define DEFAULT_CACHE_POOL_MAX_CHUNKS 1000000
#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_METADATA_FORMAT CACHE_METADATA_FORMAT_UNSELECTED /* Autodetect */
#define DEFAULT_CACHE_MODE "writethrough"
#define DEFAULT_FSADM_PATH FSADM_PATH
#define DEFAULT_UMASK 0077
#define DEFAULT_FORMAT "lvm2"
@@ -180,7 +175,7 @@
#define DEFAULT_INDENT 1
#define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
#define DEFAULT_UNITS "r"
#define DEFAULT_UNITS "h"
#define DEFAULT_SUFFIX 1
#define DEFAULT_HOSTTAGS 0
@@ -202,7 +197,7 @@
#define DEFAULT_ACTIVATION_MODE "degraded"
#define DEFAULT_USE_LINEAR_TARGET 1
#define DEFAULT_STRIPE_FILLER "error"
#define DEFAULT_RAID_REGION_SIZE 2048 /* KB */
#define DEFAULT_RAID_REGION_SIZE 512 /* KB */
#define DEFAULT_INTERVAL 15
#define DEFAULT_MAX_HISTORY 100

View File

@@ -320,8 +320,8 @@ static int _compare_paths(const char *path0, const char *path1)
/* ASCII comparison */
if (strcmp(path0, path1) < 0)
return 0;
return 1;
else
return 1;
}
static int _add_alias(struct device *dev, const char *path)
@@ -706,12 +706,6 @@ static int _insert_dev(const char *path, dev_t d)
}
}
if (dm_hash_lookup(_cache.names, path) == dev) {
/* Hash already has matching entry present */
log_debug("Path already cached %s.", path);
return 1;
}
if (!(path_copy = dm_pool_strdup(_cache.mem, path))) {
log_error("Failed to duplicate path string.");
return 0;
@@ -898,10 +892,10 @@ int dev_cache_index_devs(void)
if (errno == ENOENT) {
sysfs_has_dev_block = 0;
return 1;
} else {
log_sys_error("stat", path);
return 0;
}
log_sys_error("stat", path);
return 0;
}
} else if (!sysfs_has_dev_block)
return 1;

View File

@@ -36,9 +36,6 @@
#define DEV_EXT_UDEV_DEVTYPE "DEVTYPE"
#define DEV_EXT_UDEV_DEVTYPE_DISK "disk"
/* the list of symlinks associated with device node */
#define DEV_EXT_UDEV_DEVLINKS "DEVLINKS"
/*
* DEV_EXT_UDEV_MPATH_DEVICE_PATH is set by multipath in udev db
* with value either 0 or 1. The same functionality as

View File

@@ -405,8 +405,8 @@ int dev_get_size(struct device *dev, uint64_t *size)
if ((dev->flags & DEV_REGULAR))
return _dev_get_size_file(dev, size);
return _dev_get_size_dev(dev, size);
else
return _dev_get_size_dev(dev, size);
}
int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead)

View File

@@ -28,7 +28,7 @@
#define MD_SB_MAGIC 0xa92b4efc
#define MD_RESERVED_BYTES (64 * 1024ULL)
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
#define MD_NEW_SIZE_SECTORS(x) (((x) & ~(MD_RESERVED_SECTORS - 1)) \
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
- MD_RESERVED_SECTORS)
#define MD_MAX_SYSFS_SIZE 64

View File

@@ -76,7 +76,7 @@ struct dev_types *create_dev_types(const char *proc_dir,
i++;
/* If it's not a number it may be name of section */
line_maj = atoi(line + i);
line_maj = atoi(((char *) (line + i)));
if (line_maj < 0 || line_maj >= NUMBER_OF_MAJORS) {
/*
@@ -125,10 +125,6 @@ struct dev_types *create_dev_types(const char *proc_dir,
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
dt->emcpower_major = line_maj;
/* Look for Veritas Dynamic Multipathing */
if (!strncmp("VxDMP", line + i, 5) && isspace(*(line + i + 5)))
dt->vxdmp_major = line_maj;
if (!strncmp("loop", line + i, 4) && isspace(*(line + i + 4)))
dt->loop_major = line_maj;
@@ -222,9 +218,6 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->power2_major)
return 1;
if (MAJOR(dev->dev) == dt->vxdmp_major)
return 1;
if ((MAJOR(dev->dev) == dt->blkext_major) &&
dev_get_primary_dev(dt, dev, &primary_dev) &&
(MAJOR(primary_dev) == dt->md_major))
@@ -253,9 +246,6 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
if (MAJOR(dev->dev) == dt->power2_major)
return "POWER2";
if (MAJOR(dev->dev) == dt->vxdmp_major)
return "VXDMP";
if (MAJOR(dev->dev) == dt->blkext_major)
return "BLKEXT";
@@ -615,38 +605,38 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
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("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
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_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
} 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_warn("WARNING: " MSG_FAILED_SIG_OFFSET MSG_WIPING_SKIPPED, type, name);
return 2;
}
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_warn("WARNING: " MSG_FAILED_SIG_LENGTH MSG_WIPING_SKIPPED, type, name);
return 2;
}
usage = "partition table";
} else
@@ -986,100 +976,3 @@ int dev_is_rotational(struct dev_types *dt, struct device *dev)
return 1;
}
#endif
#ifdef UDEV_SYNC_SUPPORT
/*
* Udev daemon usually has 30s timeout to process each event by default.
* But still, that value can be changed in udev configuration and we
* don't have libudev API to read the actual timeout value used.
*/
/* FIXME: Is this long enough to wait for udev db to get initialized?
*
* Take also into consideration that this check is done for each
* device that is scanned so we don't want to wait for a long time
* if there's something wrong with udev, e.g. timeouts! With current
* libudev API, we can't recognize whether the event processing has
* not finished yet and it's still being processed or whether it has
* failed already due to timeout in udev - in both cases the
* udev_device_get_is_initialized returns 0.
*/
#define UDEV_DEV_IS_MPATH_COMPONENT_ITERATION_COUNT 100
#define UDEV_DEV_IS_MPATH_COMPONENT_USLEEP 100000
int udev_dev_is_mpath_component(struct device *dev)
{
struct udev *udev_context = udev_get_library_context();
struct udev_device *udev_device = NULL;
const char *value;
int initialized = 0;
unsigned i = 0;
int ret = 0;
if (!udev_context) {
log_warn("WARNING: No udev context available to check if device %s is multipath component.", dev_name(dev));
return 0;
}
while (1) {
if (i >= UDEV_DEV_IS_MPATH_COMPONENT_ITERATION_COUNT)
break;
if (udev_device)
udev_device_unref(udev_device);
if (!(udev_device = udev_device_new_from_devnum(udev_context, 'b', dev->dev))) {
log_warn("WARNING: Failed to get udev device handler for device %s.", dev_name(dev));
return 0;
}
#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
if ((initialized = udev_device_get_is_initialized(udev_device)))
break;
#else
if ((initialized = (udev_device_get_property_value(udev_device, DEV_EXT_UDEV_DEVLINKS) != NULL)))
break;
#endif
log_debug("Device %s not initialized in udev database (%u/%u, %u microseconds).", dev_name(dev),
i + 1, UDEV_DEV_IS_MPATH_COMPONENT_ITERATION_COUNT,
i * UDEV_DEV_IS_MPATH_COMPONENT_USLEEP);
usleep(UDEV_DEV_IS_MPATH_COMPONENT_USLEEP);
i++;
}
if (!initialized) {
log_warn("WARNING: Device %s not initialized in udev database even after waiting %u microseconds.",
dev_name(dev), i * UDEV_DEV_IS_MPATH_COMPONENT_USLEEP);
goto out;
}
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH)) {
log_debug("Device %s is multipath component based on blkid variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
ret = 1;
goto out;
}
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
if (value && !strcmp(value, "1")) {
log_debug("Device %s is multipath component based on multipath variable in udev db (%s=\"%s\").",
dev_name(dev), DEV_EXT_UDEV_MPATH_DEVICE_PATH, value);
ret = 1;
goto out;
}
out:
udev_device_unref(udev_device);
return ret;
}
#else
int udev_dev_is_mpath_component(struct device *dev)
{
return 0;
}
#endif

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