mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-11 20:58:50 +03:00
Merge with master 9c5a85ce249f6
This commit is contained in:
parent
ee4df99b36
commit
2621f3da87
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,13 +1,16 @@
|
||||
*.5
|
||||
*.7
|
||||
*.8
|
||||
*.a
|
||||
*.d
|
||||
*.o
|
||||
*.orig
|
||||
*.pc
|
||||
*.pot
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*.swp
|
||||
*.sw*
|
||||
*~
|
||||
|
||||
.export.sym
|
||||
@ -17,11 +20,11 @@
|
||||
Makefile
|
||||
make.tmpl
|
||||
|
||||
configure.h
|
||||
version.h
|
||||
|
||||
/autom4te.cache/
|
||||
/autoscan.log
|
||||
/config.log
|
||||
/config.status
|
||||
/configure.scan
|
||||
/cscope.out
|
||||
/tags
|
||||
/tmp/
|
||||
|
12
Makefile.in
12
Makefile.in
@ -95,7 +95,7 @@ endif
|
||||
DISTCLEAN_TARGETS += cscope.out
|
||||
CLEAN_DIRS += autom4te.cache
|
||||
|
||||
check check_system check_cluster check_local check_lvmetad unit: all
|
||||
check check_system check_cluster check_local check_lvmetad check_lvmpolld unit: all
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate: tools
|
||||
@ -223,3 +223,13 @@ memcheck: test-programs
|
||||
ruby-test:
|
||||
$(RUBY) report-generators/test/ts.rb
|
||||
endif
|
||||
|
||||
ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
all: tags
|
||||
tags:
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags | head -1)" || $(RM) tags
|
||||
test -f tags || find $(top_srcdir) -maxdepth 4 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
|
||||
DISTCLEAN_TARGETS += tags
|
||||
endif
|
||||
|
@ -1 +1 @@
|
||||
1.02.98-git (2015-05-15)
|
||||
1.02.106-git (2015-08-17)
|
||||
|
89
WHATS_NEW
89
WHATS_NEW
@ -1,14 +1,99 @@
|
||||
Version 2.02.121 -
|
||||
Version 2.02.129 -
|
||||
===================================
|
||||
Support for raid types raid0 and raid0_meta
|
||||
|
||||
Version 2.02.128 - 17th August 2015
|
||||
===================================
|
||||
Allocation setting cache_pool_cachemode is replaced by cache_mode.
|
||||
Don't attempt to close config file that couldn't be opened.
|
||||
Check for valid cache mode in validation of cache segment.
|
||||
Change internal interface handling cache mode and policy.
|
||||
When no cache policy specified, prefer smq (if available) over mq.
|
||||
Add demo cache-mq and cache-smq profiles.
|
||||
Add cmd profilable allocation/cache_policy,cache_settings,cache_mode.
|
||||
Require cache_check 0.5.4 for use of --clear-needs-check-flag.
|
||||
Fix lvmetad udev rules to not override SYSTEMD_WANTS, add the service instead.
|
||||
|
||||
Version 2.02.127 - 10th August 2015
|
||||
===================================
|
||||
Do not init filters, locking, lvmetad, lvmpolld if command doesn't use it.
|
||||
Order fields in struct cmd_context more logically.
|
||||
Add lock_type to lvmcache VG summary and info structs.
|
||||
Fix regression in cache causing some PVs to bypass filters (2.02.105).
|
||||
Make configure --enable-realtime the default now.
|
||||
Update .gitignore and configure.in files to reflect usage of current tree.
|
||||
|
||||
Version 2.02.126 - 24th July 2015
|
||||
=================================
|
||||
Fix long option hyphen removal. (2.02.122)
|
||||
Fix clvmd freeze if client disappears without first releasing its locks.
|
||||
Fix lvconvert segfaults while performing snapshots merge.
|
||||
Ignore errors during detection if use_blkid_wiping=1 and --force is used.
|
||||
Recognise DM_ABORT_ON_INTERNAL_ERRORS env var override in lvm logging fn.
|
||||
Fix alloc segfault when extending LV with fewer stripes than in first seg.
|
||||
Fix handling of cache policy name.
|
||||
Set cache policy before with the first lvm2 cache pool metadata commit.
|
||||
Fix detection of thin-pool overprovisioning (2.02.124).
|
||||
Fix lvmpolld segfaults on 32 bit architectures.
|
||||
Add lvmlockd lock_args validation to vg_validate.
|
||||
Fix ignored --startstopservices option if running lvmconf with systemd.
|
||||
Hide sanlock LVs when processing LVs in VG unless named or --all used.
|
||||
|
||||
Version 2.02.125 - 7th July 2015
|
||||
================================
|
||||
Fix getline memory usage in lvmpolld.
|
||||
Add support --clear-needs-check-flag for cache_check of cache pool metadata.
|
||||
Add lvmetactl for developer use only.
|
||||
Rename global/lock_retries to lvmlockd_retries.
|
||||
Replace --enable-lvmlockd by --enable-lockd-sanlock and --enable-lockd-dlm.
|
||||
|
||||
Version 2.02.124 - 3rd July 2015
|
||||
================================
|
||||
Move sending thin pool messages from resume to suspend phase.
|
||||
Report warning when pool is overprovisioned and not auto resized.
|
||||
Recognize free-form date/time values for lv_time field in selection criteria.
|
||||
Added experimental lvmlockd with configure --enable-lvmlockd.
|
||||
Fix regression in select to match string fields if using synonyms (2.02.123).
|
||||
Fix regression when printing more lv names via display_lvname (2.02.122).
|
||||
Add missing error logging to unlock_vg and sync_local_dev_names callers.
|
||||
|
||||
Version 2.02.123 - 30th June 2015
|
||||
=================================
|
||||
Add report/time_format lvm.conf option to define time format for report.
|
||||
Fix makefile shell compare == when building lvmetad lvmpolld (2.02.120).
|
||||
Add --type full to lvmconfig for full configuration tree view.
|
||||
Add undocumented environment variables to lvm man page. (2.02.119)
|
||||
Add device synchronization point before activating a new snapshot.
|
||||
Add --withspaces to lvmconfig to add spaces in output for better readability.
|
||||
Add custom main function to libdaemon.
|
||||
Use lvmetad to track out-of-date metadata discovered.
|
||||
|
||||
Version 2.02.122 - 20th June 2015
|
||||
=================================
|
||||
Flush stdout before printing to stderr.
|
||||
Use pre-allocated buffer for printed LV names in display_lvname.
|
||||
Support thins with size of external origin unaligned with thin pool chunk.
|
||||
Allow extension of reduced thin volumes with external origins.
|
||||
Consider snapshot and origin LV as unusable if component devices suspended.
|
||||
Fix lvmconfig segfault on settings with undefined default value (2.02.120).
|
||||
Add explicit 's' (shared) LV activation mode.
|
||||
Ignore hyphens in long options names (i.e. --long-option == --longoption).
|
||||
|
||||
Version 2.02.121 - 12th June 2015
|
||||
=================================
|
||||
Distinguish between on-disk and lvmetad versions of text metadata.
|
||||
Remove DL_LIBS from Makefiles for daemons that don't need them.
|
||||
Zero errno in before strtoul call in dmsetup if tested after the call.
|
||||
Zero errno in before strtoul call in lvmpolld.
|
||||
Fix a segfault in pvscan --cache --background command.
|
||||
Fix test for AREA_PV when checking for failed mirrors.
|
||||
Do not use --sysinit in lvm2-activation{-early,-net}.service if lvmpolld used.
|
||||
Maintain outdated PV info in lvmetad till all old metadata is gone from disk.
|
||||
Do not fail polling when poll LV not found (already finished or removed).
|
||||
Replace poll_get_copy_vg/lv fns with vg_read() and find_lv() in polldaemon.
|
||||
Close all device fds only in before sleep call in polldaemon.
|
||||
Support for raid types raid0 and raid0_meta
|
||||
Simplify Makefile targets that generate exported symbols.
|
||||
Move various -D settings from Makefiles to configure.h.
|
||||
|
||||
Version 2.02.120 - 15th May 2015
|
||||
================================
|
||||
|
82
WHATS_NEW_DM
82
WHATS_NEW_DM
@ -1,5 +1,83 @@
|
||||
Version 1.02.98 -
|
||||
===============================
|
||||
Version 1.02.106 -
|
||||
===================================
|
||||
|
||||
Version 1.02.105 - 17th August 2015
|
||||
===================================
|
||||
Fix 'dmstats list -o all' segfault.
|
||||
Separate dmstats statistics fields from region information fields.
|
||||
Add interval and interval_ns fields to dmstats reports.
|
||||
Do not include internal glibc headers in libdm-timestamp.c (1.02.104)
|
||||
Exit immediately if no device is supplied to dmsetup wipe_table.
|
||||
Suppress dmsetup report headings when no data is output. (1.02.104)
|
||||
Adjust dmsetup usage/help output selection to match command invoked.
|
||||
Fix dmsetup -o all to select correct fields in splitname report.
|
||||
Restructure internal dmsetup argument handling across all commands.
|
||||
Add dm_report_is_empty() to indicate there is no data awaiting output.
|
||||
Add more arg validation for dm_tree_node_add_cache_target().
|
||||
Add --alldevices switch to replace use of --force for stats create / delete.
|
||||
|
||||
Version 1.02.104 - 10th August 2015
|
||||
===================================
|
||||
Add dmstats.8 man page
|
||||
Add dmstats --segments switch to create one region per device segment.
|
||||
Add dmstats --regionid, --allregions to specify a single / all stats regions.
|
||||
Add dmstats --allprograms for stats commands that filter by program ID.
|
||||
Add dmstats --auxdata and --programid args to specify aux data and program ID.
|
||||
Add report stats sub-command to provide repeating stats reports.
|
||||
Add clear, delete, list, and print stats sub-commands.
|
||||
Add create stats sub-command and --start, --length, --areas and --areasize.
|
||||
Recognize 'dmstats' as an alias for 'dmsetup stats' when run with this name.
|
||||
Add a 'stats' command to dmsetup to configure, manage and report stats data.
|
||||
Add statistics fields to dmsetup -o.
|
||||
Add libdm-stats library to allow management of device-mapper statistics.
|
||||
Add --nosuffix to suppress dmsetup unit suffixes in report output.
|
||||
Add --units to control dmsetup report field output units.
|
||||
Add support to redisplay column headings for repeating column reports.
|
||||
Fix report header and row resource leaks.
|
||||
Report timestamps of ioctls with dmsetup -vvv.
|
||||
Recognize report field name variants without any underscores too.
|
||||
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
||||
Add dm_timestamp functions to libdevmapper.
|
||||
Recognise vg/lv name format in dmsetup.
|
||||
Move size display code to libdevmapper as dm_size_to_string.
|
||||
|
||||
Version 1.02.103 - 24th July 2015
|
||||
=================================
|
||||
Introduce libdevmapper wrappers for all malloc-related functions.
|
||||
|
||||
Version 1.02.102 - 7th July 2015
|
||||
================================
|
||||
Include tool.h for default non-library use.
|
||||
Introduce format macros with embedded % such as FMTu64.
|
||||
|
||||
Version 1.02.101 - 3rd July 2015
|
||||
================================
|
||||
Add experimental support to passing messages in suspend tree.
|
||||
Add dm_report_value_cache_{set,get} to support caching during report/select.
|
||||
Add dm_report_reserved_handler to handle report reserved value actions.
|
||||
Support dynamic value in select: DM_REPORT_FIELD_RESERVED_VALUE_DYNAMIC_VALUE.
|
||||
Support fuzzy names in select: DM_REPORT_FIELD_RESERVED_VALUE_FUZZY_NAMES.
|
||||
Thin pool trace messages show a device name and major:minor.
|
||||
|
||||
Version 1.02.100 - 30th June 2015
|
||||
=================================
|
||||
Add since, after, until and before time operators to be used in selection.
|
||||
Add support for time in reports and selection: DM_REPORT_FIELD_TYPE_TIME.
|
||||
Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
|
||||
Support report reserved value names: DM_REPORT_FIELD_RESERVED_VALUE_NAMED.
|
||||
Add DM_CONFIG_VALUE_FMT_{INT_OCTAL,STRING_NO_QUOTES} config value format flag.
|
||||
Add DM_CONFIG_VALUE_FMT_COMMON_{ARRAY,EXTRA_SPACE} config value format flag.
|
||||
Add dm_config_value_{get,set}_format_flags to get and set config value format.
|
||||
|
||||
Version 1.02.99 - 20th June 2015
|
||||
================================
|
||||
New dm_tree_node_set_thin_pool_read_only(DM_1_02_99) for read-only thin pool.
|
||||
Enhance error message when thin-pool message fails.
|
||||
Fix dmeventd logging to avoid threaded use of static variable.
|
||||
Remove redundant dmeventd SIGALRM coded.
|
||||
|
||||
Version 1.02.98 - 12th June 2015
|
||||
================================
|
||||
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
|
||||
Use copy of errno made after each dm ioctl call in case errno changes later.
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@ -20,15 +20,19 @@ CONFDEST=lvm.conf
|
||||
CONFLOCAL=lvmlocal.conf
|
||||
|
||||
PROFILE_TEMPLATES=command_profile_template.profile metadata_profile_template.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) $(srcdir)/thin-generic.profile $(srcdir)/thin-performance.profile
|
||||
PROFILES=$(PROFILE_TEMPLATES) \
|
||||
$(srcdir)/cache-mq.profile \
|
||||
$(srcdir)/cache-smq.profile \
|
||||
$(srcdir)/thin-generic.profile \
|
||||
$(srcdir)/thin-performance.profile
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
.PHONY: install_conf install_localconf install_profiles
|
||||
|
||||
generate:
|
||||
(cat $(top_srcdir)/conf/example.conf.base && LD_LIBRARY_PATH=$(top_builddir)/libdm:$(LD_LIBRARY_PATH) $(top_builddir)/tools/lvm dumpconfig --type default --unconfigured --withcomments --ignorelocal) > 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 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 \
|
||||
|
20
conf/cache-mq.profile
Normal file
20
conf/cache-mq.profile
Normal file
@ -0,0 +1,20 @@
|
||||
# Demo configuration 'mq' cache policy
|
||||
#
|
||||
# Note: This policy has been deprecated in favor of the smq policy
|
||||
# keyword "default" means, setting is left with kernel defaults.
|
||||
#
|
||||
|
||||
allocation {
|
||||
cache_pool_chunk_size = 64
|
||||
cache_mode = "writethrough"
|
||||
cache_policy = "mq"
|
||||
cache_settings {
|
||||
mq {
|
||||
sequential_threshold = "default" # #nr_sequential_ios
|
||||
random_threshold = "default" # #nr_random_ios
|
||||
read_promote_adjustment = "default"
|
||||
write_promote_adjustment = "default"
|
||||
discard_promote_adjustment = "default"
|
||||
}
|
||||
}
|
||||
}
|
14
conf/cache-smq.profile
Normal file
14
conf/cache-smq.profile
Normal file
@ -0,0 +1,14 @@
|
||||
# Demo configuration 'smq' cache policy
|
||||
#
|
||||
# The stochastic multi-queue (smq) policy addresses some of the problems
|
||||
# with the multiqueue (mq) policy and uses less memory.
|
||||
#
|
||||
|
||||
allocation {
|
||||
cache_pool_chunk_size = 64
|
||||
cache_mode = "writethrough"
|
||||
cache_policy = "smq"
|
||||
cache_settings {
|
||||
# currently no settins for "smq" policy
|
||||
}
|
||||
}
|
@ -4,6 +4,17 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
@ -92,7 +103,6 @@ devices {
|
||||
# Example:
|
||||
# preferred_names = [ "^/dev/mpath/", "^/dev/mapper/mpath", "^/dev/[hs]d" ]
|
||||
# This configuration option does not have a default value defined.
|
||||
# preferred_names=[]
|
||||
|
||||
# Configuration option devices/filter.
|
||||
# Limit the block devices that are used by LVM commands.
|
||||
@ -128,8 +138,7 @@ devices {
|
||||
# Example:
|
||||
# Use anchors to be very specific.
|
||||
# filter = [ "a|^/dev/hda8$|", "r|.*/|" ]
|
||||
# This configuration option does not have a default value defined.
|
||||
# filter = []
|
||||
# filter = [ "a|.*/|" ]
|
||||
|
||||
# Configuration option devices/global_filter.
|
||||
# Limit the block devices that are used by LVM system components.
|
||||
@ -138,8 +147,7 @@ devices {
|
||||
# and lvmetad. Use global_filter to hide devices from these LVM
|
||||
# system components. The syntax is the same as devices/filter.
|
||||
# Devices rejected by global_filter are not opened by LVM.
|
||||
# This configuration option does not have a default value defined.
|
||||
# global_filter = []
|
||||
# global_filter = [ "a|.*/|" ]
|
||||
|
||||
# Configuration option devices/cache_dir.
|
||||
# Directory in which to store the device cache file.
|
||||
@ -167,7 +175,6 @@ devices {
|
||||
# types = [ "fd", 16 ]
|
||||
# This configuration option is advanced.
|
||||
# This configuration option does not have a default value defined.
|
||||
# types = []
|
||||
|
||||
# Configuration option devices/sysfs_scan.
|
||||
# Restrict device scanning to block devices appearing in sysfs.
|
||||
@ -197,7 +204,7 @@ devices {
|
||||
|
||||
# Configuration option devices/default_data_alignment.
|
||||
# Default alignment of the start of a PV data area in MB.
|
||||
# If set to 0, a value of 64KB will be used.
|
||||
# If set to 0, a value of 64KiB will be used.
|
||||
# Set to 1 for 1MiB, 2 for 2MiB, etc.
|
||||
# default_data_alignment = 1
|
||||
|
||||
@ -215,7 +222,7 @@ devices {
|
||||
data_alignment_detection = 1
|
||||
|
||||
# Configuration option devices/data_alignment.
|
||||
# Alignment of the start of a PV data area in KB.
|
||||
# Alignment of the start of a PV data area in KiB.
|
||||
# If a PV is placed directly on an md device and
|
||||
# md_chunk_alignment or data_alignment_detection are enabled,
|
||||
# then this setting is ignored. Otherwise, md_chunk_alignment
|
||||
@ -227,10 +234,10 @@ devices {
|
||||
# Detect PV data alignment offset based on sysfs device information.
|
||||
# The start of a PV aligned data area will be shifted by the
|
||||
# alignment_offset exposed in sysfs. This offset is often 0, but
|
||||
# may be non-zero. Certain 4KB sector drives that compensate for
|
||||
# may be non-zero. Certain 4KiB sector drives that compensate for
|
||||
# windows partitioning will have an alignment_offset of 3584 bytes
|
||||
# (sector 7 is the lowest aligned logical block, the 4KB sectors start
|
||||
# at LBA -1, and consequently sector 63 is aligned on a 4KB boundary).
|
||||
# (sector 7 is the lowest aligned logical block, the 4KiB sectors start
|
||||
# at LBA -1, and consequently sector 63 is aligned on a 4KiB boundary).
|
||||
# pvcreate --dataalignmentoffset will skip this detection.
|
||||
data_alignment_offset_detection = 1
|
||||
|
||||
@ -275,9 +282,9 @@ devices {
|
||||
require_restorefile_with_uuid = 1
|
||||
|
||||
# Configuration option devices/pv_min_size.
|
||||
# Minimum size (in KB) of block devices which can be used as PVs.
|
||||
# Minimum size in KiB of block devices which can be used as PVs.
|
||||
# In a clustered environment all nodes must use the same value.
|
||||
# Any value smaller than 512KB is ignored. The previous built-in
|
||||
# Any value smaller than 512KiB is ignored. The previous built-in
|
||||
# value was 512.
|
||||
pv_min_size = 2048
|
||||
|
||||
@ -296,7 +303,7 @@ devices {
|
||||
}
|
||||
|
||||
# Configuration section allocation.
|
||||
# How LVM selects free space for Logical Volumes.
|
||||
# How LVM selects space and applies properties to LVs.
|
||||
allocation {
|
||||
|
||||
# Configuration option allocation/cling_tag_list.
|
||||
@ -316,7 +323,6 @@ allocation {
|
||||
# they are situated.
|
||||
# cling_tag_list = [ "@site1", "@site2" ]
|
||||
# This configuration option does not have a default value defined.
|
||||
# cling_tag_list = []
|
||||
|
||||
# Configuration option allocation/maximise_cling.
|
||||
# Use a previous allocation algorithm.
|
||||
@ -336,13 +342,13 @@ allocation {
|
||||
# MD device signatures, swap signature, and LUKS signatures.
|
||||
# To see the list of signatures recognized by blkid, check the
|
||||
# output of the 'blkid -k' command.
|
||||
use_blkid_wiping = 1
|
||||
use_blkid_wiping = @DEFAULT_USE_BLKID_WIPING@
|
||||
|
||||
# Configuration option allocation/wipe_signatures_when_zeroing_new_lvs.
|
||||
# Look for and erase any signatures while zeroing a new LV.
|
||||
# Zeroing is controlled by the -Z/--zero option, and if not
|
||||
# specified, zeroing is used by default if possible.
|
||||
# Zeroing simply overwrites the first 4 KiB of a new LV
|
||||
# Zeroing simply overwrites the first 4KiB of a new LV
|
||||
# with zeroes and does no signature detection or wiping.
|
||||
# Signature wiping goes beyond zeroing and detects exact
|
||||
# types and positions of signatures within the whole LV.
|
||||
@ -368,17 +374,31 @@ allocation {
|
||||
# Cache pool metadata and data will always use different PVs.
|
||||
cache_pool_metadata_require_separate_pvs = 0
|
||||
|
||||
# Configuration option allocation/cache_pool_cachemode.
|
||||
# The default cache mode used for new cache pools.
|
||||
# Configuration option allocation/cache_mode.
|
||||
# The default cache mode used for new cache.
|
||||
# Possible options are: writethrough, writeback.
|
||||
# writethrough - Data blocks are immediately written from
|
||||
# the cache to disk.
|
||||
# writeback - Data blocks are written from the cache back
|
||||
# to disk after some delay to improve performance.
|
||||
# cache_pool_cachemode = "writethrough"
|
||||
# This setting replaces allocation/cache_pool_cachemode.
|
||||
# cache_mode = "writethrough"
|
||||
|
||||
# Configuration option allocation/cache_policy.
|
||||
# The default cache policy used for new cache volume.
|
||||
# For the kernel 4.2 and newer 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.
|
||||
|
||||
# Configuration section allocation/cache_settings.
|
||||
# Individual settings for policies.
|
||||
# See the help for individual policies for more info.
|
||||
# cache_settings {
|
||||
# }
|
||||
|
||||
# Configuration option allocation/cache_pool_chunk_size.
|
||||
# The minimal chunk size (in kiB) for cache pool volumes.
|
||||
# The minimal chunk size in KiB for cache pool volumes.
|
||||
# Using a chunk_size that is too large can result in wasteful
|
||||
# use of the cache, where small reads and writes can cause
|
||||
# large sections of an LV to be mapped into the cache. However,
|
||||
@ -386,10 +406,9 @@ allocation {
|
||||
# overhead trying to manage the numerous chunks that become mapped
|
||||
# into the cache. The former is more of a problem than the latter
|
||||
# in most cases, so we default to a value that is on the smaller
|
||||
# end of the spectrum. Supported values range from 32(kiB) to
|
||||
# 1048576 in multiples of 32.
|
||||
# end of the spectrum. Supported values range from 32KiB to
|
||||
# 1GiB in multiples of 32.
|
||||
# This configuration option does not have a default value defined.
|
||||
# cache_pool_chunk_size = 128
|
||||
|
||||
# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
|
||||
# Thin pool metdata and data will always use different PVs.
|
||||
@ -419,18 +438,17 @@ allocation {
|
||||
# thin_pool_chunk_size_policy = "generic"
|
||||
|
||||
# Configuration option allocation/thin_pool_chunk_size.
|
||||
# The minimal chunk size (in KB) for thin pool volumes.
|
||||
# The minimal chunk size in KiB for thin pool volumes.
|
||||
# Larger chunk sizes may improve performance for plain
|
||||
# thin volumes, however using them for snapshot volumes
|
||||
# is less efficient, as it consumes more space and takes
|
||||
# extra time for copying. When unset, lvm tries to estimate
|
||||
# chunk size starting from 64KB. Supported values are in
|
||||
# the range 64 to 1048576.
|
||||
# chunk size starting from 64KiB. Supported values are in
|
||||
# the range 64KiB to 1GiB.
|
||||
# This configuration option does not have a default value defined.
|
||||
# thin_pool_chunk_size = 128
|
||||
|
||||
# Configuration option allocation/physical_extent_size.
|
||||
# Default physical extent size to use for new VGs (in KB).
|
||||
# Default physical extent size in KiB to use for new VGs.
|
||||
# physical_extent_size = 4096
|
||||
}
|
||||
|
||||
@ -461,7 +479,6 @@ log {
|
||||
# Configuration option log/file.
|
||||
# Write error and debug log messages to a file specified here.
|
||||
# This configuration option does not have a default value defined.
|
||||
# file = ""
|
||||
|
||||
# Configuration option log/overwrite.
|
||||
# Overwrite the log file each time the program is run.
|
||||
@ -492,7 +509,7 @@ log {
|
||||
# Configuration option log/activation.
|
||||
# Log messages during activation.
|
||||
# Don't use this in low memory situations (can deadlock).
|
||||
# activation = 0
|
||||
activation = 0
|
||||
|
||||
# Configuration option log/debug_classes.
|
||||
# Select log messages by class.
|
||||
@ -502,8 +519,7 @@ log {
|
||||
# memory, devices, activation, allocation,
|
||||
# lvmetad, metadata, cache, locking, lvmpolld.
|
||||
# Use "all" to see everything.
|
||||
debug_classes = ["memory", "devices", "activation", "allocation",
|
||||
"lvmetad", "metadata", "cache", "locking", "lvmpolld"]
|
||||
debug_classes = [ "memory", "devices", "activation", "allocation", "lvmetad", "metadata", "cache", "locking", "lvmpolld" ]
|
||||
}
|
||||
|
||||
# Configuration section backup.
|
||||
@ -600,7 +616,7 @@ global {
|
||||
# The LVM1 tools need to be installed with .lvm1 suffices,
|
||||
# e.g. vgscan.lvm1. They will stop working once the lvm2
|
||||
# on-disk metadata format is used.
|
||||
# fallback_to_lvm1 = 0
|
||||
# fallback_to_lvm1 = @DEFAULT_FALLBACK_TO_LVM1@
|
||||
|
||||
# Configuration option global/format.
|
||||
# The default metadata format that commands should use.
|
||||
@ -613,11 +629,9 @@ global {
|
||||
# If support for LVM1 metadata was compiled as a shared library use
|
||||
# format_libraries = "liblvm2format1.so"
|
||||
# This configuration option does not have a default value defined.
|
||||
# format_libraries = []
|
||||
|
||||
# Configuration option global/segment_libraries.
|
||||
# This configuration option does not have a default value defined.
|
||||
# segment_libraries = []
|
||||
|
||||
# Configuration option global/proc.
|
||||
# Location of proc filesystem.
|
||||
@ -694,7 +708,6 @@ global {
|
||||
# Configuration option global/library_dir.
|
||||
# Search this directory first for shared libraries.
|
||||
# This configuration option does not have a default value defined.
|
||||
# library_dir = ""
|
||||
|
||||
# Configuration option global/locking_library.
|
||||
# The external locking library to use for locking_type 2.
|
||||
@ -780,11 +793,11 @@ global {
|
||||
sparse_segtype_default = "@DEFAULT_SPARSE_SEGTYPE@"
|
||||
|
||||
# Configuration option global/lvdisplay_shows_full_device_path.
|
||||
# Enable this to reinstate the previous lvdisplay name format.
|
||||
# The default format for displaying LV names in lvdisplay was changed
|
||||
# in version 2.02.89 to show the LV name and path separately.
|
||||
# Previously this was always shown as /dev/vgname/lvname even when that
|
||||
# was never a valid path in the /dev filesystem.
|
||||
# Enable this option to reinstate the previous format.
|
||||
# lvdisplay_shows_full_device_path = 0
|
||||
|
||||
# Configuration option global/use_lvmetad.
|
||||
@ -822,6 +835,23 @@ global {
|
||||
# is seen.
|
||||
use_lvmetad = @DEFAULT_USE_LVMETAD@
|
||||
|
||||
# Configuration option global/use_lvmlockd.
|
||||
# Use lvmlockd for locking among hosts using LVM on shared storage.
|
||||
use_lvmlockd = 0
|
||||
|
||||
# Configuration option global/lvmlockd_lock_retries.
|
||||
# Retry lvmlockd lock requests this many times.
|
||||
# lvmlockd_lock_retries = 3
|
||||
|
||||
# Configuration option global/sanlock_lv_extend.
|
||||
# Size in MiB to extend the internal LV holding sanlock locks.
|
||||
# The internal LV holds locks for each LV in the VG, and after
|
||||
# enough LVs have been created, the internal LV needs to be extended.
|
||||
# lvcreate will automatically extend the internal LV when needed by
|
||||
# the amount specified here. Setting this to 0 disables the
|
||||
# automatic extension and can cause lvcreate to fail.
|
||||
# sanlock_lv_extend = 256
|
||||
|
||||
# Configuration option global/thin_check_executable.
|
||||
# The full path to the thin_check command.
|
||||
# LVM uses this command to check that a thin metadata
|
||||
@ -856,12 +886,11 @@ global {
|
||||
# ignorable errors and fix them later.
|
||||
# With thin_check version 3.2 or newer you should add
|
||||
# --clear-needs-check-flag.
|
||||
# thin_check_options = ["-q", "--clear-needs-check-flag"]
|
||||
# thin_check_options = [ "-q", "--clear-needs-check-flag" ]
|
||||
|
||||
# Configuration option global/thin_repair_options.
|
||||
# List of options passed to the thin_repair command.
|
||||
# This configuration option does not have a default value defined.
|
||||
# thin_repair_options = ""
|
||||
# thin_repair_options = [ "" ]
|
||||
|
||||
# Configuration option global/thin_disabled_features.
|
||||
# Features to not use in the thin driver.
|
||||
@ -873,7 +902,15 @@ global {
|
||||
# Example:
|
||||
# thin_disabled_features = [ "discards", "block_size" ]
|
||||
# This configuration option does not have a default value defined.
|
||||
# thin_disabled_features = []
|
||||
|
||||
# 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: policy_mq, policy_smq.
|
||||
# Example:
|
||||
# cache_disabled_features = [ "policy_smq" ]
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option global/cache_check_executable.
|
||||
# The full path to the cache_check command.
|
||||
@ -886,6 +923,8 @@ global {
|
||||
# Also see cache_check_options.
|
||||
# The cache tools are available from the package
|
||||
# device-mapper-persistent-data.
|
||||
# With cache_check version 5.0 or newer you should add
|
||||
# --clear-needs-check-flag.
|
||||
# cache_check_executable = "@CACHE_CHECK_CMD@"
|
||||
|
||||
# Configuration option global/cache_dump_executable.
|
||||
@ -904,12 +943,11 @@ global {
|
||||
|
||||
# Configuration option global/cache_check_options.
|
||||
# List of options passed to the cache_check command.
|
||||
# cache_check_options = "-q"
|
||||
# cache_check_options = [ "-q", "--clear-needs-check-flag" ]
|
||||
|
||||
# Configuration option global/cache_repair_options.
|
||||
# List of options passed to the cache_repair command.
|
||||
# This configuration option does not have a default value defined.
|
||||
# cache_repair_options = ""
|
||||
# cache_repair_options = [ "" ]
|
||||
|
||||
# Configuration option global/system_id_source.
|
||||
# The method LVM uses to set the local system ID.
|
||||
@ -925,29 +963,29 @@ global {
|
||||
# 'local' section of an lvm configuration file, e.g. lvmlocal.conf.
|
||||
# uname - Set the system ID from the hostname (uname) of the system.
|
||||
# System IDs beginning localhost are not permitted.
|
||||
# machineid - Use the contents of the file @CONFDIR@/machine-id to set the
|
||||
# machineid - Use the contents of the machine-id file to set the
|
||||
# system ID. Some systems create this file at installation time.
|
||||
# See 'man machine-id'.
|
||||
# See 'man machine-id' and global/etc.
|
||||
# file - Use the contents of another file (system_id_file) to set
|
||||
# the system ID.
|
||||
# system_id_source = "none"
|
||||
system_id_source = "none"
|
||||
|
||||
# Configuration option global/system_id_file.
|
||||
# The full path to the file containing a system ID.
|
||||
# This is used when system_id_source is set to 'file'.
|
||||
# Comments starting with the character # are ignored.
|
||||
# This configuration option does not have a default value defined.
|
||||
# system_id_file = ""
|
||||
|
||||
# Configuration option global/use_lvmpolld.
|
||||
# Use lvmpolld to supervise long running LVM commands.
|
||||
# When enabled, control of long running LVM commands is transferred
|
||||
# from the original LVM command to the lvmpolld daemon. This allows
|
||||
# from the original LVM command to the lvmpolld daemon. This allows
|
||||
# the operation to continue independent of the original LVM command.
|
||||
# After lvmpolld takes over, the LVM command displays the progress
|
||||
# of the ongoing operation. lvmpolld itself runs LVM commands to manage
|
||||
# the progress of ongoing operations. lvmpolld can be used as a native
|
||||
# of the ongoing operation. lvmpolld itself runs LVM commands to manage
|
||||
# the progress of ongoing operations. lvmpolld can be used as a native
|
||||
# systemd service, which allows it to be started on demand, and to use
|
||||
# its own control group. When this option is disabled, LVM commands will
|
||||
# its own control group. When this option is disabled, LVM commands will
|
||||
# supervise long running operations by forking themselves.
|
||||
use_lvmpolld = @DEFAULT_USE_LVMPOLLD@
|
||||
}
|
||||
@ -1016,12 +1054,12 @@ activation {
|
||||
use_linear_target = 1
|
||||
|
||||
# Configuration option activation/reserved_stack.
|
||||
# Stack size in KB to reserve for use while devices are suspended.
|
||||
# Stack size in KiB to reserve for use while devices are suspended.
|
||||
# Insufficent reserve risks I/O deadlock during device suspension.
|
||||
reserved_stack = 64
|
||||
|
||||
# Configuration option activation/reserved_memory.
|
||||
# Memory size in KB to reserve for use while devices are suspended.
|
||||
# Memory size in KiB to reserve for use while devices are suspended.
|
||||
# Insufficent reserve risks I/O deadlock during device suspension.
|
||||
reserved_memory = 8192
|
||||
|
||||
@ -1048,7 +1086,6 @@ activation {
|
||||
# Example:
|
||||
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
|
||||
# This configuration option does not have a default value defined.
|
||||
# volume_list = []
|
||||
|
||||
# Configuration option activation/auto_activation_volume_list.
|
||||
# Only LVs selected by this list are auto-activated.
|
||||
@ -1080,7 +1117,6 @@ activation {
|
||||
# Possible options are: vgname, vgname/lvname, @tag, @*
|
||||
# See volume_list for how these options are matched to LVs.
|
||||
# This configuration option does not have a default value defined.
|
||||
# auto_activation_volume_list = []
|
||||
|
||||
# Configuration option activation/read_only_volume_list.
|
||||
# LVs in this list are activated in read-only mode.
|
||||
@ -1092,7 +1128,6 @@ activation {
|
||||
# Possible options are: vgname, vgname/lvname, @tag, @*
|
||||
# See volume_list for how these options are matched to LVs.
|
||||
# This configuration option does not have a default value defined.
|
||||
# read_only_volume_list = []
|
||||
|
||||
# Configuration option activation/raid_region_size.
|
||||
# Size in KiB of each raid or mirror synchronization region.
|
||||
@ -1221,7 +1256,7 @@ activation {
|
||||
# Auto-extending a thin pool adds this percent extra space.
|
||||
# The amount of additional space added to a thin pool is this
|
||||
# percent of its current size.
|
||||
thin_pool_autoextend_percent=20
|
||||
thin_pool_autoextend_percent = 20
|
||||
|
||||
# Configuration option activation/mlock_filter.
|
||||
# Do not mlock these memory areas.
|
||||
@ -1240,7 +1275,6 @@ activation {
|
||||
# mlock_filter = [ "locale/locale-archive", "gconv/gconv-modules.cache" ]
|
||||
# This configuration option is advanced.
|
||||
# This configuration option does not have a default value defined.
|
||||
# mlock_filter = []
|
||||
|
||||
# Configuration option activation/use_mlockall.
|
||||
# Use the old behavior of mlockall to pin all memory.
|
||||
@ -1256,7 +1290,7 @@ activation {
|
||||
monitoring = 1
|
||||
|
||||
# Configuration option activation/polling_interval.
|
||||
# Check pvmove or lvconvert progress at this interval (seconds)
|
||||
# Check pvmove or lvconvert progress at this interval (seconds).
|
||||
# When pvmove or lvconvert must wait for the kernel to finish
|
||||
# synchronising or merging data, they check and report progress
|
||||
# at intervals of this number of seconds.
|
||||
@ -1294,6 +1328,16 @@ activation {
|
||||
# sometimes assist with data recovery.
|
||||
# The '--activationmode' option overrides this setting.
|
||||
activation_mode = "degraded"
|
||||
|
||||
# Configuration option activation/lock_start_list.
|
||||
# Locking is started only for VGs selected by this list.
|
||||
# The rules are the same as those for LVs in volume_list.
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration option activation/auto_lock_start_list.
|
||||
# Locking is auto-started only for VGs selected by this list.
|
||||
# The rules are the same as those for LVs in auto_activation_volume_list.
|
||||
# This configuration option does not have a default value defined.
|
||||
}
|
||||
|
||||
# Configuration section metadata.
|
||||
@ -1361,7 +1405,6 @@ activation {
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
# This configuration option is advanced.
|
||||
# This configuration option does not have a default value defined.
|
||||
# dirs = []
|
||||
# }
|
||||
|
||||
# Configuration section report.
|
||||
@ -1410,7 +1453,7 @@ activation {
|
||||
|
||||
# Configuration option report/colums_as_rows.
|
||||
# Output each column as a row.
|
||||
# If set, this also implies report/prefixes = 1.
|
||||
# If set, this also implies report/prefixes=1.
|
||||
# colums_as_rows = 0
|
||||
|
||||
# Configuration option report/binary_values_as_numeric.
|
||||
@ -1420,6 +1463,80 @@ activation {
|
||||
# value could not be determined).
|
||||
# binary_values_as_numeric = 0
|
||||
|
||||
# Configuration option report/time_format.
|
||||
# Set time format for fields reporting time values.
|
||||
# Format specification is a string which may contain special character
|
||||
# sequences and ordinary character sequences. Ordinary character sequences
|
||||
# are copied verbatim. Each special character sequence is introduced by '%'
|
||||
# character and such sequence is then substituted with a value as described below:
|
||||
# %a The abbreviated name of the day of the week according to the
|
||||
# current locale.
|
||||
# %A The full name of the day of the week according to the current locale.
|
||||
# %b The abbreviated month name according to the current locale.
|
||||
# %B The full month name according to the current locale.
|
||||
# %c The preferred date and time representation for the current locale. (alt E)
|
||||
# %C The century number (year/100) as a 2-digit integer. (alt E)
|
||||
# %d The day of the month as a decimal number (range 01 to 31). (alt O)
|
||||
# %D Equivalent to %m/%d/%y. (For Americans only. Americans should
|
||||
# note that in other countries%d/%m/%y is rather common. This means
|
||||
# that in international context this format is ambiguous and should not
|
||||
# be used.
|
||||
# %e Like %d, the day of the month as a decimal number, but a leading zero
|
||||
# is replaced by a space. (alt O)
|
||||
# %E Modifier: use alternative local-dependent representation if available.
|
||||
# %F Equivalent to %Y-%m-%d (the ISO 8601 date format).
|
||||
# %G The ISO 8601 week-based year with century as adecimal number. The 4-digit
|
||||
# year corresponding to the ISO week number (see %V). This has the same
|
||||
# format and value as %Y, except that if the ISO week number belongs to
|
||||
# the previous or next year, that year is used instead.
|
||||
# %g Like %G, but without century, that is, with a 2-digit year (00-99).
|
||||
# %h Equivalent to %b.
|
||||
# %H The hour as a decimal number using a 24-hour clock (range 00 to 23). (alt O)
|
||||
# %I The hour as a decimal number using a 12-hour clock (range 01 to 12). (alt O)
|
||||
# %j The day of the year as a decimal number (range 001 to 366).
|
||||
# %k The hour (24-hour clock) as a decimal number (range 0 to 23);
|
||||
# single digits are preceded by a blank. (See also %H.)
|
||||
# %l The hour (12-hour clock) as a decimal number (range 1 to 12);
|
||||
# single digits are preceded by a blank. (See also %I.)
|
||||
# %m The month as a decimal number (range 01 to 12). (alt O)
|
||||
# %M The minute as a decimal number (range 00 to 59). (alt O)
|
||||
# %O Modifier: use alternative numeric symbols.
|
||||
# %p Either "AM" or "PM" according to the given time value,
|
||||
# or the corresponding strings for the current locale. Noon is
|
||||
# treated as "PM" and midnight as "AM".
|
||||
# %P Like %p but in lowercase: "am" or "pm" or a corresponding
|
||||
# string for the current locale.
|
||||
# %r The time in a.m. or p.m. notation. In the POSIX locale this is
|
||||
# equivalent to %I:%M:%S %p.
|
||||
# %R The time in 24-hour notation (%H:%M). For a version including
|
||||
# the seconds, see %T below.
|
||||
# %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)
|
||||
# %S The second as a decimal number (range 00 to 60).
|
||||
# (The range is up to 60 to allow for occasional leap seconds.) (alt O)
|
||||
# %t A tab character.
|
||||
# %T The time in 24-hour notation (%H:%M:%S).
|
||||
# %u The day of the week as a decimal, range 1 to 7, Monday being 1.
|
||||
# See also %w. (alt O)
|
||||
# %U The week number of the current year as a decimal number,
|
||||
# range 00 to 53, starting with the first Sunday as the first
|
||||
# day of week 01. See also %V and %W. (alt O)
|
||||
# %V The ISO 8601 week number of the current year as a decimal number,
|
||||
# range 01 to 53, where week 1 is the first week that has at least 4 days
|
||||
# in the new year. See also %U and %W. (alt O)
|
||||
# %w The day of the week as a decimal, range 0 to 6, Sunday being 0.
|
||||
# See also %u. (alt O)
|
||||
# %W The week number of the current year as a decimal number, range 00 to 53,
|
||||
# starting with the first Monday as the first day of week 01. (alt O)
|
||||
# %x The preferred date representation for the current locale without the time. (alt E)
|
||||
# %X The preferred time representation for the current locale without the date. (alt E)
|
||||
# %y The year as a decimal number without a century (range 00 to 99). (alt E, alt O)
|
||||
# %Y The year as a decimal number including the century. (alt E)
|
||||
# %z The +hhmm or -hhmm numeric timezone (that is, the hour and minute
|
||||
# offset from UTC).
|
||||
# %Z The timezone name or abbreviation.
|
||||
# %% A literal '%' character.
|
||||
# time_format = "%Y-%m-%d %T %z"
|
||||
|
||||
# Configuration option report/devtypes_sort.
|
||||
# List of columns to sort by when reporting 'lvm devtypes' command.
|
||||
# See 'lvm devtypes -o help' for the list of possible fields.
|
||||
@ -1572,7 +1689,6 @@ dmeventd {
|
||||
# bar is given to the hosts named machine1 and machine2.
|
||||
# tags { foo { } bar { host_list = [ "machine1", "machine2" ] } }
|
||||
# This configuration section has variable name.
|
||||
# This configuration section does not have a default value defined.
|
||||
# tag {
|
||||
|
||||
# Configuration option tags/<tag>/host_list.
|
||||
@ -1582,6 +1698,5 @@ dmeventd {
|
||||
# matches an entry in this list, the name of the
|
||||
# subsection is applied to the machine as a 'host tag'.
|
||||
# This configuration option does not have a default value defined.
|
||||
# host_list = ""
|
||||
# }
|
||||
# }
|
||||
|
@ -36,8 +36,7 @@ local {
|
||||
# Example:
|
||||
# Set the system_id to the string 'host1'.
|
||||
# system_id = "host1"
|
||||
# This configuration option does not have a default value defined.
|
||||
# system_id=""
|
||||
# system_id = ""
|
||||
|
||||
# Configuration option local/extra_system_ids.
|
||||
# A list of extra VG system IDs the local host can access.
|
||||
@ -49,5 +48,10 @@ local {
|
||||
# Use this only after consulting 'man lvmsystemid'
|
||||
# to be certain of correct usage and possible dangers.
|
||||
# This configuration option does not have a default value defined.
|
||||
# extra_system_ids=[]
|
||||
|
||||
# Configuration option local/host_id.
|
||||
# The lvmlockd sanlock host_id.
|
||||
# This must be a unique among all hosts,
|
||||
# and must be between 1 and 2000.
|
||||
# host_id = 0
|
||||
}
|
||||
|
229
configure.in
229
configure.in
@ -39,6 +39,9 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
LVMETAD=no
|
||||
LVMPOLLD=no
|
||||
LVMLOCKD=no
|
||||
LOCKDSANLOCK=no
|
||||
LOCKDDLM=no
|
||||
ODIRECT=yes
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
@ -88,14 +91,19 @@ AC_PATH_TOOL(CSCOPE_CMD, cscope)
|
||||
dnl -- Check for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_MAJOR
|
||||
AC_HEADER_STDBOOL
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_HEADERS([locale.h stddef.h syslog.h sys/file.h sys/time.h assert.h \
|
||||
langinfo.h libgen.h signal.h sys/mman.h sys/resource.h sys/utsname.h \
|
||||
sys/wait.h time.h], ,
|
||||
[AC_MSG_ERROR(bailing out)])
|
||||
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
|
||||
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
|
||||
signal.h stdarg.h stddef.h stdio.h stdlib.h string.h sys/file.h \
|
||||
sys/ioctl.h syslog.h sys/mman.h sys/param.h sys/resource.h sys/stat.h \
|
||||
sys/time.h sys/types.h sys/utsname.h sys/wait.h time.h \
|
||||
unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||
|
||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h)
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
@ -104,16 +112,13 @@ case "$host_os" in
|
||||
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||
esac
|
||||
|
||||
AC_CHECK_HEADERS([ctype.h dirent.h errno.h fcntl.h getopt.h inttypes.h limits.h \
|
||||
stdarg.h stdio.h stdlib.h string.h sys/ioctl.h sys/param.h sys/stat.h \
|
||||
sys/types.h unistd.h], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_CHECK_HEADERS(termios.h sys/statvfs.h)
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_CHECK_TYPES([ptrdiff_t])
|
||||
AC_STRUCT_TM
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIGNAL
|
||||
@ -129,15 +134,13 @@ AC_TYPE_UINT8_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
AC_STRUCT_TM
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for functions
|
||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize \
|
||||
gettimeofday memset mkdir mkfifo rmdir munmap nl_langinfo setenv setlocale \
|
||||
strcasecmp strchr strcspn strspn strdup strncasecmp strerror strrchr \
|
||||
strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
|
||||
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
|
||||
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
|
||||
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
|
||||
AC_FUNC_ALLOCA
|
||||
AC_FUNC_CLOSEDIR_VOID
|
||||
AC_FUNC_CHOWN
|
||||
@ -145,6 +148,7 @@ AC_FUNC_FORK
|
||||
AC_FUNC_LSTAT
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_MKTIME
|
||||
AC_FUNC_MMAP
|
||||
AC_FUNC_REALLOC
|
||||
AC_FUNC_STAT
|
||||
@ -171,6 +175,9 @@ AC_SUBST(HAVE_FULL_RELRO)
|
||||
################################################################################
|
||||
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||
AC_PREFIX_DEFAULT(/usr)
|
||||
if test "$prefix" = NONE; then
|
||||
datarootdir=${ac_default_prefix}/share
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the ownership of the files
|
||||
@ -263,8 +270,13 @@ AC_ARG_ENABLE(lvm1_fallback,
|
||||
AC_MSG_RESULT($LVM1_FALLBACK)
|
||||
|
||||
if test "$LVM1_FALLBACK" = yes; then
|
||||
DEFAULT_FALLBACK_TO_LVM1=1
|
||||
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
|
||||
else
|
||||
DEFAULT_FALLBACK_TO_LVM1=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1],
|
||||
[Fall back to LVM1 by default if device-mapper is missing from the kernel.])
|
||||
|
||||
################################################################################
|
||||
dnl -- format1 inclusion type
|
||||
@ -552,6 +564,12 @@ case "$CACHE" in
|
||||
*) AC_MSG_ERROR([--with-cache parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
dnl -- cache_check needs-check flag
|
||||
AC_ARG_ENABLE(cache_check_needs_check,
|
||||
AC_HELP_STRING([--disable-cache_check_needs_check],
|
||||
[required if cache_check version is < 0.5]),
|
||||
CACHE_CHECK_NEEDS_CHECK=$enableval, CACHE_CHECK_NEEDS_CHECK=yes)
|
||||
|
||||
# Test if necessary cache tools are available
|
||||
# if not - use plain defaults and warn user
|
||||
case "$CACHE" in
|
||||
@ -565,6 +583,28 @@ case "$CACHE" in
|
||||
CACHE_CONFIGURE_WARN=y
|
||||
fi
|
||||
fi
|
||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||
$CACHE_CHECK_CMD -V 2>/dev/null >conftest.tmp
|
||||
read -r CACHE_CHECK_VSN < conftest.tmp
|
||||
IFS=. read -r CACHE_CHECK_VSN_MAJOR CACHE_CHECK_VSN_MINOR CACHE_CHECK_VSN_PATCH < conftest.tmp
|
||||
rm -f conftest.tmp
|
||||
|
||||
# Require version >= 0.5.4 for --clear-needs-check-flag
|
||||
if test -z "$CACHE_CHECK_VSN_MAJOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_MINOR" \
|
||||
|| test -z "$CACHE_CHECK_VSN_PATCH"; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Bad version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
elif test "$CACHE_CHECK_VSN_MAJOR" -eq 0 ; then
|
||||
if test "$CACHE_CHECK_VSN_MINOR" -lt 5 \
|
||||
|| test "$CACHE_CHECK_VSN_MINOR" -eq 5 -a "$CACHE_CHECK_VSN_PATCH" -lt 4; then
|
||||
AC_MSG_WARN([$CACHE_CHECK_CMD: Old version "$CACHE_CHECK_VSN" found])
|
||||
CACHE_CHECK_VERSION_WARN=y
|
||||
CACHE_CHECK_NEEDS_CHECK=no
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Empty means a config way to ignore cache dumping
|
||||
if test "$CACHE_DUMP_CMD" = "autodetect"; then
|
||||
AC_PATH_TOOL(CACHE_DUMP_CMD, cache_dump)
|
||||
@ -592,6 +632,12 @@ case "$CACHE" in
|
||||
CACHE_CONFIGURE_WARN=y
|
||||
}
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether cache_check supports the needs-check flag])
|
||||
AC_MSG_RESULT([$CACHE_CHECK_NEEDS_CHECK])
|
||||
if test "$CACHE_CHECK_NEEDS_CHECK" = yes; then
|
||||
AC_DEFINE([CACHE_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'cache_check' tool requires the --clear-needs-check-flag option])
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -620,8 +666,8 @@ AC_MSG_RESULT($READLINE)
|
||||
dnl -- Disable realtime clock support
|
||||
AC_MSG_CHECKING(whether to enable realtime support)
|
||||
AC_ARG_ENABLE(realtime,
|
||||
AC_HELP_STRING([--enable-realtime], [enable realtime clock support]),
|
||||
REALTIME=$enableval)
|
||||
AC_HELP_STRING([--disable-realtime], [disable realtime clock support]),
|
||||
REALTIME=$enableval, REALTIME=yes)
|
||||
AC_MSG_RESULT($REALTIME)
|
||||
|
||||
################################################################################
|
||||
@ -1026,6 +1072,13 @@ if test "$TESTING" = yes; then
|
||||
PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Set LVM2 testsuite data
|
||||
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
|
||||
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
|
||||
AC_DEFINE_UNQUOTED(TESTSUITE_DATA, ["$(eval echo $(eval echo $TESTSUITE_DATA))"], [Path to testsuite data])
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable valgrind awareness of memory pools
|
||||
AC_MSG_CHECKING(whether to enable valgrind awareness of pools)
|
||||
@ -1071,6 +1124,96 @@ AC_MSG_RESULT($LVMETAD)
|
||||
|
||||
BUILD_LVMETAD=$LVMETAD
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmpolld
|
||||
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||
AC_ARG_ENABLE(lvmpolld,
|
||||
AC_HELP_STRING([--enable-lvmpolld],
|
||||
[enable the LVM Polling Daemon]),
|
||||
LVMPOLLD=$enableval)
|
||||
AC_MSG_RESULT($LVMPOLLD)
|
||||
|
||||
BUILD_LVMPOLLD=$LVMPOLLD
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lockdsanlock
|
||||
AC_MSG_CHECKING(whether to build lockdsanlock)
|
||||
AC_ARG_ENABLE(lockd-sanlock,
|
||||
AC_HELP_STRING([--enable-lockd-sanlock],
|
||||
[enable the LVM lock daemon using sanlock]),
|
||||
LOCKDSANLOCK=$enableval)
|
||||
AC_MSG_RESULT($LOCKDSANLOCK)
|
||||
|
||||
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
|
||||
|
||||
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||
AC_DEFINE([LOCKDSANLOCK_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd sanlock option.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Look for sanlock libraries
|
||||
if test "$BUILD_LOCKDSANLOCK" = yes; then
|
||||
PKG_CHECK_MODULES(LOCKD_SANLOCK, libsanlock_client, [HAVE_LOCKD_SANLOCK=yes], $bailout)
|
||||
BUILD_LVMLOCKD=yes
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lockddlm
|
||||
AC_MSG_CHECKING(whether to build lockddlm)
|
||||
AC_ARG_ENABLE(lockd-dlm,
|
||||
AC_HELP_STRING([--enable-lockd-dlm],
|
||||
[enable the LVM lock daemon using dlm]),
|
||||
LOCKDDLM=$enableval)
|
||||
AC_MSG_RESULT($LOCKDDLM)
|
||||
|
||||
BUILD_LOCKDDLM=$LOCKDDLM
|
||||
|
||||
if test "$BUILD_LOCKDDLM" = yes; then
|
||||
AC_DEFINE([LOCKDDLM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd dlm option.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Look for dlm libraries
|
||||
if test "$BUILD_LOCKDDLM" = yes; then
|
||||
PKG_CHECK_MODULES(LOCKD_DLM, libdlm, [HAVE_LOCKD_DLM=yes], $bailout)
|
||||
BUILD_LVMLOCKD=yes
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmlockd
|
||||
|
||||
AC_MSG_CHECKING(whether to build lvmlockd)
|
||||
AC_MSG_RESULT($BUILD_LVMLOCKD)
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AS_IF([test -n "$BUILD_LVMPOLLD"], [BUILD_LVMPOLLD=yes; AC_MSG_WARN([Enabling lvmpolld - required by lvmlockd.])])
|
||||
AS_IF([test -n "$BUILD_LVMETAD"], [BUILD_LVMETAD=yes; AC_MSG_WARN([Enabling lvmetad - required by lvmlockd.])])
|
||||
AC_MSG_CHECKING([defaults for use_lvmlockd])
|
||||
AC_ARG_ENABLE(use_lvmlockd,
|
||||
AC_HELP_STRING([--disable-use-lvmlockd],
|
||||
[disable usage of LVM lock daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMLOCKD=1 ;;
|
||||
*) DEFAULT_USE_LVMLOCKD=0 ;;
|
||||
esac], DEFAULT_USE_LVMLOCKD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMLOCKD)
|
||||
AC_DEFINE([LVMLOCKD_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd.])
|
||||
|
||||
AC_ARG_WITH(lvmlockd-pidfile,
|
||||
AC_HELP_STRING([--with-lvmlockd-pidfile=PATH],
|
||||
[lvmlockd pidfile [PID_DIR/lvmlockd.pid]]),
|
||||
LVMLOCKD_PIDFILE=$withval,
|
||||
LVMLOCKD_PIDFILE="$DEFAULT_PID_DIR/lvmlockd.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMLOCKD_PIDFILE, ["$LVMLOCKD_PIDFILE"],
|
||||
[Path to lvmlockd pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMLOCKD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMLOCKD, [$DEFAULT_USE_LVMLOCKD],
|
||||
[Use lvmlockd by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Check lvmetad
|
||||
if test "$BUILD_LVMETAD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmetad])
|
||||
AC_ARG_ENABLE(use_lvmetad,
|
||||
@ -1097,16 +1240,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
|
||||
[Use lvmetad by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmpolld
|
||||
AC_MSG_CHECKING(whether to build lvmpolld)
|
||||
AC_ARG_ENABLE(lvmpolld,
|
||||
AC_HELP_STRING([--enable-lvmpolld],
|
||||
[enable the LVM Polling Daemon]),
|
||||
LVMPOLLD=$enableval)
|
||||
AC_MSG_RESULT($LVMPOLLD)
|
||||
|
||||
BUILD_LVMPOLLD=$LVMPOLLD
|
||||
|
||||
dnl -- Check lvmpolld
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmpolld])
|
||||
AC_ARG_ENABLE(use_lvmpolld,
|
||||
@ -1133,6 +1267,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
|
||||
[Use lvmpolld by default.])
|
||||
|
||||
################################################################################
|
||||
|
||||
dnl -- Enable blkid wiping functionality
|
||||
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
|
||||
AC_ARG_ENABLE(blkid_wiping,
|
||||
@ -1152,9 +1287,16 @@ if test "$BLKID_WIPING" != no; then
|
||||
fi])
|
||||
if test "$BLKID_WIPING" = yes; then
|
||||
BLKID_PC="blkid"
|
||||
DEFAULT_USE_BLKID_WIPING=1
|
||||
AC_DEFINE([BLKID_WIPING_SUPPORT], 1, [Define to 1 to use libblkid detection of signatures when wiping.])
|
||||
else
|
||||
DEFAULT_USE_BLKID_WIPING=1
|
||||
fi
|
||||
else
|
||||
DEFAULT_USE_BLKID_WIPING=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_BLKID_WIPING, [$DEFAULT_USE_BLKID_WIPING],
|
||||
[Use blkid wiping by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
|
||||
@ -1395,6 +1537,10 @@ if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
AC_CHECK_LIB(m, log10,
|
||||
[M_LIBS="-lm"], hard_bailout)
|
||||
|
||||
################################################################################
|
||||
AC_CHECK_LIB([pthread], [pthread_mutex_lock],
|
||||
[PTHREAD_LIBS="-lpthread"], hard_bailout)
|
||||
@ -1435,9 +1581,11 @@ if test "$REALTIME" = yes; then
|
||||
if test "$HAVE_REALTIME" = yes; then
|
||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||
LIBS="-lrt $LIBS"
|
||||
RT_PC="librt"
|
||||
else
|
||||
AC_MSG_WARN(Disabling realtime clock)
|
||||
fi
|
||||
AC_MSG_RESULT($HAVE_REALTIME)
|
||||
fi
|
||||
|
||||
dnl Check if the system has struct stat st_ctim.
|
||||
@ -1585,6 +1733,19 @@ if test "$READLINE" = yes; then
|
||||
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_CHECK_FUNCS(atexit,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_CHECK_FUNCS(strpbrk,,hard_bailout)
|
||||
AC_FUNC_STRERROR_R
|
||||
fi
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
||||
@ -1742,11 +1903,13 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[[()]]' '{print $2}'`
|
||||
AC_SUBST(APPLIB)
|
||||
AC_SUBST(AWK)
|
||||
AC_SUBST(BLKID_PC)
|
||||
AC_SUBST(BLKID_WIPING)
|
||||
AC_SUBST(BUILD_CMIRRORD)
|
||||
AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMETAD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
AC_SUBST(BUILD_LVMLOCKD)
|
||||
AC_SUBST(BUILD_LOCKDSANLOCK)
|
||||
AC_SUBST(BUILD_LOCKDDLM)
|
||||
AC_SUBST(CACHE)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CFLOW_CMD)
|
||||
@ -1776,6 +1939,7 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_FALLBACK_TO_LVM1)
|
||||
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_PID_DIR)
|
||||
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
|
||||
@ -1783,8 +1947,10 @@ AC_SUBST(DEFAULT_RAID10_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_SYS_DIR)
|
||||
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
|
||||
AC_SUBST(DEFAULT_USE_LVMETAD)
|
||||
AC_SUBST(DEFAULT_USE_LVMPOLLD)
|
||||
AC_SUBST(DEFAULT_USE_LVMLOCKD)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
AC_SUBST(DLM_CFLAGS)
|
||||
AC_SUBST(DLM_LIBS)
|
||||
@ -1822,6 +1988,7 @@ AC_SUBST(OCF)
|
||||
AC_SUBST(OCFDIR)
|
||||
AC_SUBST(PKGCONFIG)
|
||||
AC_SUBST(POOL)
|
||||
AC_SUBST(M_LIBS)
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PYTHON)
|
||||
AC_SUBST(PYTHON_BINDINGS)
|
||||
@ -1830,6 +1997,7 @@ AC_SUBST(PYTHON_LIBDIRS)
|
||||
AC_SUBST(QUORUM_CFLAGS)
|
||||
AC_SUBST(QUORUM_LIBS)
|
||||
AC_SUBST(RAID)
|
||||
AC_SUBST(RT_PC)
|
||||
AC_SUBST(READLINE_LIBS)
|
||||
AC_SUBST(REPLICATORS)
|
||||
AC_SUBST(SACKPT_CFLAGS)
|
||||
@ -1842,6 +2010,7 @@ AC_SUBST(SNAPSHOTS)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(TESTING)
|
||||
AC_SUBST(TESTSUITE_DATA)
|
||||
AC_SUBST(THIN)
|
||||
AC_SUBST(THIN_CHECK_CMD)
|
||||
AC_SUBST(THIN_DUMP_CMD)
|
||||
@ -1862,6 +2031,7 @@ AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMETAD_PIDFILE)
|
||||
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||
AC_SUBST(LVMLOCKD_PIDFILE)
|
||||
AC_SUBST(CLVMD_PIDFILE)
|
||||
AC_SUBST(CMIRRORD_PIDFILE)
|
||||
AC_SUBST(interface)
|
||||
@ -1896,6 +2066,7 @@ daemons/dmeventd/plugins/snapshot/Makefile
|
||||
daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/lvmetad/Makefile
|
||||
daemons/lvmpolld/Makefile
|
||||
daemons/lvmlockd/Makefile
|
||||
conf/Makefile
|
||||
conf/example.conf
|
||||
conf/lvmlocal.conf
|
||||
@ -1942,6 +2113,8 @@ 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
|
||||
|
@ -15,7 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
|
||||
|
||||
ifneq ("@CLVMD@", "none")
|
||||
SUBDIRS += clvmd
|
||||
@ -40,8 +40,12 @@ ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
SUBDIRS += lvmpolld
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMLOCKD@", "yes")
|
||||
SUBDIRS += lvmlockd
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd
|
||||
endif
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
@ -323,6 +323,7 @@ void cmd_client_cleanup(struct local_client *client)
|
||||
int lkid;
|
||||
char *lockname;
|
||||
|
||||
DEBUGLOG("Client thread cleanup (%p)\n", client);
|
||||
if (!client->bits.localsock.private)
|
||||
return;
|
||||
|
||||
@ -331,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("cleanup: Unlocking lock %s %x\n", lockname, lkid);
|
||||
DEBUGLOG("Cleanup (%p): Unlocking lock %s %x\n", client, lockname, lkid);
|
||||
(void) sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
@ -339,7 +340,6 @@ void cmd_client_cleanup(struct local_client *client)
|
||||
client->bits.localsock.private = NULL;
|
||||
}
|
||||
|
||||
|
||||
static int restart_clvmd(void)
|
||||
{
|
||||
const char **argv;
|
||||
|
@ -18,15 +18,10 @@
|
||||
#ifndef _LVM_CLVMD_COMMON_H
|
||||
#define _LVM_CLVMD_COMMON_H
|
||||
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvm-logging.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#endif
|
||||
|
@ -243,7 +243,7 @@ static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
||||
"%" PRIsize_t " left, %" PRIsize_t " members\n",
|
||||
FMTsize_t " left, %" PRIsize_t " members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
|
@ -223,6 +223,7 @@ void debuglog(const char *fmt, ...)
|
||||
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime_r(&P, buf_ctime) + 4);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
break;
|
||||
case DEBUG_SYSLOG:
|
||||
if (!syslog_init) {
|
||||
@ -598,7 +599,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* This needs to be started after cluster initialisation
|
||||
as it may need to take out locks */
|
||||
DEBUGLOG("starting LVM thread\n");
|
||||
DEBUGLOG("Starting LVM thread\n");
|
||||
DEBUGLOG("Main cluster socket fd %d (%p) with local socket %d (%p)\n",
|
||||
local_client_head.fd, &local_client_head, newfd->fd, newfd);
|
||||
|
||||
/* Don't let anyone else to do work until we are started */
|
||||
pthread_create(&lvm_thread, &stack_attr, lvm_thread_fn, &lvm_params);
|
||||
@ -698,7 +701,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
newfd->type = LOCAL_SOCK;
|
||||
newfd->callback = local_sock_callback;
|
||||
newfd->bits.localsock.all_success = 1;
|
||||
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
|
||||
DEBUGLOG("Got new connection on fd %d (%p)\n", newfd->fd, newfd);
|
||||
*new_client = newfd;
|
||||
}
|
||||
return 1;
|
||||
@ -850,18 +853,48 @@ static void main_loop(int cmd_timeout)
|
||||
struct local_client *thisfd;
|
||||
struct timeval tv = { cmd_timeout, 0 };
|
||||
int quorate = clops->is_quorate();
|
||||
int client_count = 0;
|
||||
int max_fd = 0;
|
||||
struct local_client *lastfd = &local_client_head;
|
||||
struct local_client *nextfd = local_client_head.next;
|
||||
|
||||
/* Wait on the cluster FD and all local sockets/pipes */
|
||||
local_client_head.fd = clops->get_main_cluster_fd();
|
||||
FD_ZERO(&in);
|
||||
|
||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||
client_count++;
|
||||
max_fd = max(max_fd, thisfd->fd);
|
||||
}
|
||||
|
||||
if (max_fd > FD_SETSIZE - 32) {
|
||||
fprintf(stderr, "WARNING: There are too many connections to clvmd. Investigate and take action now!\n");
|
||||
fprintf(stderr, "WARNING: Your cluster may freeze up if the number of clvmd file descriptors (%d) exceeds %d.\n", max_fd + 1, FD_SETSIZE);
|
||||
}
|
||||
|
||||
for (thisfd = &local_client_head; thisfd; thisfd = nextfd, nextfd = thisfd ? thisfd->next : NULL) {
|
||||
|
||||
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
|
||||
struct local_client *free_fd = thisfd;
|
||||
lastfd->next = nextfd;
|
||||
DEBUGLOG("removeme set for %p with %d monitored fds remaining\n", free_fd, client_count - 1);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
lastfd = thisfd;
|
||||
|
||||
if (thisfd->removeme)
|
||||
continue;
|
||||
|
||||
/* if the cluster is not quorate then don't listen for new requests */
|
||||
if ((thisfd->type != LOCAL_RENDEZVOUS &&
|
||||
thisfd->type != LOCAL_SOCK) || quorate)
|
||||
FD_SET(thisfd->fd, &in);
|
||||
if (thisfd->fd < FD_SETSIZE)
|
||||
FD_SET(thisfd->fd, &in);
|
||||
}
|
||||
|
||||
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
|
||||
@ -877,31 +910,20 @@ static void main_loop(int cmd_timeout)
|
||||
}
|
||||
|
||||
if (select_status > 0) {
|
||||
struct local_client *lastfd = NULL;
|
||||
char csid[MAX_CSID_LEN];
|
||||
char buf[max_cluster_message];
|
||||
|
||||
for (thisfd = &local_client_head; thisfd; thisfd = thisfd->next) {
|
||||
if (thisfd->removeme && !cleanup_zombie(thisfd)) {
|
||||
struct local_client *free_fd = thisfd;
|
||||
lastfd->next = thisfd->next;
|
||||
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(thisfd->fd, &in)) {
|
||||
if (thisfd->fd < FD_SETSIZE && FD_ISSET(thisfd->fd, &in)) {
|
||||
struct local_client *newfd = NULL;
|
||||
int ret;
|
||||
|
||||
/* FIXME Remove from main thread in case it blocks! */
|
||||
/* Do callback */
|
||||
ret = thisfd->callback(thisfd, buf, sizeof(buf),
|
||||
csid, &newfd);
|
||||
/* Ignore EAGAIN */
|
||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
|
||||
lastfd = thisfd;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -917,17 +939,16 @@ static void main_loop(int cmd_timeout)
|
||||
DEBUGLOG("ret == %d, errno = %d. removing client\n",
|
||||
ret, errno);
|
||||
thisfd->removeme = 1;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* New client...simply add it to the list */
|
||||
if (newfd) {
|
||||
newfd->next = thisfd->next;
|
||||
thisfd->next = newfd;
|
||||
break;
|
||||
thisfd = newfd;
|
||||
}
|
||||
}
|
||||
lastfd = thisfd;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1420,7 +1441,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
thisfd->bits.localsock.in_progress = TRUE;
|
||||
thisfd->bits.localsock.state = PRE_COMMAND;
|
||||
thisfd->bits.localsock.cleanup_needed = 1;
|
||||
DEBUGLOG("Creating pre&post thread\n");
|
||||
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("Created pre&post thread, state = %d\n", status);
|
||||
@ -1674,7 +1695,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
sigset_t ss;
|
||||
int pipe_fd = client->bits.localsock.pipe;
|
||||
|
||||
DEBUGLOG("Pre&post thread (%p), pipe %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
|
||||
@ -1694,7 +1715,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
if ((status = do_pre_command(client)))
|
||||
client->bits.localsock.all_success = 0;
|
||||
|
||||
DEBUGLOG("Pre&post thread (%p) writes status %d down to pipe %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 */
|
||||
@ -1976,7 +1997,7 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
{
|
||||
/* If msg is NULL then this is a cleanup request */
|
||||
if (cmd->msg == NULL) {
|
||||
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
|
||||
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);
|
||||
|
@ -510,7 +510,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
|
||||
|
||||
if (!cmd->config_initialized || config_files_changed(cmd)) {
|
||||
if (!cmd->initialized.config || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (do_refresh_cache()) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
@ -899,7 +899,7 @@ int init_clvm(struct dm_hash_table *excl_uuid)
|
||||
if (!get_initial_state(excl_uuid))
|
||||
log_error("Cannot load initial lock states.");
|
||||
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1))) {
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,26 +16,21 @@
|
||||
* dmeventd - dm event daemon to monitor active mapped devices
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include "tool.h"
|
||||
|
||||
#include "configure.h"
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
//#include "libmultilog.h"
|
||||
#include "dm-logging.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
#include <fcntl.h> /* for musl libc */
|
||||
@ -133,51 +128,20 @@ void debuglog(const char *fmt, ...)
|
||||
|
||||
static const char *decode_cmd(uint32_t cmd)
|
||||
{
|
||||
static char buf[128];
|
||||
const char *command;
|
||||
|
||||
switch (cmd) {
|
||||
case DM_EVENT_CMD_ACTIVE:
|
||||
command = "ACTIVE";
|
||||
break;
|
||||
case DM_EVENT_CMD_REGISTER_FOR_EVENT:
|
||||
command = "REGISTER_FOR_EVENT";
|
||||
break;
|
||||
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT:
|
||||
command = "UNREGISTER_FOR_EVENT";
|
||||
break;
|
||||
case DM_EVENT_CMD_GET_REGISTERED_DEVICE:
|
||||
command = "GET_REGISTERED_DEVICE";
|
||||
break;
|
||||
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE:
|
||||
command = "GET_NEXT_REGISTERED_DEVICE";
|
||||
break;
|
||||
case DM_EVENT_CMD_SET_TIMEOUT:
|
||||
command = "SET_TIMEOUT";
|
||||
break;
|
||||
case DM_EVENT_CMD_GET_TIMEOUT:
|
||||
command = "GET_TIMEOUT";
|
||||
break;
|
||||
case DM_EVENT_CMD_HELLO:
|
||||
command = "HELLO";
|
||||
break;
|
||||
case DM_EVENT_CMD_DIE:
|
||||
command = "DIE";
|
||||
break;
|
||||
case DM_EVENT_CMD_GET_STATUS:
|
||||
command = "GET_STATUS";
|
||||
break;
|
||||
case DM_EVENT_CMD_GET_PARAMETERS:
|
||||
command = "GET_PARAMETERS";
|
||||
break;
|
||||
default:
|
||||
command = "unknown";
|
||||
break;
|
||||
case DM_EVENT_CMD_ACTIVE: return "ACTIVE";
|
||||
case DM_EVENT_CMD_REGISTER_FOR_EVENT: return "REGISTER_FOR_EVENT";
|
||||
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT: return "UNREGISTER_FOR_EVENT";
|
||||
case DM_EVENT_CMD_GET_REGISTERED_DEVICE: return "GET_REGISTERED_DEVICE";
|
||||
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE: return "GET_NEXT_REGISTERED_DEVICE";
|
||||
case DM_EVENT_CMD_SET_TIMEOUT: return "SET_TIMEOUT";
|
||||
case DM_EVENT_CMD_GET_TIMEOUT: return "GET_TIMEOUT";
|
||||
case DM_EVENT_CMD_HELLO: return "HELLO";
|
||||
case DM_EVENT_CMD_DIE: return "DIE";
|
||||
case DM_EVENT_CMD_GET_STATUS: return "GET_STATUS";
|
||||
case DM_EVENT_CMD_GET_PARAMETERS: return "GET_PARAMETERS";
|
||||
default: return "unknown";
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s (0x%x)", command, cmd);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1598,9 +1562,6 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
{
|
||||
int die;
|
||||
struct dm_event_daemon_message msg = { 0 };
|
||||
#ifdef DEBUG
|
||||
const char *cmd;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read the request from the client (client_read, client_write
|
||||
@ -1609,7 +1570,8 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
if (!_client_read(fifos, &msg))
|
||||
return;
|
||||
|
||||
DEBUGLOG("%s processing...", cmd = decode_cmd(msg.cmd));
|
||||
DEBUGLOG("%s (0x%x) processing...", decode_cmd(msg.cmd), msg.cmd);
|
||||
|
||||
die = (msg.cmd == DM_EVENT_CMD_DIE) ? 1 : 0;
|
||||
|
||||
/* _do_process_request fills in msg (if memory allows for
|
||||
@ -1621,7 +1583,7 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
|
||||
dm_free(msg.data);
|
||||
|
||||
DEBUGLOG("%s completed.", cmd);
|
||||
DEBUGLOG("%s (0x%x) completed.", decode_cmd(msg.cmd), msg.cmd);
|
||||
|
||||
if (die) {
|
||||
if (unlink(DMEVENTD_PIDFILE))
|
||||
@ -1671,10 +1633,8 @@ static void _cleanup_unused_threads(void)
|
||||
if (ret == ESRCH) {
|
||||
thread->status = DM_THREAD_DONE;
|
||||
} else if (ret) {
|
||||
syslog(LOG_ERR,
|
||||
"Unable to terminate thread: %s\n",
|
||||
strerror(-ret));
|
||||
stack;
|
||||
syslog(LOG_ERR, "Unable to terminate thread: %s",
|
||||
strerror(ret));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1706,8 +1666,7 @@ static void _cleanup_unused_threads(void)
|
||||
|
||||
static void _sig_alarm(int signum __attribute__((unused)))
|
||||
{
|
||||
DEBUGLOG("Received SIGALRM.");
|
||||
pthread_testcancel();
|
||||
/* empty SIG_IGN */;
|
||||
}
|
||||
|
||||
/* Init thread signal handling. */
|
||||
|
@ -17,15 +17,10 @@
|
||||
//#include "libmultilog.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
|
||||
|
@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
SOURCES = lvmetad-core.c
|
||||
SOURCES2 = testclient.c
|
||||
|
||||
TARGETS = lvmetad
|
||||
TARGETS = lvmetad lvmetactl
|
||||
|
||||
.PHONY: install_lvmetad
|
||||
|
||||
@ -41,6 +41,10 @@ lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||
|
||||
lvmetactl: lvmetactl.o $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ lvmetactl.o $(LVMLIBS)
|
||||
|
||||
# TODO: No idea. No idea how to test either.
|
||||
#ifneq ("$(CFLOW_CMD)", "")
|
||||
#CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
|
183
daemons/lvmetad/lvmetactl.c
Normal file
183
daemons/lvmetad/lvmetactl.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
|
||||
daemon_handle h;
|
||||
|
||||
static void print_reply(daemon_reply reply)
|
||||
{
|
||||
const char *a = daemon_reply_str(reply, "response", NULL);
|
||||
const char *b = daemon_reply_str(reply, "status", NULL);
|
||||
const char *c = daemon_reply_str(reply, "reason", NULL);
|
||||
|
||||
printf("response \"%s\" status \"%s\" reason \"%s\"\n",
|
||||
a ? a : "", b ? b : "", c ? c : "");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
daemon_reply reply;
|
||||
char *cmd;
|
||||
char *uuid;
|
||||
char *name;
|
||||
int val;
|
||||
int ver;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("lvmeta dump\n");
|
||||
printf("lvmeta pv_list\n");
|
||||
printf("lvmeta vg_list\n");
|
||||
printf("lvmeta vg_lookup_name <name>\n");
|
||||
printf("lvmeta vg_lookup_uuid <uuid>\n");
|
||||
printf("lvmeta pv_lookup_uuid <uuid>\n");
|
||||
printf("lvmeta set_global_invalid 0|1\n");
|
||||
printf("lvmeta get_global_invalid\n");
|
||||
printf("lvmeta set_vg_version <uuid> <version>\n");
|
||||
printf("lvmeta vg_lock_type <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd = argv[1];
|
||||
|
||||
h = lvmetad_open(NULL);
|
||||
|
||||
if (!strcmp(cmd, "dump")) {
|
||||
reply = daemon_send_simple(h, "dump",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_list")) {
|
||||
reply = daemon_send_simple(h, "pv_list",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_list")) {
|
||||
reply = daemon_send_simple(h, "vg_list",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "set_global_invalid")) {
|
||||
if (argc < 3) {
|
||||
printf("set_global_invalid 0|1\n");
|
||||
return -1;
|
||||
}
|
||||
val = atoi(argv[2]);
|
||||
|
||||
reply = daemon_send_simple(h, "set_global_info",
|
||||
"global_invalid = %d", val,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "get_global_invalid")) {
|
||||
reply = daemon_send_simple(h, "get_global_info",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "set_vg_version")) {
|
||||
if (argc < 4) {
|
||||
printf("set_vg_version <uuid> <ver>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
ver = atoi(argv[3]);
|
||||
|
||||
reply = daemon_send_simple(h, "set_vg_info",
|
||||
"uuid = %s", uuid,
|
||||
"version = %d", ver,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
print_reply(reply);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lookup_name")) {
|
||||
if (argc < 3) {
|
||||
printf("vg_lookup_name <name>\n");
|
||||
return -1;
|
||||
}
|
||||
name = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"name = %s", name,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lookup_uuid")) {
|
||||
if (argc < 3) {
|
||||
printf("vg_lookup_uuid <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else if (!strcmp(cmd, "vg_lock_type")) {
|
||||
struct dm_config_node *metadata;
|
||||
const char *lock_type;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("vg_lock_type <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "vg_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
/* printf("%s\n", reply.buffer.mem); */
|
||||
|
||||
metadata = dm_config_find_node(reply.cft->root, "metadata");
|
||||
if (!metadata) {
|
||||
printf("no metadata\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
|
||||
if (!lock_type) {
|
||||
printf("no lock_type\n");
|
||||
goto out;
|
||||
}
|
||||
printf("lock_type %s\n", lock_type);
|
||||
|
||||
} else if (!strcmp(cmd, "pv_lookup_uuid")) {
|
||||
if (argc < 3) {
|
||||
printf("pv_lookup_uuid <uuid>\n");
|
||||
return -1;
|
||||
}
|
||||
uuid = argv[2];
|
||||
|
||||
reply = daemon_send_simple(h, "pv_lookup",
|
||||
"uuid = %s", uuid,
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
printf("%s\n", reply.buffer.mem);
|
||||
|
||||
} else {
|
||||
printf("unknown command\n");
|
||||
goto out_close;
|
||||
}
|
||||
out:
|
||||
daemon_reply_destroy(reply);
|
||||
out_close:
|
||||
daemon_close(h);
|
||||
return 0;
|
||||
}
|
@ -14,23 +14,114 @@
|
||||
|
||||
#define _XOPEN_SOURCE 500 /* pthread */
|
||||
|
||||
#include "configure.h"
|
||||
#define _REENTRANT
|
||||
|
||||
#include "tool.h"
|
||||
|
||||
#include "daemon-io.h"
|
||||
#include "config-util.h"
|
||||
#include "daemon-server.h"
|
||||
#include "daemon-log.h"
|
||||
#include "lvm-version.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <math.h> /* fabs() */
|
||||
#include <float.h> /* DBL_EPSILON */
|
||||
|
||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||
|
||||
/*
|
||||
* valid/invalid state of cached metadata
|
||||
*
|
||||
* Normally when using lvmetad, the state is kept up-to-date through a
|
||||
* combination of notifications from clients and updates triggered by uevents.
|
||||
* When using lvmlockd, the lvmetad state is expected to become out of
|
||||
* date (invalid/stale) when other hosts make changes to the metadata on disk.
|
||||
*
|
||||
* To deal with this, the metadata cached in lvmetad can be flagged as invalid.
|
||||
* This invalid flag is returned along with the metadata when read by a
|
||||
* command. The command can check for the invalid flag and decide that it
|
||||
* should either use the stale metadata (uncommon), or read the latest metadata
|
||||
* from disk rather than using the invalid metadata that was returned. If the
|
||||
* command reads the latest metadata from disk, it can choose to send it to
|
||||
* lvmetad to update the cached copy and clear the invalid flag in lvmetad.
|
||||
* Otherwise, the next command to read the metadata from lvmetad will also
|
||||
* receive the invalid metadata with the invalid flag (and like the previous
|
||||
* command, it too may choose to read the latest metadata from disk and can
|
||||
* then also choose to update the lvmetad copy.)
|
||||
*
|
||||
* For purposes of tracking the invalid state, LVM metadata is considered
|
||||
* to be either VG-specific or global. VG-specific metadata is metadata
|
||||
* that is isolated to a VG, such as the LVs it contains. Global
|
||||
* metadata is metadata that is not isolated to a single VG. Global
|
||||
* metdata includes:
|
||||
* . the VG namespace (which VG names are used)
|
||||
* . the set of orphan PVs (which PVs are in VGs and which are not)
|
||||
* . properties of orphan PVs (the size of an orphan PV)
|
||||
*
|
||||
* If the metadata for a single VG becomes invalid, the VGFL_INVALID
|
||||
* flag can be set in the vg_info struct for that VG. If the global
|
||||
* metdata becomes invalid, the GLFL_INVALID flag can be set in the
|
||||
* lvmetad daemon state.
|
||||
*
|
||||
* If a command reads VG metadata and VGFL_INVALID is set, an
|
||||
* extra config node called "vg_invalid" is added to the config
|
||||
* data returned to the command.
|
||||
*
|
||||
* If a command reads global metdata and GLFL_INVALID is set, an
|
||||
* extra config node called "global_invalid" is added to the
|
||||
* config data returned to the command.
|
||||
*
|
||||
* If a command sees vg_invalid, and wants the latest VG metadata,
|
||||
* it only needs to scan disks of the PVs in that VG.
|
||||
* It can then use vg_update to send the latest metadata to lvmetad
|
||||
* which clears the VGFL_INVALID flag.
|
||||
*
|
||||
* If a command sees global_invalid, and wants the latest metadata,
|
||||
* it should scan all devices to update lvmetad, and then send
|
||||
* lvmetad the "set_global_info global_invalid=0" message to clear
|
||||
* GLFL_INVALID.
|
||||
*
|
||||
* (When rescanning devices to update lvmetad, the command must use
|
||||
* the global filter cmd->lvmetad_filter so that it processes the same
|
||||
* devices that are seen by lvmetad.)
|
||||
*
|
||||
* The lvmetad INVALID flags can be set by sending lvmetad the messages:
|
||||
*
|
||||
* . set_vg_info with the latest VG seqno. If the VG seqno is larger
|
||||
* than the cached VG seqno, VGFL_INVALID is set for the VG.
|
||||
*
|
||||
* . set_global_info with global_invalid=1 sets GLFL_INVALID.
|
||||
*
|
||||
* Different entities could use these functions to invalidate metadata
|
||||
* if/when they detected that the cache is stale. How they detect that
|
||||
* the cache is stale depends on the details of the specific entity.
|
||||
*
|
||||
* In the case of lvmlockd, it embeds values into its locks to keep track
|
||||
* of when other nodes have changed metadata on disk related to those locks.
|
||||
* When acquring locks it can look at these values and detect that
|
||||
* the metadata associated with the lock has been changed.
|
||||
* When the values change, it uses set_vg_info/set_global_info to
|
||||
* invalidate the lvmetad cache.
|
||||
*
|
||||
* The values that lvmlockd distributes through its locks are the
|
||||
* latest VG seqno in VG locks and a global counter in the global lock.
|
||||
* When a host acquires a VG lock and sees that the embedded seqno is
|
||||
* larger than it was previously, it knows that it should invalidate the
|
||||
* lvmetad cache for the VG. If the host acquires the global lock
|
||||
* and sees that the counter is larger than previously, it knows that
|
||||
* it should invalidate the global info in lvmetad. This invalidation
|
||||
* is done before the lock is returned to the command. This way the
|
||||
* invalid flag will be set on the metadata before the command reads
|
||||
* it from lvmetad.
|
||||
*/
|
||||
|
||||
struct vg_info {
|
||||
int64_t external_version;
|
||||
uint32_t flags; /* VGFL_ */
|
||||
};
|
||||
|
||||
#define GLFL_INVALID 0x00000001
|
||||
#define VGFL_INVALID 0x00000001
|
||||
|
||||
typedef struct {
|
||||
log_state *log; /* convenience */
|
||||
const char *log_config;
|
||||
@ -41,6 +132,7 @@ typedef struct {
|
||||
struct dm_hash_table *vgid_to_metadata;
|
||||
struct dm_hash_table *vgid_to_vgname;
|
||||
struct dm_hash_table *vgid_to_outdated_pvs;
|
||||
struct dm_hash_table *vgid_to_info;
|
||||
struct dm_hash_table *vgname_to_vgid;
|
||||
struct dm_hash_table *pvid_to_vgid;
|
||||
struct {
|
||||
@ -51,6 +143,7 @@ typedef struct {
|
||||
pthread_mutex_t pvid_to_vgid;
|
||||
} lock;
|
||||
char token[128];
|
||||
uint32_t flags; /* GLFL_ */
|
||||
pthread_mutex_t token_lock;
|
||||
} lvmetad_state;
|
||||
|
||||
@ -71,6 +164,7 @@ static void destroy_metadata_hashes(lvmetad_state *s)
|
||||
dm_hash_destroy(s->vgid_to_metadata);
|
||||
dm_hash_destroy(s->vgid_to_vgname);
|
||||
dm_hash_destroy(s->vgid_to_outdated_pvs);
|
||||
dm_hash_destroy(s->vgid_to_info);
|
||||
dm_hash_destroy(s->vgname_to_vgid);
|
||||
|
||||
dm_hash_destroy(s->device_to_pvid);
|
||||
@ -84,6 +178,7 @@ static void create_metadata_hashes(lvmetad_state *s)
|
||||
s->vgid_to_metadata = dm_hash_create(32);
|
||||
s->vgid_to_vgname = dm_hash_create(32);
|
||||
s->vgid_to_outdated_pvs = dm_hash_create(32);
|
||||
s->vgid_to_info = dm_hash_create(32);
|
||||
s->pvid_to_vgid = dm_hash_create(32);
|
||||
s->vgname_to_vgid = dm_hash_create(32);
|
||||
}
|
||||
@ -247,6 +342,30 @@ static int update_pv_status(lvmetad_state *s,
|
||||
return complete;
|
||||
}
|
||||
|
||||
static struct dm_config_node *add_last_node(struct dm_config_tree *cft, const char *node_name)
|
||||
{
|
||||
struct dm_config_node *cn, *last;
|
||||
|
||||
cn = cft->root;
|
||||
last = cn;
|
||||
|
||||
while (cn->sib) {
|
||||
last = cn->sib;
|
||||
cn = last;
|
||||
}
|
||||
|
||||
cn = dm_config_create_node(cft, node_name);
|
||||
if (!cn)
|
||||
return NULL;
|
||||
|
||||
cn->v = NULL;
|
||||
cn->sib = NULL;
|
||||
cn->parent = cft->root;
|
||||
last->sib = cn;
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
static struct dm_config_node *make_pv_node(lvmetad_state *s, const char *pvid,
|
||||
struct dm_config_tree *cft,
|
||||
struct dm_config_node *parent,
|
||||
@ -310,6 +429,9 @@ static response pv_list(lvmetad_state *s, request r)
|
||||
cn = make_pv_node(s, id, res.cft, cn_pvs, cn);
|
||||
}
|
||||
|
||||
if (s->flags & GLFL_INVALID)
|
||||
add_last_node(res.cft, "global_invalid");
|
||||
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
|
||||
return res;
|
||||
@ -354,6 +476,9 @@ static response pv_lookup(lvmetad_state *s, request r)
|
||||
pv->key = "physical_volume";
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
|
||||
if (s->flags & GLFL_INVALID)
|
||||
add_last_node(res.cft, "global_invalid");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -422,6 +547,9 @@ static response vg_list(lvmetad_state *s, request r)
|
||||
}
|
||||
|
||||
unlock_vgid_to_metadata(s);
|
||||
|
||||
if (s->flags & GLFL_INVALID)
|
||||
add_last_node(res.cft, "global_invalid");
|
||||
bad:
|
||||
return res;
|
||||
}
|
||||
@ -499,6 +627,7 @@ static response vg_lookup(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_tree *cft;
|
||||
struct dm_config_node *metadata, *n;
|
||||
struct vg_info *info;
|
||||
response res = { 0 };
|
||||
|
||||
const char *uuid = daemon_request_str(r, "uuid", NULL);
|
||||
@ -563,66 +692,22 @@ static response vg_lookup(lvmetad_state *s, request r)
|
||||
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
|
||||
chain_outdated_pvs(s, uuid, res.cft, n);
|
||||
|
||||
if (s->flags & GLFL_INVALID)
|
||||
add_last_node(res.cft, "global_invalid");
|
||||
|
||||
info = dm_hash_lookup(s->vgid_to_info, uuid);
|
||||
if (info && (info->flags & VGFL_INVALID)) {
|
||||
n = add_last_node(res.cft, "vg_invalid");
|
||||
if (!n)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return res;
|
||||
bad:
|
||||
unlock_vg(s, uuid);
|
||||
return reply_fail("out of memory");
|
||||
}
|
||||
|
||||
/* Test if the doubles are close enough to be considered equal */
|
||||
static int close_enough(double d1, double d2)
|
||||
{
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
}
|
||||
|
||||
static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (a->type > b->type)
|
||||
return 1;
|
||||
if (a->type < b->type)
|
||||
return -1;
|
||||
|
||||
switch (a->type) {
|
||||
case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
|
||||
case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
|
||||
case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
|
||||
case DM_CFG_EMPTY_ARRAY: return 0;
|
||||
}
|
||||
|
||||
if (r == 0 && a->next && b->next)
|
||||
r = compare_value(a->next, b->next);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
|
||||
{
|
||||
int result = 0;
|
||||
if (a->v && b->v)
|
||||
result = compare_value(a->v, b->v);
|
||||
if (a->v && !b->v)
|
||||
result = 1;
|
||||
if (!a->v && b->v)
|
||||
result = -1;
|
||||
if (a->child && b->child)
|
||||
result = compare_config(a->child, b->child);
|
||||
|
||||
if (result) {
|
||||
// DEBUGLOG("config inequality at %s / %s", a->key, b->key);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (a->sib && b->sib)
|
||||
result = compare_config(a->sib, b->sib);
|
||||
if (a->sib && !b->sib)
|
||||
result = 1;
|
||||
if (!a->sib && b->sib)
|
||||
result = -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
|
||||
|
||||
enum update_pvid_mode { UPDATE_ONLY, REMOVE_EMPTY, MARK_OUTDATED };
|
||||
@ -914,7 +999,8 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
|
||||
DEBUGLOG(s, "pv_gone (updated): %s / %" PRIu64, pvid, device);
|
||||
|
||||
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
|
||||
if (!(pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid)))
|
||||
return reply_unknown("PVID does not exist");
|
||||
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
|
||||
|
||||
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
|
||||
@ -936,9 +1022,6 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
dm_free(vgid);
|
||||
}
|
||||
|
||||
if (!pvmeta)
|
||||
return reply_unknown("PVID does not exist");
|
||||
|
||||
if (!alt_device)
|
||||
dm_config_destroy(pvmeta);
|
||||
|
||||
@ -1131,6 +1214,39 @@ out_of_mem:
|
||||
NULL);
|
||||
}
|
||||
|
||||
static response vg_clear_outdated_pvs(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_tree *outdated_pvs;
|
||||
const char *vgid = daemon_request_str(r, "vgid", NULL);
|
||||
|
||||
if (!vgid)
|
||||
return reply_fail("need VG UUID");
|
||||
|
||||
if ((outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid))) {
|
||||
dm_config_destroy(outdated_pvs);
|
||||
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
|
||||
}
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
|
||||
static void vg_info_update(lvmetad_state *s, const char *uuid,
|
||||
struct dm_config_node *metadata)
|
||||
{
|
||||
struct vg_info *info;
|
||||
int64_t cache_version;
|
||||
|
||||
cache_version = dm_config_find_int64(metadata, "metadata/seqno", -1);
|
||||
if (cache_version == -1)
|
||||
return;
|
||||
|
||||
info = (struct vg_info *) dm_hash_lookup(s->vgid_to_info, uuid);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (cache_version >= info->external_version)
|
||||
info->flags &= ~VGFL_INVALID;
|
||||
}
|
||||
|
||||
static response vg_update(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
|
||||
@ -1148,6 +1264,8 @@ static response vg_update(lvmetad_state *s, request r)
|
||||
* call; if client does not commit, die */
|
||||
if (!update_metadata(s, vgname, vgid, metadata, NULL, NULL))
|
||||
return reply_fail("metadata update failed");
|
||||
|
||||
vg_info_update(s, vgid, metadata);
|
||||
}
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
@ -1168,6 +1286,71 @@ static response vg_remove(lvmetad_state *s, request r)
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
|
||||
static response set_global_info(lvmetad_state *s, request r)
|
||||
{
|
||||
const int global_invalid = daemon_request_int(r, "global_invalid", -1);
|
||||
|
||||
if (global_invalid == 1)
|
||||
s->flags |= GLFL_INVALID;
|
||||
|
||||
else if (global_invalid == 0)
|
||||
s->flags &= ~GLFL_INVALID;
|
||||
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
|
||||
static response get_global_info(lvmetad_state *s, request r)
|
||||
{
|
||||
return daemon_reply_simple("OK", "global_invalid = %d",
|
||||
(s->flags & GLFL_INVALID) ? 1 : 0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static response set_vg_info(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_tree *vg;
|
||||
struct vg_info *info;
|
||||
const char *uuid = daemon_request_str(r, "uuid", NULL);
|
||||
const int64_t new_version = daemon_request_int(r, "version", -1);
|
||||
int64_t cache_version;
|
||||
|
||||
if (!uuid)
|
||||
goto out;
|
||||
|
||||
if (new_version == -1)
|
||||
goto out;
|
||||
|
||||
vg = dm_hash_lookup(s->vgid_to_metadata, uuid);
|
||||
if (!vg)
|
||||
goto out;
|
||||
|
||||
if (!new_version)
|
||||
goto inval;
|
||||
|
||||
cache_version = dm_config_find_int64(vg->root, "metadata/seqno", -1);
|
||||
|
||||
if (cache_version != -1 && new_version != -1 && cache_version >= new_version)
|
||||
goto out;
|
||||
inval:
|
||||
info = dm_hash_lookup(s->vgid_to_info, uuid);
|
||||
if (!info) {
|
||||
info = malloc(sizeof(struct vg_info));
|
||||
if (!info)
|
||||
goto bad;
|
||||
memset(info, 0, sizeof(struct vg_info));
|
||||
if (!dm_hash_insert(s->vgid_to_info, uuid, (void*)info))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
info->external_version = new_version;
|
||||
info->flags |= VGFL_INVALID;
|
||||
|
||||
out:
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
bad:
|
||||
return reply_fail("out of memory");
|
||||
}
|
||||
|
||||
static void _dump_cft(struct buffer *buf, struct dm_hash_table *ht, const char *key_addr)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
@ -1205,6 +1388,52 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
|
||||
buffer_append(buf, "}\n");
|
||||
}
|
||||
|
||||
static void _dump_info_version(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
|
||||
{
|
||||
char *append;
|
||||
struct dm_hash_node *n = dm_hash_get_first(ht);
|
||||
struct vg_info *info;
|
||||
|
||||
buffer_append(buf, name);
|
||||
buffer_append(buf, " {\n");
|
||||
|
||||
while (n) {
|
||||
const char *key = dm_hash_get_key(ht, n);
|
||||
info = dm_hash_get_data(ht, n);
|
||||
buffer_append(buf, " ");
|
||||
(void) dm_asprintf(&append, "%s = %lld", key, (long long)info->external_version);
|
||||
if (append)
|
||||
buffer_append(buf, append);
|
||||
buffer_append(buf, "\n");
|
||||
dm_free(append);
|
||||
n = dm_hash_get_next(ht, n);
|
||||
}
|
||||
buffer_append(buf, "}\n");
|
||||
}
|
||||
|
||||
static void _dump_info_flags(struct buffer *buf, struct dm_hash_table *ht, const char *name, int int_key)
|
||||
{
|
||||
char *append;
|
||||
struct dm_hash_node *n = dm_hash_get_first(ht);
|
||||
struct vg_info *info;
|
||||
|
||||
buffer_append(buf, name);
|
||||
buffer_append(buf, " {\n");
|
||||
|
||||
while (n) {
|
||||
const char *key = dm_hash_get_key(ht, n);
|
||||
info = dm_hash_get_data(ht, n);
|
||||
buffer_append(buf, " ");
|
||||
(void) dm_asprintf(&append, "%s = %llx", key, (long long)info->flags);
|
||||
if (append)
|
||||
buffer_append(buf, append);
|
||||
buffer_append(buf, "\n");
|
||||
dm_free(append);
|
||||
n = dm_hash_get_next(ht, n);
|
||||
}
|
||||
buffer_append(buf, "}\n");
|
||||
}
|
||||
|
||||
static response dump(lvmetad_state *s)
|
||||
{
|
||||
response res = { 0 };
|
||||
@ -1239,6 +1468,12 @@ static response dump(lvmetad_state *s)
|
||||
buffer_append(b, "\n# DEVICE to PVID mapping\n\n");
|
||||
_dump_pairs(b, s->device_to_pvid, "device_to_pvid", 1);
|
||||
|
||||
buffer_append(b, "\n# VGID to INFO version mapping\n\n");
|
||||
_dump_info_version(b, s->vgid_to_info, "vgid_to_info", 0);
|
||||
|
||||
buffer_append(b, "\n# VGID to INFO flags mapping\n\n");
|
||||
_dump_info_flags(b, s->vgid_to_info, "vgid_to_info", 0);
|
||||
|
||||
unlock_pvid_to_vgid(s);
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
unlock_vgid_to_metadata(s);
|
||||
@ -1260,7 +1495,7 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
|
||||
if (strcmp(token, state->token) && strcmp(rq, "dump")) {
|
||||
if (strcmp(token, state->token) && strcmp(rq, "dump") && strcmp(token, "skip")) {
|
||||
pthread_mutex_unlock(&state->token_lock);
|
||||
return daemon_reply_simple("token_mismatch",
|
||||
"expected = %s", state->token,
|
||||
@ -1289,6 +1524,9 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
if (!strcmp(rq, "vg_update"))
|
||||
return vg_update(state, r);
|
||||
|
||||
if (!strcmp(rq, "vg_clear_outdated_pvs"))
|
||||
return vg_clear_outdated_pvs(state, r);
|
||||
|
||||
if (!strcmp(rq, "vg_remove"))
|
||||
return vg_remove(state, r);
|
||||
|
||||
@ -1301,6 +1539,15 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
if (!strcmp(rq, "vg_list"))
|
||||
return vg_list(state, r);
|
||||
|
||||
if (!strcmp(rq, "set_global_info"))
|
||||
return set_global_info(state, r);
|
||||
|
||||
if (!strcmp(rq, "get_global_info"))
|
||||
return get_global_info(state, r);
|
||||
|
||||
if (!strcmp(rq, "set_vg_info"))
|
||||
return set_vg_info(state, r);
|
||||
|
||||
if (!strcmp(rq, "dump"))
|
||||
return dump(state);
|
||||
|
||||
|
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmetad-client.h"
|
||||
#include "label.h"
|
||||
#include "lvmcache.h"
|
||||
@ -109,7 +124,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (argc > 1) {
|
||||
int i;
|
||||
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0);
|
||||
struct cmd_context *cmd = create_toolcontext(0, NULL, 0, 0, 1, 1);
|
||||
for (i = 1; i < argc; ++i) {
|
||||
const char *uuid = NULL;
|
||||
scan(h, argv[i]);
|
||||
|
@ -18,19 +18,14 @@
|
||||
#ifndef _LVM_LVMPOLLD_COMMON_H
|
||||
#define _LVM_LVMPOLLD_COMMON_H
|
||||
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "tool.h"
|
||||
|
||||
#include "lvmpolld-cmd-utils.h"
|
||||
#include "lvmpolld-protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif /* _LVM_LVMPOLLD_COMMON_H */
|
||||
|
@ -529,7 +529,7 @@ static response progress_info(client_handle h, struct lvmpolld_state *ls, reques
|
||||
if (st.polling_finished)
|
||||
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
|
||||
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
|
||||
LVMPD_PARM_VALUE " = %d", st.cmd_state.signal ?: st.cmd_state.retcode,
|
||||
LVMPD_PARM_VALUE " = %d", (int64_t)(st.cmd_state.signal ?: st.cmd_state.retcode),
|
||||
NULL);
|
||||
else
|
||||
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
|
||||
@ -566,6 +566,8 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
|
||||
cmdenvp = cmdenvp_ctr(pdlv);
|
||||
if (!cmdenvp) {
|
||||
pdlv_destroy(pdlv);
|
||||
@ -573,7 +575,6 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
pdlv->cmdenvp = cmdenvp;
|
||||
|
||||
return pdlv;
|
||||
@ -584,12 +585,16 @@ static int spawn_detached_thread(struct lvmpolld_lv *pdlv)
|
||||
int r;
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (pthread_attr_init(&attr) != 0)
|
||||
return 0;
|
||||
|
||||
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
|
||||
return 0;
|
||||
|
||||
r = pthread_create(&pdlv->tid, &attr, fork_and_poll, (void *)pdlv);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
if (pthread_attr_destroy(&attr) != 0)
|
||||
return 0;
|
||||
|
||||
return !r;
|
||||
}
|
||||
@ -852,7 +857,7 @@ enum action_index {
|
||||
ACTION_MAX /* keep at the end */
|
||||
};
|
||||
|
||||
static const action_fn_t const actions[] = { [ACTION_DUMP] = action_dump };
|
||||
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
||||
|
||||
static int _make_action(enum action_index idx, void *args)
|
||||
{
|
||||
|
@ -325,6 +325,7 @@ struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv
|
||||
|
||||
data->pdlv = NULL;
|
||||
data->line = NULL;
|
||||
data->line_size = 0;
|
||||
data->fout = data->ferr = NULL;
|
||||
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
|
||||
|
||||
@ -365,7 +366,8 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
pdst_unlock(data->pdlv->pdst);
|
||||
}
|
||||
|
||||
dm_free(data->line);
|
||||
/* may get reallocated in getline(). dm_free must not be used */
|
||||
free(data->line);
|
||||
|
||||
if (data->fout && !fclose(data->fout))
|
||||
data->outpipe[0] = -1;
|
||||
@ -374,16 +376,16 @@ void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
data->errpipe[0] = -1;
|
||||
|
||||
if (data->outpipe[0] >= 0)
|
||||
close(data->outpipe[0]);
|
||||
(void) close(data->outpipe[0]);
|
||||
|
||||
if (data->outpipe[1] >= 0)
|
||||
close(data->outpipe[1]);
|
||||
(void) close(data->outpipe[1]);
|
||||
|
||||
if (data->errpipe[0] >= 0)
|
||||
close(data->errpipe[0]);
|
||||
(void) close(data->errpipe[0]);
|
||||
|
||||
if (data->errpipe[1] >= 0)
|
||||
close(data->errpipe[1]);
|
||||
(void) close(data->errpipe[1]);
|
||||
|
||||
dm_free(data);
|
||||
}
|
||||
|
@ -137,6 +137,17 @@ hosts. Overall, this is not hard, but the devil is in the details. I would
|
||||
possibly disable lvmetad for clustered volume groups in the first phase and
|
||||
only proceed when the local mode is robust and well tested.
|
||||
|
||||
With lvmlockd, lvmetad state is kept up to date by flagging either an
|
||||
individual VG as "invalid", or the global state as "invalid". When either
|
||||
the VG or the global state are read, this invalid flag is returned along
|
||||
with the data. The client command can check for this invalid state and
|
||||
decide to read the information from disk rather than use the stale cached
|
||||
data. After the latest data is read from disk, the command may choose to
|
||||
send it to lvmetad to update the cache. lvmlockd uses version numbers
|
||||
embedded in its VG and global locks to detect when cached data becomes
|
||||
invalid, and it then tells lvmetad to set the related invalid flag.
|
||||
dct, 2015-06-23
|
||||
|
||||
Protocol & co.
|
||||
--------------
|
||||
|
||||
|
@ -3,11 +3,13 @@
|
||||
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
|
||||
@top_srcdir@/daemons/lvmpolld/lvmpolld-protocol.h
|
||||
@top_srcdir@/daemons/lvmpolld/polling_ops.h
|
||||
@top_srcdir@/daemons/lvmlockd/lvmlockd-client.h
|
||||
@top_srcdir@/liblvm/lvm2app.h
|
||||
@top_srcdir@/lib/activate/activate.h
|
||||
@top_srcdir@/lib/activate/targets.h
|
||||
@top_srcdir@/lib/cache/lvmcache.h
|
||||
@top_srcdir@/lib/cache/lvmetad.h
|
||||
@top_srcdir@/lib/locking/lvmlockd.h
|
||||
@top_srcdir@/lib/commands/toolcontext.h
|
||||
@top_srcdir@/lib/config/config.h
|
||||
@top_srcdir@/lib/config/config_settings.h
|
||||
@ -74,3 +76,4 @@
|
||||
@top_srcdir@/libdm/misc/kdev_t.h
|
||||
@top_srcdir@/po/pogen.h
|
||||
@top_srcdir@/tools/lvm2cmd.h
|
||||
@top_srcdir@/tools/tool.h
|
||||
|
@ -82,7 +82,6 @@ SOURCES =\
|
||||
format_text/format-text.c \
|
||||
format_text/import.c \
|
||||
format_text/import_vsn1.c \
|
||||
format_text/tags.c \
|
||||
format_text/text_label.c \
|
||||
freeseg/freeseg.c \
|
||||
label/label.c \
|
||||
@ -123,11 +122,6 @@ SOURCES =\
|
||||
uuid/uuid.c \
|
||||
zero/zero.c
|
||||
|
||||
ifeq ("@HAVE_REALTIME@", "yes")
|
||||
SOURCES +=\
|
||||
misc/timestamp.c
|
||||
endif
|
||||
|
||||
ifeq ("@LVM1@", "internal")
|
||||
SOURCES +=\
|
||||
format1/disk-rep.c \
|
||||
@ -201,6 +195,11 @@ ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
lvmpolld/lvmpolld-client.c
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMLOCKD@", "yes")
|
||||
SOURCES +=\
|
||||
locking/lvmlockd.c
|
||||
endif
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
|
||||
LIBS += -ldevmapper-event
|
||||
|
@ -180,7 +180,7 @@ int lv_passes_auto_activation_filter(struct cmd_context *cmd, struct logical_vol
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
|
||||
if (!(cn = find_config_tree_array(cmd, activation_auto_activation_volume_list_CFG, NULL))) {
|
||||
log_verbose("activation/auto_activation_volume_list configuration setting "
|
||||
"not defined: All logical volumes will be auto-activated.");
|
||||
return 1;
|
||||
@ -473,7 +473,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, activation_volume_list_CFG, NULL))) {
|
||||
if (!(cn = find_config_tree_array(cmd, activation_volume_list_CFG, NULL))) {
|
||||
log_verbose("activation/volume_list configuration setting "
|
||||
"not defined: Checking only host tags for %s/%s",
|
||||
lv->vg->name, lv->name);
|
||||
@ -502,7 +502,7 @@ static int _passes_readonly_filter(struct cmd_context *cmd,
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||
if (!(cn = find_config_tree_array(cmd, activation_read_only_volume_list_CFG, NULL)))
|
||||
return 0;
|
||||
|
||||
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
|
||||
@ -654,8 +654,8 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
* in progress - as only those could lead to opened files
|
||||
*/
|
||||
if (with_open_count) {
|
||||
if (locking_is_clustered())
|
||||
sync_local_dev_names(cmd); /* Wait to have udev in sync */
|
||||
if (locking_is_clustered() && !sync_local_dev_names(cmd)) /* Wait to have udev in sync */
|
||||
return_0;
|
||||
else if (fs_has_non_delete_ops())
|
||||
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
|
||||
}
|
||||
@ -1875,7 +1875,9 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
goto_out;
|
||||
|
||||
/* Ignore origin_only unless LV is origin in both old and new metadata */
|
||||
if (!lv_is_thin_volume(ondisk_lv) && !(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
|
||||
/* or LV is thin or thin pool volume */
|
||||
if (!lv_is_thin_volume(ondisk_lv) && !lv_is_thin_pool(ondisk_lv) &&
|
||||
!(lv_is_origin(ondisk_lv) && lv_is_origin(incore_lv)))
|
||||
laopts->origin_only = 0;
|
||||
|
||||
if (test_mode()) {
|
||||
@ -2049,7 +2051,6 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
int messages_only = 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
@ -2057,10 +2058,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
|
||||
if (lv_is_thin_pool(lv) && laopts->origin_only)
|
||||
messages_only = 1;
|
||||
|
||||
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv))
|
||||
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
|
||||
laopts->origin_only = 0;
|
||||
|
||||
if (test_mode()) {
|
||||
@ -2072,13 +2070,15 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
|
||||
log_debug_activation("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
|
||||
error_if_not_active ? "" : " if active",
|
||||
laopts->origin_only ? " without snapshots" : "",
|
||||
laopts->origin_only ?
|
||||
(lv_is_thin_pool(lv) ? " pool only" :
|
||||
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
|
||||
laopts->revert ? " (reverting)" : "");
|
||||
|
||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists || !(info.suspended || messages_only)) {
|
||||
if (!info.exists || !info.suspended) {
|
||||
if (error_if_not_active)
|
||||
goto_out;
|
||||
r = 1;
|
||||
@ -2334,6 +2334,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (info.exists && !info.suspended && info.live_table &&
|
||||
(info.read_only == read_only_lv(lv, laopts))) {
|
||||
r = 1;
|
||||
log_debug_activation("Volume is already active.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,7 @@ struct dev_manager {
|
||||
uint32_t pvmove_mirror_count;
|
||||
int flush_required;
|
||||
int activation; /* building activation tree */
|
||||
int suspend; /* building suspend tree */
|
||||
int skip_external_lv;
|
||||
struct dm_list pending_delete; /* str_list of dlid(s) with pending delete */
|
||||
unsigned track_pending_delete;
|
||||
@ -453,6 +454,78 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _device_is_suspended(int major, int minor)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_major_minor(dmt, major, minor, 1))
|
||||
goto_out;
|
||||
|
||||
if (activation_checks() && !dm_task_enable_checks(dmt))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_run(dmt) ||
|
||||
!dm_task_get_info(dmt, &info)) {
|
||||
log_error("Failed to get info for device %d:%d", major, minor);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = info.exists && info.suspended;
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _ignore_suspended_snapshot_component(struct device *dev)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
char *params, *target_type = NULL;
|
||||
uint64_t start, length;
|
||||
int major1, minor1, major2, minor2;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
|
||||
return_0;
|
||||
|
||||
if (!dm_task_set_major_minor(dmt, MAJOR(dev->dev), MINOR(dev->dev), 1))
|
||||
goto_out;
|
||||
|
||||
if (activation_checks() && !dm_task_enable_checks(dmt))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("Failed to get state of snapshot or snapshot origin device");
|
||||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!strcmp(target_type, "snapshot")) {
|
||||
if (sscanf(params, "%d:%d %d:%d", &major1, &minor1, &major2, &minor2) != 4) {
|
||||
log_error("Incorrect snapshot table found");
|
||||
goto_out;
|
||||
}
|
||||
r = r || _device_is_suspended(major1, minor1) || _device_is_suspended(major2, minor2);
|
||||
} else if (!strcmp(target_type, "snapshot-origin")) {
|
||||
if (sscanf(params, "%d:%d", &major1, &minor1) != 2) {
|
||||
log_error("Incorrect snapshot-origin table found");
|
||||
goto_out;
|
||||
}
|
||||
r = r || _device_is_suspended(major1, minor1);
|
||||
}
|
||||
} while (next);
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_is_usable
|
||||
* @dev
|
||||
@ -561,15 +634,25 @@ int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
* supported anymore and in general using mirrors in a stack
|
||||
* is disabled by default (with a warning that if enabled,
|
||||
* it could cause various deadlocks).
|
||||
* This is former check used, but it's not correct as it
|
||||
* disables snapshot-origins to be used in a stack in
|
||||
* general, not just over mirrors!
|
||||
* Similar situation can happen with RAID devices where
|
||||
* a RAID device can be snapshotted.
|
||||
* If one of the RAID legs are down and we're doing
|
||||
* lvconvert --repair, there's a time period in which
|
||||
* snapshot components are (besides other devs) suspended.
|
||||
* See also https://bugzilla.redhat.com/show_bug.cgi?id=1219222
|
||||
* for an example where this causes problems.
|
||||
*
|
||||
* This is a quick check for now, but replace it with more
|
||||
* robust and better check that would check the stack
|
||||
* correctly, not just snapshots but any cobimnation possible
|
||||
* in a stack - use proper dm tree to check this instead.
|
||||
*/
|
||||
/*if (check.check_suspended && target_type && !strcmp(target_type, "snapshot-origin")) {
|
||||
log_debug_activation("%s: Snapshot-origin device %s not usable.",
|
||||
dev_name(dev), name);
|
||||
if (check.check_suspended && target_type &&
|
||||
(!strcmp(target_type, "snapshot") || !strcmp(target_type, "snapshot-origin")) &&
|
||||
_ignore_suspended_snapshot_component(dev)) {
|
||||
log_debug_activation("%s: %s device %s not usable.", dev_name(dev), target_type, name);
|
||||
goto out;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (target_type && strcmp(target_type, "error"))
|
||||
only_error_target = 0;
|
||||
@ -1843,7 +1926,6 @@ struct pool_cb_data {
|
||||
int skip_zero; /* to skip zeroed device header (check first 64B) */
|
||||
int exec; /* which binary to call */
|
||||
int opts;
|
||||
const char *defaults;
|
||||
const char *global;
|
||||
};
|
||||
|
||||
@ -1851,7 +1933,6 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
dm_node_callback_t type, void *cb_data)
|
||||
{
|
||||
int ret, status, fd;
|
||||
char *split;
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const struct pool_cb_data *data = cb_data;
|
||||
@ -1866,23 +1947,19 @@ static int _pool_callback(struct dm_tree_node *node,
|
||||
if (!*argv[0])
|
||||
return 1; /* Checking disabled */
|
||||
|
||||
if ((cn = find_config_tree_node(mlv->vg->cmd, data->opts, NULL))) {
|
||||
for (cv = cn->v; cv && args < 16; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"global/%s_check_options",
|
||||
data->global);
|
||||
return 0;
|
||||
}
|
||||
argv[++args] = cv->v.str;
|
||||
}
|
||||
} else {
|
||||
/* Use default options (no support for options with spaces) */
|
||||
if (!(split = dm_pool_strdup(data->dm->mem, data->defaults))) {
|
||||
log_error("Failed to duplicate defaults.");
|
||||
if (!(cn = find_config_tree_array(mlv->vg->cmd, data->opts, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for pool check options.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv && args < 16; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"global/%s_check_options",
|
||||
data->global);
|
||||
return 0;
|
||||
}
|
||||
args = dm_split_words(split, 16, 0, (char**) argv + 1);
|
||||
argv[++args] = cv->v.str;
|
||||
}
|
||||
|
||||
if (args == 16) {
|
||||
@ -1973,14 +2050,12 @@ static int _pool_register_callback(struct dev_manager *dm,
|
||||
data->skip_zero = 1;
|
||||
data->exec = global_thin_check_executable_CFG;
|
||||
data->opts = global_thin_check_options_CFG;
|
||||
data->defaults = DEFAULT_THIN_CHECK_OPTION1 " " DEFAULT_THIN_CHECK_OPTION2;
|
||||
data->global = "thin";
|
||||
} else if (lv_is_cache(lv)) { /* cache pool */
|
||||
data->pool_lv = first_seg(lv)->pool_lv;
|
||||
data->skip_zero = dm->activation;
|
||||
data->exec = global_cache_check_executable_CFG;
|
||||
data->opts = global_cache_check_options_CFG;
|
||||
data->defaults = DEFAULT_CACHE_CHECK_OPTION1;
|
||||
data->global = "cache";
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
|
||||
@ -1992,6 +2067,11 @@ static int _pool_register_callback(struct dev_manager *dm,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Declaration to resolve suspend tree and message passing for thin-pool */
|
||||
static int _add_target_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree_node *dnode,
|
||||
struct lv_segment *seg,
|
||||
struct lv_activate_opts *laopts);
|
||||
/*
|
||||
* Add LV and any known dependencies
|
||||
*/
|
||||
@ -2060,15 +2140,43 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
*/
|
||||
if (!_add_dev_to_dtree(dm, dtree, lv, lv_layer(lv)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* TODO: change API and move this code
|
||||
* Could be easier to handle this in _add_dev_to_dtree()
|
||||
* and base this according to info.exists ?
|
||||
*/
|
||||
if (!dm->activation) {
|
||||
/* Setup callback for non-activation partial tree */
|
||||
/* Activation gets own callback when needed */
|
||||
/* TODO: extend _cached_dm_info() to return dnode */
|
||||
if (!(uuid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
|
||||
return_0;
|
||||
if ((node = dm_tree_find_node_by_uuid(dtree, uuid)) &&
|
||||
!_pool_register_callback(dm, node, lv))
|
||||
return_0;
|
||||
if ((node = dm_tree_find_node_by_uuid(dtree, uuid))) {
|
||||
if (origin_only) {
|
||||
struct lv_activate_opts laopts = {
|
||||
.origin_only = 1,
|
||||
.send_messages = 1 /* Node with messages */
|
||||
};
|
||||
/*
|
||||
* Add some messsages if right node exist in the table only
|
||||
* when building SUSPEND tree for origin-only thin-pool.
|
||||
*
|
||||
* TODO: Fix call of '_add_target_to_dtree()' to add message
|
||||
* to thin-pool node as we already know the pool node exists
|
||||
* in the table. Any better/cleaner API way ?
|
||||
*
|
||||
* Probably some 'new' target method to add messages for any node?
|
||||
*/
|
||||
if (dm->suspend &&
|
||||
!dm_list_empty(&(first_seg(lv)->thin_messages)) &&
|
||||
!_add_target_to_dtree(dm, node, first_seg(lv), &laopts))
|
||||
return_0;
|
||||
} else {
|
||||
/* Setup callback for non-activation partial tree */
|
||||
/* Activation gets own callback when needed */
|
||||
/* TODO: extend _cached_dm_info() to return dnode */
|
||||
if (!_pool_register_callback(dm, node, lv))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2167,7 +2275,7 @@ static struct dm_tree *_create_partial_dtree(struct dev_manager *dm, const struc
|
||||
|
||||
dm_tree_set_optional_uuid_suffixes(dtree, &uuid_suffix_list[0]);
|
||||
|
||||
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv)) ? origin_only : 0))
|
||||
if (!_add_lv_to_dtree(dm, dtree, lv, (lv_is_origin(lv) || lv_is_thin_volume(lv) || lv_is_thin_pool(lv)) ? origin_only : 0))
|
||||
goto_bad;
|
||||
|
||||
return dtree;
|
||||
@ -2627,7 +2735,7 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
return_0;
|
||||
|
||||
/* Add pool layer */
|
||||
if (seg->pool_lv &&
|
||||
if (seg->pool_lv && !laopts->origin_only &&
|
||||
!_add_new_lv_to_dtree(dm, dtree, seg->pool_lv, laopts,
|
||||
lv_layer(seg->pool_lv)))
|
||||
return_0;
|
||||
@ -3081,7 +3189,10 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
int r = 0;
|
||||
|
||||
if (action < DM_ARRAY_SIZE(_action_names))
|
||||
log_debug_activation("Creating %s tree for %s.", _action_names[action], lv->name);
|
||||
log_debug_activation("Creating %s%s tree for %s.",
|
||||
_action_names[action],
|
||||
(laopts->origin_only) ? " origin-only" : "",
|
||||
display_lvname(lv));
|
||||
|
||||
/* Some LV can be used for top level tree */
|
||||
/* TODO: add more.... */
|
||||
@ -3091,6 +3202,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
}
|
||||
/* Some targets may build bigger tree for activation */
|
||||
dm->activation = ((action == PRELOAD) || (action == ACTIVATE));
|
||||
dm->suspend = (action == SUSPEND_WITH_LOCKFS) || (action == SUSPEND);
|
||||
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
|
||||
return_0;
|
||||
|
||||
@ -3135,7 +3247,9 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
case PRELOAD:
|
||||
case ACTIVATE:
|
||||
/* Add all required new devices to tree */
|
||||
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts, (lv_is_origin(lv) && laopts->origin_only) ? "real" : NULL))
|
||||
if (!_add_new_lv_to_dtree(dm, dtree, lv, laopts,
|
||||
(lv_is_origin(lv) && laopts->origin_only) ? "real" :
|
||||
(lv_is_thin_pool(lv) && laopts->origin_only) ? "tpool" : NULL))
|
||||
goto_out;
|
||||
|
||||
/* Preload any devices required before any suspensions */
|
||||
@ -3173,7 +3287,6 @@ out_no_root:
|
||||
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts)
|
||||
{
|
||||
laopts->send_messages = 1;
|
||||
if (!_tree_action(dm, lv, laopts, ACTIVATE))
|
||||
return_0;
|
||||
|
||||
|
53
lib/cache/lvmcache.c
vendored
53
lib/cache/lvmcache.c
vendored
@ -56,6 +56,7 @@ struct lvmcache_vginfo {
|
||||
char _padding[7];
|
||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||
char *creation_host;
|
||||
char *lock_type;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
size_t vgmetadata_size;
|
||||
@ -1447,7 +1448,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
|
||||
const char *creation_host)
|
||||
const char *creation_host, const char *lock_type)
|
||||
{
|
||||
if (!info || !info->vginfo)
|
||||
return 1;
|
||||
@ -1460,11 +1461,11 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
||||
info->vginfo->status = vgstatus;
|
||||
|
||||
if (!creation_host)
|
||||
return 1;
|
||||
goto set_lock_type;
|
||||
|
||||
if (info->vginfo->creation_host && !strcmp(creation_host,
|
||||
info->vginfo->creation_host))
|
||||
return 1;
|
||||
goto set_lock_type;
|
||||
|
||||
if (info->vginfo->creation_host)
|
||||
dm_free(info->vginfo->creation_host);
|
||||
@ -1478,6 +1479,24 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
||||
log_debug_cache("lvmcache: %s: VG %s: Set creation host to %s.",
|
||||
dev_name(info->dev), info->vginfo->vgname, creation_host);
|
||||
|
||||
set_lock_type:
|
||||
|
||||
if (!lock_type)
|
||||
goto out;
|
||||
|
||||
if (info->vginfo->lock_type && !strcmp(lock_type, info->vginfo->lock_type))
|
||||
goto out;
|
||||
|
||||
if (info->vginfo->lock_type)
|
||||
dm_free(info->vginfo->lock_type);
|
||||
|
||||
if (!(info->vginfo->lock_type = dm_strdup(lock_type))) {
|
||||
log_error("cache creation host alloc failed for %s",
|
||||
lock_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1546,7 +1565,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
|
||||
vgsummary->creation_host, info->fmt) ||
|
||||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
|
||||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host) ||
|
||||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type) ||
|
||||
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
|
||||
return_0;
|
||||
|
||||
@ -1561,7 +1580,8 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
struct lvmcache_vgsummary vgsummary = {
|
||||
.vgname = vg->name,
|
||||
.vgstatus = vg->status,
|
||||
.vgid = vg->id
|
||||
.vgid = vg->id,
|
||||
.lock_type = vg->lock_type
|
||||
};
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
@ -1856,14 +1876,12 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: when could this ever happen?
|
||||
* If this does happen, identify when/why here, and
|
||||
* if not, remove this code.
|
||||
* This happens when running pvcreate on an existing PV.
|
||||
*/
|
||||
if (strcmp(pvid_s, existing->dev->pvid)) {
|
||||
log_warn("Replacing dev %s pvid %s with dev %s pvid %s",
|
||||
dev_name(existing->dev), existing->dev->pvid,
|
||||
dev_name(dev), pvid_s);
|
||||
log_verbose("Replacing dev %s pvid %s with dev %s pvid %s",
|
||||
dev_name(existing->dev), existing->dev->pvid,
|
||||
dev_name(dev), pvid_s);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2327,3 +2345,16 @@ int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
if (vginfo->lock_type && !strcmp(vginfo->lock_type, "sanlock"))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
14
lib/cache/lvmcache.h
vendored
14
lib/cache/lvmcache.h
vendored
@ -39,11 +39,23 @@ struct disk_locn;
|
||||
|
||||
struct lvmcache_vginfo;
|
||||
|
||||
/*
|
||||
* vgsummary represents a summary of the VG that is read
|
||||
* without a lock. The info does not come through vg_read(),
|
||||
* but through reading mdas. It provides information about
|
||||
* the VG that is needed to lock the VG and then read it fully
|
||||
* with vg_read(), after which the VG summary should be checked
|
||||
* against the full VG metadata to verify it was correct (since
|
||||
* it was read without a lock.)
|
||||
*
|
||||
* Once read, vgsummary information is saved in lvmcache_vginfo.
|
||||
*/
|
||||
struct lvmcache_vgsummary {
|
||||
const char *vgname;
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
char *creation_host;
|
||||
const char *lock_type;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
};
|
||||
@ -176,4 +188,6 @@ int lvmcache_found_duplicate_pvs(void);
|
||||
|
||||
void lvmcache_set_preferred_duplicates(const char *vgid);
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
||||
|
492
lib/cache/lvmetad.c
vendored
492
lib/cache/lvmetad.c
vendored
@ -22,6 +22,7 @@
|
||||
#include "format-text.h" // TODO for disk_locn, used as a DA representation
|
||||
#include "crc.h"
|
||||
#include "lvm-signal.h"
|
||||
#include "lvmlockd.h"
|
||||
|
||||
#define SCAN_TIMEOUT_SECONDS 80
|
||||
#define MAX_RESCANS 10 /* Maximum number of times to scan all PVs and retry if the daemon returns a token mismatch error */
|
||||
@ -34,6 +35,8 @@ static char *_lvmetad_token = NULL;
|
||||
static const char *_lvmetad_socket = NULL;
|
||||
static struct cmd_context *_lvmetad_cmd = NULL;
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
void lvmetad_disconnect(void)
|
||||
{
|
||||
if (_lvmetad_connected)
|
||||
@ -145,7 +148,7 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
|
||||
static daemon_reply _lvmetad_send(const char *id, ...)
|
||||
{
|
||||
va_list ap;
|
||||
daemon_reply repl;
|
||||
daemon_reply repl = { 0 };
|
||||
daemon_request req;
|
||||
unsigned num_rescans = 0;
|
||||
unsigned total_usecs_waited = 0;
|
||||
@ -155,8 +158,10 @@ static daemon_reply _lvmetad_send(const char *id, ...)
|
||||
retry:
|
||||
req = daemon_request_make(id);
|
||||
|
||||
if (_lvmetad_token)
|
||||
daemon_request_extend(req, "token = %s", _lvmetad_token, NULL);
|
||||
if (_lvmetad_token && !daemon_request_extend(req, "token = %s", _lvmetad_token, NULL)) {
|
||||
repl.error = ENOMEM;
|
||||
return repl;
|
||||
}
|
||||
|
||||
va_start(ap, id);
|
||||
daemon_request_extend_v(req, ap);
|
||||
@ -417,6 +422,7 @@ static int _pv_update_struct_pv(struct physical_volume *pv, struct format_instan
|
||||
struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct volume_group *vg2 = NULL;
|
||||
daemon_reply reply;
|
||||
int found;
|
||||
char uuid[64];
|
||||
@ -483,9 +489,21 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
|
||||
|
||||
top->key = name;
|
||||
if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
|
||||
if (!(vg = import_vg_from_lvmetad_config_tree(reply.cft, fid)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* locking may have detected a newer vg version and
|
||||
* invalidated the cached vg.
|
||||
*/
|
||||
if (dm_config_find_node(reply.cft->root, "vg_invalid")) {
|
||||
log_debug_lvmetad("Update invalid lvmetad cache for VG %s", vgname);
|
||||
vg2 = lvmetad_pvscan_vg(cmd, vg);
|
||||
release_vg(vg);
|
||||
vg = vg2;
|
||||
fid = vg->fid;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
@ -934,6 +952,51 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
|
||||
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
|
||||
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
|
||||
|
||||
/*
|
||||
* pvscan --cache does not perform any lvmlockd locking, and
|
||||
* pvscan --cache -aay skips autoactivation in lockd VGs.
|
||||
*
|
||||
* pvscan --cache populates lvmetad with VG metadata from disk.
|
||||
* No lvmlockd locking is needed. It is expected that lockd VG
|
||||
* metadata that is read by pvscan and populated in lvmetad may
|
||||
* be immediately stale due to changes to the VG from other hosts
|
||||
* during or after this pvscan. This is normal and not a problem.
|
||||
* When a subsequent lvm command uses the VG, it will lock the VG
|
||||
* with lvmlockd, read the VG from lvmetad, and update the cached
|
||||
* copy from disk if necessary.
|
||||
*
|
||||
* pvscan --cache -aay does not activate LVs in lockd VGs because
|
||||
* activation requires locking, and a lock-start operation is needed
|
||||
* on a lockd VG before any locking can be performed in it.
|
||||
*
|
||||
* An equivalent of pvscan --cache -aay for lockd VGs is:
|
||||
* 1. pvscan --cache
|
||||
* 2. vgchange --lock-start
|
||||
* 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
|
||||
*
|
||||
* [We could eventually add support for autoactivating lockd VGs
|
||||
* using pvscan by incorporating the lock start step (which can
|
||||
* take a long time), but there may be a better option than
|
||||
* continuing to overload pvscan.]
|
||||
*
|
||||
* Stages of starting a lockd VG:
|
||||
*
|
||||
* . pvscan --cache populates lockd VGs in lvmetad without locks,
|
||||
* and this initial cached copy may quickly become stale.
|
||||
*
|
||||
* . vgchange --lock-start VG reads the VG without the VG lock
|
||||
* because no locks are available until the locking is started.
|
||||
* It only uses the VG name and lock_type from the VG metadata,
|
||||
* and then only uses it to start the VG lockspace in lvmlockd.
|
||||
*
|
||||
* . Further lvm commands, e.g. activation, can then lock the VG
|
||||
* with lvmlockd and use current VG metdata.
|
||||
*/
|
||||
if (handler && vg && is_lockd_type(vg->lock_type)) {
|
||||
log_debug_lvmetad("Skip pvscan activation for lockd type VG %s", vg->name);
|
||||
handler = NULL;
|
||||
}
|
||||
|
||||
if (result && handler) {
|
||||
status = daemon_reply_str(reply, "status", "<missing>");
|
||||
vgname = daemon_reply_str(reply, "vgname", "<missing>");
|
||||
@ -1001,7 +1064,8 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
struct _lvmetad_pvscan_baton *b = baton;
|
||||
struct volume_group *this;
|
||||
|
||||
this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1);
|
||||
if (!(this = mda_is_ignored(mda) ? NULL : mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
|
||||
return 1;
|
||||
|
||||
/* FIXME Also ensure contents match etc. */
|
||||
if (!b->vg || this->seqno > b->vg->seqno)
|
||||
@ -1012,6 +1076,100 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lock manager may detect that the vg cached in lvmetad is out of date,
|
||||
* due to something like an lvcreate from another host.
|
||||
* This is limited to changes that only affect the vg (not global state like
|
||||
* orphan PVs), so we only need to reread mdas on the vg's existing pvs.
|
||||
*/
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
struct volume_group *vg_ret = NULL;
|
||||
struct dm_config_tree *vgmeta_ret = NULL;
|
||||
struct dm_config_tree *vgmeta;
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
/* missing pv */
|
||||
if (!pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
if (!(info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
|
||||
log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
baton.vg = NULL;
|
||||
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
|
||||
if (!baton.fid)
|
||||
return NULL;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(pvl->pv->dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
|
||||
if (!baton.vg) {
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
log_error("VG export to config tree failed");
|
||||
release_vg(baton.vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!vgmeta_ret) {
|
||||
vgmeta_ret = vgmeta;
|
||||
} else {
|
||||
if (!compare_config(vgmeta_ret->root, vgmeta->root)) {
|
||||
log_error("VG metadata comparison failed");
|
||||
dm_config_destroy(vgmeta);
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
release_vg(baton.vg);
|
||||
return NULL;
|
||||
}
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
|
||||
release_vg(baton.vg);
|
||||
}
|
||||
|
||||
if (vgmeta_ret) {
|
||||
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
|
||||
log_error("VG import from config tree failed");
|
||||
lvmcache_fmt(info)->ops->destroy_instance(fid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update lvmetad with the newly read version of the VG.
|
||||
* The "precommitted" name is a misnomer in this case,
|
||||
* but that is the field which lvmetad_vg_update() uses
|
||||
* to send the metadata cft to lvmetad.
|
||||
*/
|
||||
vg_ret->cft_precommitted = vgmeta_ret;
|
||||
if (!lvmetad_vg_update(vg_ret))
|
||||
log_error("Failed to update lvmetad with new VG meta");
|
||||
vg_ret->cft_precommitted = NULL;
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
}
|
||||
out:
|
||||
return vg_ret;
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
activation_handler handler, int ignore_obsolete)
|
||||
{
|
||||
@ -1161,3 +1319,327 @@ int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handl
|
||||
{
|
||||
return _lvmetad_pvscan_all_devs(cmd, handler, 1);
|
||||
}
|
||||
|
||||
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg)
|
||||
{
|
||||
char uuid[64];
|
||||
daemon_reply reply;
|
||||
int result;
|
||||
|
||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
|
||||
reply = _lvmetad_send("vg_clear_outdated_pvs", "vgid = %s", uuid, NULL);
|
||||
result = _lvmetad_handle_reply(reply, "clear the list of outdated PVs", vg->name, NULL);
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Records the state of cached PVs in lvmetad so we can look for changes
|
||||
* after rescanning.
|
||||
*/
|
||||
struct pv_cache_list {
|
||||
struct dm_list list;
|
||||
dev_t devt;
|
||||
struct id pvid;
|
||||
const char *vgid;
|
||||
unsigned found : 1;
|
||||
unsigned update_udev : 1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Get the list of PVs known to lvmetad.
|
||||
*/
|
||||
static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *pvc_list)
|
||||
{
|
||||
daemon_reply reply;
|
||||
struct dm_config_node *cn;
|
||||
struct pv_cache_list *pvcl;
|
||||
const char *pvid_txt;
|
||||
const char *vgid;
|
||||
|
||||
if (!lvmetad_active())
|
||||
return 1;
|
||||
|
||||
log_debug_lvmetad("Asking lvmetad for complete list of known PVs");
|
||||
reply = _lvmetad_send("pv_list", NULL);
|
||||
if (!_lvmetad_handle_reply(reply, "list PVs", "", NULL)) {
|
||||
log_error("lvmetad message failed.");
|
||||
daemon_reply_destroy(reply);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes"))) {
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
if (!(pvcl = dm_pool_zalloc(cmd->mem, sizeof(*pvcl)))) {
|
||||
log_error("pv_cache_list allocation failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvid_txt = cn->key;
|
||||
if (!id_read_format(&pvcl->pvid, pvid_txt)) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
|
||||
pvcl->devt = dm_config_find_int(cn->child, "device", 0);
|
||||
|
||||
if ((vgid = dm_config_find_str(cn->child, "vgid", NULL)))
|
||||
pvcl->vgid = dm_pool_strdup(cmd->mem, vgid);
|
||||
|
||||
dm_list_add(pvc_list, &pvcl->list);
|
||||
}
|
||||
}
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opening the device RDWR should trigger a udev db update.
|
||||
* FIXME: is there a better way to update the udev db than
|
||||
* doing an open/close of the device? - For example writing
|
||||
* "change" to /sys/block/<device>/uevent?
|
||||
*/
|
||||
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
log_debug_devs("device %d:%d open to update udev",
|
||||
(int)MAJOR(devt), (int)MINOR(devt));
|
||||
|
||||
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
|
||||
log_error("_update_pv_in_udev no dev found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare before and after PV lists from before/after rescanning,
|
||||
* and update udev db for changes.
|
||||
*
|
||||
* For PVs that have changed pvid or vgid in lvmetad from rescanning,
|
||||
* there may be information in the udev database to update, so open
|
||||
* these devices to trigger a udev update.
|
||||
*
|
||||
* "before" refers to the list of pvs from lvmetad before rescanning
|
||||
* "after" refers to the list of pvs from lvmetad after rescanning
|
||||
*
|
||||
* Comparing both lists, we can see which PVs changed (pvid or vgid),
|
||||
* and trigger a udev db update for those.
|
||||
*/
|
||||
static void _update_changed_pvs_in_udev(struct cmd_context *cmd,
|
||||
struct dm_list *pvc_before,
|
||||
struct dm_list *pvc_after)
|
||||
{
|
||||
struct pv_cache_list *before;
|
||||
struct pv_cache_list *after;
|
||||
char id_before[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
char id_after[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
int found;
|
||||
|
||||
dm_list_iterate_items(before, pvc_before) {
|
||||
found = 0;
|
||||
|
||||
dm_list_iterate_items(after, pvc_after) {
|
||||
if (after->found)
|
||||
continue;
|
||||
|
||||
if (before->devt != after->devt)
|
||||
continue;
|
||||
|
||||
if (!id_equal(&before->pvid, &after->pvid)) {
|
||||
memset(id_before, 0, sizeof(id_before));
|
||||
memset(id_after, 0, sizeof(id_after));
|
||||
strncpy(&id_before[0], (char *) &before->pvid, sizeof(id_before) - 1);
|
||||
strncpy(&id_after[0], (char *) &after->pvid, sizeof(id_after) - 1);
|
||||
|
||||
log_debug_devs("device %d:%d changed pvid from %s to %s",
|
||||
(int)MAJOR(before->devt), (int)MINOR(before->devt),
|
||||
id_before, id_after);
|
||||
|
||||
before->update_udev = 1;
|
||||
|
||||
} else if ((before->vgid && !after->vgid) ||
|
||||
(after->vgid && !before->vgid) ||
|
||||
(before->vgid && after->vgid && strcmp(before->vgid, after->vgid))) {
|
||||
|
||||
log_debug_devs("device %d:%d changed vg from %s to %s",
|
||||
(int)MAJOR(before->devt), (int)MINOR(before->devt),
|
||||
before->vgid ?: "none", after->vgid ?: "none");
|
||||
|
||||
before->update_udev = 1;
|
||||
}
|
||||
|
||||
after->found = 1;
|
||||
before->found = 1;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
memset(id_before, 0, sizeof(id_before));
|
||||
strncpy(&id_before[0], (char *) &before->pvid, sizeof(id_before) - 1);
|
||||
|
||||
log_debug_devs("device %d:%d pvid %s vg %s is gone",
|
||||
(int)MAJOR(before->devt), (int)MINOR(before->devt),
|
||||
id_before, before->vgid ? before->vgid : "none");
|
||||
|
||||
before->update_udev = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items(before, pvc_before) {
|
||||
if (before->update_udev)
|
||||
_update_pv_in_udev(cmd, before->devt);
|
||||
}
|
||||
|
||||
dm_list_iterate_items(after, pvc_after) {
|
||||
if (after->update_udev)
|
||||
_update_pv_in_udev(cmd, after->devt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Before this command was run, some external entity may have
|
||||
* invalidated lvmetad's cache of global information, e.g. lvmlockd.
|
||||
*
|
||||
* The global information includes things like a new VG, a
|
||||
* VG that was removed, the assignment of a PV to a VG;
|
||||
* any change that is not isolated within a single VG.
|
||||
*
|
||||
* The external entity, like a lock manager, would invalidate
|
||||
* the lvmetad global cache if it detected that the global
|
||||
* information had been changed on disk by something other
|
||||
* than a local lvm command, e.g. an lvm command on another
|
||||
* host with access to the same devices. (How it detects
|
||||
* the change is specific to lock manager or other entity.)
|
||||
*
|
||||
* The effect is that metadata on disk is newer than the metadata
|
||||
* in the local lvmetad daemon, and the local lvmetad's cache
|
||||
* should be updated from disk before this command uses it.
|
||||
*
|
||||
* So, using this function, a command checks if lvmetad's global
|
||||
* cache is valid. If so, it does nothing. If not, it rescans
|
||||
* devices to update the lvmetad cache, then it notifies lvmetad
|
||||
* that it's cache is valid again (consistent with what's on disk.)
|
||||
* This command can then go ahead and use the newly refreshed metadata.
|
||||
*
|
||||
* 1. Check if the lvmetad global cache is invalid.
|
||||
* 2. If so, reread metadata from all devices and update the lvmetad cache.
|
||||
* 3. Tell lvmetad that the global cache is now valid.
|
||||
*/
|
||||
|
||||
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
{
|
||||
struct dm_list pvc_before; /* pv_cache_list */
|
||||
struct dm_list pvc_after; /* pv_cache_list */
|
||||
daemon_reply reply;
|
||||
int global_invalid;
|
||||
|
||||
dm_list_init(&pvc_before);
|
||||
dm_list_init(&pvc_after);
|
||||
|
||||
if (!lvmlockd_use()) {
|
||||
log_error(INTERNAL_ERROR "validate global cache without lvmlockd");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lvmetad_used())
|
||||
return;
|
||||
|
||||
log_debug_lvmetad("Validating global lvmetad cache");
|
||||
|
||||
if (force)
|
||||
goto do_scan;
|
||||
|
||||
reply = daemon_send_simple(_lvmetad, "get_global_info",
|
||||
"token = %s", "skip",
|
||||
NULL);
|
||||
|
||||
if (reply.error) {
|
||||
log_error("lvmetad_validate_global_cache get_global_info error %d", reply.error);
|
||||
goto do_scan;
|
||||
}
|
||||
|
||||
if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
|
||||
log_error("lvmetad_validate_global_cache get_global_info not ok");
|
||||
goto do_scan;
|
||||
}
|
||||
|
||||
global_invalid = daemon_reply_int(reply, "global_invalid", -1);
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
if (!global_invalid) {
|
||||
/* cache is valid */
|
||||
return;
|
||||
}
|
||||
|
||||
do_scan:
|
||||
/*
|
||||
* Save the current state of pvs from lvmetad so after devices are
|
||||
* scanned, we can compare to the new state to see if pvs changed.
|
||||
*/
|
||||
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
|
||||
|
||||
/*
|
||||
* Update the local lvmetad cache so it correctly reflects any
|
||||
* changes made on remote hosts.
|
||||
*/
|
||||
lvmetad_pvscan_all_devs(cmd, NULL);
|
||||
|
||||
/*
|
||||
* Clear the global_invalid flag in lvmetad.
|
||||
* Subsequent local commands that read global state
|
||||
* from lvmetad will not see global_invalid until
|
||||
* another host makes another global change.
|
||||
*/
|
||||
reply = daemon_send_simple(_lvmetad, "set_global_info",
|
||||
"token = %s", "skip",
|
||||
"global_invalid = %d", 0,
|
||||
NULL);
|
||||
if (reply.error)
|
||||
log_error("lvmetad_validate_global_cache set_global_info error %d", reply.error);
|
||||
|
||||
if (strcmp(daemon_reply_str(reply, "response", ""), "OK"))
|
||||
log_error("lvmetad_validate_global_cache set_global_info not ok");
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
/*
|
||||
* Populate this command's lvmcache structures from lvmetad.
|
||||
*/
|
||||
lvmcache_seed_infos_from_lvmetad(cmd);
|
||||
|
||||
/*
|
||||
* Update the local udev database to reflect PV changes from
|
||||
* other hosts.
|
||||
*
|
||||
* Compare the before and after PV lists, and if a PV's
|
||||
* pvid or vgid has changed, then open that device to trigger
|
||||
* a uevent to update the udev db.
|
||||
*
|
||||
* This has no direct benefit to lvm, but is just a best effort
|
||||
* attempt to keep the udev db updated and reflecting current
|
||||
* lvm information.
|
||||
*
|
||||
* FIXME: lvmcache_seed_infos_from_lvmetad() and _lvmetad_get_pv_cache_list()
|
||||
* each get pv_list from lvmetad, and they could share a single pv_list reply.
|
||||
*/
|
||||
if (!dm_list_empty(&pvc_before)) {
|
||||
_lvmetad_get_pv_cache_list(cmd, &pvc_after);
|
||||
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
|
||||
}
|
||||
}
|
||||
|
5
lib/cache/lvmetad.h
vendored
5
lib/cache/lvmetad.h
vendored
@ -166,6 +166,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler);
|
||||
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
|
||||
|
||||
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
|
||||
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
|
||||
|
||||
# else /* LVMETAD_SUPPORT */
|
||||
|
||||
# define lvmetad_init(cmd) do { } while (0)
|
||||
@ -192,6 +195,8 @@ int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handl
|
||||
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
|
||||
# define lvmetad_pvscan_all_devs(cmd, handler) (0)
|
||||
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
|
||||
# define lvmetad_vg_clear_outdated_pvs(vg) (1)
|
||||
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
|
||||
|
||||
# endif /* LVMETAD_SUPPORT */
|
||||
|
||||
|
@ -25,6 +25,11 @@
|
||||
#include "lv_alloc.h"
|
||||
#include "defaults.h"
|
||||
|
||||
static const char _cache_module[] = "cache";
|
||||
|
||||
/* TODO: using static field here, maybe should be a part of segment_type */
|
||||
static unsigned _feature_mask;
|
||||
|
||||
#define SEG_LOG_ERROR(t, p...) \
|
||||
log_error(t " segment %s of logical volume %s.", ## p, \
|
||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||
@ -66,20 +71,16 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
if (dm_config_has_node(sn, "cache_mode")) {
|
||||
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
|
||||
return SEG_LOG_ERROR("cache_mode must be a string in");
|
||||
if (!set_cache_pool_feature(&seg->feature_flags, str))
|
||||
if (!cache_set_mode(seg, str))
|
||||
return SEG_LOG_ERROR("Unknown cache_mode in");
|
||||
} else
|
||||
/* When missed in metadata, it's an old stuff - use writethrough */
|
||||
seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
}
|
||||
|
||||
if (dm_config_has_node(sn, "policy")) {
|
||||
if (!(str = dm_config_find_str(sn, "policy", NULL)))
|
||||
return SEG_LOG_ERROR("policy must be a string in");
|
||||
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
|
||||
return SEG_LOG_ERROR("Failed to duplicate policy in");
|
||||
} else
|
||||
/* Cannot use 'just' default, so pick one */
|
||||
seg->policy_name = DEFAULT_CACHE_POOL_POLICY; /* FIXME make configurable */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in policy args:
|
||||
@ -99,6 +100,9 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
* If the policy is not present, default policy is used.
|
||||
*/
|
||||
if ((sn = dm_config_find_node(sn, "policy_settings"))) {
|
||||
if (!seg->policy_name)
|
||||
return SEG_LOG_ERROR("policy_settings must have a policy_name in");
|
||||
|
||||
if (sn->v)
|
||||
return SEG_LOG_ERROR("policy_settings must be a section in");
|
||||
|
||||
@ -127,24 +131,33 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
|
||||
{
|
||||
const char *cache_mode;
|
||||
|
||||
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
|
||||
return_0;
|
||||
|
||||
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
|
||||
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
|
||||
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
|
||||
if (seg->policy_name)
|
||||
/*
|
||||
* Cache pool used by a cache LV holds data. Not ideal,
|
||||
* but not worth to break backward compatibility, by shifting
|
||||
* content to cache segment
|
||||
*/
|
||||
if (cache_mode_is_set(seg)) {
|
||||
if (!(cache_mode = get_cache_mode_name(seg)))
|
||||
return_0;
|
||||
outf(f, "cache_mode = \"%s\"", cache_mode);
|
||||
}
|
||||
|
||||
if (seg->policy_name) {
|
||||
outf(f, "policy = \"%s\"", seg->policy_name);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
if (seg->policy_settings) {
|
||||
if (strcmp(seg->policy_settings->key, "policy_settings")) {
|
||||
log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
|
||||
seg->policy_settings->key);
|
||||
return 0;
|
||||
}
|
||||
if (seg->policy_settings->child)
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -157,12 +170,29 @@ static void _destroy(struct segment_type *segtype)
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _target_present(struct cmd_context *cmd,
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
const struct lv_segment *seg __attribute__((unused)),
|
||||
unsigned *attributes __attribute__((unused)))
|
||||
{
|
||||
uint32_t maj, min, patchlevel;
|
||||
/* List of features with their kernel target version */
|
||||
static const struct feature {
|
||||
uint32_t maj;
|
||||
uint32_t min;
|
||||
unsigned cache_feature;
|
||||
const char feature[12];
|
||||
const char module[12]; /* check dm-%s */
|
||||
} _features[] = {
|
||||
{ 1, 3, CACHE_FEATURE_POLICY_MQ, "policy_mq", "cache-mq" },
|
||||
{ 1, 8, CACHE_FEATURE_POLICY_SMQ, "policy_smq", "cache-smq" },
|
||||
};
|
||||
static const char _lvmconf[] = "global/cache_disabled_features";
|
||||
static unsigned _attrs = 0;
|
||||
static int _cache_checked = 0;
|
||||
static int _cache_present = 0;
|
||||
uint32_t maj, min, patchlevel;
|
||||
unsigned i;
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
|
||||
if (!_cache_checked) {
|
||||
_cache_present = target_present(cmd, "cache", 1);
|
||||
@ -176,11 +206,53 @@ static int _target_present(struct cmd_context *cmd,
|
||||
|
||||
if ((maj < 1) ||
|
||||
((maj == 1) && (min < 3))) {
|
||||
log_error("The cache kernel module is version %u.%u.%u."
|
||||
" Version 1.3.0+ is required.",
|
||||
_cache_present = 0;
|
||||
log_error("The cache kernel module is version %u.%u.%u. "
|
||||
"Version 1.3.0+ is required.",
|
||||
maj, min, patchlevel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i) {
|
||||
if (((maj > _features[i].maj) ||
|
||||
(maj == _features[i].maj && min >= _features[i].min)) &&
|
||||
(!_features[i].module[0] || module_present(cmd, _features[i].module)))
|
||||
_attrs |= _features[i].cache_feature;
|
||||
else
|
||||
log_very_verbose("Target %s does not support %s.",
|
||||
_cache_module, _features[i].feature);
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes) {
|
||||
if (!_feature_mask) {
|
||||
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
|
||||
if ((cn = find_config_tree_array(cmd, global_cache_disabled_features_CFG, NULL))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Ignoring invalid string in config file %s.",
|
||||
_lvmconf);
|
||||
continue;
|
||||
}
|
||||
str = cv->v.str;
|
||||
if (!*str)
|
||||
continue;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||
if (strcasecmp(str, _features[i].feature) == 0)
|
||||
_feature_mask |= _features[i].cache_feature;
|
||||
}
|
||||
}
|
||||
|
||||
_feature_mask = ~_feature_mask;
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(_features); ++i)
|
||||
if ((_attrs & _features[i].cache_feature) &&
|
||||
!(_feature_mask & _features[i].cache_feature))
|
||||
log_very_verbose("Target %s %s support disabled by %s",
|
||||
_cache_module, _features[i].feature, _lvmconf);
|
||||
}
|
||||
*attributes = _attrs & _feature_mask;
|
||||
}
|
||||
|
||||
return _cache_present;
|
||||
@ -306,7 +378,9 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
metadata_uuid,
|
||||
data_uuid,
|
||||
origin_uuid,
|
||||
seg->cleaner_policy ? "cleaner" : cache_pool_seg->policy_name,
|
||||
seg->cleaner_policy ? "cleaner" :
|
||||
/* undefined policy name -> likely an old "mq" */
|
||||
cache_pool_seg->policy_name ? : "mq",
|
||||
seg->cleaner_policy ? NULL : cache_pool_seg->policy_settings,
|
||||
cache_pool_seg->chunk_size))
|
||||
return_0;
|
||||
@ -368,5 +442,8 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return_0;
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
/* Reset mask for recalc */
|
||||
_feature_mask = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -245,8 +245,10 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
||||
const struct dm_config_value *cv;
|
||||
int debug_classes = 0;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, log_debug_classes_CFG, NULL)))
|
||||
return DEFAULT_LOGGED_DEBUG_CLASSES;
|
||||
if (!(cn = find_config_tree_array(cmd, log_debug_classes_CFG, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for log/debug_classes.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
@ -413,6 +415,57 @@ static int _check_config(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *_set_time_format(struct cmd_context *cmd)
|
||||
{
|
||||
/* Compared to strftime, we do not allow "newline" character - the %n in format. */
|
||||
static const char *allowed_format_chars = "aAbBcCdDeFGghHIjklmMpPrRsStTuUVwWxXyYzZ%";
|
||||
static const char *allowed_alternative_format_chars_e = "cCxXyY";
|
||||
static const char *allowed_alternative_format_chars_o = "deHImMSuUVwWy";
|
||||
static const char *chars_to_check;
|
||||
const char *tf = find_config_tree_str(cmd, report_time_format_CFG, NULL);
|
||||
const char *p_fmt;
|
||||
size_t i;
|
||||
char c;
|
||||
|
||||
if (!*tf) {
|
||||
log_error("Configured time format is empty string.");
|
||||
goto bad;
|
||||
} else {
|
||||
p_fmt = tf;
|
||||
while ((c = *p_fmt)) {
|
||||
if (c == '%') {
|
||||
c = *++p_fmt;
|
||||
if (c == 'E') {
|
||||
c = *++p_fmt;
|
||||
chars_to_check = allowed_alternative_format_chars_e;
|
||||
} else if (c == 'O') {
|
||||
c = *++p_fmt;
|
||||
chars_to_check = allowed_alternative_format_chars_o;
|
||||
} else
|
||||
chars_to_check = allowed_format_chars;
|
||||
|
||||
for (i = 0; chars_to_check[i]; i++) {
|
||||
if (c == chars_to_check[i])
|
||||
break;
|
||||
}
|
||||
if (!chars_to_check[i])
|
||||
goto_bad;
|
||||
}
|
||||
else if (isprint(c))
|
||||
p_fmt++;
|
||||
else {
|
||||
log_error("Configured time format contains non-printable characters.");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tf;
|
||||
bad:
|
||||
log_error("Invalid time format \"%s\" supplied.", tf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int process_profilable_config(struct cmd_context *cmd)
|
||||
{
|
||||
if (!(cmd->default_settings.unit_factor =
|
||||
@ -426,6 +479,8 @@ int process_profilable_config(struct cmd_context *cmd)
|
||||
cmd->report_binary_values_as_numeric = find_config_tree_bool(cmd, report_binary_values_as_numeric_CFG, NULL);
|
||||
cmd->default_settings.suffix = find_config_tree_bool(cmd, global_suffix_CFG, NULL);
|
||||
cmd->report_list_item_separator = find_config_tree_str(cmd, report_list_item_separator_CFG, NULL);
|
||||
if (!(cmd->time_format = _set_time_format(cmd)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -477,8 +532,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
int64_t pv_min_kb;
|
||||
const char *lvmetad_socket;
|
||||
const char *lvmpolld_socket;
|
||||
int udev_disabled = 0;
|
||||
char sysfs_dir[PATH_MAX];
|
||||
|
||||
@ -599,7 +652,7 @@ static int _process_config(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if ((cn = find_config_tree_node(cmd, activation_mlock_filter_CFG, NULL)))
|
||||
if ((cn = find_config_tree_array(cmd, activation_mlock_filter_CFG, NULL)))
|
||||
for (cv = cn->v; cv; cv = cv->next)
|
||||
if ((cv->type != DM_CFG_STRING) || !cv->v.str[0])
|
||||
log_error("Ignoring invalid activation/mlock_filter entry in config file");
|
||||
@ -621,41 +674,9 @@ static int _process_config(struct cmd_context *cmd)
|
||||
init_detect_internal_vg_cache_corruption
|
||||
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
|
||||
|
||||
lvmetad_disconnect();
|
||||
lvmpolld_disconnect();
|
||||
|
||||
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
|
||||
if (!lvmetad_socket)
|
||||
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
|
||||
|
||||
/* TODO?
|
||||
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
|
||||
DEFAULT_RUN_DIR "/lvmetad.socket");
|
||||
*/
|
||||
lvmetad_set_socket(lvmetad_socket);
|
||||
cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL);
|
||||
lvmetad_set_token(cn ? cn->v : NULL);
|
||||
|
||||
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
|
||||
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
|
||||
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
|
||||
"Clustered environment not supported by lvmetad yet.");
|
||||
lvmetad_set_active(NULL, 0);
|
||||
} else
|
||||
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
||||
|
||||
lvmetad_init(cmd);
|
||||
|
||||
if (!_init_system_id(cmd))
|
||||
return_0;
|
||||
|
||||
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
|
||||
if (!lvmpolld_socket)
|
||||
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
|
||||
lvmpolld_set_socket(lvmpolld_socket);
|
||||
|
||||
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -962,15 +983,9 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
|
||||
init_obtain_device_list_from_udev(device_list_from_udev);
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, devices_scan_CFG, NULL))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
log_error("Failed to add /dev to internal "
|
||||
"device cache");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("device/scan not in config file: "
|
||||
"Defaulting to /dev");
|
||||
return 1;
|
||||
if (!(cn = find_config_tree_array(cmd, devices_scan_CFG, NULL))) {
|
||||
log_error(INTERNAL_ERROR "Unable to find configuration for devices/scan.");
|
||||
return_0;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@ -1008,7 +1023,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, devices_loopfiles_CFG, NULL)))
|
||||
if (!(cn = find_config_tree_array(cmd, devices_loopfiles_CFG, NULL)))
|
||||
return 1;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@ -1146,7 +1161,7 @@ bad:
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
*/
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
||||
@ -1154,6 +1169,11 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
const struct dm_config_node *cn;
|
||||
struct timespec ts, cts;
|
||||
|
||||
if (!cmd->initialized.connections) {
|
||||
log_error(INTERNAL_ERROR "connections must be initialized before filters");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
cmd->lvmetad_filter = _init_lvmetad_filter_chain(cmd);
|
||||
@ -1183,7 +1203,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
}
|
||||
|
||||
/* filter component 1 */
|
||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||
if ((cn = find_config_tree_array(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filter_components[1] = regex_filter_create(cn->v)))
|
||||
goto_bad;
|
||||
/* we have two filter components - create composite filter */
|
||||
@ -1234,6 +1254,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
dev_cache);
|
||||
}
|
||||
|
||||
cmd->initialized.filters = 1;
|
||||
return 1;
|
||||
bad:
|
||||
if (!filter) {
|
||||
@ -1257,6 +1278,7 @@ bad:
|
||||
if (cmd->lvmetad_filter)
|
||||
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
|
||||
|
||||
cmd->initialized.filters = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1300,7 +1322,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs if not static */
|
||||
if (!is_static() &&
|
||||
(cn = find_config_tree_node(cmd, global_format_libraries_CFG, NULL))) {
|
||||
(cn = find_config_tree_array(cmd, global_format_libraries_CFG, NULL))) {
|
||||
|
||||
const struct dm_config_value *cv;
|
||||
struct format_type *(*init_format_fn) (struct cmd_context *);
|
||||
@ -1466,7 +1488,7 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
#ifdef HAVE_LIBDL
|
||||
/* Load any formats in shared libs unless static */
|
||||
if (!is_static() &&
|
||||
(cn = find_config_tree_node(cmd, global_segment_libraries_CFG, NULL))) {
|
||||
(cn = find_config_tree_array(cmd, global_segment_libraries_CFG, NULL))) {
|
||||
|
||||
const struct dm_config_value *cv;
|
||||
int (*init_multiple_segtypes_fn) (struct cmd_context *,
|
||||
@ -1630,11 +1652,80 @@ static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *na
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_lvmetad(struct cmd_context *cmd)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
const char *lvmetad_socket;
|
||||
|
||||
lvmetad_disconnect();
|
||||
|
||||
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
|
||||
if (!lvmetad_socket)
|
||||
lvmetad_socket = DEFAULT_RUN_DIR "/lvmetad.socket";
|
||||
|
||||
/* TODO?
|
||||
lvmetad_socket = find_config_tree_str(cmd, "lvmetad/socket_path",
|
||||
DEFAULT_RUN_DIR "/lvmetad.socket");
|
||||
*/
|
||||
|
||||
lvmetad_set_socket(lvmetad_socket);
|
||||
cn = find_config_tree_array(cmd, devices_global_filter_CFG, NULL);
|
||||
lvmetad_set_token(cn ? cn->v : NULL);
|
||||
|
||||
if (find_config_tree_int(cmd, global_locking_type_CFG, NULL) == 3 &&
|
||||
find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL)) {
|
||||
log_warn("WARNING: configuration setting use_lvmetad overridden to 0 due to locking_type 3. "
|
||||
"Clustered environment not supported by lvmetad yet.");
|
||||
lvmetad_set_active(NULL, 0);
|
||||
} else
|
||||
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
||||
|
||||
lvmetad_init(cmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_lvmpolld(struct cmd_context *cmd)
|
||||
{
|
||||
const char *lvmpolld_socket;
|
||||
|
||||
lvmpolld_disconnect();
|
||||
|
||||
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
|
||||
if (!lvmpolld_socket)
|
||||
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
|
||||
lvmpolld_set_socket(lvmpolld_socket);
|
||||
|
||||
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_connections(struct cmd_context *cmd)
|
||||
{
|
||||
|
||||
if (!_init_lvmetad(cmd)) {
|
||||
log_error("Failed to initialize lvmetad connection.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_init_lvmpolld(cmd)) {
|
||||
log_error("Failed to initialize lvmpolld connection.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
cmd->initialized.connections = 1;
|
||||
return 1;
|
||||
bad:
|
||||
cmd->initialized.connections = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
const char *system_dir,
|
||||
unsigned set_buffering,
|
||||
unsigned threaded)
|
||||
unsigned threaded,
|
||||
unsigned set_connections,
|
||||
unsigned set_filters)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
FILE *new_stream;
|
||||
@ -1772,15 +1863,12 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
goto_out;
|
||||
|
||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||
find_config_tree_node(cmd, devices_types_CFG, NULL))))
|
||||
find_config_tree_array(cmd, devices_types_CFG, NULL))))
|
||||
goto_out;
|
||||
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto_out;
|
||||
|
||||
if (!_init_filters(cmd, 1))
|
||||
goto_out;
|
||||
|
||||
memlock_init(cmd);
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
@ -1799,12 +1887,18 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
|
||||
_init_globals(cmd);
|
||||
|
||||
if (set_connections && !init_connections(cmd))
|
||||
return_0;
|
||||
|
||||
if (set_filters && !init_filters(cmd, 1))
|
||||
goto_out;
|
||||
|
||||
cmd->default_settings.cache_vgmetadata = 1;
|
||||
cmd->current_settings = cmd->default_settings;
|
||||
|
||||
cmd->config_initialized = 1;
|
||||
cmd->initialized.config = 1;
|
||||
out:
|
||||
if (!cmd->config_initialized) {
|
||||
if (!cmd->initialized.config) {
|
||||
destroy_toolcontext(cmd);
|
||||
cmd = NULL;
|
||||
}
|
||||
@ -1876,14 +1970,19 @@ static void _destroy_filters(struct cmd_context *cmd)
|
||||
cmd->full_filter->destroy(cmd->full_filter);
|
||||
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
|
||||
}
|
||||
cmd->initialized.filters = 0;
|
||||
}
|
||||
|
||||
int refresh_filters(struct cmd_context *cmd)
|
||||
{
|
||||
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
|
||||
|
||||
if (!cmd->initialized.filters)
|
||||
/* if filters not initialized, there's nothing to refresh */
|
||||
return 1;
|
||||
|
||||
_destroy_filters(cmd);
|
||||
if (!(r = _init_filters(cmd, 0)))
|
||||
if (!(r = init_filters(cmd, 0)))
|
||||
stack;
|
||||
|
||||
/*
|
||||
@ -1912,7 +2011,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
_destroy_filters(cmd);
|
||||
|
||||
if (!dev_cache_exit())
|
||||
stack;
|
||||
@ -1930,7 +2028,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
|
||||
_destroy_config(cmd);
|
||||
|
||||
cmd->config_initialized = 0;
|
||||
cmd->initialized.config = 0;
|
||||
|
||||
cmd->hosttags = 0;
|
||||
|
||||
@ -1987,15 +2085,12 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
return_0;
|
||||
|
||||
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
|
||||
find_config_tree_node(cmd, devices_types_CFG, NULL))))
|
||||
find_config_tree_array(cmd, devices_types_CFG, NULL))))
|
||||
return_0;
|
||||
|
||||
if (!_init_dev_cache(cmd))
|
||||
return_0;
|
||||
|
||||
if (!_init_filters(cmd, 0))
|
||||
return_0;
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
return_0;
|
||||
|
||||
@ -2008,7 +2103,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_backup(cmd))
|
||||
return_0;
|
||||
|
||||
cmd->config_initialized = 1;
|
||||
cmd->initialized.config = 1;
|
||||
|
||||
if (cmd->initialized.connections && !init_connections(cmd))
|
||||
return_0;
|
||||
|
||||
if (!refresh_filters(cmd))
|
||||
return_0;
|
||||
|
||||
reset_lvm_errno(1);
|
||||
return 1;
|
||||
|
@ -60,29 +60,59 @@ struct config_tree_list {
|
||||
struct dm_config_tree *cft;
|
||||
};
|
||||
|
||||
struct cmd_context_initialized_parts {
|
||||
unsigned config:1; /* used to reinitialize config if previous init was not successful */
|
||||
unsigned filters:1;
|
||||
unsigned connections:1;
|
||||
};
|
||||
|
||||
/* FIXME Split into tool & library contexts */
|
||||
/* command-instance-related variables needed by library */
|
||||
struct cmd_context {
|
||||
struct dm_pool *libmem; /* For permanent config data */
|
||||
struct dm_pool *mem; /* Transient: Cleared between each command */
|
||||
/*
|
||||
* Memory handlers.
|
||||
*/
|
||||
struct dm_pool *libmem; /* for permanent config data */
|
||||
struct dm_pool *mem; /* transient: cleared between each command */
|
||||
|
||||
const struct format_type *fmt; /* Current format to use by default */
|
||||
struct format_type *fmt_backup; /* Format to use for backups */
|
||||
|
||||
struct dm_list formats; /* Available formats */
|
||||
struct dm_list segtypes; /* Available segment types */
|
||||
const char *system_id;
|
||||
const char *hostname;
|
||||
const char *kernel_vsn;
|
||||
|
||||
unsigned rand_seed;
|
||||
char *linebuffer;
|
||||
/*
|
||||
* Command line and arguments.
|
||||
*/
|
||||
const char *cmd_line;
|
||||
struct command *command;
|
||||
char **argv;
|
||||
struct arg_values *arg_values;
|
||||
struct dm_list arg_value_groups;
|
||||
unsigned is_long_lived:1; /* Optimises persistent_filter handling */
|
||||
|
||||
/*
|
||||
* Format handlers.
|
||||
*/
|
||||
const struct format_type *fmt; /* current format to use by default */
|
||||
struct format_type *fmt_backup; /* format to use for backups */
|
||||
struct dm_list formats; /* available formats */
|
||||
struct dm_list segtypes; /* available segment types */
|
||||
|
||||
/*
|
||||
* Machine and system identification.
|
||||
*/
|
||||
const char *system_id;
|
||||
const char *hostname;
|
||||
const char *kernel_vsn;
|
||||
|
||||
/*
|
||||
* Device identification.
|
||||
*/
|
||||
struct dev_types *dev_types; /* recognized extra device types. */
|
||||
|
||||
/*
|
||||
* Initialization state.
|
||||
*/
|
||||
struct cmd_context_initialized_parts initialized;
|
||||
|
||||
/*
|
||||
* Switches.
|
||||
*/
|
||||
unsigned is_long_lived:1; /* optimises persistent_filter handling */
|
||||
unsigned handles_missing_pvs:1;
|
||||
unsigned handles_unknown_segments:1;
|
||||
unsigned use_linear_target:1;
|
||||
@ -93,59 +123,72 @@ struct cmd_context {
|
||||
unsigned report_binary_values_as_numeric:1;
|
||||
unsigned metadata_read_only:1;
|
||||
unsigned ignore_clustered_vgs:1;
|
||||
unsigned threaded:1; /* Set if running within a thread e.g. clvmd */
|
||||
|
||||
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
|
||||
unsigned threaded:1; /* set if running within a thread e.g. clvmd */
|
||||
unsigned independent_metadata_areas:1; /* active formats have MDAs outside PVs */
|
||||
unsigned unknown_system_id:1;
|
||||
unsigned include_foreign_vgs:1;
|
||||
unsigned include_active_foreign_vgs:1;
|
||||
unsigned error_foreign_vgs:1;
|
||||
|
||||
struct dev_types *dev_types;
|
||||
unsigned include_foreign_vgs:1; /* report/display cmds can reveal foreign VGs */
|
||||
unsigned include_shared_vgs:1; /* report/display cmds can reveal lockd VGs */
|
||||
unsigned include_active_foreign_vgs:1; /* cmd should process foreign VGs with active LVs */
|
||||
unsigned vg_read_print_access_error:1; /* print access errors from vg_read */
|
||||
unsigned lockd_gl_disable:1;
|
||||
unsigned lockd_vg_disable:1;
|
||||
unsigned lockd_lv_disable:1;
|
||||
unsigned lockd_gl_removed:1;
|
||||
unsigned lockd_vg_default_sh:1;
|
||||
unsigned lockd_vg_enforce_sh:1;
|
||||
|
||||
/*
|
||||
* Use of filters depends on whether lvmetad is used or not:
|
||||
*
|
||||
* - if lvmetad is used:
|
||||
* - cmd->lvmetad_filter used when scanning devices for lvmetad
|
||||
* - cmd->filter used when processing lvmetad responses
|
||||
* - cmd->full_filter used for remaining situations
|
||||
*
|
||||
* - if lvmetad is not used:
|
||||
* - cmd->lvmetad_filter is NULL
|
||||
* - cmd->filter == cmd->full_filter used for all situations
|
||||
*
|
||||
* Filtering.
|
||||
*/
|
||||
struct dev_filter *lvmetad_filter;
|
||||
struct dev_filter *filter;
|
||||
struct dev_filter *full_filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
struct dev_filter *lvmetad_filter; /* pre-lvmetad filter chain */
|
||||
struct dev_filter *filter; /* post-lvmetad filter chain */
|
||||
struct dev_filter *full_filter; /* lvmetad_filter + filter */
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
|
||||
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
||||
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
|
||||
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
int config_initialized; /* used to reinitialize config if previous init was not successful */
|
||||
|
||||
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
|
||||
|
||||
/* selected settings with original default/configured value which can be changed during cmd processing */
|
||||
struct config_info default_settings;
|
||||
/* may contain changed values compared to default_settings */
|
||||
struct config_info current_settings;
|
||||
/*
|
||||
* Configuration.
|
||||
*/
|
||||
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
||||
struct profile_params *profile_params; /* profile handling params including loaded profile configs */
|
||||
struct dm_config_tree *cft; /* the whole cascade: CONFIG_STRING -> CONFIG_PROFILE -> CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
struct dm_hash_table *cft_def_hash; /* config definition hash used for validity check (item type + item recognized) */
|
||||
struct config_info default_settings; /* selected settings with original default/configured value which can be changed during cmd processing */
|
||||
struct config_info current_settings; /* may contain changed values compared to default_settings */
|
||||
|
||||
/*
|
||||
* Archives and backups.
|
||||
*/
|
||||
struct archive_params *archive_params;
|
||||
struct backup_params *backup_params;
|
||||
const char *stripe_filler;
|
||||
|
||||
/* List of defined tags */
|
||||
struct dm_list tags;
|
||||
const char *report_list_item_separator;
|
||||
/*
|
||||
* Host tags.
|
||||
*/
|
||||
struct dm_list tags; /* list of defined tags */
|
||||
int hosttags;
|
||||
|
||||
const char *lib_dir; /* Cache value global/library_dir */
|
||||
/*
|
||||
* Paths.
|
||||
*/
|
||||
const char *lib_dir; /* cache value global/library_dir */
|
||||
char system_dir[PATH_MAX];
|
||||
char dev_dir[PATH_MAX];
|
||||
char proc_dir[PATH_MAX];
|
||||
|
||||
/*
|
||||
* Buffers.
|
||||
*/
|
||||
char display_buffer[NAME_LEN * 10]; /* ring buffer for upto 10 longest vg/lv names */
|
||||
unsigned display_lvname_idx; /* index to ring buffer */
|
||||
char *linebuffer;
|
||||
|
||||
/*
|
||||
* Others - unsorted.
|
||||
*/
|
||||
const char *report_list_item_separator;
|
||||
const char *time_format;
|
||||
unsigned rand_seed;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -155,13 +198,17 @@ struct cmd_context {
|
||||
struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
const char *system_dir,
|
||||
unsigned set_buffering,
|
||||
unsigned threaded);
|
||||
unsigned threaded,
|
||||
unsigned set_connections,
|
||||
unsigned set_filters);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_filters(struct cmd_context *cmd);
|
||||
int process_profilable_config(struct cmd_context *cmd);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
int init_lvmcache_orphans(struct cmd_context *cmd);
|
||||
int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache);
|
||||
int init_connections(struct cmd_context *cmd);
|
||||
|
||||
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);
|
||||
|
||||
|
@ -581,8 +581,11 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
if (!(cf->dev = dev_create_file(filename, NULL, NULL, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_open_readonly_buffered(cf->dev))
|
||||
if (!dev_open_readonly_buffered(cf->dev)) {
|
||||
dev_destroy_file(cf->dev);
|
||||
cf->dev = NULL;
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
|
||||
@ -666,22 +669,28 @@ static void _log_type_error(const char *path, cfg_def_type_t actual,
|
||||
actual_type_name, expected_type_name);
|
||||
}
|
||||
|
||||
static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
||||
const cfg_def_item_t *def)
|
||||
static struct dm_config_value *_get_def_array_values(struct cmd_context *cmd,
|
||||
struct dm_config_tree *cft,
|
||||
const cfg_def_item_t *def,
|
||||
uint32_t format_flags)
|
||||
{
|
||||
const char *def_enc_value;
|
||||
char *enc_value, *token, *p, *r;
|
||||
struct dm_config_value *array = NULL, *v = NULL, *oldv = NULL;
|
||||
|
||||
if (!def->default_value.v_CFG_TYPE_STRING) {
|
||||
def_enc_value = cfg_def_get_default_value(cmd, def, CFG_TYPE_ARRAY, NULL);
|
||||
|
||||
if (!def_enc_value) {
|
||||
if (!(array = dm_config_create_value(cft))) {
|
||||
log_error("Failed to create default empty array for %s.", def->name);
|
||||
return NULL;
|
||||
}
|
||||
array->type = DM_CFG_EMPTY_ARRAY;
|
||||
dm_config_value_set_format_flags(array, format_flags);
|
||||
return array;
|
||||
}
|
||||
|
||||
if (!(p = token = enc_value = dm_strdup(def->default_value.v_CFG_TYPE_STRING))) {
|
||||
if (!(p = token = enc_value = dm_strdup(def_enc_value))) {
|
||||
log_error("_get_def_array_values: dm_strdup failed");
|
||||
return NULL;
|
||||
}
|
||||
@ -710,6 +719,9 @@ static struct dm_config_value *_get_def_array_values(struct dm_config_tree *cft,
|
||||
dm_free(enc_value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dm_config_value_set_format_flags(v, format_flags);
|
||||
|
||||
if (oldv)
|
||||
oldv->next = v;
|
||||
if (!array)
|
||||
@ -839,7 +851,7 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
|
||||
}
|
||||
|
||||
if (!v_def && (def->type & CFG_TYPE_ARRAY)) {
|
||||
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cft, def)))
|
||||
if (!(v_def_array = v_def_iter = _get_def_array_values(handle->cmd, handle->cft, def, 0)))
|
||||
return_0;
|
||||
do {
|
||||
/* iterate over each element of the array and check its value */
|
||||
@ -1031,9 +1043,14 @@ static int _config_def_check_tree(struct cft_check_handle *handle,
|
||||
size_t buf_size, struct dm_config_node *root)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
cfg_def_item_t *def;
|
||||
int valid, r = 1;
|
||||
size_t len;
|
||||
|
||||
def = cfg_def_get_item_p(root->id);
|
||||
if (def->flags & CFG_SECTION_NO_CHECK)
|
||||
return 1;
|
||||
|
||||
for (cn = root->child; cn; cn = cn->sib) {
|
||||
if ((valid = _config_def_check_node(handle, vp, pvp, rp, prp,
|
||||
buf_size, cn)) && !cn->v) {
|
||||
@ -1355,6 +1372,106 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct dm_config_node *_get_array_def_node(struct cmd_context *cmd,
|
||||
cfg_def_item_t *def,
|
||||
struct profile *profile)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
|
||||
if (def->flags & CFG_DEFAULT_UNDEFINED)
|
||||
return NULL;
|
||||
|
||||
if (!(cn = dm_config_create_node(cmd->cft, def->name))) {
|
||||
log_error("Failed to create default array node for %s.", def->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(cn->v = _get_def_array_values(cmd, cmd->cft, def, 0))) {
|
||||
dm_pool_free(cmd->cft->mem, cn);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
struct _config_array_out_handle {
|
||||
struct dm_pool *mem;
|
||||
char *str;
|
||||
};
|
||||
|
||||
static int _config_array_line(const struct dm_config_node *cn, const char *line, void *baton)
|
||||
{
|
||||
struct _config_array_out_handle *handle = (struct _config_array_out_handle *) baton;
|
||||
|
||||
if (!(handle->str = dm_pool_strdup(handle->mem, line))) {
|
||||
log_error("_config_array_line: dm_pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _log_array_value_used(struct dm_pool *mem, const struct dm_config_node *cn,
|
||||
const char *path, int default_used)
|
||||
{
|
||||
struct _config_array_out_handle out_handle = { 0 };
|
||||
struct dm_config_node_out_spec out_spec = { 0 };
|
||||
uint32_t old_format_flags;
|
||||
|
||||
out_handle.mem = mem;
|
||||
out_spec.line_fn = _config_array_line;
|
||||
|
||||
old_format_flags = dm_config_value_get_format_flags(cn->v);
|
||||
dm_config_value_set_format_flags(cn->v,
|
||||
DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES |
|
||||
DM_CONFIG_VALUE_FMT_COMMON_ARRAY);
|
||||
|
||||
if (!dm_config_write_one_node_out(cn, &out_spec, &out_handle)) {
|
||||
log_error("_log_array_value_used: failed to write node value");
|
||||
out_handle.mem = NULL;
|
||||
}
|
||||
|
||||
if (default_used)
|
||||
log_very_verbose("%s not found in config: defaulting to %s",
|
||||
path, out_handle.mem ? out_handle.str : "<unknown>");
|
||||
else
|
||||
log_very_verbose("Setting %s to %s",
|
||||
path, out_handle.mem ? out_handle.str : "<unknown>");
|
||||
|
||||
if (out_handle.mem)
|
||||
dm_pool_free(out_handle.mem, out_handle.str);
|
||||
dm_config_value_set_format_flags(cn->v, old_format_flags);
|
||||
}
|
||||
|
||||
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
int profile_applied;
|
||||
const struct dm_config_node *cn = NULL, *cn_def = NULL;
|
||||
profile_applied = _apply_local_profile(cmd, profile);
|
||||
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||
|
||||
if (!(item->type & CFG_TYPE_ARRAY))
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as array.", path);
|
||||
|
||||
if (_config_disabled(cmd, item, path) ||
|
||||
!(cn = find_config_tree_node(cmd, id, profile)))
|
||||
cn_def = _get_array_def_node(cmd, item, profile);
|
||||
|
||||
if (cn)
|
||||
_log_array_value_used(cmd->cft->mem, cn, path, 0);
|
||||
else if (cn_def) {
|
||||
_log_array_value_used(cmd->cft->mem, cn_def, path, 1);
|
||||
cn = cn_def;
|
||||
}
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
/* Insert cn2 after cn1 */
|
||||
static void _insert_config_node(struct dm_config_node **cn1,
|
||||
struct dm_config_node *cn2)
|
||||
@ -1553,14 +1670,9 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
char commentline[MAX_COMMENT_LINE+1];
|
||||
|
||||
if (cn->id < 0)
|
||||
if (cn->id <= 0)
|
||||
return 1;
|
||||
|
||||
if (!cn->id) {
|
||||
log_error(INTERNAL_ERROR "Configuration node %s has invalid id.", cn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
|
||||
return 1;
|
||||
|
||||
@ -1582,6 +1694,11 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
if (cfg_def->comment) {
|
||||
int pos = 0;
|
||||
while (_copy_one_line(cfg_def->comment, commentline, &pos, strlen(cfg_def->comment))) {
|
||||
if ((commentline[0] == '#') && (strlen(commentline) == 1)) {
|
||||
if (!out->tree_spec->withspaces)
|
||||
continue;
|
||||
commentline[0] = '\0';
|
||||
}
|
||||
fprintf(out->fp, "%s# %s\n", line, commentline);
|
||||
/* withsummary prints only the first comment line. */
|
||||
if (!out->tree_spec->withcomments)
|
||||
@ -1603,6 +1720,13 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
|
||||
if (cfg_def->flags & CFG_DEFAULT_UNDEFINED)
|
||||
fprintf(out->fp, "%s# This configuration %s does not have a default value defined.\n", line, node_type_name);
|
||||
|
||||
if (cfg_def->flags & CFG_DEFAULT_COMMENTED)
|
||||
fprintf(out->fp, "%s# This configuration %s has an automatic default value.\n", line, node_type_name);
|
||||
|
||||
if ((out->tree_spec->type == CFG_DEF_TREE_FULL) &&
|
||||
(out->tree_spec->check_status[cn->id] & CFG_USED))
|
||||
fprintf(out->fp, "%s# Value defined in existing configuration has been used for this setting.\n", line);
|
||||
}
|
||||
|
||||
if (out->tree_spec->withversions) {
|
||||
@ -1620,6 +1744,16 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _should_print_cfg_with_undef_def_val(struct out_baton *out, cfg_def_item_t *cfg_def,
|
||||
const struct dm_config_node *cn)
|
||||
{
|
||||
if (!(cfg_def->flags & CFG_DEFAULT_UNDEFINED))
|
||||
return 1;
|
||||
|
||||
/* print it only if the value is directly defined in some config = it's used */
|
||||
return out->tree_spec->check_status && (out->tree_spec->check_status[cn->id] & CFG_USED);
|
||||
}
|
||||
|
||||
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
||||
{
|
||||
struct out_baton *out = baton;
|
||||
@ -1662,14 +1796,23 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
|
||||
}
|
||||
|
||||
/* Usual tree view with nodes and their values. */
|
||||
|
||||
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
|
||||
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
|
||||
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
|
||||
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
|
||||
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
|
||||
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
|
||||
if (space_prefix)
|
||||
dm_pool_free(out->mem, space_prefix);
|
||||
} else
|
||||
/* print with # at the front to comment out the line */
|
||||
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
|
||||
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
|
||||
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
|
||||
if (space_prefix)
|
||||
dm_pool_free(out->mem, space_prefix);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* print the line as it is */
|
||||
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
|
||||
fprintf(out->fp, "%s\n", line);
|
||||
|
||||
return 1;
|
||||
@ -1739,15 +1882,20 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
const char *str;
|
||||
uint32_t format_flags = 0;
|
||||
|
||||
if (!(cn = dm_config_create_node(cft, def->name))) {
|
||||
log_error("Failed to create default config setting node.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(def->type & CFG_TYPE_SECTION) && (!(cn->v = dm_config_create_value(cft)))) {
|
||||
log_error("Failed to create default config setting node value.");
|
||||
return NULL;
|
||||
if (!(def->type & CFG_TYPE_SECTION) && !(def->type & CFG_TYPE_ARRAY)) {
|
||||
if (!(cn->v = dm_config_create_value(cft))) {
|
||||
log_error("Failed to create default config setting node value.");
|
||||
return NULL;
|
||||
}
|
||||
if (spec->withspaces)
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
|
||||
}
|
||||
|
||||
cn->id = def->id;
|
||||
@ -1755,6 +1903,9 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
if (spec->unconfigured && def->default_unconfigured_value.v_UNCONFIGURED) {
|
||||
cn->v->type = DM_CFG_STRING;
|
||||
cn->v->v.str = cfg_def_get_default_unconfigured_value_hint(spec->cmd, def);
|
||||
if (def->type != CFG_TYPE_STRING)
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_STRING_NO_QUOTES;
|
||||
dm_config_value_set_format_flags(cn->v, format_flags);
|
||||
} else if (!(def->type & CFG_TYPE_ARRAY)) {
|
||||
switch (def->type) {
|
||||
case CFG_TYPE_SECTION:
|
||||
@ -1767,6 +1918,8 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
case CFG_TYPE_INT:
|
||||
cn->v->type = DM_CFG_INT;
|
||||
cn->v->v.i = cfg_def_get_default_value_hint(spec->cmd, def, CFG_TYPE_INT, NULL);
|
||||
if (def->flags & CFG_FORMAT_INT_OCTAL)
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_INT_OCTAL;
|
||||
break;
|
||||
case CFG_TYPE_FLOAT:
|
||||
cn->v->type = DM_CFG_FLOAT;
|
||||
@ -1783,8 +1936,13 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
cn->v = _get_def_array_values(cft, def);
|
||||
dm_config_value_set_format_flags(cn->v, format_flags);
|
||||
} else {
|
||||
if (spec->withspaces)
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_EXTRA_SPACES;
|
||||
format_flags |= DM_CONFIG_VALUE_FMT_COMMON_ARRAY;
|
||||
cn->v = _get_def_array_values(spec->cmd, cft, def, format_flags);
|
||||
}
|
||||
|
||||
cn->child = NULL;
|
||||
if (parent) {
|
||||
@ -1816,6 +1974,8 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
||||
return 1;
|
||||
|
||||
switch (spec->type) {
|
||||
case CFG_DEF_TREE_FULL:
|
||||
/* fall through */
|
||||
case CFG_DEF_TREE_MISSING:
|
||||
if (!spec->check_status) {
|
||||
log_error_once(INTERNAL_ERROR "couldn't determine missing "
|
||||
@ -1823,9 +1983,12 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
||||
return 1;
|
||||
}
|
||||
if ((spec->check_status[id] & CFG_USED) ||
|
||||
(def->flags & CFG_NAME_VARIABLE) ||
|
||||
(def->since_version > spec->version) ||
|
||||
_should_skip_deprecated_def_node(def, spec))
|
||||
(def->flags & CFG_NAME_VARIABLE))
|
||||
return 1;
|
||||
|
||||
if ((spec->type == CFG_DEF_TREE_MISSING) &&
|
||||
((def->since_version > spec->version) ||
|
||||
_should_skip_deprecated_def_node(def, spec)))
|
||||
return 1;
|
||||
break;
|
||||
case CFG_DEF_TREE_NEW:
|
||||
@ -1834,7 +1997,9 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
||||
return 1;
|
||||
break;
|
||||
case CFG_DEF_TREE_PROFILABLE:
|
||||
/* fall through */
|
||||
case CFG_DEF_TREE_PROFILABLE_CMD:
|
||||
/* fall through */
|
||||
case CFG_DEF_TREE_PROFILABLE_MDA:
|
||||
if (!(def->flags & CFG_PROFILABLE) ||
|
||||
(def->since_version > spec->version) ||
|
||||
@ -1890,7 +2055,7 @@ bad:
|
||||
|
||||
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
||||
{
|
||||
struct dm_config_tree *cft;
|
||||
struct dm_config_tree *cft = NULL, *tmp_cft = NULL;
|
||||
struct dm_config_node *root = NULL, *relay = NULL, *tmp;
|
||||
int id;
|
||||
|
||||
@ -1914,7 +2079,33 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
||||
}
|
||||
|
||||
cft->root = root;
|
||||
|
||||
if (spec->type == CFG_DEF_TREE_FULL) {
|
||||
if (!(tmp_cft = dm_config_create())) {
|
||||
log_error("Failed to create temporary config tree while creating full tree.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(tmp_cft->root = dm_config_clone_node_with_mem(cft->mem, spec->current_cft->root, 1))) {
|
||||
log_error("Failed to clone current config tree.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!merge_config_tree(spec->cmd, cft, tmp_cft, CONFIG_MERGE_TYPE_RAW)) {
|
||||
log_error("Failed to merge default and current config tree.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
dm_config_destroy(tmp_cft);
|
||||
}
|
||||
|
||||
return cft;
|
||||
bad:
|
||||
if (cft)
|
||||
dm_config_destroy(cft);
|
||||
if (tmp_cft)
|
||||
dm_config_destroy(tmp_cft);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
|
||||
|
@ -50,7 +50,7 @@ struct profile_params {
|
||||
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
||||
};
|
||||
|
||||
#define CFG_PATH_MAX_LEN 64
|
||||
#define CFG_PATH_MAX_LEN 128
|
||||
|
||||
/*
|
||||
* Structures used for definition of a configuration tree.
|
||||
@ -119,6 +119,10 @@ typedef union {
|
||||
#define CFG_DEFAULT_RUN_TIME 0x100
|
||||
/* whether the configuration setting is disabled (and hence defaults always used) */
|
||||
#define CFG_DISABLED 0x200
|
||||
/* whether to print integers in octal form (prefixed by "0") */
|
||||
#define CFG_FORMAT_INT_OCTAL 0x400
|
||||
/* whether to disable checks for the whole config section subtree */
|
||||
#define CFG_SECTION_NO_CHECK 0x800
|
||||
|
||||
/* configuration definition item structure */
|
||||
typedef struct cfg_def_item {
|
||||
@ -139,7 +143,7 @@ typedef struct cfg_def_item {
|
||||
typedef enum {
|
||||
CFG_DEF_TREE_CURRENT, /* tree of nodes with values currently set in the config */
|
||||
CFG_DEF_TREE_MISSING, /* tree of nodes missing in current config using default values */
|
||||
CFG_DEF_TREE_COMPLETE, /* CURRENT + MISSING, the tree actually used within execution, not implemented yet */
|
||||
CFG_DEF_TREE_FULL, /* CURRENT + MISSING, the tree actually used within execution */
|
||||
CFG_DEF_TREE_DEFAULT, /* tree of all possible config nodes with default values */
|
||||
CFG_DEF_TREE_NEW, /* tree of all new nodes that appeared in given version */
|
||||
CFG_DEF_TREE_PROFILABLE, /* tree of all nodes that are customizable by profiles */
|
||||
@ -151,18 +155,20 @@ typedef enum {
|
||||
|
||||
/* configuration definition tree specification */
|
||||
struct config_def_tree_spec {
|
||||
struct cmd_context *cmd; /* command context (for run-time defaults */
|
||||
cfg_def_tree_t type; /* tree type */
|
||||
uint16_t version; /* tree at this LVM2 version */
|
||||
unsigned ignoreadvanced:1; /* do not include advanced configs */
|
||||
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||
unsigned ignoredeprecated:1; /* do not include deprecated configs */
|
||||
unsigned ignorelocal:1; /* do not include the local section */
|
||||
unsigned withsummary:1; /* include first line of comments - a summary */
|
||||
unsigned withcomments:1; /* include all comment lines */
|
||||
unsigned withversions:1; /* include versions */
|
||||
unsigned unconfigured:1; /* use unconfigured path strings */
|
||||
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
|
||||
struct cmd_context *cmd; /* command context (for run-time defaults */
|
||||
struct dm_config_tree *current_cft; /* current config tree which is defined explicitly - defaults are not used */
|
||||
cfg_def_tree_t type; /* tree type */
|
||||
uint16_t version; /* tree at this LVM2 version */
|
||||
unsigned ignoreadvanced:1; /* do not include advanced configs */
|
||||
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||
unsigned ignoredeprecated:1; /* do not include deprecated configs */
|
||||
unsigned ignorelocal:1; /* do not include the local section */
|
||||
unsigned withsummary:1; /* include first line of comments - a summary */
|
||||
unsigned withcomments:1; /* include all comment lines */
|
||||
unsigned withversions:1; /* include versions */
|
||||
unsigned withspaces:1; /* add more spaces in output for better readability */
|
||||
unsigned unconfigured:1; /* use unconfigured path strings */
|
||||
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
|
||||
};
|
||||
|
||||
|
||||
@ -268,6 +274,7 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
|
||||
int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
const struct dm_config_node *find_config_tree_array(struct cmd_context *cmd, int id, struct profile *profile);
|
||||
|
||||
/*
|
||||
* Functions for configuration settings for which the default
|
||||
@ -289,5 +296,7 @@ int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, str
|
||||
#define get_default_unconfigured_allocation_thin_pool_chunk_size_CFG NULL
|
||||
int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
|
||||
const char *get_default_allocation_cache_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_policy_CFG NULL
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -51,11 +51,14 @@
|
||||
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
||||
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
||||
#define DEFAULT_WAIT_FOR_LOCKS 1
|
||||
#define DEFAULT_LVMLOCKD_LOCK_RETRIES 3
|
||||
#define DEFAULT_PRIORITISE_WRITE_LOCKS 1
|
||||
#define DEFAULT_USE_MLOCKALL 0
|
||||
#define DEFAULT_METADATA_READ_ONLY 0
|
||||
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
|
||||
|
||||
#define DEFAULT_SANLOCK_LV_EXTEND_MB 256
|
||||
|
||||
#define DEFAULT_MIRRORLOG MIRROR_LOG_DISK
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||
@ -80,12 +83,15 @@
|
||||
#ifdef THIN_CHECK_NEEDS_CHECK
|
||||
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_THIN_CHECK_OPTION2 "--clear-needs-check-flag"
|
||||
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1 "#S" DEFAULT_THIN_CHECK_OPTION2
|
||||
#else
|
||||
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_THIN_CHECK_OPTION2 ""
|
||||
# define DEFAULT_THIN_CHECK_OPTIONS_CONFIG "#S" DEFAULT_THIN_CHECK_OPTION1
|
||||
#endif
|
||||
|
||||
#define DEFAULT_THIN_REPAIR_OPTIONS ""
|
||||
#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 (16 * 1024 * 1024) /* KB */
|
||||
#define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||
@ -97,23 +103,27 @@
|
||||
#define DEFAULT_THIN_POOL_ZERO 1
|
||||
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
||||
|
||||
#define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
|
||||
#ifdef CACHE_CHECK_NEEDS_CHECK
|
||||
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_CACHE_CHECK_OPTION2 "--clear-needs-check-flag"
|
||||
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1 "#S" DEFAULT_CACHE_CHECK_OPTION2
|
||||
#else
|
||||
# define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_CACHE_CHECK_OPTION2 ""
|
||||
# define DEFAULT_CACHE_CHECK_OPTIONS_CONFIG "#S" DEFAULT_CACHE_CHECK_OPTION1
|
||||
#endif
|
||||
|
||||
#define DEFAULT_CACHE_REPAIR_OPTION1 ""
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_CACHE_REPAIR_OPTION1
|
||||
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||
#define DEFAULT_CACHE_POOL_CACHEMODE "writethrough"
|
||||
#define DEFAULT_CACHE_POOL_POLICY "mq"
|
||||
#define DEFAULT_CACHE_POLICY "mq"
|
||||
#define DEFAULT_CACHE_MODE "writethrough"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#ifdef LVM1_FALLBACK
|
||||
# define DEFAULT_FALLBACK_TO_LVM1 1
|
||||
#else
|
||||
# define DEFAULT_FALLBACK_TO_LVM1 0
|
||||
#endif
|
||||
|
||||
#define DEFAULT_FORMAT "lvm2"
|
||||
|
||||
#define DEFAULT_STRIPESIZE 64 /* KB */
|
||||
@ -144,11 +154,6 @@
|
||||
# define DEFAULT_LOG_FACILITY LOG_USER
|
||||
#endif
|
||||
|
||||
#define DEFAULT_LOGGED_DEBUG_CLASSES (LOG_CLASS_MEM | LOG_CLASS_DEVS | \
|
||||
LOG_CLASS_ACTIVATION | LOG_CLASS_ALLOC | LOG_CLASS_LVMETAD | \
|
||||
LOG_CLASS_METADATA | LOG_CLASS_CACHE | LOG_CLASS_LOCKING | \
|
||||
LOG_CLASS_LVMPOLLD)
|
||||
|
||||
#define DEFAULT_SYSLOG 1
|
||||
#define DEFAULT_VERBOSE 0
|
||||
#define DEFAULT_SILENT 0
|
||||
@ -194,6 +199,7 @@
|
||||
#define DEFAULT_REP_QUOTED 1
|
||||
#define DEFAULT_REP_SEPARATOR " "
|
||||
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
|
||||
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
|
||||
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
@ -223,4 +229,6 @@
|
||||
#define DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD 100
|
||||
#define DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT 20
|
||||
|
||||
#define DEFAULT_CY_LOCK_TYPE "sanlock"
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
@ -71,6 +71,16 @@ static void _dev_init(struct device *dev, int max_error_count)
|
||||
dm_list_init(&dev->open_list);
|
||||
}
|
||||
|
||||
void dev_destroy_file(struct device *dev)
|
||||
{
|
||||
if (!(dev->flags & DEV_ALLOCED))
|
||||
return;
|
||||
|
||||
dm_free((void *) dm_list_item(dev->aliases.n, struct dm_str_list)->str);
|
||||
dm_free(dev->aliases.n);
|
||||
dm_free(dev);
|
||||
}
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct dm_str_list *alias, int use_malloc)
|
||||
{
|
||||
@ -681,10 +691,12 @@ static int _init_preferred_names(struct cmd_context *cmd)
|
||||
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, devices_preferred_names_CFG, NULL)) ||
|
||||
if (!(cn = find_config_tree_array(cmd, devices_preferred_names_CFG, NULL)) ||
|
||||
cn->v->type == DM_CFG_EMPTY_ARRAY) {
|
||||
log_very_verbose("devices/preferred_names not found in config file: "
|
||||
"using built-in preferences");
|
||||
log_very_verbose("devices/preferred_names %s: "
|
||||
"using built-in preferences",
|
||||
cn && cn->v->type == DM_CFG_EMPTY_ARRAY ? "is empty"
|
||||
: "not found in config");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -943,7 +955,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
if (d)
|
||||
dm_hash_remove(_cache.names, name);
|
||||
log_sys_very_verbose("stat", name);
|
||||
return NULL;
|
||||
d = NULL;
|
||||
}
|
||||
|
||||
if (d && (buf.st_rdev != d->dev)) {
|
||||
|
@ -586,12 +586,8 @@ static void _close(struct device *dev)
|
||||
|
||||
log_debug_devs("Closed %s", dev_name(dev));
|
||||
|
||||
if (dev->flags & DEV_ALLOCED) {
|
||||
dm_free((void *) dm_list_item(dev->aliases.n, struct dm_str_list)->
|
||||
str);
|
||||
dm_free(dev->aliases.n);
|
||||
dm_free(dev);
|
||||
}
|
||||
if (dev->flags & DEV_ALLOCED)
|
||||
dev_destroy_file(dev);
|
||||
}
|
||||
|
||||
static int _dev_close(struct device *dev, int immediate)
|
||||
|
@ -528,12 +528,14 @@ static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
|
||||
((flag_list & TYPE_DM_SNAPSHOT_COW) && !strcmp(type, "DM_snapshot_cow")));
|
||||
}
|
||||
|
||||
#define MSG_FAILED_SIG_OFFSET "Failed to get offset of the %s signature on %s."
|
||||
#define MSG_FAILED_SIG_LENGTH "Failed to get length of the %s signature on %s."
|
||||
#define MSG_WIPING_SKIPPED " Wiping skipped."
|
||||
|
||||
static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude, uint32_t types_no_prompt,
|
||||
int yes, force_t force)
|
||||
{
|
||||
static const char _msg_failed_offset[] = "Failed to get offset of the %s signature on %s.";
|
||||
static const char _msg_failed_length[] = "Failed to get length of the %s signature on %s.";
|
||||
static const char _msg_wiping[] = "Wiping %s signature on %s.";
|
||||
const char *offset = NULL, *type = NULL, *magic = NULL,
|
||||
*usage = NULL, *label = NULL, *uuid = NULL;
|
||||
@ -544,21 +546,41 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
if (_type_in_flag_list(type, types_to_exclude))
|
||||
return 2;
|
||||
if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) {
|
||||
log_error(_msg_failed_offset, type, name);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (blkid_probe_lookup_value(probe, "SBMAGIC", &magic, &len)) {
|
||||
log_error(_msg_failed_length, type, name);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else if (!blkid_probe_lookup_value(probe, "PTTYPE", &type, NULL)) {
|
||||
if (blkid_probe_lookup_value(probe, "PTMAGIC_OFFSET", &offset, NULL)) {
|
||||
log_error(_msg_failed_offset, type, name);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (blkid_probe_lookup_value(probe, "PTMAGIC", &magic, &len)) {
|
||||
log_error(_msg_failed_length, type, name);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
usage = "partition table";
|
||||
} else
|
||||
|
@ -123,6 +123,7 @@ void dev_flush(struct device *dev);
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct dm_str_list *alias, int use_malloc);
|
||||
void dev_destroy_file(struct device *dev);
|
||||
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||
|
@ -24,10 +24,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
||||
|
||||
static const struct {
|
||||
alloc_policy_t alloc;
|
||||
const char str[14]; /* must be changed when size extends 13 chars */
|
||||
@ -86,6 +82,38 @@ alloc_policy_t get_alloc_from_string(const char *str)
|
||||
return ALLOC_INVALID;
|
||||
}
|
||||
|
||||
const char *get_lock_type_string(lock_type_t lock_type)
|
||||
{
|
||||
switch (lock_type) {
|
||||
case LOCK_TYPE_INVALID:
|
||||
return "invalid";
|
||||
case LOCK_TYPE_NONE:
|
||||
return "none";
|
||||
case LOCK_TYPE_CLVM:
|
||||
return "clvm";
|
||||
case LOCK_TYPE_DLM:
|
||||
return "dlm";
|
||||
case LOCK_TYPE_SANLOCK:
|
||||
return "sanlock";
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
lock_type_t get_lock_type_from_string(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return LOCK_TYPE_NONE;
|
||||
if (!strcmp(str, "none"))
|
||||
return LOCK_TYPE_NONE;
|
||||
if (!strcmp(str, "clvm"))
|
||||
return LOCK_TYPE_CLVM;
|
||||
if (!strcmp(str, "dlm"))
|
||||
return LOCK_TYPE_DLM;
|
||||
if (!strcmp(str, "sanlock"))
|
||||
return LOCK_TYPE_SANLOCK;
|
||||
return LOCK_TYPE_INVALID;
|
||||
}
|
||||
|
||||
static const char *_percent_types[7] = { "NONE", "VG", "FREE", "LV", "PVS", "ORIGIN" };
|
||||
|
||||
const char *get_percent_string(percent_type_t def)
|
||||
@ -95,168 +123,49 @@ const char *get_percent_string(percent_type_t def)
|
||||
|
||||
const char *display_lvname(const struct logical_volume *lv)
|
||||
{
|
||||
/* On allocation failure, just return the LV name. */
|
||||
return lv_fullname_dup(lv->vg->cmd->mem, lv) ? : lv->name;
|
||||
}
|
||||
char *name;
|
||||
int r;
|
||||
|
||||
#define BASE_UNKNOWN 0
|
||||
#define BASE_SHARED 1
|
||||
#define BASE_1024 8
|
||||
#define BASE_1000 15
|
||||
#define BASE_SPECIAL 21
|
||||
#define NUM_UNIT_PREFIXES 6
|
||||
#define NUM_SPECIAL 3
|
||||
if ((lv->vg->cmd->display_lvname_idx + NAME_LEN) >= sizeof((lv->vg->cmd->display_buffer)))
|
||||
lv->vg->cmd->display_lvname_idx = 0;
|
||||
|
||||
name = lv->vg->cmd->display_buffer + lv->vg->cmd->display_lvname_idx;
|
||||
r = dm_snprintf(name, NAME_LEN, "%s/%s", lv->vg->name, lv->name);
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Full LV name \"%s/%s\" is too long.", lv->vg->name, lv->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv->vg->cmd->display_lvname_idx += r + 1;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Size supplied in sectors */
|
||||
static const char *_display_size(const struct cmd_context *cmd,
|
||||
uint64_t size, size_len_t sl)
|
||||
uint64_t size, dm_size_suffix_t suffix_type)
|
||||
{
|
||||
unsigned base = BASE_UNKNOWN;
|
||||
unsigned s;
|
||||
int suffix, precision;
|
||||
uint64_t byte = UINT64_C(0);
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
const char * const size_str[][3] = {
|
||||
/* BASE_UNKNOWN */
|
||||
{" ", " ", " "}, /* [0] */
|
||||
|
||||
/* BASE_SHARED - Used if cmd->si_unit_consistency = 0 */
|
||||
{" Exabyte", " EB", "E"}, /* [1] */
|
||||
{" Petabyte", " PB", "P"}, /* [2] */
|
||||
{" Terabyte", " TB", "T"}, /* [3] */
|
||||
{" Gigabyte", " GB", "G"}, /* [4] */
|
||||
{" Megabyte", " MB", "M"}, /* [5] */
|
||||
{" Kilobyte", " KB", "K"}, /* [6] */
|
||||
{" Byte ", " B", "B"}, /* [7] */
|
||||
|
||||
/* BASE_1024 - Used if cmd->si_unit_consistency = 1 */
|
||||
{" Exbibyte", " EiB", "e"}, /* [8] */
|
||||
{" Pebibyte", " PiB", "p"}, /* [9] */
|
||||
{" Tebibyte", " TiB", "t"}, /* [10] */
|
||||
{" Gibibyte", " GiB", "g"}, /* [11] */
|
||||
{" Mebibyte", " MiB", "m"}, /* [12] */
|
||||
{" Kibibyte", " KiB", "k"}, /* [13] */
|
||||
{" Byte ", " B", "b"}, /* [14] */
|
||||
|
||||
/* BASE_1000 - Used if cmd->si_unit_consistency = 1 */
|
||||
{" Exabyte", " EB", "E"}, /* [15] */
|
||||
{" Petabyte", " PB", "P"}, /* [16] */
|
||||
{" Terabyte", " TB", "T"}, /* [17] */
|
||||
{" Gigabyte", " GB", "G"}, /* [18] */
|
||||
{" Megabyte", " MB", "M"}, /* [19] */
|
||||
{" Kilobyte", " kB", "K"}, /* [20] */
|
||||
|
||||
/* BASE_SPECIAL */
|
||||
{" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */
|
||||
{" Units ", " Un", "U"}, /* [22] */
|
||||
{" Sectors ", " Se", "S"}, /* [23] */
|
||||
};
|
||||
|
||||
if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) {
|
||||
log_error("no memory for size display buffer");
|
||||
return "";
|
||||
}
|
||||
|
||||
suffix = cmd->current_settings.suffix;
|
||||
|
||||
if (!cmd->si_unit_consistency) {
|
||||
/* Case-independent match */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[BASE_SHARED + s][2]) {
|
||||
base = BASE_SHARED;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Case-dependent match for powers of 1000 */
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (cmd->current_settings.unit_type ==
|
||||
*size_str[BASE_1000 + s][2]) {
|
||||
base = BASE_1000;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Case-dependent match for powers of 1024 */
|
||||
if (base == BASE_UNKNOWN)
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES; s++)
|
||||
if (cmd->current_settings.unit_type ==
|
||||
*size_str[BASE_1024 + s][2]) {
|
||||
base = BASE_1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (base == BASE_UNKNOWN)
|
||||
/* Check for special units - s, b or u */
|
||||
for (s = 0; s < NUM_SPECIAL; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[BASE_SPECIAL + s][2]) {
|
||||
base = BASE_SPECIAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == UINT64_C(0)) {
|
||||
if (base == BASE_UNKNOWN)
|
||||
s = 0;
|
||||
sprintf(size_buf, "0%s", suffix ? size_str[base + s][sl] : "");
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
size *= UINT64_C(512);
|
||||
|
||||
if (base != BASE_UNKNOWN)
|
||||
byte = cmd->current_settings.unit_factor;
|
||||
else {
|
||||
/* Human-readable style */
|
||||
if (cmd->current_settings.unit_type == 'H') {
|
||||
units = UINT64_C(1000);
|
||||
base = BASE_1000;
|
||||
} else {
|
||||
units = UINT64_C(1024);
|
||||
base = BASE_1024;
|
||||
}
|
||||
|
||||
if (!cmd->si_unit_consistency)
|
||||
base = BASE_SHARED;
|
||||
|
||||
byte = units * units * units * units * units * units;
|
||||
|
||||
for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++)
|
||||
byte /= units;
|
||||
|
||||
suffix = 1;
|
||||
}
|
||||
|
||||
/* FIXME Make precision configurable */
|
||||
switch (toupper(*size_str[base + s][SIZE_UNIT])) {
|
||||
case 'B':
|
||||
case 'S':
|
||||
precision = 0;
|
||||
break;
|
||||
default:
|
||||
precision = 2;
|
||||
}
|
||||
|
||||
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
|
||||
(double) size / byte, suffix ? size_str[base + s][sl] : "");
|
||||
|
||||
return size_buf;
|
||||
return dm_size_to_string(cmd->mem, size, cmd->current_settings.unit_type,
|
||||
cmd->si_unit_consistency,
|
||||
cmd->current_settings.unit_factor,
|
||||
cmd->current_settings.suffix,
|
||||
suffix_type);
|
||||
}
|
||||
|
||||
const char *display_size_long(const struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_LONG);
|
||||
return _display_size(cmd, size, DM_SIZE_LONG);
|
||||
}
|
||||
|
||||
const char *display_size_units(const struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_UNIT);
|
||||
return _display_size(cmd, size, DM_SIZE_UNIT);
|
||||
}
|
||||
|
||||
const char *display_size(const struct cmd_context *cmd, uint64_t size)
|
||||
{
|
||||
return _display_size(cmd, size, SIZE_SHORT);
|
||||
return _display_size(cmd, size, DM_SIZE_SHORT);
|
||||
}
|
||||
|
||||
void pvdisplay_colons(const struct physical_volume *pv)
|
||||
@ -474,7 +383,7 @@ int lvdisplay_full(struct cmd_context *cmd,
|
||||
log_print("LV UUID %s", uuid);
|
||||
log_print("LV Write Access %s", access_str);
|
||||
log_print("LV Creation host, time %s, %s",
|
||||
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv));
|
||||
lv_host_dup(cmd->mem, lv), lv_time_dup(cmd->mem, lv, 1));
|
||||
|
||||
if (lv_is_origin(lv)) {
|
||||
log_print("LV snapshot status source of");
|
||||
|
@ -64,6 +64,9 @@ const char *get_alloc_string(alloc_policy_t alloc);
|
||||
char alloc_policy_char(alloc_policy_t alloc);
|
||||
alloc_policy_t get_alloc_from_string(const char *str);
|
||||
|
||||
const char *get_lock_type_string(lock_type_t lock_type);
|
||||
lock_type_t get_lock_type_from_string(const char *str);
|
||||
|
||||
const char *get_percent_string(percent_type_t def);
|
||||
|
||||
char yes_no_prompt(const char *prompt, ...) __attribute__ ((format(printf, 1, 2)));
|
||||
|
@ -164,7 +164,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && vg_is_exported(vg)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!*vg->lvm1_system_id ||
|
||||
if (!vg->lvm1_system_id || !*vg->lvm1_system_id ||
|
||||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
|
@ -381,19 +381,61 @@ static int _print_flag_config(struct formatter *f, uint64_t status, int type)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int _out_tags(struct formatter *f, struct dm_list *tagsl)
|
||||
static char *_alloc_printed_str_list(struct dm_list *list)
|
||||
{
|
||||
char *tag_buffer;
|
||||
struct dm_str_list *sl;
|
||||
int first = 1;
|
||||
size_t size = 0;
|
||||
char *buffer, *buf;
|
||||
|
||||
if (!dm_list_empty(tagsl)) {
|
||||
if (!(tag_buffer = alloc_printed_tags(tagsl)))
|
||||
dm_list_iterate_items(sl, list)
|
||||
/* '"' + item + '"' + ',' + ' ' */
|
||||
size += strlen(sl->str) + 4;
|
||||
/* '[' + ']' + '\0' */
|
||||
size += 3;
|
||||
|
||||
if (!(buffer = buf = dm_malloc(size))) {
|
||||
log_error("Could not allocate memory for string list buffer.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!emit_to_buffer(&buf, &size, "["))
|
||||
goto_bad;
|
||||
|
||||
dm_list_iterate_items(sl, list) {
|
||||
if (!first) {
|
||||
if (!emit_to_buffer(&buf, &size, ", "))
|
||||
goto_bad;
|
||||
} else
|
||||
first = 0;
|
||||
|
||||
if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!emit_to_buffer(&buf, &size, "]"))
|
||||
goto_bad;
|
||||
|
||||
return buffer;
|
||||
|
||||
bad:
|
||||
dm_free(buffer);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
static int _out_list(struct formatter *f, struct dm_list *list,
|
||||
const char *list_name)
|
||||
{
|
||||
char *buffer;
|
||||
|
||||
if (!dm_list_empty(list)) {
|
||||
if (!(buffer = _alloc_printed_str_list(list)))
|
||||
return_0;
|
||||
if (!out_text(f, "tags = %s", tag_buffer)) {
|
||||
dm_free(tag_buffer);
|
||||
if (!out_text(f, "%s = %s", list_name, buffer)) {
|
||||
dm_free(buffer);
|
||||
return_0;
|
||||
}
|
||||
dm_free(tag_buffer);
|
||||
dm_free(buffer);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -431,7 +473,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
if (!_print_flag_config(f, status, VG_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &vg->tags))
|
||||
if (!_out_list(f, &vg->tags, "tags"))
|
||||
return_0;
|
||||
|
||||
if (vg->system_id && *vg->system_id)
|
||||
@ -439,8 +481,11 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
else if (vg->lvm1_system_id && *vg->lvm1_system_id)
|
||||
outf(f, "system_id = \"%s\"", vg->lvm1_system_id);
|
||||
|
||||
if (vg->lock_type)
|
||||
if (vg->lock_type) {
|
||||
outf(f, "lock_type = \"%s\"", vg->lock_type);
|
||||
if (vg->lock_args)
|
||||
outf(f, "lock_args = \"%s\"", vg->lock_args);
|
||||
}
|
||||
|
||||
outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
||||
vg->extent_size);
|
||||
@ -518,7 +563,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
if (!_print_flag_config(f, pv->status, PV_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &pv->tags))
|
||||
if (!_out_list(f, &pv->tags, "tags"))
|
||||
return_0;
|
||||
|
||||
outsize(f, pv->size, "dev_size = %" PRIu64, pv->size);
|
||||
@ -557,7 +602,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
outnl(f);
|
||||
outf(f, "type = \"%s\"", seg->segtype->name);
|
||||
|
||||
if (!_out_tags(f, &seg->tags))
|
||||
if (!_out_list(f, &seg->tags, "tags"))
|
||||
return_0;
|
||||
|
||||
if (seg->segtype->ops->text_export &&
|
||||
@ -660,7 +705,7 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
if (!_print_flag_config(f, status, LV_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &lv->tags))
|
||||
if (!_out_list(f, &lv->tags, "tags"))
|
||||
return_0;
|
||||
|
||||
if (lv->timestamp) {
|
||||
@ -676,6 +721,9 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
lv->timestamp);
|
||||
}
|
||||
|
||||
if (lv->lock_args)
|
||||
outf(f, "lock_args = \"%s\"", lv->lock_args);
|
||||
|
||||
if (lv->alloc != ALLOC_INHERIT)
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
@ -69,6 +69,7 @@ static const struct flag _lv_flags[] = {
|
||||
{LV_NOSCAN, NULL, 0},
|
||||
{LV_TEMPORARY, NULL, 0},
|
||||
{POOL_METADATA_SPARE, NULL, 0},
|
||||
{LOCKD_SANLOCK_LV, NULL, 0},
|
||||
{RAID, NULL, 0},
|
||||
{RAID_META, NULL, 0},
|
||||
{RAID_IMAGE, NULL, 0},
|
||||
|
@ -453,8 +453,9 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
"not match expected name %s.", vgname);
|
||||
|
||||
bad:
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)) &&
|
||||
!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
|
||||
stack;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -2237,7 +2238,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
if (limit_applied)
|
||||
log_very_verbose("Using limited metadata area size on %s "
|
||||
"with value %" PRIu64 " (limited by %s of "
|
||||
"%" PRIu64 ").", pv_dev_name(pv),
|
||||
FMTu64 ").", pv_dev_name(pv),
|
||||
mda_size, limit_name, limit);
|
||||
|
||||
if (mda_size) {
|
||||
@ -2491,7 +2492,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if ((cn = find_config_tree_node(cmd, metadata_dirs_CFG, NULL))) {
|
||||
if ((cn = find_config_tree_array(cmd, metadata_dirs_CFG, NULL))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
|
@ -47,7 +47,8 @@ struct text_vg_version_ops {
|
||||
int (*check_version) (const struct dm_config_tree * cf);
|
||||
struct volume_group *(*read_vg) (struct format_instance * fid,
|
||||
const struct dm_config_tree *cf,
|
||||
unsigned use_cached_pvs);
|
||||
unsigned use_cached_pvs,
|
||||
unsigned allow_lvmetad_extensions);
|
||||
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
|
||||
time_t *when, char **desc);
|
||||
int (*read_vgname) (const struct format_type *fmt,
|
||||
@ -60,9 +61,6 @@ struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||
int print_flags(uint64_t status, int type, char *buffer, size_t size);
|
||||
int read_flags(uint64_t *status, int type, const struct dm_config_value *cv);
|
||||
|
||||
char *alloc_printed_tags(struct dm_list *tags);
|
||||
int read_tags(struct dm_pool *mem, struct dm_list *tags, const struct dm_config_value *cv);
|
||||
|
||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
|
||||
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
|
||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
|
@ -146,7 +146,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, single_device)))
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, single_device, 0)))
|
||||
goto_out;
|
||||
|
||||
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
|
||||
@ -174,8 +174,9 @@ struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
when, desc);
|
||||
}
|
||||
|
||||
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid)
|
||||
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid,
|
||||
unsigned allow_lvmetad_extensions)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct text_vg_version_ops **vsn;
|
||||
@ -190,7 +191,7 @@ struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft
|
||||
* The only path to this point uses cached vgmetadata,
|
||||
* so it can use cached PV state too.
|
||||
*/
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, 1)))
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
|
||||
stack;
|
||||
else if ((vg_missing = vg_missing_pv_count(vg))) {
|
||||
log_verbose("There are %d physical volumes missing.",
|
||||
@ -203,3 +204,15 @@ struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft
|
||||
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid)
|
||||
{
|
||||
return _import_vg_from_config_tree(cft, fid, 0);
|
||||
}
|
||||
|
||||
struct volume_group *import_vg_from_lvmetad_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid)
|
||||
{
|
||||
return _import_vg_from_config_tree(cft, fid, 1);
|
||||
}
|
||||
|
@ -20,11 +20,13 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lvmetad.h"
|
||||
#include "lvmlockd.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "segtype.h"
|
||||
#include "text_import.h"
|
||||
#include "defaults.h"
|
||||
#include "str_list.h"
|
||||
|
||||
typedef int (*section_fn) (struct format_instance * fid,
|
||||
struct volume_group * vg, const struct dm_config_node * pvn,
|
||||
@ -153,6 +155,26 @@ static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, i
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_str_list(struct dm_pool *mem, struct dm_list *list, const struct dm_config_value *cv)
|
||||
{
|
||||
if (cv->type == DM_CFG_EMPTY_ARRAY)
|
||||
return 1;
|
||||
|
||||
while (cv) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Found an item that is not a string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_add(mem, list, dm_pool_strdup(mem, cv->v.str)))
|
||||
return_0;
|
||||
|
||||
cv = cv->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_pv(struct format_instance *fid,
|
||||
struct volume_group *vg, const struct dm_config_node *pvn,
|
||||
const struct dm_config_node *vgn __attribute__((unused)),
|
||||
@ -269,7 +291,7 @@ static int _read_pv(struct format_instance *fid,
|
||||
|
||||
/* Optional tags */
|
||||
if (dm_config_get_list(pvn, "tags", &cv) &&
|
||||
!(read_tags(mem, &pv->tags, cv))) {
|
||||
!(_read_str_list(mem, &pv->tags, cv))) {
|
||||
log_error("Couldn't read tags for physical volume %s in %s.",
|
||||
pv_dev_name(pv), vg->name);
|
||||
return 0;
|
||||
@ -384,7 +406,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
|
||||
|
||||
/* Optional tags */
|
||||
if (dm_config_get_list(sn_child, "tags", &cv) &&
|
||||
!(read_tags(mem, &seg->tags, cv))) {
|
||||
!(_read_str_list(mem, &seg->tags, cv))) {
|
||||
log_error("Couldn't read tags for a segment of %s/%s.",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
@ -583,6 +605,30 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The LV lock_args string is generated in lvmlockd, and the content
|
||||
* depends on the lock_type.
|
||||
*
|
||||
* lock_type dlm does not use LV lock_args, so the LV lock_args field
|
||||
* is just set to "dlm".
|
||||
*
|
||||
* lock_type sanlock uses the LV lock_args field to save the
|
||||
* location on disk of that LV's sanlock lock. The disk name is
|
||||
* specified in the VG lock_args. The lock_args string begins
|
||||
* with a version number, e.g. 1.0.0, followed by a colon, followed
|
||||
* by a number. The number is the offset on disk where sanlock is
|
||||
* told to find the LV's lock.
|
||||
* e.g. lock_args = 1.0.0:70254592
|
||||
* means that the lock is located at offset 70254592.
|
||||
*
|
||||
* The lvmlockd code for each specific lock manager also validates
|
||||
* the lock_args before using it to access the lock manager.
|
||||
*/
|
||||
if (dm_config_get_str(lvn, "lock_args", &str)) {
|
||||
if (!(lv->lock_args = dm_pool_strdup(mem, str)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
lv->alloc = ALLOC_INHERIT;
|
||||
if (dm_config_get_str(lvn, "allocation_policy", &str)) {
|
||||
lv->alloc = get_alloc_from_string(str);
|
||||
@ -621,7 +667,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
|
||||
|
||||
/* Optional tags */
|
||||
if (dm_config_get_list(lvn, "tags", &cv) &&
|
||||
!(read_tags(mem, &lv->tags, cv))) {
|
||||
!(_read_str_list(mem, &lv->tags, cv))) {
|
||||
log_error("Couldn't read tags for logical volume %s/%s.",
|
||||
vg->name, lv->name);
|
||||
return 0;
|
||||
@ -648,6 +694,12 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
|
||||
vg->pool_metadata_spare_lv = lv;
|
||||
}
|
||||
|
||||
if (!lv_is_visible(lv) && !strcmp(lv->name, LOCKD_SANLOCK_LV_NAME)) {
|
||||
log_debug_metadata("Logical volume %s is sanlock lv.", lv->name);
|
||||
lv->status |= LOCKD_SANLOCK_LV;
|
||||
vg->sanlock_lv = lv;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -745,7 +797,8 @@ static int _read_sections(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
const struct dm_config_tree *cft,
|
||||
unsigned use_cached_pvs)
|
||||
unsigned use_cached_pvs,
|
||||
unsigned allow_lvmetad_extensions)
|
||||
{
|
||||
const struct dm_config_node *vgn;
|
||||
const struct dm_config_value *cv;
|
||||
@ -799,6 +852,32 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* The VG lock_args string is generated in lvmlockd, and the content
|
||||
* depends on the lock_type. lvmlockd begins the lock_args string
|
||||
* with a version number, e.g. 1.0.0, followed by a colon, followed
|
||||
* by a string that depends on the lock manager. The string after
|
||||
* the colon is information needed to use the lock manager for the VG.
|
||||
*
|
||||
* For sanlock, the string is the name of the internal LV used to store
|
||||
* sanlock locks. lvmlockd needs to know where the locks are located
|
||||
* so it can pass that location to sanlock which needs to access the locks.
|
||||
* e.g. lock_args = 1.0.0:lvmlock
|
||||
* means that the locks are located on the the LV "lvmlock".
|
||||
*
|
||||
* For dlm, the string is the dlm cluster name. lvmlockd needs to use
|
||||
* a dlm lockspace in this cluster to use the VG.
|
||||
* e.g. lock_args = 1.0.0:foo
|
||||
* means that the host needs to be a member of the cluster "foo".
|
||||
*
|
||||
* The lvmlockd code for each specific lock manager also validates
|
||||
* the lock_args before using it to access the lock manager.
|
||||
*/
|
||||
if (dm_config_get_str(vgn, "lock_args", &str)) {
|
||||
if (!(vg->lock_args = dm_pool_strdup(vg->vgmem, str)))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_id(&vg->id, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vg->name);
|
||||
goto bad;
|
||||
@ -887,12 +966,15 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
_read_sections(fid, "outdated_pvs", _read_pv, vg,
|
||||
vgn, pv_hash, lv_hash, 1, &scan_done_once);
|
||||
if (allow_lvmetad_extensions)
|
||||
_read_sections(fid, "outdated_pvs", _read_pv, vg,
|
||||
vgn, pv_hash, lv_hash, 1, &scan_done_once);
|
||||
else if (dm_config_has_node(vgn, "outdated_pvs"))
|
||||
log_error(INTERNAL_ERROR "Unexpected outdated_pvs section in metadata of VG %s.", vg->name);
|
||||
|
||||
/* Optional tags */
|
||||
if (dm_config_get_list(vgn, "tags", &cv) &&
|
||||
!(read_tags(vg->vgmem, &vg->tags, cv))) {
|
||||
!(_read_str_list(vg->vgmem, &vg->tags, cv))) {
|
||||
log_error("Couldn't read tags for volume group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
@ -954,6 +1036,11 @@ static void _read_desc(struct dm_pool *mem,
|
||||
*when = u;
|
||||
}
|
||||
|
||||
/*
|
||||
* It would be more accurate to call this _read_vgsummary().
|
||||
* It is used to read vgsummary information about a VG
|
||||
* before locking and reading the VG via vg_read().
|
||||
*/
|
||||
static int _read_vgname(const struct format_type *fmt, const struct dm_config_tree *cft,
|
||||
struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
@ -990,6 +1077,8 @@ static int _read_vgname(const struct format_type *fmt, const struct dm_config_tr
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_config_get_str(vgn, "lock_type", &vgsummary->lock_type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "import-export.h"
|
||||
#include "str_list.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
char *alloc_printed_tags(struct dm_list *tagsl)
|
||||
{
|
||||
struct dm_str_list *sl;
|
||||
int first = 1;
|
||||
size_t size = 0;
|
||||
char *buffer, *buf;
|
||||
|
||||
dm_list_iterate_items(sl, tagsl)
|
||||
/* '"' + tag + '"' + ',' + ' ' */
|
||||
size += strlen(sl->str) + 4;
|
||||
/* '[' + ']' + '\0' */
|
||||
size += 3;
|
||||
|
||||
if (!(buffer = buf = dm_malloc(size))) {
|
||||
log_error("Could not allocate memory for tag list buffer.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!emit_to_buffer(&buf, &size, "["))
|
||||
goto_bad;
|
||||
|
||||
dm_list_iterate_items(sl, tagsl) {
|
||||
if (!first) {
|
||||
if (!emit_to_buffer(&buf, &size, ", "))
|
||||
goto_bad;
|
||||
} else
|
||||
first = 0;
|
||||
|
||||
if (!emit_to_buffer(&buf, &size, "\"%s\"", sl->str))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!emit_to_buffer(&buf, &size, "]"))
|
||||
goto_bad;
|
||||
|
||||
return buffer;
|
||||
|
||||
bad:
|
||||
dm_free(buffer);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
int read_tags(struct dm_pool *mem, struct dm_list *tagsl, const struct dm_config_value *cv)
|
||||
{
|
||||
if (cv->type == DM_CFG_EMPTY_ARRAY)
|
||||
return 1;
|
||||
|
||||
while (cv) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Found a tag that is not a string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_add(mem, tagsl, dm_pool_strdup(mem, cv->v.str)))
|
||||
return_0;
|
||||
|
||||
cv = cv->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -105,7 +105,8 @@ static void _update_lvmcache_orphan(struct lvmcache_info *info)
|
||||
|
||||
memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
|
||||
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
if (!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
|
||||
stack;
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
|
@ -128,8 +128,9 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cmd, suppress_messages);
|
||||
log_warn("WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
log_warn_suppress(suppress_messages,
|
||||
"WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
return 1;
|
||||
|
||||
case 1:
|
||||
|
@ -195,9 +195,10 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
|
||||
#define unlock_vg(cmd, vol) \
|
||||
do { \
|
||||
if (is_real_vg(vol)) \
|
||||
sync_dev_names(cmd); \
|
||||
(void) lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL); \
|
||||
if (is_real_vg(vol) && !sync_dev_names(cmd)) \
|
||||
stack; \
|
||||
if (!lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL)) \
|
||||
stack; \
|
||||
} while (0)
|
||||
#define unlock_and_release_vg(cmd, vg, vol) \
|
||||
do { \
|
||||
|
2604
lib/locking/lvmlockd.c
Normal file
2604
lib/locking/lvmlockd.c
Normal file
File diff suppressed because it is too large
Load Diff
246
lib/locking/lvmlockd.h
Normal file
246
lib/locking/lvmlockd.h
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*/
|
||||
|
||||
#ifndef _LVMLOCKD_H
|
||||
#define _LVMLOCKD_H
|
||||
|
||||
#include "config-util.h"
|
||||
#include "daemon-client.h"
|
||||
|
||||
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
|
||||
|
||||
/* lockd_gl flags */
|
||||
#define LDGL_UPDATE_NAMES 0x00000001
|
||||
|
||||
/* lockd_lv flags */
|
||||
#define LDLV_MODE_NO_SH 0x00000001
|
||||
#define LDLV_PERSISTENT 0x00000002
|
||||
|
||||
/* lvmlockd result flags */
|
||||
#define LD_RF_NO_LOCKSPACES 0x00000001
|
||||
#define LD_RF_NO_GL_LS 0x00000002
|
||||
#define LD_RF_WARN_GL_REMOVED 0x00000004
|
||||
#define LD_RF_DUP_GL_LS 0x00000008
|
||||
#define LD_RF_INACTIVE_LS 0x00000010
|
||||
#define LD_RF_ADD_LS_ERROR 0x00000020
|
||||
|
||||
/* lockd_state flags */
|
||||
#define LDST_EX 0x00000001
|
||||
#define LDST_SH 0x00000002
|
||||
#define LDST_FAIL_REQUEST 0x00000004
|
||||
#define LDST_FAIL_NOLS 0x00000008
|
||||
#define LDST_FAIL_STARTING 0x00000010
|
||||
#define LDST_FAIL_OTHER 0x00000020
|
||||
#define LDST_FAIL (LDST_FAIL_REQUEST | LDST_FAIL_NOLS | LDST_FAIL_STARTING | LDST_FAIL_OTHER)
|
||||
|
||||
#ifdef LVMLOCKD_SUPPORT
|
||||
|
||||
/* lvmlockd connection and communication */
|
||||
|
||||
void lvmlockd_set_socket(const char *sock);
|
||||
void lvmlockd_set_use(int use);
|
||||
int lvmlockd_use(void);
|
||||
void lvmlockd_init(struct cmd_context *cmd);
|
||||
void lvmlockd_connect(void);
|
||||
void lvmlockd_disconnect(void);
|
||||
|
||||
/* vgcreate/vgremove use init/free */
|
||||
|
||||
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count);
|
||||
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg);
|
||||
void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
/* vgrename */
|
||||
|
||||
int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success);
|
||||
|
||||
/* start and stop the lockspace for a vg */
|
||||
|
||||
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int lockd_start_wait(struct cmd_context *cmd);
|
||||
|
||||
/* locking */
|
||||
|
||||
int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type);
|
||||
int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags);
|
||||
int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
|
||||
uint32_t flags, uint32_t *lockd_state);
|
||||
int lockd_vg_update(struct volume_group *vg);
|
||||
|
||||
int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id,
|
||||
const char *lock_args, const char *def_mode, uint32_t flags);
|
||||
int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const char *def_mode, uint32_t flags);
|
||||
|
||||
/* lvcreate/lvremove use init/free */
|
||||
|
||||
int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv,
|
||||
struct lvcreate_params *lp);
|
||||
int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *lock_type, const char **lock_args);
|
||||
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id, const char *lock_args);
|
||||
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd);
|
||||
|
||||
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
int lockd_lv_uses_lock(struct logical_volume *lv);
|
||||
|
||||
#else /* LVMLOCKD_SUPPORT */
|
||||
|
||||
static inline void lvmlockd_set_socket(const char *sock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void lvmlockd_set_use(int use)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void lvmlockd_init(struct cmd_context *cmd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void lvmlockd_disconnect(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void lvmlockd_connect(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int lvmlockd_use(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lockd_start_wait(struct cmd_context *cmd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lockd_gl_create(struct cmd_context *cmd, const char *def_mode, const char *vg_lock_type)
|
||||
{
|
||||
/*
|
||||
* When lvm is built without lvmlockd support, creating a VG with
|
||||
* a shared lock type should fail.
|
||||
*/
|
||||
if (is_lockd_type(vg_lock_type)) {
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
|
||||
uint32_t flags, uint32_t *lockd_state)
|
||||
{
|
||||
*lockd_state = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_vg_update(struct volume_group *vg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id,
|
||||
const char *lock_args, const char *def_mode, uint32_t flags)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const char *def_mode, uint32_t flags)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct lvcreate_params *lp)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *lock_type, const char **lock_args)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id, const char *lock_args)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
{
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lockd_lv_uses_lock(struct logical_volume *lv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LVMLOCKD_SUPPORT */
|
||||
|
||||
#endif /* _LVMLOCKD_H */
|
@ -36,7 +36,7 @@ static int _indent = 1;
|
||||
static int _log_suppress = 0;
|
||||
static char _msg_prefix[30] = " ";
|
||||
static int _already_logging = 0;
|
||||
static int _abort_on_internal_errors = 0;
|
||||
static int _abort_on_internal_errors_config = 0;
|
||||
|
||||
static lvm2_log_fn_t _lvm2_log_fn = NULL;
|
||||
|
||||
@ -69,7 +69,7 @@ void init_log_file(const char *log_file, int append)
|
||||
static const char statfile[] = "/proc/self/stat";
|
||||
const char *env;
|
||||
int pid;
|
||||
long long starttime;
|
||||
unsigned long long starttime;
|
||||
FILE *st;
|
||||
int i = 0;
|
||||
|
||||
@ -92,9 +92,6 @@ void init_log_file(const char *log_file, int append)
|
||||
"%llu", &pid, &starttime) != 2) {
|
||||
log_warn("WARNING: Cannot parse content of %s.", statfile);
|
||||
} else {
|
||||
if (fclose(st))
|
||||
log_sys_debug("fclose", statfile);
|
||||
|
||||
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
|
||||
"%s_%s_%d_%lld", log_file, env, pid, starttime) < 0) {
|
||||
log_warn("WARNING: Debug log file path is too long for epoch.");
|
||||
@ -104,7 +101,11 @@ void init_log_file(const char *log_file, int append)
|
||||
append = 1; /* force */
|
||||
}
|
||||
}
|
||||
|
||||
if (st && fclose(st))
|
||||
log_sys_debug("fclose", statfile);
|
||||
}
|
||||
|
||||
no_epoch:
|
||||
if (!(_log_file = fopen(log_file, append ? "a" : "w"))) {
|
||||
log_sys_error("fopen", log_file);
|
||||
@ -217,9 +218,10 @@ void init_indent(int indent)
|
||||
_indent = indent;
|
||||
}
|
||||
|
||||
/* If present, environment setting will override this. */
|
||||
void init_abort_on_internal_errors(int fatal)
|
||||
{
|
||||
_abort_on_internal_errors = fatal;
|
||||
_abort_on_internal_errors_config = fatal;
|
||||
}
|
||||
|
||||
void reset_lvm_errno(int store_errmsg)
|
||||
@ -276,10 +278,24 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
size_t msglen;
|
||||
const char *indent_spaces = "";
|
||||
FILE *stream;
|
||||
static int _abort_on_internal_errors_env_present = -1;
|
||||
static int _abort_on_internal_errors_env = 0;
|
||||
char *env_str;
|
||||
|
||||
level &= ~(_LOG_STDERR|_LOG_ONCE);
|
||||
|
||||
if (_abort_on_internal_errors &&
|
||||
if (_abort_on_internal_errors_env_present < 0) {
|
||||
if ((env_str = getenv("DM_ABORT_ON_INTERNAL_ERRORS"))) {
|
||||
_abort_on_internal_errors_env_present = 1;
|
||||
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
|
||||
_abort_on_internal_errors_env = strcmp(env_str, "0");
|
||||
} else
|
||||
_abort_on_internal_errors_env_present = 0;
|
||||
}
|
||||
|
||||
/* Use value from environment if present, otherwise use value from config. */
|
||||
if (((_abort_on_internal_errors_env_present && _abort_on_internal_errors_env) ||
|
||||
(!_abort_on_internal_errors_env_present && _abort_on_internal_errors_config)) &&
|
||||
!strncmp(format, INTERNAL_ERROR, sizeof(INTERNAL_ERROR) - 1)) {
|
||||
fatal_internal_error = 1;
|
||||
/* Internal errors triggering abort cannot be suppressed. */
|
||||
@ -385,6 +401,8 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
default:
|
||||
/* Typically only log_warn goes to stdout */
|
||||
stream = (use_stderr || (level != _LOG_WARN)) ? stderr : stdout;
|
||||
if (stream == stderr)
|
||||
fflush(stdout);
|
||||
fprintf(stream, "%s%s%s%s", buf, log_command_name(),
|
||||
_msg_prefix, indent_spaces);
|
||||
vfprintf(stream, trformat, ap);
|
||||
|
@ -37,8 +37,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* FILE */
|
||||
#include <string.h> /* strerror() */
|
||||
#include <errno.h>
|
||||
|
||||
#define EUNCLASSIFIED -1 /* Generic error code */
|
||||
|
@ -106,6 +106,7 @@ static void _explain_error_codes(int retcode)
|
||||
/* lvmpolld specific return codes */
|
||||
case LVMPD_RET_DUP_FAILED:
|
||||
log_error("lvmpolld failed to duplicate file descriptors.");
|
||||
/* fall through */
|
||||
case LVMPD_RET_EXC_FAILED:
|
||||
log_error("lvmpolld failed to exec() lvm binary.");
|
||||
break;
|
||||
@ -146,7 +147,7 @@ static struct progress_info _request_progress_info(const char *uuid, unsigned ab
|
||||
}
|
||||
|
||||
if (abort_polling &&
|
||||
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", abort_polling, NULL)) {
|
||||
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)abort_polling, NULL)) {
|
||||
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
|
||||
goto out_req;
|
||||
}
|
||||
@ -227,14 +228,14 @@ static int _process_poll_init(const struct cmd_context *cmd, const char *poll_ty
|
||||
}
|
||||
|
||||
if (parms->aborting &&
|
||||
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", parms->aborting, NULL))) {
|
||||
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", (int64_t)(parms->aborting), NULL))) {
|
||||
log_error("Failed to create %s request." , poll_type);
|
||||
goto out_req;
|
||||
}
|
||||
|
||||
if (cmd->handles_missing_pvs &&
|
||||
!(daemon_request_extend(req, LVMPD_PARM_HANDLE_MISSING_PVS " = %d",
|
||||
cmd->handles_missing_pvs, NULL))) {
|
||||
(int64_t)(cmd->handles_missing_pvs), NULL))) {
|
||||
log_error("Failed to create %s request." , poll_type);
|
||||
goto out_req;
|
||||
}
|
||||
|
@ -29,7 +29,17 @@
|
||||
#define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
|
||||
#define DM_MAX_HINT_WIDTH (4+16) /* bytes. FIXME Configurable? */
|
||||
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
int cache_mode_is_set(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
return (seg->feature_flags & (DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH)) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *get_cache_mode_name(const struct lv_segment *seg)
|
||||
{
|
||||
if (seg->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
|
||||
return "writeback";
|
||||
@ -46,19 +56,48 @@ const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str)
|
||||
int cache_set_mode(struct lv_segment *seg, const char *str)
|
||||
{
|
||||
struct cmd_context *cmd = seg->lv->vg->cmd;
|
||||
int id;
|
||||
uint64_t mode;
|
||||
|
||||
if (!str && !seg_is_cache(seg))
|
||||
return 1; /* Defaults only for cache */
|
||||
|
||||
if (seg_is_cache(seg))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (!str) {
|
||||
if (cache_mode_is_set(seg))
|
||||
return 1; /* Default already set in cache pool */
|
||||
|
||||
id = allocation_cache_mode_CFG;
|
||||
|
||||
/* If present, check backward compatible settings */
|
||||
if (!find_config_node(cmd, cmd->cft, id) &&
|
||||
find_config_node(cmd, cmd->cft, allocation_cache_pool_cachemode_CFG))
|
||||
id = allocation_cache_pool_cachemode_CFG;
|
||||
|
||||
str = find_config_tree_str(cmd, id, NULL);
|
||||
}
|
||||
|
||||
if (!strcmp(str, "writeback"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
mode = DM_CACHE_FEATURE_WRITEBACK;
|
||||
else if (!strcmp(str, "writethrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passhrough"))
|
||||
*feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
mode = DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strcmp(str, "passthrough"))
|
||||
mode = DM_CACHE_FEATURE_PASSTHROUGH;
|
||||
else {
|
||||
log_error("Cache pool feature \"%s\" is unknown.", str);
|
||||
log_error("Cannot set unknown cache mode \"%s\".", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->feature_flags &= ~(DM_CACHE_FEATURE_WRITEBACK |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_PASSTHROUGH);
|
||||
seg->feature_flags |= mode;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -322,7 +361,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
|
||||
dirty_blocks = status->cache->dirty_blocks;
|
||||
dm_pool_destroy(status->mem);
|
||||
if (dirty_blocks) {
|
||||
log_print_unless_silent("%" PRIu64 " blocks must still be flushed.",
|
||||
log_print_unless_silent(FMTu64 " blocks must still be flushed.",
|
||||
dirty_blocks);
|
||||
sleep(1);
|
||||
}
|
||||
@ -395,36 +434,104 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
|
||||
}
|
||||
|
||||
int lv_cache_setpolicy(struct logical_volume *lv, struct dm_config_tree *policy)
|
||||
static const char *_get_default_cache_policy(struct cmd_context *cmd)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
const char *name;
|
||||
struct dm_config_node *cn;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, "cache");
|
||||
unsigned attr = ~0;
|
||||
const char *def = NULL;
|
||||
|
||||
if (lv_is_cache(lv))
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = policy->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = policy = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
if (!segtype ||
|
||||
!segtype->ops->target_present ||
|
||||
!segtype->ops->target_present(cmd, NULL, &attr)) {
|
||||
log_warn("WARNING: Cannot detect default cache policy, using \""
|
||||
DEFAULT_CACHE_POLICY "\".");
|
||||
return DEFAULT_CACHE_POLICY;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node(policy->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
if (attr & CACHE_FEATURE_POLICY_SMQ)
|
||||
def = "smq";
|
||||
else if (attr & CACHE_FEATURE_POLICY_MQ)
|
||||
def = "mq";
|
||||
else {
|
||||
log_error("Default cache policy is not available.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((name = dm_config_find_str(policy->root, "policy", NULL)) &&
|
||||
!(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name)))
|
||||
goto_out;
|
||||
log_debug_metadata("Detected default cache_policy \"%s\".", def);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
int cache_set_policy(struct lv_segment *seg, const char *name,
|
||||
const struct dm_config_tree *settings)
|
||||
{
|
||||
struct dm_config_node *cn;
|
||||
const struct dm_config_node *cns;
|
||||
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
|
||||
int r = 0;
|
||||
const int passed_seg_is_cache = seg_is_cache(seg);
|
||||
|
||||
if (passed_seg_is_cache)
|
||||
seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (name) {
|
||||
if (!(seg->policy_name = dm_pool_strdup(seg->lv->vg->vgmem, name))) {
|
||||
log_error("Failed to duplicate policy name.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!seg->policy_name && passed_seg_is_cache) {
|
||||
if (!(seg->policy_name = find_config_tree_str(seg->lv->vg->cmd, allocation_cache_policy_CFG, NULL)) &&
|
||||
!(seg->policy_name = _get_default_cache_policy(seg->lv->vg->cmd)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (settings) {
|
||||
if (!seg->policy_name) {
|
||||
log_error(INTERNAL_ERROR "Can't set policy settings without policy name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->policy_settings) {
|
||||
if (!(old = dm_config_create()))
|
||||
goto_out;
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
new->root = settings->root;
|
||||
old->root = seg->policy_settings;
|
||||
new->cascade = old;
|
||||
if (!(tmp = dm_config_flatten(new)))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
|
||||
!(seg->policy_settings = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, cn, 0)))
|
||||
goto_out;
|
||||
} else if (passed_seg_is_cache && /* Look for command's profile cache_policies */
|
||||
(cns = find_config_tree_node(seg->lv->vg->cmd, allocation_cache_settings_CFG_SECTION, NULL))) {
|
||||
/* Try to find our section for given policy */
|
||||
for (cn = cns->child; cn; cn = cn->sib) {
|
||||
/* Only matching section names */
|
||||
if (cn->v || strcmp(cn->key, seg->policy_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!cn->child)
|
||||
break;
|
||||
|
||||
if (!(new = dm_config_create()))
|
||||
goto_out;
|
||||
|
||||
if (!(new->root = dm_config_clone_node_with_mem(new->mem,
|
||||
cn->child, 1)))
|
||||
goto_out;
|
||||
|
||||
if (!(seg->policy_settings = dm_config_create_node(new, "policy_settings")))
|
||||
goto_out;
|
||||
|
||||
seg->policy_settings->child = new->root;
|
||||
|
||||
break; /* Only first match counts */
|
||||
}
|
||||
}
|
||||
|
||||
restart: /* remove any 'default" nodes */
|
||||
cn = seg->policy_settings ? seg->policy_settings->child : NULL;
|
||||
@ -439,12 +546,13 @@ restart: /* remove any 'default" nodes */
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (old)
|
||||
dm_config_destroy(old);
|
||||
if (new)
|
||||
dm_config_destroy(new);
|
||||
if (tmp)
|
||||
dm_config_destroy(tmp);
|
||||
if (new)
|
||||
dm_config_destroy(new);
|
||||
if (old)
|
||||
dm_config_destroy(old);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "segtype.h"
|
||||
#include "str_list.h"
|
||||
#include "lvmlockd.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/utsname.h>
|
||||
@ -87,7 +88,7 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
|
||||
if (range_format) {
|
||||
if (dm_snprintf(extent_str, sizeof(extent_str),
|
||||
"%" PRIu32, extent + seg->area_len - 1) < 0) {
|
||||
FMTu32, extent + seg->area_len - 1) < 0) {
|
||||
log_error("Extent number dm_snprintf failed");
|
||||
return NULL;
|
||||
}
|
||||
@ -139,7 +140,7 @@ char *lvseg_discards_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
|
||||
char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
const char *name = get_cache_pool_cachemode_name(seg);
|
||||
const char *name = get_cache_mode_name(seg);
|
||||
|
||||
if (!name)
|
||||
return_NULL;
|
||||
@ -883,17 +884,16 @@ int lv_set_creation(struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv, int iso_mode)
|
||||
{
|
||||
char buffer[50];
|
||||
char buffer[4096];
|
||||
struct tm *local_tm;
|
||||
time_t ts = (time_t)lv->timestamp;
|
||||
const char *format = iso_mode ? DEFAULT_TIME_FORMAT : lv->vg->cmd->time_format;
|
||||
|
||||
if (!ts ||
|
||||
!(local_tm = localtime(&ts)) ||
|
||||
/* FIXME: make this lvm.conf configurable */
|
||||
!strftime(buffer, sizeof(buffer),
|
||||
"%Y-%m-%d %T %z", local_tm))
|
||||
!strftime(buffer, sizeof(buffer), format, local_tm))
|
||||
buffer[0] = 0;
|
||||
|
||||
return dm_pool_strdup(mem, buffer);
|
||||
@ -921,9 +921,22 @@ static int _lv_is_exclusive(struct logical_volume *lv)
|
||||
int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
enum activation_change activate, int needs_exclusive)
|
||||
{
|
||||
PFLA("activate=%x", activate);
|
||||
const char *ay_with_mode = NULL;
|
||||
|
||||
if (activate == CHANGE_ASY)
|
||||
ay_with_mode = "sh";
|
||||
if (activate == CHANGE_AEY)
|
||||
ay_with_mode = "ex";
|
||||
|
||||
if (is_change_activating(activate) &&
|
||||
!lockd_lv(cmd, lv, ay_with_mode, LDLV_PERSISTENT)) {
|
||||
log_error("Failed to lock logical volume %s/%s", lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (activate) {
|
||||
case CHANGE_AN:
|
||||
PFLA("activate=%x", activate);
|
||||
deactivate:
|
||||
PFL();
|
||||
log_verbose("Deactivating logical volume \"%s\"", lv->name);
|
||||
@ -968,8 +981,9 @@ PFL();
|
||||
if (!activate_lv_excl(cmd, lv))
|
||||
return_0;
|
||||
break;
|
||||
default: /* CHANGE_AY */
|
||||
PFL();
|
||||
case CHANGE_ASY:
|
||||
case CHANGE_AY:
|
||||
default:
|
||||
if (needs_exclusive || _lv_is_exclusive(lv))
|
||||
goto exclusive;
|
||||
log_verbose("Activating logical volume \"%s\".", lv->name);
|
||||
@ -977,6 +991,10 @@ PFL();
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!is_change_activating(activate) &&
|
||||
!lockd_lv(cmd, lv, "un", LDLV_PERSISTENT))
|
||||
log_error("Failed to unlock logical volume %s/%s", lv->vg->name, lv->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1016,6 +1034,12 @@ char *lv_profile_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
return dm_pool_strdup(mem, profile_name);
|
||||
}
|
||||
|
||||
char *lv_lock_args_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
const char *lock_args = lv->lock_args ? lv->lock_args : "";
|
||||
return dm_pool_strdup(mem, lock_args);
|
||||
}
|
||||
|
||||
/* For given LV find recursively the LV which holds lock for it */
|
||||
const struct logical_volume *lv_lock_holder(const struct logical_volume *lv)
|
||||
{
|
||||
|
@ -51,7 +51,9 @@ struct logical_volume {
|
||||
struct dm_list segs_using_this_lv;
|
||||
|
||||
uint64_t timestamp;
|
||||
unsigned new_lock_args:1;
|
||||
const char *hostname;
|
||||
const char *lock_args;
|
||||
};
|
||||
|
||||
struct lv_with_info_and_seg_status;
|
||||
@ -91,7 +93,7 @@ char *lvseg_monitor_dup(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_tags_dup(const struct lv_segment *seg);
|
||||
char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv, int iso_mode);
|
||||
char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
int lv_set_creation(struct logical_volume *lv,
|
||||
const char *hostname, uint64_t timestamp);
|
||||
@ -103,6 +105,7 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv);
|
||||
const struct logical_volume *lv_ondisk(const struct logical_volume *lv);
|
||||
struct profile *lv_config_profile(const struct logical_volume *lv);
|
||||
char *lv_profile_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_lock_args_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
int lv_mirror_image_in_sync(const struct logical_volume *lv);
|
||||
int lv_raid_image_in_sync(const struct logical_volume *lv);
|
||||
int lv_raid_healthy(const struct logical_volume *lv);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "lvm-exec.h"
|
||||
#include "lvm-signal.h"
|
||||
#include "memlock.h"
|
||||
#include "lvmlockd.h"
|
||||
|
||||
typedef enum {
|
||||
PREFERRED,
|
||||
@ -70,6 +71,7 @@ struct alloc_state {
|
||||
uint32_t areas_size;
|
||||
uint32_t log_area_count_still_needed; /* Number of areas still needing to be allocated for the log */
|
||||
uint32_t allocated; /* Total number of extents allocated so far */
|
||||
uint32_t num_positional_areas; /* Number of parallel allocations that must be contiguous/cling */
|
||||
};
|
||||
|
||||
struct lv_names {
|
||||
@ -1508,6 +1510,28 @@ PFLA("lv->le_count=%u", lv->le_count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_refresh_suspend_resume(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
if (!cmd->partial_activation && (lv->status & PARTIAL_LV)) {
|
||||
log_error("Refusing refresh of partial LV %s."
|
||||
" Use '--activationmode partial' to override.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!suspend_lv(cmd, lv)) {
|
||||
log_error("Failed to suspend %s.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!resume_lv(cmd, lv)) {
|
||||
log_error("Failed to reactivate %s.", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove given number of extents from LV.
|
||||
*/
|
||||
@ -2499,6 +2523,10 @@ static int _is_condition(struct cmd_context *cmd __attribute__((unused)),
|
||||
if (!pvmatch->condition(pvmatch, pvseg, pvmatch->pva))
|
||||
return 1; /* Continue */
|
||||
|
||||
if (positional && (s >= pvmatch->alloc_state->num_positional_areas))
|
||||
return 1;
|
||||
|
||||
/* FIXME The previous test should make this one redundant. */
|
||||
if (positional && (s >= pvmatch->alloc_state->areas_size))
|
||||
return 1;
|
||||
|
||||
@ -2736,6 +2764,8 @@ static void _clear_areas(struct alloc_state *alloc_state)
|
||||
{
|
||||
uint32_t s;
|
||||
|
||||
alloc_state->num_positional_areas = 0;
|
||||
|
||||
for (s = 0; s < alloc_state->areas_size; s++)
|
||||
alloc_state->areas[s].pva = NULL;
|
||||
}
|
||||
@ -2778,9 +2808,10 @@ static void _report_needed_allocation_space(struct alloc_handle *ah,
|
||||
metadata_count = alloc_state->log_area_count_still_needed;
|
||||
}
|
||||
|
||||
log_debug_alloc("Still need %s%" PRIu32 " total extents from %" PRIu32 " remaining:",
|
||||
log_debug_alloc("Still need %s%" PRIu32 " total extents from %" PRIu32 " remaining (%" PRIu32 " positional slots):",
|
||||
ah->approx_alloc ? "up to " : "",
|
||||
parallel_area_size * parallel_areas_count + metadata_size * metadata_count, pv_maps_size(pvms));
|
||||
parallel_area_size * parallel_areas_count + metadata_size * metadata_count, pv_maps_size(pvms),
|
||||
alloc_state->num_positional_areas);
|
||||
log_debug_alloc(" %" PRIu32 " (%" PRIu32 " data/%" PRIu32
|
||||
" parity) parallel areas of %" PRIu32 " extents each",
|
||||
parallel_areas_count, ah->area_count, ah->parity_count, parallel_area_size);
|
||||
@ -2835,7 +2866,6 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
struct pv_area *pva;
|
||||
unsigned preferred_count = 0;
|
||||
unsigned already_found_one;
|
||||
unsigned ix_offset = 0; /* Offset for non-preferred allocations */
|
||||
unsigned ix_log_offset; /* Offset to start of areas to use for log */
|
||||
unsigned too_small_for_log_count; /* How many too small for log? */
|
||||
unsigned iteration_count = 0; /* cling_to_alloced may need 2 iterations */
|
||||
@ -2845,27 +2875,28 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
uint32_t devices_needed = ah->area_count + ah->parity_count;
|
||||
uint32_t required;
|
||||
|
||||
/* ix_offset holds the number of parallel allocations that must be contiguous/cling */
|
||||
_clear_areas(alloc_state);
|
||||
_reset_unreserved(pvms);
|
||||
|
||||
/* num_positional_areas holds the number of parallel allocations that must be contiguous/cling */
|
||||
/* These appear first in the array, so it is also the offset to the non-preferred allocations */
|
||||
/* At most one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG or A_CLING_TO_ALLOCED may be set */
|
||||
if (!(alloc_parms->flags & A_POSITIONAL_FILL))
|
||||
ix_offset = 0;
|
||||
alloc_state->num_positional_areas = 0;
|
||||
else if (alloc_parms->flags & (A_CONTIGUOUS_TO_LVSEG | A_CLING_TO_LVSEG))
|
||||
ix_offset = _stripes_per_mimage(alloc_parms->prev_lvseg) * alloc_parms->prev_lvseg->area_count;
|
||||
alloc_state->num_positional_areas = _stripes_per_mimage(alloc_parms->prev_lvseg) * alloc_parms->prev_lvseg->area_count;
|
||||
else if (alloc_parms->flags & A_CLING_TO_ALLOCED)
|
||||
ix_offset = ah->area_count;
|
||||
alloc_state->num_positional_areas = ah->area_count;
|
||||
|
||||
if (alloc_parms->alloc == ALLOC_NORMAL || (alloc_parms->flags & A_CLING_TO_ALLOCED))
|
||||
log_debug_alloc("Cling_to_allocated is %sset",
|
||||
alloc_parms->flags & A_CLING_TO_ALLOCED ? "" : "not ");
|
||||
|
||||
if (alloc_parms->flags & A_POSITIONAL_FILL)
|
||||
log_debug_alloc("%u preferred area(s) to be filled positionally.", ix_offset);
|
||||
log_debug_alloc("%u preferred area(s) to be filled positionally.", alloc_state->num_positional_areas);
|
||||
else
|
||||
log_debug_alloc("Areas to be sorted and filled sequentially.");
|
||||
|
||||
_clear_areas(alloc_state);
|
||||
_reset_unreserved(pvms);
|
||||
|
||||
_report_needed_allocation_space(ah, alloc_state, pvms);
|
||||
|
||||
/* ix holds the number of areas found on other PVs */
|
||||
@ -2873,7 +2904,7 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
if (log_iteration_count) {
|
||||
log_debug_alloc("Found %u areas for %" PRIu32 " parallel areas and %" PRIu32 " log areas so far.", ix, devices_needed, alloc_state->log_area_count_still_needed);
|
||||
} else if (iteration_count)
|
||||
log_debug_alloc("Filled %u out of %u preferred areas so far.", preferred_count, ix_offset);
|
||||
log_debug_alloc("Filled %u out of %u preferred areas so far.", preferred_count, alloc_state->num_positional_areas);
|
||||
|
||||
/*
|
||||
* Provide for escape from the loop if no progress is made.
|
||||
@ -2914,7 +2945,7 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
* not enough for the logs.
|
||||
*/
|
||||
if (log_iteration_count) {
|
||||
for (s = devices_needed; s < ix + ix_offset; s++)
|
||||
for (s = devices_needed; s < ix + alloc_state->num_positional_areas; s++)
|
||||
if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv)
|
||||
goto next_pv;
|
||||
/* On a second pass, avoid PVs already used in an uncommitted area */
|
||||
@ -2962,8 +2993,8 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
}
|
||||
|
||||
/* Reserve required amount of pva */
|
||||
required = _calc_required_extents(ah, pva, ix + ix_offset - 1, max_to_allocate, alloc_parms->alloc);
|
||||
if (!_reserve_required_area(ah, alloc_state, pva, required, ix + ix_offset - 1, pva->unreserved))
|
||||
required = _calc_required_extents(ah, pva, ix + alloc_state->num_positional_areas - 1, max_to_allocate, alloc_parms->alloc);
|
||||
if (!_reserve_required_area(ah, alloc_state, pva, required, ix + alloc_state->num_positional_areas - 1, pva->unreserved))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@ -2974,23 +3005,23 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
/* With cling and contiguous we stop if we found a match for *all* the areas */
|
||||
/* FIXME Rename these variables! */
|
||||
if ((alloc_parms->alloc == ALLOC_ANYWHERE &&
|
||||
ix + ix_offset >= devices_needed + alloc_state->log_area_count_still_needed) ||
|
||||
(preferred_count == ix_offset &&
|
||||
(ix_offset == devices_needed + alloc_state->log_area_count_still_needed)))
|
||||
ix + alloc_state->num_positional_areas >= devices_needed + alloc_state->log_area_count_still_needed) ||
|
||||
(preferred_count == alloc_state->num_positional_areas &&
|
||||
(alloc_state->num_positional_areas == devices_needed + alloc_state->log_area_count_still_needed)))
|
||||
break;
|
||||
}
|
||||
} while ((alloc_parms->alloc == ALLOC_ANYWHERE && last_ix != ix && ix < devices_needed + alloc_state->log_area_count_still_needed) ||
|
||||
/* With cling_to_alloced and normal, if there were gaps in the preferred areas, have a second iteration */
|
||||
(alloc_parms->alloc == ALLOC_NORMAL && preferred_count &&
|
||||
(preferred_count < ix_offset || alloc_state->log_area_count_still_needed) &&
|
||||
(preferred_count < alloc_state->num_positional_areas || alloc_state->log_area_count_still_needed) &&
|
||||
(alloc_parms->flags & A_CLING_TO_ALLOCED) && !iteration_count++) ||
|
||||
/* Extra iteration needed to fill log areas on PVs already used? */
|
||||
(alloc_parms->alloc == ALLOC_NORMAL && preferred_count == ix_offset && !ah->mirror_logs_separate &&
|
||||
(alloc_parms->alloc == ALLOC_NORMAL && preferred_count == alloc_state->num_positional_areas && !ah->mirror_logs_separate &&
|
||||
(ix + preferred_count >= devices_needed) &&
|
||||
(ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed) && !log_iteration_count++));
|
||||
|
||||
/* Non-zero ix means at least one USE_AREA was returned */
|
||||
if (preferred_count < ix_offset && !(alloc_parms->flags & A_CLING_TO_ALLOCED) && !ix)
|
||||
if (preferred_count < alloc_state->num_positional_areas && !(alloc_parms->flags & A_CLING_TO_ALLOCED) && !ix)
|
||||
return 1;
|
||||
|
||||
if (ix + preferred_count < devices_needed + alloc_state->log_area_count_still_needed)
|
||||
@ -3005,17 +3036,17 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
}
|
||||
} else if (ix > 1) {
|
||||
log_debug_alloc("Sorting %u areas", ix);
|
||||
qsort(alloc_state->areas + ix_offset, ix, sizeof(*alloc_state->areas),
|
||||
qsort(alloc_state->areas + alloc_state->num_positional_areas, ix, sizeof(*alloc_state->areas),
|
||||
_comp_area);
|
||||
}
|
||||
|
||||
/* If there are gaps in our preferred areas, fill them from the sorted part of the array */
|
||||
if (preferred_count && preferred_count != ix_offset) {
|
||||
if (preferred_count && preferred_count != alloc_state->num_positional_areas) {
|
||||
for (s = 0; s < devices_needed; s++)
|
||||
if (!alloc_state->areas[s].pva) {
|
||||
alloc_state->areas[s].pva = alloc_state->areas[ix_offset].pva;
|
||||
alloc_state->areas[s].used = alloc_state->areas[ix_offset].used;
|
||||
alloc_state->areas[ix_offset++].pva = NULL;
|
||||
alloc_state->areas[s].pva = alloc_state->areas[alloc_state->num_positional_areas].pva;
|
||||
alloc_state->areas[s].used = alloc_state->areas[alloc_state->num_positional_areas].used;
|
||||
alloc_state->areas[alloc_state->num_positional_areas++].pva = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3029,14 +3060,14 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
/* FIXME This logic is due to its heritage and can be simplified! */
|
||||
if (alloc_state->log_area_count_still_needed) {
|
||||
/* How many areas are too small for the log? */
|
||||
while (too_small_for_log_count < ix_offset + ix &&
|
||||
(*(alloc_state->areas + ix_offset + ix - 1 -
|
||||
while (too_small_for_log_count < alloc_state->num_positional_areas + ix &&
|
||||
(*(alloc_state->areas + alloc_state->num_positional_areas + ix - 1 -
|
||||
too_small_for_log_count)).used < ah->log_len)
|
||||
too_small_for_log_count++;
|
||||
ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
|
||||
ix_log_offset = alloc_state->num_positional_areas + ix - too_small_for_log_count - ah->log_area_count;
|
||||
}
|
||||
|
||||
if (ix + ix_offset < devices_needed +
|
||||
if (ix + alloc_state->num_positional_areas < devices_needed +
|
||||
(alloc_state->log_area_count_still_needed ? alloc_state->log_area_count_still_needed +
|
||||
too_small_for_log_count : 0))
|
||||
return 1;
|
||||
@ -3050,12 +3081,12 @@ static int _find_some_parallel_space(struct alloc_handle *ah,
|
||||
/*
|
||||
* This code covers the initial allocation - after that there is something to 'cling' to
|
||||
* and we shouldn't get this far.
|
||||
* ix_offset is assumed to be 0 with A_PARTITION_BY_TAGS.
|
||||
* alloc_state->num_positional_areas is assumed to be 0 with A_PARTITION_BY_TAGS.
|
||||
*
|
||||
* FIXME Consider a second attempt with A_PARTITION_BY_TAGS if, for example, the largest area
|
||||
* had all the tags set, but other areas don't.
|
||||
*/
|
||||
if ((alloc_parms->flags & A_PARTITION_BY_TAGS) && !ix_offset) {
|
||||
if ((alloc_parms->flags & A_PARTITION_BY_TAGS) && !alloc_state->num_positional_areas) {
|
||||
if (!_limit_to_one_area_per_tag(ah, alloc_state, ix_log_offset, &ix))
|
||||
return_0;
|
||||
|
||||
@ -4376,6 +4407,18 @@ int lv_rename_update(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lvmlockd LV lock is only acquired here to ensure the LV is not
|
||||
* active on another host. This requests a transient LV lock.
|
||||
* If the LV is active, a persistent LV lock already exists in
|
||||
* lvmlockd, and the transient lock request does nothing.
|
||||
* If the LV is not active, then no LV lock exists and the transient
|
||||
* lock request acquires the LV lock (or fails). The transient lock
|
||||
* is automatically released when the command exits.
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0))
|
||||
return_0;
|
||||
|
||||
if (update_mda && !archive(vg))
|
||||
return_0;
|
||||
|
||||
@ -4535,7 +4578,7 @@ static int _fsadm_cmd(struct cmd_context *cmd,
|
||||
argv[i++] = lv_path;
|
||||
|
||||
if (fcmd == FSADM_CMD_RESIZE) {
|
||||
if (dm_snprintf(size_buf, sizeof(size_buf), "%" PRIu64 "K",
|
||||
if (dm_snprintf(size_buf, sizeof(size_buf), FMTu64 "K",
|
||||
(uint64_t) lp->extents * (vg->extent_size / 2)) < 0) {
|
||||
log_error("Couldn't generate new LV size string");
|
||||
return 0;
|
||||
@ -4768,7 +4811,9 @@ static int _lvresize_check_lv(struct cmd_context *cmd, struct logical_volume *lv
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_is_visible(lv) && !lv_is_thin_pool_metadata(lv)) {
|
||||
/* FIXME: use a status flag instead of the name "lvmlock". */
|
||||
|
||||
if (!lv_is_visible(lv) && !lv_is_thin_pool_metadata(lv) && strcmp(lv->name, "lvmlock")) {
|
||||
log_error("Can't resize internal logical volume %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
@ -5268,16 +5313,6 @@ static int _lvresize_check_type(struct cmd_context *cmd, const struct logical_vo
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv &&
|
||||
(lp->resize == LV_EXTEND)) {
|
||||
/*
|
||||
* TODO: currently we do not support extension of already reduced thin volume.
|
||||
* But it might be possible to create combined mapping of some part of
|
||||
* the external origin followed by zero target.
|
||||
*/
|
||||
if (first_seg(lv)->external_lv->size > lv->size) {
|
||||
log_error("Extension of reduced thin volume with external origin is unsupported.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Validate thin target supports bigger size of thin volume then external origin */
|
||||
if (first_seg(lv)->external_lv->size <= lv->size &&
|
||||
!thin_pool_feature_supported(first_seg(lv)->pool_lv, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND)) {
|
||||
@ -5358,6 +5393,8 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd,
|
||||
lp->extents - (lv->le_count - first_seg(lv)->reshape_len),
|
||||
pvh, alloc, lp->approx_alloc))
|
||||
return_NULL;
|
||||
else if (!pool_check_overprovisioning(lv))
|
||||
return_NULL;
|
||||
|
||||
if (old_extents == lv->le_count)
|
||||
log_print_unless_silent("Size of logical volume %s unchanged from %s (%" PRIu32 " extents).",
|
||||
@ -5432,6 +5469,13 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the LV is locked from activation, this lock call is a no-op.
|
||||
* Otherwise, this acquires a transient lock on the lv (not PERSISTENT).
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0))
|
||||
return_0;
|
||||
|
||||
if (lp->sizeargs &&
|
||||
!(lock_lv = _lvresize_volume(cmd, lv, lp, pvh)))
|
||||
return_0;
|
||||
@ -5792,6 +5836,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int format1_reload_required = 0;
|
||||
int visible;
|
||||
struct logical_volume *pool_lv = NULL;
|
||||
struct logical_volume *lock_lv = lv;
|
||||
struct lv_segment *cache_seg = NULL;
|
||||
int ask_discard;
|
||||
struct lv_list *lvl;
|
||||
@ -5838,14 +5883,19 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
log_error("Can't remove logical volume %s used by a pool.",
|
||||
lv->name);
|
||||
return 0;
|
||||
} else if (lv_is_thin_volume(lv))
|
||||
} else if (lv_is_thin_volume(lv)) {
|
||||
pool_lv = first_seg(lv)->pool_lv;
|
||||
lock_lv = pool_lv;
|
||||
}
|
||||
|
||||
if (lv_is_locked(lv)) {
|
||||
log_error("Can't remove locked LV %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lockd_lv(cmd, lock_lv, "ex", LDLV_PERSISTENT))
|
||||
return_0;
|
||||
|
||||
/* FIXME Ensure not referred to by another existing LVs */
|
||||
ask_discard = find_config_tree_bool(cmd, devices_issue_discards_CFG, NULL);
|
||||
|
||||
@ -6020,6 +6070,9 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
backup(vg);
|
||||
|
||||
lockd_lv(cmd, lock_lv, "un", LDLV_PERSISTENT);
|
||||
lockd_free_lv(cmd, vg, lv->name, &lv->lvid.id[1], lv->lock_args);
|
||||
|
||||
if (!suppress_remove_message && visible)
|
||||
log_print_unless_silent("Logical volume \"%s\" successfully removed", lv->name);
|
||||
|
||||
@ -6353,7 +6406,7 @@ int remove_layers_for_segments(struct cmd_context *cmd,
|
||||
log_error("Layer boundary mismatch: "
|
||||
"%s:%" PRIu32 "-%" PRIu32 " on "
|
||||
"%s:%" PRIu32 " / "
|
||||
"%" PRIu32 "-%" PRIu32 " / ",
|
||||
FMTu32 "-" FMTu32 " / ",
|
||||
lv->name, seg->le, seg->area_len,
|
||||
layer_lv->name, seg_le(seg, s),
|
||||
lseg->le, lseg->area_len);
|
||||
@ -6854,7 +6907,12 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
|
||||
/* nothing to do */
|
||||
return 1;
|
||||
|
||||
sync_local_dev_names(lv->vg->cmd); /* Wait until devices are available */
|
||||
/* Wait until devices are available */
|
||||
if (!sync_local_dev_names(lv->vg->cmd)) {
|
||||
log_error("Failed to sync local devices before wiping LV %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_is_active_locally(lv)) {
|
||||
log_error("Volume \"%s/%s\" is not active locally.",
|
||||
@ -7175,7 +7233,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
|
||||
if (seg_is_pool(lp))
|
||||
status |= LVM_WRITE; /* Pool is always writable */
|
||||
else if (seg_is_cache(lp) || seg_is_thin_volume(lp)) {
|
||||
else if (seg_is_cache(lp) || seg_is_thin_volume(lp)) {
|
||||
/* Resolve pool volume */
|
||||
if (!lp->pool_name) {
|
||||
/* Should be already checked */
|
||||
@ -7251,7 +7309,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
display_lvname(origin_lv));
|
||||
return NULL;
|
||||
}
|
||||
} else if (pool_lv && seg_is_cache(lp)) {
|
||||
} else if (seg_is_cache(lp)) {
|
||||
if (!pool_lv) {
|
||||
log_error(INTERNAL_ERROR "Pool LV for cache is missing.");
|
||||
return NULL;
|
||||
}
|
||||
if (!lv_is_cache_pool(pool_lv)) {
|
||||
log_error("Logical volume %s is not a cache pool.",
|
||||
display_lvname(pool_lv));
|
||||
@ -7400,6 +7462,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
if (!archive(vg))
|
||||
return_NULL;
|
||||
|
||||
|
||||
if (pool_lv && seg_is_thin_volume(lp)) {
|
||||
/* Ensure all stacked messages are submitted */
|
||||
if ((pool_is_active(pool_lv) || is_change_activating(lp->activate)) &&
|
||||
@ -7424,6 +7487,14 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
lv->major, lv->minor);
|
||||
}
|
||||
|
||||
/*
|
||||
* The specific LV may not use a lock. lockd_init_lv() sets
|
||||
* lv->lock_args to NULL if this LV does not use its own lock.
|
||||
*/
|
||||
|
||||
if (!lockd_init_lv(vg->cmd, vg, lv, lp))
|
||||
return_NULL;
|
||||
|
||||
dm_list_splice(&lv->tags, &lp->tags);
|
||||
|
||||
if (!lv_extend(lv, create_segtype,
|
||||
@ -7438,15 +7509,26 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
memlock_unlock(vg->cmd);
|
||||
|
||||
if (seg_is_cache_pool(lp) || seg_is_cache(lp)) {
|
||||
pool_lv = pool_lv ? : lv;
|
||||
first_seg(pool_lv)->chunk_size = lp->chunk_size;
|
||||
first_seg(pool_lv)->feature_flags = lp->feature_flags;
|
||||
/* TODO: some calc_policy solution for cache ? */
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
|
||||
THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
|
||||
if (!cache_set_mode(first_seg(lv), lp->cache_mode)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
pool_lv = pool_lv ? : lv;
|
||||
if (lp->chunk_size) {
|
||||
first_seg(pool_lv)->chunk_size = lp->chunk_size;
|
||||
/* TODO: some calc_policy solution for cache ? */
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
|
||||
THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
}
|
||||
} else if (seg_is_raid(lp)) {
|
||||
if (!(seg_is_raid0(lp) || seg_is_raid0_meta(lp))) {
|
||||
first_seg(lv)->min_recovery_rate = lp->min_recovery_rate;
|
||||
@ -7493,6 +7575,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
if (!pool_check_overprovisioning(lv))
|
||||
return_NULL;
|
||||
|
||||
/* FIXME Log allocation and attachment should have happened inside lv_extend. */
|
||||
if (lp->log_count &&
|
||||
!seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) {
|
||||
@ -7567,11 +7652,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
/* When change is activating, don't duplicate backup call */
|
||||
if (!is_change_activating(lp->activate))
|
||||
backup(vg);
|
||||
}
|
||||
if (is_change_activating(lp->activate)) {
|
||||
if (!dm_list_empty(&first_seg(pool_lv)->thin_messages)) {
|
||||
/* Send message so that table preload knows new thin */
|
||||
if (!lv_is_active(pool_lv)) {
|
||||
/* Avoid multiple thin-pool activations in this case */
|
||||
@ -7589,25 +7671,24 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
/* Keep thin pool active until thin volume is activated */
|
||||
if (!update_pool_lv(pool_lv, (thin_pool_was_active < 0) ? 1 : 0)) {
|
||||
if (!update_pool_lv(pool_lv, 1)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
}
|
||||
backup(vg);
|
||||
|
||||
backup(vg);
|
||||
if (!lv_active_change(cmd, lv, lp->activate, 0)) {
|
||||
log_error("Failed to activate thin %s.", lv->name);
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
if (!lv_active_change(cmd, lv, lp->activate, 0)) {
|
||||
log_error("Failed to activate thin %s.", lv->name);
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
/* Restore inactive state if needed */
|
||||
if (!thin_pool_was_active &&
|
||||
!deactivate_lv(cmd, pool_lv)) {
|
||||
log_error("Failed to deactivate thin pool %s.",
|
||||
display_lvname(pool_lv));
|
||||
return NULL;
|
||||
}
|
||||
/* Restore inactive state if needed */
|
||||
if (!thin_pool_was_active &&
|
||||
!deactivate_lv(cmd, pool_lv)) {
|
||||
log_error("Failed to deactivate thin pool %s.",
|
||||
display_lvname(pool_lv));
|
||||
return NULL;
|
||||
}
|
||||
} else if (lp->snapshot) {
|
||||
lv->status |= LV_TEMPORARY;
|
||||
@ -7636,13 +7717,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_is_cache_pool(lv) && !origin_lv) {
|
||||
if (lp->cache_policy && !lv_cache_setpolicy(lv, lp->cache_policy))
|
||||
return NULL; /* revert? */
|
||||
if (!lv_update_and_reload(lv))
|
||||
return NULL; /* FIXME: revert */
|
||||
}
|
||||
|
||||
if (seg_is_cache(lp) || (origin_lv && lv_is_cache_pool(lv))) {
|
||||
/* Finish cache conversion magic */
|
||||
if (origin_lv) {
|
||||
@ -7662,8 +7736,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
lv = tmp_lv;
|
||||
|
||||
if (lp->cache_policy && !lv_cache_setpolicy(lv, lp->cache_policy))
|
||||
return NULL; /* revert? */
|
||||
if (!cache_set_mode(first_seg(lv), lp->cache_mode))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings))
|
||||
return_NULL; /* revert? */
|
||||
|
||||
if (!lv_update_and_reload(lv)) {
|
||||
/* FIXME Do a better revert */
|
||||
@ -7678,6 +7755,13 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
goto deactivate_and_revert_new_lv; /* Let's retry on error path */
|
||||
}
|
||||
|
||||
/* Get in sync with deactivation, before reusing LV as snapshot */
|
||||
if (!sync_local_dev_names(lv->vg->cmd)) {
|
||||
log_error("Failed to sync local devices before creating snapshot using %s.",
|
||||
display_lvname(lv));
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
/* Create zero origin volume for spare snapshot */
|
||||
if (lp->virtual_extents &&
|
||||
!(origin_lv = _create_virtual_origin(cmd, vg, lv->name,
|
||||
@ -7735,6 +7819,8 @@ deactivate_and_revert_new_lv:
|
||||
}
|
||||
|
||||
revert_new_lv:
|
||||
lockd_free_lv(vg->cmd, vg, lp->lv_name, &lv->lvid.id[1], lp->lock_args);
|
||||
|
||||
/* FIXME Better to revert to backup of metadata? */
|
||||
if (!lv_remove(lv) || !vg_write(vg) || !vg_commit(vg))
|
||||
log_error("Manual intervention may be required to remove "
|
||||
|
@ -218,6 +218,26 @@ PFLA("segtype=%s seg->area_len=%u seg->area_count=%u parity_devs=%u area_multipl
|
||||
}
|
||||
|
||||
}
|
||||
if (seg_is_cache_pool(seg) &&
|
||||
!dm_list_empty(&seg->lv->segs_using_this_lv)) {
|
||||
switch (seg->feature_flags &
|
||||
(DM_CACHE_FEATURE_PASSTHROUGH |
|
||||
DM_CACHE_FEATURE_WRITETHROUGH |
|
||||
DM_CACHE_FEATURE_WRITEBACK)) {
|
||||
case DM_CACHE_FEATURE_PASSTHROUGH:
|
||||
case DM_CACHE_FEATURE_WRITETHROUGH:
|
||||
case DM_CACHE_FEATURE_WRITEBACK:
|
||||
break;
|
||||
default:
|
||||
log_error("LV %s has invalid cache's feature flag.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (!seg->policy_name) {
|
||||
log_error("LV %s is missing cache policy name.", lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
if (seg_is_pool(seg)) {
|
||||
if (seg->area_count != 1 ||
|
||||
seg_type(seg, 0) != AREA_LV) {
|
||||
@ -241,8 +261,7 @@ PFLA("segtype=%s seg->area_len=%u seg->area_count=%u parity_devs=%u area_multipl
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (seg_is_pool(seg) &&
|
||||
!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size)) {
|
||||
if (!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size)) {
|
||||
log_error("LV %s: %s segment %u has invalid chunk size %u.",
|
||||
lv->name, seg->segtype->name, seg_count, seg->chunk_size);
|
||||
inc_error_count;
|
||||
|
@ -101,7 +101,6 @@
|
||||
#define THIN_POOL_DATA UINT64_C(0x0000004000000000) /* LV - Internal use only */
|
||||
#define THIN_POOL_METADATA UINT64_C(0x0000008000000000) /* LV - Internal use only */
|
||||
#define POOL_METADATA_SPARE UINT64_C(0x0000010000000000) /* LV - Internal use only */
|
||||
|
||||
#define LV_WRITEMOSTLY UINT64_C(0x0000020000000000) /* LV (RAID1) */
|
||||
|
||||
#define LV_ACTIVATION_SKIP UINT64_C(0x0000040000000000) /* LV */
|
||||
@ -137,7 +136,8 @@
|
||||
vg->removed_lvs for quick lookup.
|
||||
*/
|
||||
#define LV_ERROR_WHEN_FULL UINT64_C(0x0080000000000000) /* LV - error when full */
|
||||
/* Next unused flag: UINT64_C(0x0100000000000000) */
|
||||
#define LOCKD_SANLOCK_LV UINT64_C(0x0100000000000000) /* LV - Internal use only */
|
||||
/* Next unused flag: UINT64_C(0x0200000000000000) */
|
||||
|
||||
/* Format features flags */
|
||||
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
|
||||
@ -186,6 +186,7 @@
|
||||
#define FAILED_RECOVERY 0x00000200U
|
||||
#define FAILED_SYSTEMID 0x00000400U
|
||||
#define FAILED_LOCK_TYPE 0x00000800U
|
||||
#define FAILED_LOCK_MODE 0x00001000U
|
||||
#define SUCCESS 0x00000000U
|
||||
|
||||
#define VGMETADATACOPIES_ALL UINT32_MAX
|
||||
@ -233,6 +234,7 @@
|
||||
#define lv_is_pool_data(lv) (((lv)->status & (CACHE_POOL_DATA | THIN_POOL_DATA)) ? 1 : 0)
|
||||
#define lv_is_pool_metadata(lv) (((lv)->status & (CACHE_POOL_METADATA | THIN_POOL_METADATA)) ? 1 : 0)
|
||||
#define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
|
||||
#define lv_is_lockd_sanlock_lv(lv) (((lv)->status & LOCKD_SANLOCK_LV) ? 1 : 0)
|
||||
|
||||
#define lv_is_rlog(lv) (((lv)->status & REPLICATOR_LOG) ? 1 : 0)
|
||||
|
||||
@ -267,6 +269,14 @@ typedef enum {
|
||||
THIN_DISCARDS_PASSDOWN,
|
||||
} thin_discards_t;
|
||||
|
||||
typedef enum {
|
||||
LOCK_TYPE_INVALID = -1,
|
||||
LOCK_TYPE_NONE = 0,
|
||||
LOCK_TYPE_CLVM = 1,
|
||||
LOCK_TYPE_DLM = 2,
|
||||
LOCK_TYPE_SANLOCK = 3,
|
||||
} lock_type_t;
|
||||
|
||||
struct cmd_context;
|
||||
struct format_handler;
|
||||
struct labeller;
|
||||
@ -649,9 +659,9 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
* Return a handle to VG metadata.
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags);
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state);
|
||||
struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags);
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state);
|
||||
|
||||
/*
|
||||
* Test validity of a VG handle.
|
||||
@ -694,6 +704,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name);
|
||||
int vg_remove_mdas(struct volume_group *vg);
|
||||
int vg_remove_check(struct volume_group *vg);
|
||||
void vg_remove_pvs(struct volume_group *vg);
|
||||
int vg_remove_direct(struct volume_group *vg);
|
||||
int vg_remove(struct volume_group *vg);
|
||||
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *new_name);
|
||||
@ -747,6 +758,8 @@ int lv_empty(struct logical_volume *lv);
|
||||
/* Empty an LV and add error segment */
|
||||
int replace_lv_with_error_segment(struct logical_volume *lv);
|
||||
|
||||
int lv_refresh_suspend_resume(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
/* Entry point for all LV extent allocations */
|
||||
int lv_extend(struct logical_volume *lv,
|
||||
const struct segment_type *segtype,
|
||||
@ -837,7 +850,8 @@ typedef enum activation_change {
|
||||
CHANGE_AEY = 2, /* activate exclusively */
|
||||
CHANGE_ALY = 3, /* activate locally */
|
||||
CHANGE_ALN = 4, /* deactivate locally */
|
||||
CHANGE_AAY = 5 /* automatic activation */
|
||||
CHANGE_AAY = 5, /* automatic activation */
|
||||
CHANGE_ASY = 6 /* activate shared */
|
||||
} activation_change_t;
|
||||
|
||||
/* Returns true, when change activates device */
|
||||
@ -869,12 +883,15 @@ struct lvcreate_params {
|
||||
#define THIN_CHUNK_SIZE_CALC_METHOD_GENERIC 0x01
|
||||
#define THIN_CHUNK_SIZE_CALC_METHOD_PERFORMANCE 0x02
|
||||
int thin_chunk_size_calc_policy;
|
||||
unsigned needs_lockd_init : 1;
|
||||
|
||||
const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
|
||||
const char *lv_name; /* all */
|
||||
const char *origin_name; /* snap */
|
||||
const char *pool_name; /* thin */
|
||||
|
||||
const char *lock_args;
|
||||
|
||||
/* Keep args given by the user on command line */
|
||||
/* FIXME: create some more universal solution here */
|
||||
#define PASS_ARG_CHUNK_SIZE 0x01
|
||||
@ -893,8 +910,9 @@ struct lvcreate_params {
|
||||
uint32_t min_recovery_rate; /* RAID */
|
||||
uint32_t max_recovery_rate; /* RAID */
|
||||
|
||||
uint64_t feature_flags; /* cache */
|
||||
struct dm_config_tree *cache_policy; /* cache */
|
||||
const char *cache_mode; /* cache */
|
||||
const char *policy_name; /* cache */
|
||||
struct dm_config_tree *policy_settings; /* cache */
|
||||
|
||||
const struct segment_type *segtype; /* all */
|
||||
unsigned target_attr; /* all */
|
||||
@ -1150,8 +1168,11 @@ struct lv_status_cache {
|
||||
dm_percent_t dirty_usage;
|
||||
};
|
||||
|
||||
const char *get_cache_pool_cachemode_name(const struct lv_segment *seg);
|
||||
int set_cache_pool_feature(uint64_t *feature_flags, const char *str);
|
||||
const char *get_cache_mode_name(const struct lv_segment *cache_seg);
|
||||
int cache_mode_is_set(const struct lv_segment *seg);
|
||||
int cache_set_mode(struct lv_segment *cache_seg, const char *str);
|
||||
int cache_set_policy(struct lv_segment *cache_seg, const char *name,
|
||||
const struct dm_config_tree *settings);
|
||||
int update_cache_pool_params(const struct segment_type *segtype,
|
||||
struct volume_group *vg, unsigned attr,
|
||||
int passed_args, uint32_t pool_data_extents,
|
||||
@ -1162,7 +1183,6 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv);
|
||||
struct logical_volume *lv_cache_create(struct logical_volume *pool,
|
||||
struct logical_volume *origin);
|
||||
int lv_cache_remove(struct logical_volume *cache_lv);
|
||||
int lv_cache_setpolicy(struct logical_volume *cache_lv, struct dm_config_tree *pol);
|
||||
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
|
||||
/* -- metadata/cache_manip.c */
|
||||
|
||||
@ -1223,6 +1243,8 @@ struct vgcreate_params {
|
||||
int clustered; /* FIXME: put this into a 'status' variable instead? */
|
||||
uint32_t vgmetadatacopies;
|
||||
const char *system_id;
|
||||
const char *lock_type;
|
||||
const char *lock_args;
|
||||
};
|
||||
|
||||
int validate_major_minor(const struct cmd_context *cmd,
|
||||
@ -1234,4 +1256,7 @@ int vgcreate_params_validate(struct cmd_context *cmd,
|
||||
int validate_vg_rename_params(struct cmd_context *cmd,
|
||||
const char *vg_name_old,
|
||||
const char *vg_name_new);
|
||||
|
||||
int is_lockd_type(const char *lock_type);
|
||||
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "locking.h"
|
||||
#include "archiver.h"
|
||||
#include "defaults.h"
|
||||
#include "lvmlockd.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <sys/param.h>
|
||||
@ -557,20 +558,14 @@ void vg_remove_pvs(struct volume_group *vg)
|
||||
}
|
||||
}
|
||||
|
||||
int vg_remove(struct volume_group *vg)
|
||||
int vg_remove_direct(struct volume_group *vg)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
int ret = 1;
|
||||
|
||||
if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_remove_mdas(vg)) {
|
||||
log_error("vg_remove_mdas %s failed", vg->name);
|
||||
unlock_vg(vg->cmd, VG_ORPHANS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -604,6 +599,8 @@ int vg_remove(struct volume_group *vg)
|
||||
if (!lvmetad_vg_remove(vg))
|
||||
stack;
|
||||
|
||||
lockd_vg_update(vg);
|
||||
|
||||
if (!backup_remove(vg->cmd, vg->name))
|
||||
stack;
|
||||
|
||||
@ -612,6 +609,20 @@ int vg_remove(struct volume_group *vg)
|
||||
else
|
||||
log_error("Volume group \"%s\" not properly removed", vg->name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vg_remove(struct volume_group *vg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE, NULL)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vg_remove_direct(vg);
|
||||
|
||||
unlock_vg(vg->cmd, VG_ORPHANS);
|
||||
return ret;
|
||||
}
|
||||
@ -2428,6 +2439,7 @@ struct validate_hash {
|
||||
struct dm_hash_table *lvname;
|
||||
struct dm_hash_table *lvid;
|
||||
struct dm_hash_table *pvid;
|
||||
struct dm_hash_table *lv_lock_args;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2472,6 +2484,75 @@ static int _lv_validate_references_single(struct logical_volume *lv, void *data)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Format is <version>:<info>
|
||||
*/
|
||||
static int _validate_lock_args_chars(const char *lock_args)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
int found_colon = 0;
|
||||
int r = 1;
|
||||
|
||||
for (i = 0; i < strlen(lock_args); i++) {
|
||||
c = lock_args[i];
|
||||
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+' && c != ':') {
|
||||
log_error(INTERNAL_ERROR "Invalid character at index %d of lock_args \"%s\"",
|
||||
i, lock_args);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (c == ':' && found_colon) {
|
||||
log_error(INTERNAL_ERROR "Invalid colon at index %d of lock_args \"%s\"",
|
||||
i, lock_args);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (c == ':')
|
||||
found_colon = 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _validate_vg_lock_args(struct volume_group *vg)
|
||||
{
|
||||
if (!_validate_lock_args_chars(vg->lock_args)) {
|
||||
log_error(INTERNAL_ERROR "VG %s has invalid lock_args chars", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For lock_type sanlock, LV lock_args are <version>:<info>
|
||||
* For lock_type dlm, LV lock_args are not used, and lock_args is
|
||||
* just set to "dlm".
|
||||
*/
|
||||
static int _validate_lv_lock_args(struct logical_volume *lv)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (!strcmp(lv->vg->lock_type, "sanlock")) {
|
||||
if (!_validate_lock_args_chars(lv->lock_args)) {
|
||||
log_error(INTERNAL_ERROR "LV %s/%s has invalid lock_args chars",
|
||||
lv->vg->name, display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (!strcmp(lv->vg->lock_type, "dlm")) {
|
||||
if (strcmp(lv->lock_args, "dlm")) {
|
||||
log_error(INTERNAL_ERROR "LV %s/%s has invalid lock_args \"%s\"",
|
||||
lv->vg->name, display_lvname(lv), lv->lock_args);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int vg_validate(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
@ -2786,6 +2867,129 @@ int vg_validate(struct volume_group *vg)
|
||||
|
||||
if (vg_max_lv_reached(vg))
|
||||
stack;
|
||||
|
||||
if (!(vhash.lv_lock_args = dm_hash_create(lv_count))) {
|
||||
log_error("Failed to allocate lv_lock_args hash");
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_lockd_type(vg->lock_type)) {
|
||||
if (!vg->lock_args) {
|
||||
log_error(INTERNAL_ERROR "VG %s with lock_type %s without lock_args",
|
||||
vg->name, vg->lock_type);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (vg_is_clustered(vg)) {
|
||||
log_error(INTERNAL_ERROR "VG %s with lock_type %s is clustered",
|
||||
vg->name, vg->lock_type);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (vg->system_id && vg->system_id[0]) {
|
||||
log_error(INTERNAL_ERROR "VG %s with lock_type %s has system_id %s",
|
||||
vg->name, vg->lock_type, vg->system_id);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (strcmp(vg->lock_type, "sanlock") && strcmp(vg->lock_type, "dlm")) {
|
||||
log_error(INTERNAL_ERROR "VG %s has unknown lock_type %s",
|
||||
vg->name, vg->lock_type);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!_validate_vg_lock_args(vg))
|
||||
r = 0;
|
||||
} else {
|
||||
if (vg->lock_args) {
|
||||
log_error(INTERNAL_ERROR "VG %s has lock_args %s without lock_type",
|
||||
vg->name, vg->lock_args);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (is_lockd_type(vg->lock_type)) {
|
||||
if (lockd_lv_uses_lock(lvl->lv)) {
|
||||
if (vg->skip_validate_lock_args)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* FIXME: make missing lock_args an error.
|
||||
* There are at least two cases where this
|
||||
* check doesn't work correctly:
|
||||
*
|
||||
* 1. When creating a cow snapshot,
|
||||
* (lvcreate -s -L1M -n snap1 vg/lv1),
|
||||
* lockd_lv_uses_lock() uses lv_is_cow()
|
||||
* which depends on lv->snapshot being
|
||||
* set, but it's not set at this point,
|
||||
* so lockd_lv_uses_lock() cannot identify
|
||||
* the LV as a cow_lv, and thinks it needs
|
||||
* a lock when it doesn't. To fix this we
|
||||
* probably need to validate by finding the
|
||||
* origin LV, then finding all its snapshots
|
||||
* which will have no lock_args.
|
||||
*
|
||||
* 2. When converting an LV to a thin pool
|
||||
* without using an existing metadata LV,
|
||||
* (lvconvert --type thin-pool vg/poolX),
|
||||
* there is an intermediate LV created,
|
||||
* probably for the metadata LV, and
|
||||
* validate is called on the VG in this
|
||||
* intermediate state, which finds the
|
||||
* newly created LV which is not yet
|
||||
* identified as a metadata LV, and
|
||||
* does not have any lock_args. To fix
|
||||
* this we might be able to find the place
|
||||
* where the intermediate LV is created,
|
||||
* and set new variable on it like for vgs,
|
||||
* lv->skip_validate_lock_args.
|
||||
*/
|
||||
if (!lvl->lv->lock_args) {
|
||||
/*
|
||||
log_verbose("LV %s/%s missing lock_args",
|
||||
vg->name, lvl->lv->name);
|
||||
r = 0;
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_validate_lv_lock_args(lvl->lv)) {
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(vg->lock_type, "sanlock")) {
|
||||
if (dm_hash_lookup(vhash.lv_lock_args, lvl->lv->lock_args)) {
|
||||
log_error(INTERNAL_ERROR "LV %s/%s has duplicate lock_args %s.",
|
||||
vg->name, lvl->lv->name, lvl->lv->lock_args);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(vhash.lv_lock_args, lvl->lv->lock_args, lvl)) {
|
||||
log_error("Failed to hash lvname.");
|
||||
r = 0;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (lvl->lv->lock_args) {
|
||||
log_error(INTERNAL_ERROR "LV %s/%s shouldn't have lock_args",
|
||||
vg->name, lvl->lv->name);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lvl->lv->lock_args) {
|
||||
log_error(INTERNAL_ERROR "LV %s/%s with no lock_type has lock_args %s",
|
||||
vg->name, lvl->lv->name, lvl->lv->lock_args);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (vhash.lvid)
|
||||
dm_hash_destroy(vhash.lvid);
|
||||
@ -2793,6 +2997,8 @@ out:
|
||||
dm_hash_destroy(vhash.lvname);
|
||||
if (vhash.pvid)
|
||||
dm_hash_destroy(vhash.pvid);
|
||||
if (vhash.lv_lock_args)
|
||||
dm_hash_destroy(vhash.lv_lock_args);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -2806,8 +3012,19 @@ int vg_write(struct volume_group *vg)
|
||||
struct dm_list *mdah;
|
||||
struct pv_to_create *pv_to_create;
|
||||
struct metadata_area *mda;
|
||||
struct lv_list *lvl;
|
||||
int revert = 0, wrote = 0;
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->lock_args && !strcmp(lvl->lv->lock_args, "pending")) {
|
||||
if (!lockd_init_lv_args(vg->cmd, vg, lvl->lv, vg->lock_type, &lvl->lv->lock_args)) {
|
||||
log_error("Cannot allocate lock for new LV.");
|
||||
return 0;
|
||||
}
|
||||
lvl->lv->new_lock_args = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vg_validate(vg))
|
||||
return_0;
|
||||
|
||||
@ -2974,6 +3191,8 @@ int vg_commit(struct volume_group *vg)
|
||||
|
||||
cache_updated = _vg_commit_mdas(vg);
|
||||
|
||||
lockd_vg_update(vg);
|
||||
|
||||
if (cache_updated) {
|
||||
/* Instruct remote nodes to upgrade cached metadata. */
|
||||
if (!remote_commit_cached_metadata(vg))
|
||||
@ -3007,6 +3226,14 @@ int vg_commit(struct volume_group *vg)
|
||||
void vg_revert(struct volume_group *vg)
|
||||
{
|
||||
struct metadata_area *mda;
|
||||
struct lv_list *lvl;
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->new_lock_args) {
|
||||
lockd_free_lv(vg->cmd, vg, lvl->lv->name, &lvl->lv->lvid.id[1], lvl->lv->lock_args);
|
||||
lvl->lv->new_lock_args = 0;
|
||||
}
|
||||
}
|
||||
|
||||
release_vg(vg->vg_precommitted); /* VG is no longer needed */
|
||||
vg->vg_precommitted = NULL;
|
||||
@ -3241,7 +3468,10 @@ static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return_0;
|
||||
|
||||
/* Refresh metadata after orphan write */
|
||||
drop_cached_metadata(vg);
|
||||
if (!drop_cached_metadata(vg)) {
|
||||
log_error("Unable to drop cached metadata for VG %s while wiping outdated PVs.", vg->name);
|
||||
return 0;
|
||||
}
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
@ -3307,9 +3537,11 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
*consistent = _repair_inconsistent_vg(correct_vg);
|
||||
else
|
||||
*consistent = !reappeared;
|
||||
if (_wipe_outdated_pvs(cmd, correct_vg, &correct_vg->pvs_outdated))
|
||||
if (_wipe_outdated_pvs(cmd, correct_vg, &correct_vg->pvs_outdated)) {
|
||||
/* clear the list */
|
||||
dm_list_init(&correct_vg->pvs_outdated);
|
||||
lvmetad_vg_clear_outdated_pvs(correct_vg);
|
||||
}
|
||||
}
|
||||
return correct_vg;
|
||||
}
|
||||
@ -3816,6 +4048,16 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
release_vg(vg);
|
||||
}
|
||||
|
||||
/*
|
||||
* When using lvmlockd we should never reach this point.
|
||||
* The VG is locked, then vg_read() is done, which gets
|
||||
* the latest VG from lvmetad, or disk if lvmetad has
|
||||
* been invalidated. When we get here the VG should
|
||||
* always be cached and returned above.
|
||||
*/
|
||||
if (lvmlockd_use())
|
||||
log_error(INTERNAL_ERROR "vg_read_by_vgid failed with lvmlockd");
|
||||
|
||||
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
|
||||
if (critical_section())
|
||||
return_NULL;
|
||||
@ -4465,13 +4707,13 @@ static struct volume_group *_recover_vg(struct cmd_context *cmd,
|
||||
return (struct volume_group *)vg;
|
||||
}
|
||||
|
||||
static int _allow_system_id(struct cmd_context *cmd, const char *system_id)
|
||||
static int _allow_extra_system_id(struct cmd_context *cmd, const char *system_id)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, local_extra_system_ids_CFG, NULL)))
|
||||
if (!(cn = find_config_tree_array(cmd, local_extra_system_ids_CFG, NULL)))
|
||||
return 0;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@ -4504,20 +4746,73 @@ static int _access_vg_clustered(struct cmd_context *cmd, struct volume_group *vg
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t lockd_state, uint32_t *failure)
|
||||
{
|
||||
if (!is_real_vg(vg->name))
|
||||
return 1;
|
||||
|
||||
if (cmd->lockd_vg_disable)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Until lock_type support is added, reject any VG that has a lock_type.
|
||||
* Local VG requires no lock from lvmlockd.
|
||||
*/
|
||||
if (vg->lock_type && vg->lock_type[0] && strcmp(vg->lock_type, "none")) {
|
||||
log_error("Cannot access VG %s with unsupported lock_type %s.",
|
||||
vg->name, vg->lock_type);
|
||||
if (!is_lockd_type(vg->lock_type))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* When lvmlockd is not used, lockd VGs are ignored by lvm
|
||||
* and cannot be used, with two exceptions:
|
||||
*
|
||||
* . The --shared option allows them to be revealed with
|
||||
* reporting/display commands.
|
||||
*
|
||||
* . If a command asks to operate on one specifically
|
||||
* by name, then an error is printed.
|
||||
*/
|
||||
if (!lvmlockd_use()) {
|
||||
/*
|
||||
* Some reporting/display commands have the --shared option
|
||||
* (like --foreign) to allow them to reveal lockd VGs that
|
||||
* are otherwise ignored. The --shared option must only be
|
||||
* permitted in commands that read the VG for report or display,
|
||||
* not any that write the VG or activate LVs.
|
||||
*/
|
||||
if (cmd->include_shared_vgs)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Some commands want the error printed by vg_read, others by ignore_vg.
|
||||
* Those using ignore_vg may choose to skip the error.
|
||||
*/
|
||||
if (cmd->vg_read_print_access_error) {
|
||||
log_error("Cannot access VG %s with lock type %s that requires lvmlockd.",
|
||||
vg->name, vg->lock_type);
|
||||
}
|
||||
|
||||
*failure |= FAILED_LOCK_TYPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lock request from lvmlockd failed. If the lock was ex,
|
||||
* we cannot continue. If the lock was sh, we could also fail
|
||||
* to continue but since the lock was sh, it means the VG is
|
||||
* only being read, and it doesn't hurt to allow reading with
|
||||
* no lock.
|
||||
*/
|
||||
if (lockd_state & LDST_FAIL) {
|
||||
if ((lockd_state & LDST_EX) || cmd->lockd_vg_enforce_sh) {
|
||||
log_error("Cannot access VG %s due to failed lock.", vg->name);
|
||||
*failure |= FAILED_LOCK_MODE;
|
||||
return 0;
|
||||
} else {
|
||||
log_warn("Reading VG %s without a lock.", vg->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -4553,7 +4848,7 @@ static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
|
||||
/*
|
||||
* A host can access a VG if the VG's system_id is in extra_system_ids list.
|
||||
*/
|
||||
if (cmd->system_id && _allow_system_id(cmd, vg->system_id))
|
||||
if (cmd->system_id && _allow_extra_system_id(cmd, vg->system_id))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
@ -4577,18 +4872,16 @@ static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Some commands always produce an error when accessing foreign VG.
|
||||
* Some commands want the error printed by vg_read, others by ignore_vg.
|
||||
* Those using ignore_vg may choose to skip the error.
|
||||
*/
|
||||
if (cmd->error_foreign_vgs) {
|
||||
if (cmd->vg_read_print_access_error) {
|
||||
log_error("Cannot access VG %s with system ID %s with local system ID %s.",
|
||||
vg->name, vg->system_id, cmd->system_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When include_foreign_vgs is 0 and error_foreign_vgs is 0,
|
||||
* the result is to silently ignore foreign vgs.
|
||||
*/
|
||||
/* Silently ignore foreign vgs. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4596,7 +4889,8 @@ static int _access_vg_systemid(struct cmd_context *cmd, struct volume_group *vg)
|
||||
/*
|
||||
* FIXME: move _vg_bad_status_bits() checks in here.
|
||||
*/
|
||||
static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg, uint32_t *failure)
|
||||
static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t lockd_state, uint32_t *failure)
|
||||
{
|
||||
if (!is_real_vg(vg->name)) {
|
||||
/* Disallow use of LVM1 orphans when a host system ID is set. */
|
||||
@ -4612,8 +4906,8 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_access_vg_lock_type(cmd, vg)) {
|
||||
*failure |= FAILED_LOCK_TYPE;
|
||||
if (!_access_vg_lock_type(cmd, vg, lockd_state, failure)) {
|
||||
/* Either FAILED_LOCK_TYPE or FAILED_LOCK_MODE were set. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4638,7 +4932,8 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
|
||||
*/
|
||||
static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t lock_flags,
|
||||
uint64_t status_flags, uint32_t misc_flags)
|
||||
uint64_t status_flags, uint32_t misc_flags,
|
||||
uint32_t lockd_state)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
int consistent = 1;
|
||||
@ -4684,7 +4979,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_vg_access_permitted(cmd, vg, &failure))
|
||||
if (!_vg_access_permitted(cmd, vg, lockd_state, &failure))
|
||||
goto bad;
|
||||
|
||||
/* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */
|
||||
@ -4760,7 +5055,7 @@ bad_no_unlock:
|
||||
* *consistent = 1.
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags)
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state)
|
||||
{
|
||||
uint64_t status = UINT64_C(0);
|
||||
uint32_t lock_flags = LCK_VG_READ;
|
||||
@ -4773,7 +5068,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
if (flags & READ_ALLOW_EXPORTED)
|
||||
status &= ~EXPORTED_VG;
|
||||
|
||||
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags);
|
||||
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags, lockd_state);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4782,9 +5077,9 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
* request the new metadata to be written and committed).
|
||||
*/
|
||||
struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags)
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state)
|
||||
{
|
||||
return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE);
|
||||
return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE, lockd_state);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5216,3 +5511,21 @@ const struct logical_volume *lv_ondisk(const struct logical_volume *lv)
|
||||
|
||||
return lvl->lv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a lock_type uses lvmlockd.
|
||||
* If not (none, clvm), return 0.
|
||||
* If so (dlm, sanlock), return 1.
|
||||
*/
|
||||
|
||||
int is_lockd_type(const char *lock_type)
|
||||
{
|
||||
if (!lock_type)
|
||||
return 0;
|
||||
if (!strcmp(lock_type, "dlm"))
|
||||
return 1;
|
||||
if (!strcmp(lock_type, "sanlock"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -460,6 +460,8 @@ struct volume_group *import_vg_from_buffer(const char *buf,
|
||||
struct format_instance *fid);
|
||||
struct volume_group *import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid);
|
||||
struct volume_group *import_vg_from_lvmetad_config_tree(const struct dm_config_tree *cft,
|
||||
struct format_instance *fid);
|
||||
|
||||
/*
|
||||
* Mirroring functions
|
||||
@ -483,6 +485,7 @@ int lv_is_merging_thin_snapshot(const struct logical_volume *lv);
|
||||
int pool_has_message(const struct lv_segment *seg,
|
||||
const struct logical_volume *lv, uint32_t device_id);
|
||||
int pool_below_threshold(const struct lv_segment *pool_seg);
|
||||
int pool_check_overprovisioning(const struct logical_volume *lv);
|
||||
int create_pool(struct logical_volume *lv, const struct segment_type *segtype,
|
||||
struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size);
|
||||
|
||||
|
@ -378,7 +378,11 @@ static int _init_mirror_log(struct cmd_context *cmd,
|
||||
backup(log_lv->vg);
|
||||
|
||||
/* Wait for events following any deactivation before reactivating */
|
||||
sync_local_dev_names(cmd);
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Aborting. Failed to sync local devices before initialising mirror log %s.",
|
||||
display_lvname(log_lv));
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to activate mirror log.");
|
||||
@ -494,7 +498,11 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
|
||||
return_0;
|
||||
|
||||
/* FIXME Is this superfluous now? */
|
||||
sync_local_dev_names(cmd);
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Failed to sync local devices when reactivating %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
@ -1173,7 +1181,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
||||
if (removed)
|
||||
*removed = old_area_count - new_area_count;
|
||||
|
||||
log_very_verbose("%" PRIu32 " image(s) removed from %s",
|
||||
log_very_verbose(FMTu32 " image(s) removed from %s",
|
||||
old_area_count - new_area_count, lv->name);
|
||||
|
||||
return 1;
|
||||
|
@ -298,7 +298,7 @@ int check_replicator_segment(const struct lv_segment *rseg)
|
||||
}
|
||||
if (rsite->fall_behind_data) {
|
||||
log_error("Defined fall_behind_data="
|
||||
"%" PRIu64 " for sync replicator %s/%s.",
|
||||
FMTu64 " for sync replicator %s/%s.",
|
||||
rsite->fall_behind_data, lv->name, rsite->name);
|
||||
r = 0;
|
||||
}
|
||||
@ -566,7 +566,7 @@ int cmd_vg_read(struct cmd_context *cmd, struct dm_list *cmd_vgs)
|
||||
|
||||
/* Iterate through alphabeticaly ordered cmd_vg list */
|
||||
dm_list_iterate_items(cvl, cmd_vgs) {
|
||||
cvl->vg = vg_read(cmd, cvl->vg_name, cvl->vgid, cvl->flags);
|
||||
cvl->vg = vg_read(cmd, cvl->vg_name, cvl->vgid, cvl->flags, 0);
|
||||
if (vg_read_error(cvl->vg)) {
|
||||
log_debug_metadata("Failed to vg_read %s", cvl->vg_name);
|
||||
return 0;
|
||||
@ -644,7 +644,7 @@ int lv_read_replicator_vgs(const struct logical_volume *lv)
|
||||
dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) {
|
||||
if (!rsite->vg_name)
|
||||
continue;
|
||||
vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, 0); // READ_WITHOUT_LOCK
|
||||
vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, 0, 0); // READ_WITHOUT_LOCK
|
||||
if (vg_read_error(vg)) {
|
||||
log_error("Unable to read volume group %s",
|
||||
rsite->vg_name);
|
||||
|
@ -284,6 +284,9 @@ int init_thin_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
int init_cache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
#endif
|
||||
|
||||
#define CACHE_FEATURE_POLICY_MQ (1U << 0)
|
||||
#define CACHE_FEATURE_POLICY_SMQ (1U << 1)
|
||||
|
||||
#define SNAPSHOT_FEATURE_FIXED_LEAK (1U << 0) /* version 1.12 */
|
||||
|
||||
#ifdef SNAPSHOT_INTERNAL
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "defaults.h"
|
||||
#include "display.h"
|
||||
|
||||
/* TODO: drop unused no_update */
|
||||
int attach_pool_message(struct lv_segment *pool_seg, dm_thin_message_t type,
|
||||
struct logical_volume *lv, uint32_t delete_id,
|
||||
int no_update)
|
||||
@ -236,6 +237,96 @@ int pool_below_threshold(const struct lv_segment *pool_seg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect overprovisioning and check lvm2 is configured for auto resize.
|
||||
*
|
||||
* If passed LV is thin volume/pool, check first only this one for overprovisiong.
|
||||
* Lots of test combined together.
|
||||
* Test is not detecting status of dmeventd, too complex for now...
|
||||
*/
|
||||
int pool_check_overprovisioning(const struct logical_volume *lv)
|
||||
{
|
||||
const struct lv_list *lvl;
|
||||
const struct seg_list *sl;
|
||||
const struct logical_volume *pool_lv = NULL;
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
const char *txt = "";
|
||||
uint64_t thinsum = 0, poolsum = 0, sz = ~0;
|
||||
int threshold, max_threshold = 0;
|
||||
int percent, min_percent = 100;
|
||||
int more_pools = 0;
|
||||
|
||||
/* When passed thin volume, check related pool first */
|
||||
if (lv_is_thin_volume(lv))
|
||||
pool_lv = first_seg(lv)->pool_lv;
|
||||
else if (lv_is_thin_pool(lv))
|
||||
pool_lv = lv;
|
||||
|
||||
if (pool_lv) {
|
||||
poolsum += pool_lv->size;
|
||||
dm_list_iterate_items(sl, &pool_lv->segs_using_this_lv)
|
||||
thinsum += sl->seg->lv->size;
|
||||
|
||||
if (thinsum <= poolsum)
|
||||
return 1; /* All thins fit into this thin pool */
|
||||
}
|
||||
|
||||
/* Sum all thins and all thin pools in VG */
|
||||
dm_list_iterate_items(lvl, &lv->vg->lvs) {
|
||||
if (!lv_is_thin_pool(lvl->lv))
|
||||
continue;
|
||||
|
||||
threshold = find_config_tree_int(cmd, activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(lvl->lv));
|
||||
percent = find_config_tree_int(cmd, activation_thin_pool_autoextend_percent_CFG,
|
||||
lv_config_profile(lvl->lv));
|
||||
if (threshold > max_threshold)
|
||||
max_threshold = threshold;
|
||||
if (percent < min_percent)
|
||||
min_percent = percent;
|
||||
|
||||
if (lvl->lv == pool_lv)
|
||||
continue; /* Skip iteration for already checked thin pool */
|
||||
|
||||
more_pools++;
|
||||
poolsum += lvl->lv->size;
|
||||
dm_list_iterate_items(sl, &lvl->lv->segs_using_this_lv)
|
||||
thinsum += sl->seg->lv->size;
|
||||
}
|
||||
|
||||
if (thinsum <= poolsum)
|
||||
return 1; /* All fits for all pools */
|
||||
|
||||
if ((sz = vg_size(lv->vg)) < thinsum)
|
||||
/* Thin sum size is above VG size */
|
||||
txt = " and the size of whole volume group";
|
||||
else if ((sz = vg_free(lv->vg)) < thinsum)
|
||||
/* Thin sum size is more then free space in a VG */
|
||||
txt = !sz ? "" : " and the amount of free space in volume group";
|
||||
else if ((max_threshold > 99) || !min_percent)
|
||||
/* There is some free space in VG, but it is not configured
|
||||
* for growing - threshold is 100% or percent is 0% */
|
||||
sz = poolsum;
|
||||
else
|
||||
sz = ~0; /* No warning */
|
||||
|
||||
if (sz != ~0) {
|
||||
log_warn("WARNING: Sum of all thin volume sizes (%s) exceeds the "
|
||||
"size of thin pool%s%s%s (%s)!",
|
||||
display_size(cmd, thinsum),
|
||||
more_pools ? "" : " ",
|
||||
more_pools ? "s" : display_lvname(pool_lv),
|
||||
txt,
|
||||
(sz > 0) ? display_size(cmd, sz) : "no free space in volume group");
|
||||
if (max_threshold > 99)
|
||||
log_print_unless_silent("For thin pool auto extension activation/thin_pool_autoextend_threshold should be below 100.");
|
||||
if (!min_percent)
|
||||
log_print_unless_silent("For thin pool auto extension activation/thin_pool_autoextend_percent should be above 0.");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate given external origin could be used with thin pool
|
||||
*/
|
||||
@ -243,12 +334,11 @@ int pool_supports_external_origin(const struct lv_segment *pool_seg, const struc
|
||||
{
|
||||
uint32_t csize = pool_seg->chunk_size;
|
||||
|
||||
if ((external_lv->size < csize) || (external_lv->size % csize)) {
|
||||
/* TODO: Validate with thin feature flag once, it will be supported */
|
||||
log_error("Can't use \"%s/%s\" as external origin with \"%s/%s\" pool. "
|
||||
if (((external_lv->size < csize) || (external_lv->size % csize)) &&
|
||||
!thin_pool_feature_supported(pool_seg->lv, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND)) {
|
||||
log_error("Can't use \"%s\" as external origin with \"%s\" pool. "
|
||||
"Size %s is not a multiple of pool's chunk size %s.",
|
||||
external_lv->vg->name, external_lv->name,
|
||||
pool_seg->lv->vg->name, pool_seg->lv->name,
|
||||
display_lvname(external_lv), display_lvname(pool_seg->lv),
|
||||
display_size(external_lv->vg->cmd, external_lv->size),
|
||||
display_size(external_lv->vg->cmd, csize));
|
||||
return 0;
|
||||
@ -336,7 +426,7 @@ static int _check_pool_create(const struct logical_volume *lv)
|
||||
|
||||
int update_pool_lv(struct logical_volume *lv, int activate)
|
||||
{
|
||||
int monitored;
|
||||
int monitored = DMEVENTD_MONITOR_IGNORE;
|
||||
int ret = 1;
|
||||
|
||||
if (!lv_is_thin_pool(lv)) {
|
||||
@ -362,28 +452,30 @@ int update_pool_lv(struct logical_volume *lv, int activate)
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
activate = 0; /* Was already active */
|
||||
|
||||
if (!(ret = _check_pool_create(lv)))
|
||||
stack;
|
||||
if (!(ret = _check_pool_create(lv)))
|
||||
stack; /* Safety guard, needs local presence of thin-pool target */
|
||||
else if (!(ret = suspend_lv_origin(lv->vg->cmd, lv)))
|
||||
/* Send messages */
|
||||
log_error("Failed to suspend and send message %s.", display_lvname(lv));
|
||||
else if (!(ret = resume_lv_origin(lv->vg->cmd, lv)))
|
||||
log_error("Failed to resume %s.", display_lvname(lv));
|
||||
|
||||
if (activate) {
|
||||
if (!deactivate_lv(lv->vg->cmd, lv)) {
|
||||
init_dmeventd_monitor(monitored);
|
||||
return_0;
|
||||
}
|
||||
init_dmeventd_monitor(monitored);
|
||||
|
||||
/* Unlock memory if possible */
|
||||
memlock_unlock(lv->vg->cmd);
|
||||
}
|
||||
/*
|
||||
* Resume active pool to send thin messages.
|
||||
* origin_only is used to skip check for resumed state
|
||||
*/
|
||||
else if (!resume_lv_origin(lv->vg->cmd, lv)) {
|
||||
log_error("Failed to resume %s.", lv->name);
|
||||
return 0;
|
||||
} else if (!(ret = _check_pool_create(lv)))
|
||||
stack;
|
||||
|
||||
/* Unlock memory if possible */
|
||||
memlock_unlock(lv->vg->cmd);
|
||||
|
||||
if (!ret)
|
||||
return_0;
|
||||
}
|
||||
|
||||
dm_list_init(&(first_seg(lv)->thin_messages));
|
||||
@ -631,7 +723,7 @@ int check_new_thin_pool(const struct logical_volume *pool_lv)
|
||||
/* Require pool to have same transaction_id as new */
|
||||
if (first_seg(pool_lv)->transaction_id != transaction_id) {
|
||||
log_error("Cannot use thin pool %s with transaction id "
|
||||
"%" PRIu64 " for thin volumes. "
|
||||
FMTu64 " for thin volumes. "
|
||||
"Expected transaction id %" PRIu64 ".",
|
||||
display_lvname(pool_lv), transaction_id,
|
||||
first_seg(pool_lv)->transaction_id);
|
||||
|
@ -134,6 +134,16 @@ char *vg_system_id_dup(const struct volume_group *vg)
|
||||
return dm_pool_strdup(vg->vgmem, vg->system_id ? : vg->lvm1_system_id ? : "");
|
||||
}
|
||||
|
||||
char *vg_lock_type_dup(const struct volume_group *vg)
|
||||
{
|
||||
return dm_pool_strdup(vg->vgmem, vg->lock_type ? : vg->lock_type ? : "");
|
||||
}
|
||||
|
||||
char *vg_lock_args_dup(const struct volume_group *vg)
|
||||
{
|
||||
return dm_pool_strdup(vg->vgmem, vg->lock_args ? : vg->lock_args ? : "");
|
||||
}
|
||||
|
||||
char *vg_uuid_dup(const struct volume_group *vg)
|
||||
{
|
||||
return id_format_and_copy(vg->vgmem, &vg->id);
|
||||
@ -637,6 +647,19 @@ int vg_set_system_id(struct volume_group *vg, const char *system_id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_set_lock_type(struct volume_group *vg, const char *lock_type)
|
||||
{
|
||||
if (!lock_type)
|
||||
lock_type = "none";
|
||||
|
||||
if (!(vg->lock_type = dm_pool_strdup(vg->vgmem, lock_type))) {
|
||||
log_error("vg_set_lock_type %s no mem", lock_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg)
|
||||
{
|
||||
char *repstr;
|
||||
@ -651,7 +674,14 @@ char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg)
|
||||
repstr[2] = (vg_is_exported(vg)) ? 'x' : '-';
|
||||
repstr[3] = (vg_missing_pv_count(vg)) ? 'p' : '-';
|
||||
repstr[4] = alloc_policy_char(vg->alloc);
|
||||
repstr[5] = (vg_is_clustered(vg)) ? 'c' : '-';
|
||||
|
||||
if (vg_is_clustered(vg))
|
||||
repstr[5] = 'c';
|
||||
else if (is_lockd_type(vg->lock_type))
|
||||
repstr[5] = 's';
|
||||
else
|
||||
repstr[5] = '-';
|
||||
|
||||
return repstr;
|
||||
}
|
||||
|
||||
@ -706,7 +736,7 @@ int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
vg->extent_count -= pv_pe_count(pv);
|
||||
|
||||
orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name,
|
||||
NULL, 0);
|
||||
NULL, 0, 0);
|
||||
|
||||
if (vg_read_error(orphan_vg))
|
||||
goto bad;
|
||||
|
@ -49,6 +49,7 @@ struct volume_group {
|
||||
struct dm_list *cmd_vgs;/* List of wanted/locked and opened VGs */
|
||||
uint32_t cmd_missing_vgs;/* Flag marks missing VG */
|
||||
uint32_t seqno; /* Metadata sequence number */
|
||||
unsigned skip_validate_lock_args : 1;
|
||||
|
||||
/*
|
||||
* The parsed on-disk copy of this VG; is NULL if this is the on-disk
|
||||
@ -71,6 +72,7 @@ struct volume_group {
|
||||
const char *system_id;
|
||||
char *lvm1_system_id;
|
||||
const char *lock_type;
|
||||
const char *lock_args;
|
||||
|
||||
uint32_t extent_size;
|
||||
uint32_t extent_count;
|
||||
@ -92,7 +94,18 @@ struct volume_group {
|
||||
|
||||
/*
|
||||
* List of physical volumes that carry outdated metadata that belongs
|
||||
* to this VG. Currently only populated when lvmetad is in use.
|
||||
* to this VG. Currently only populated when lvmetad is in use. The PVs
|
||||
* on this list could still belong to the VG (but their MDA carries an
|
||||
* out-of-date copy of the VG metadata) or they could no longer belong
|
||||
* to the VG. With lvmetad, this list is populated with all PVs that
|
||||
* have a VGID matching ours, but seqno that is smaller than the
|
||||
* current seqno for the VG. The MDAs on still-in-VG PVs are updated as
|
||||
* part of the normal vg_write/vg_commit process. The MDAs on PVs that
|
||||
* no longer belong to the VG are wiped during vg_read.
|
||||
*
|
||||
* However, even though still-in-VG PVs *may* be on the list, this is
|
||||
* not guaranteed. The in-lvmetad list is cleared whenever out-of-VG
|
||||
* outdated PVs are wiped during vg_read.
|
||||
*/
|
||||
|
||||
struct dm_list pvs_outdated;
|
||||
@ -140,6 +153,7 @@ struct volume_group {
|
||||
|
||||
struct dm_hash_table *hostnames; /* map of creation hostnames */
|
||||
struct logical_volume *pool_metadata_spare_lv; /* one per VG */
|
||||
struct logical_volume *sanlock_lv; /* one per VG */
|
||||
};
|
||||
|
||||
struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
|
||||
@ -155,11 +169,14 @@ void free_orphan_vg(struct volume_group *vg);
|
||||
char *vg_fmt_dup(const struct volume_group *vg);
|
||||
char *vg_name_dup(const struct volume_group *vg);
|
||||
char *vg_system_id_dup(const struct volume_group *vg);
|
||||
char *vg_lock_type_dup(const struct volume_group *vg);
|
||||
char *vg_lock_args_dup(const struct volume_group *vg);
|
||||
uint32_t vg_seqno(const struct volume_group *vg);
|
||||
uint64_t vg_status(const struct volume_group *vg);
|
||||
int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc);
|
||||
int vg_set_clustered(struct volume_group *vg, int clustered);
|
||||
int vg_set_system_id(struct volume_group *vg, const char *system_id);
|
||||
int vg_set_lock_type(struct volume_group *vg, const char *lock_type);
|
||||
uint64_t vg_size(const struct volume_group *vg);
|
||||
uint64_t vg_free(const struct volume_group *vg);
|
||||
uint64_t vg_extent_size(const struct volume_group *vg);
|
||||
|
@ -195,7 +195,7 @@ static int _mirrored_target_percent(void **target_state,
|
||||
pos += used;
|
||||
}
|
||||
|
||||
if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator,
|
||||
if (sscanf(pos, FMTu64 "/" FMTu64 "%n", &numerator, &denominator,
|
||||
&used) != 2) {
|
||||
log_error("Failure parsing mirror status fraction: %s", params);
|
||||
return 0;
|
||||
|
1
lib/misc/.gitignore
vendored
1
lib/misc/.gitignore
vendored
@ -1 +1,2 @@
|
||||
configure.h
|
||||
lvm-version.h
|
||||
|
@ -6,6 +6,10 @@
|
||||
/* The path to 'cache_check', if available. */
|
||||
#undef CACHE_CHECK_CMD
|
||||
|
||||
/* Define to 1 if the external 'cache_check' tool requires the
|
||||
--clear-needs-check-flag option */
|
||||
#undef CACHE_CHECK_NEEDS_CHECK
|
||||
|
||||
/* The path to 'cache_dump', if available. */
|
||||
#undef CACHE_DUMP_CMD
|
||||
|
||||
@ -68,6 +72,10 @@
|
||||
/* Default system configuration directory. */
|
||||
#undef DEFAULT_ETC_DIR
|
||||
|
||||
/* Fall back to LVM1 by default if device-mapper is missing from the kernel.
|
||||
*/
|
||||
#undef DEFAULT_FALLBACK_TO_LVM1
|
||||
|
||||
/* Name of default locking directory. */
|
||||
#undef DEFAULT_LOCK_DIR
|
||||
|
||||
@ -95,9 +103,15 @@
|
||||
/* Path to LVM system directory. */
|
||||
#undef DEFAULT_SYS_DIR
|
||||
|
||||
/* Use blkid wiping by default. */
|
||||
#undef DEFAULT_USE_BLKID_WIPING
|
||||
|
||||
/* Use lvmetad by default. */
|
||||
#undef DEFAULT_USE_LVMETAD
|
||||
|
||||
/* Use lvmlockd by default. */
|
||||
#undef DEFAULT_USE_LVMLOCKD
|
||||
|
||||
/* Use lvmpolld by default. */
|
||||
#undef DEFAULT_USE_LVMPOLLD
|
||||
|
||||
@ -131,6 +145,9 @@
|
||||
/* Library version */
|
||||
#undef DM_LIB_VERSION
|
||||
|
||||
/* Define to 1 if you have the `alarm' function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
@ -147,12 +164,18 @@
|
||||
/* Define to 1 if you have the <assert.h> header file. */
|
||||
#undef HAVE_ASSERT_H
|
||||
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#undef HAVE_ATEXIT
|
||||
|
||||
/* Define to 1 if canonicalize_file_name is available. */
|
||||
#undef HAVE_CANONICALIZE_FILE_NAME
|
||||
|
||||
/* Define to 1 if your system has a working `chown' function. */
|
||||
#undef HAVE_CHOWN
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* Define to 1 if you have the <corosync/cmap.h> header file. */
|
||||
#undef HAVE_COROSYNC_CMAP_H
|
||||
|
||||
@ -162,6 +185,10 @@
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
@ -180,6 +207,9 @@
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <float.h> header file. */
|
||||
#undef HAVE_FLOAT_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
@ -237,6 +267,9 @@
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define to 1 if you have the `localtime_r' function. */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if `lstat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_LSTAT_EMPTY_STRING_BUG
|
||||
@ -251,6 +284,9 @@
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the `memchr' function. */
|
||||
#undef HAVE_MEMCHR
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
@ -287,9 +323,15 @@
|
||||
/* Define to 1 if you have the `nl_langinfo' function. */
|
||||
#undef HAVE_NL_LANGINFO
|
||||
|
||||
/* Define to 1 if you have the <paths.h> header file. */
|
||||
#undef HAVE_PATHS_H
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#undef HAVE_PTHREAD_H
|
||||
|
||||
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||
#undef HAVE_PTRDIFF_T
|
||||
|
||||
/* Define to 1 if you have the <readline/history.h> header file. */
|
||||
#undef HAVE_READLINE_HISTORY_H
|
||||
|
||||
@ -300,6 +342,9 @@
|
||||
and to 0 otherwise. */
|
||||
#undef HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
/* Define to 1 to include support for realtime clock. */
|
||||
#undef HAVE_REALTIME
|
||||
|
||||
@ -349,6 +394,9 @@
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
@ -376,6 +424,9 @@
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#undef HAVE_STRERROR_R
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
@ -385,6 +436,12 @@
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#undef HAVE_STRNCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strndup' function. */
|
||||
#undef HAVE_STRNDUP
|
||||
|
||||
/* Define to 1 if you have the `strpbrk' function. */
|
||||
#undef HAVE_STRPBRK
|
||||
|
||||
/* Define to 1 if you have the `strrchr' function. */
|
||||
#undef HAVE_STRRCHR
|
||||
|
||||
@ -400,7 +457,10 @@
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
|
||||
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
||||
/* Define to 1 if you have the `strtoull' function. */
|
||||
#undef HAVE_STRTOULL
|
||||
|
||||
/* Define to 1 if `st_rdev' is member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_RDEV
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
@ -456,6 +516,9 @@
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/timerfd.h> header file. */
|
||||
#undef HAVE_SYS_TIMERFD_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
@ -504,12 +567,21 @@
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Internalization package */
|
||||
#undef INTL_PACKAGE
|
||||
|
||||
/* Locale-dependent data */
|
||||
#undef LOCALEDIR
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd dlm option. */
|
||||
#undef LOCKDDLM_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd sanlock option. */
|
||||
#undef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
@ -527,6 +599,12 @@
|
||||
/* Define to 1 to include code that uses lvmetad. */
|
||||
#undef LVMETAD_SUPPORT
|
||||
|
||||
/* Path to lvmlockd pidfile. */
|
||||
#undef LVMLOCKD_PIDFILE
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd. */
|
||||
#undef LVMLOCKD_SUPPORT
|
||||
|
||||
/* Path to lvmpolld pidfile. */
|
||||
#undef LVMPOLLD_PIDFILE
|
||||
|
||||
@ -565,9 +643,6 @@
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
@ -609,6 +684,12 @@
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if strerror_r returns char *. */
|
||||
#undef STRERROR_R_CHAR_P
|
||||
|
||||
/* Path to testsuite data */
|
||||
#undef TESTSUITE_DATA
|
||||
|
||||
/* The path to 'thin_check', if available. */
|
||||
#undef THIN_CHECK_CMD
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#define _LVM_LIB_H
|
||||
|
||||
/* HM FIXME: REMOVEME: devel output */
|
||||
#if 1
|
||||
#if 0
|
||||
#define USE_PFL
|
||||
#endif
|
||||
|
||||
@ -45,11 +45,6 @@
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "zu"
|
||||
#define PRIptrdiff_t "td"
|
||||
#define PRIpid_t PRId32
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define DM_EXPORTED_SYMBOL(func, ver) \
|
||||
__asm__(".symver " #func "_v" #ver ", " #func "@@DM_" #ver )
|
||||
|
@ -62,8 +62,11 @@ int exec_cmd(struct cmd_context *cmd, const char *const argv[],
|
||||
*rstatus = -1;
|
||||
|
||||
if (sync_needed)
|
||||
if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
|
||||
return_0;
|
||||
/* Flush ops and reset dm cookie */
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Failed to sync local device names before forking.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Executing:%s", _verbose_args(argv, buf, sizeof(buf)));
|
||||
|
||||
@ -148,8 +151,11 @@ FILE *pipe_open(struct cmd_context *cmd, const char *const argv[],
|
||||
char buf[PATH_MAX * 2];
|
||||
|
||||
if (sync_needed)
|
||||
if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
|
||||
return_0;
|
||||
/* Flush ops and reset dm cookie */
|
||||
if (!sync_local_dev_names(cmd)) {
|
||||
log_error("Failed to sync local device names before forking.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pipe(pipefd)) {
|
||||
log_sys_error("pipe", "");
|
||||
|
@ -33,7 +33,7 @@ static int _obtain_device_list_from_udev = DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV;
|
||||
static unsigned _external_device_info_source = DEV_EXT_NONE;
|
||||
static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
|
||||
static int _debug_level = 0;
|
||||
static int _debug_classes_logged = DEFAULT_LOGGED_DEBUG_CLASSES;
|
||||
static int _debug_classes_logged = 0;
|
||||
static int _log_cmd_name = 0;
|
||||
static int _ignorelockingfailure = 0;
|
||||
static int _security_level = SECURITY_LEVEL;
|
||||
@ -193,6 +193,11 @@ void set_cmd_name(const char *cmd)
|
||||
_cmd_name[sizeof(_cmd_name) - 1] = '\0';
|
||||
}
|
||||
|
||||
const char *get_cmd_name(void)
|
||||
{
|
||||
return _cmd_name;
|
||||
}
|
||||
|
||||
void set_sysfs_dir_path(const char *path)
|
||||
{
|
||||
strncpy(_sysfs_dir_path, path, sizeof(_sysfs_dir_path) - 1);
|
||||
|
@ -51,6 +51,7 @@ void init_detect_internal_vg_cache_corruption(int detect);
|
||||
void init_retry_deactivation(int retry);
|
||||
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
const char *get_cmd_name(void);
|
||||
void set_sysfs_dir_path(const char *path);
|
||||
|
||||
int test_mode(void);
|
||||
|
@ -95,7 +95,7 @@ void sigint_restore(void)
|
||||
--_handler_installed >= MAX_SIGINTS)
|
||||
return;
|
||||
|
||||
/* Nesting count went bellow MAX_SIGINTS. */
|
||||
/* Nesting count went below MAX_SIGINTS. */
|
||||
if (_oldmasked[_handler_installed]) {
|
||||
sigset_t sigs;
|
||||
sigprocmask(0, NULL, &sigs);
|
||||
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Rackable Systems All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstract out the time methods used so they can be adjusted later -
|
||||
* the results of these routines should stay in-core. This implementation
|
||||
* requires librt.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "timestamp.h"
|
||||
|
||||
/*
|
||||
* The realtime section uses clock_gettime with the CLOCK_MONOTONIC
|
||||
* parameter to prevent issues with time warps
|
||||
*/
|
||||
#ifdef HAVE_REALTIME
|
||||
|
||||
#include <time.h>
|
||||
#include <bits/time.h>
|
||||
|
||||
struct timestamp {
|
||||
struct timespec t;
|
||||
};
|
||||
|
||||
struct timestamp *get_timestamp(void)
|
||||
{
|
||||
struct timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = dm_malloc(sizeof(*ts))))
|
||||
return_NULL;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
|
||||
log_sys_error("clock_gettime", "get_timestamp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
/* cmp_timestamp: Compare two timestamps
|
||||
*
|
||||
* Return: -1 if t1 is less than t2
|
||||
* 0 if t1 is equal to t2
|
||||
* 1 if t1 is greater than t2
|
||||
*/
|
||||
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
|
||||
{
|
||||
if(t1->t.tv_sec < t2->t.tv_sec)
|
||||
return -1;
|
||||
if(t1->t.tv_sec > t2->t.tv_sec)
|
||||
return 1;
|
||||
|
||||
if(t1->t.tv_nsec < t2->t.tv_nsec)
|
||||
return -1;
|
||||
if(t1->t.tv_nsec > t2->t.tv_nsec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* ! HAVE_REALTIME */
|
||||
|
||||
/*
|
||||
* The !realtime section just uses gettimeofday and is therefore subject
|
||||
* to ntp-type time warps - not sure if should allow that.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
struct timestamp {
|
||||
struct timeval t;
|
||||
};
|
||||
|
||||
struct timestamp *get_timestamp(void)
|
||||
{
|
||||
struct timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = dm_malloc(sizeof(*ts))))
|
||||
return_NULL;
|
||||
|
||||
if (gettimeofday(&ts->t, NULL)) {
|
||||
log_sys_error("gettimeofday", "get_timestamp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
/* cmp_timestamp: Compare two timestamps
|
||||
*
|
||||
* Return: -1 if t1 is less than t2
|
||||
* 0 if t1 is equal to t2
|
||||
* 1 if t1 is greater than t2
|
||||
*/
|
||||
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
|
||||
{
|
||||
if(t1->t.tv_sec < t2->t.tv_sec)
|
||||
return -1;
|
||||
if(t1->t.tv_sec > t2->t.tv_sec)
|
||||
return 1;
|
||||
|
||||
if(t1->t.tv_usec < t2->t.tv_usec)
|
||||
return -1;
|
||||
if(t1->t.tv_usec > t2->t.tv_usec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_REALTIME */
|
||||
|
||||
void destroy_timestamp(struct timestamp *t)
|
||||
{
|
||||
dm_free(t);
|
||||
}
|
@ -15,6 +15,8 @@
|
||||
#ifndef _LVM_UTIL_H
|
||||
#define _LVM_UTIL_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define min(a, b) ({ typeof(a) _a = (a); \
|
||||
typeof(b) _b = (b); \
|
||||
(void) (&_a == &_b); \
|
||||
@ -33,4 +35,41 @@
|
||||
|
||||
#define KERNEL_VERSION(major, minor, release) (((major) << 16) + ((minor) << 8) + (release))
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "zu"
|
||||
#define PRIssize_t "zd"
|
||||
#define PRIptrdiff_t "td"
|
||||
#define PRIpid_t PRId32
|
||||
|
||||
/* For convenience */
|
||||
#define FMTsize_t "%" PRIsize_t
|
||||
#define FMTssize_t "%" PRIssize_t
|
||||
#define FMTptrdiff_t "%" PRIptrdiff_t
|
||||
#define FMTpid_t "%" PRIpid_t
|
||||
|
||||
#define FMTd8 "%" PRId8
|
||||
#define FMTd16 "%" PRId16
|
||||
#define FMTd32 "%" PRId32
|
||||
#define FMTd64 "%" PRId64
|
||||
|
||||
#define FMTi8 "%" PRIi8
|
||||
#define FMTi16 "%" PRIi16
|
||||
#define FMTi32 "%" PRIi32
|
||||
#define FMTi64 "%" PRIi64
|
||||
|
||||
#define FMTo8 "%" PRIo8
|
||||
#define FMTo16 "%" PRIo16
|
||||
#define FMTo32 "%" PRIo32
|
||||
#define FMTo64 "%" PRIo64
|
||||
|
||||
#define FMTu8 "%" PRIu8
|
||||
#define FMTu16 "%" PRIu16
|
||||
#define FMTu32 "%" PRIu32
|
||||
#define FMTu64 "%" PRIu64
|
||||
|
||||
#define FMTx8 "%" PRIx8
|
||||
#define FMTx16 "%" PRIx16
|
||||
#define FMTx32 "%" PRIx32
|
||||
#define FMTx64 "%" PRIx64
|
||||
|
||||
#endif
|
||||
|
@ -347,7 +347,7 @@ static int _memlock_maps(struct cmd_context *cmd, lvmlock_t lock, size_t *mstats
|
||||
}
|
||||
|
||||
line = _maps_buffer;
|
||||
cn = find_config_tree_node(cmd, activation_mlock_filter_CFG, NULL);
|
||||
cn = find_config_tree_array(cmd, activation_mlock_filter_CFG, NULL);
|
||||
|
||||
while ((line_end = strchr(line, '\n'))) {
|
||||
*line_end = '\0'; /* remove \n */
|
||||
|
@ -38,27 +38,71 @@
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define xlate16(x) (x)
|
||||
# define xlate32(x) (x)
|
||||
# define xlate64(x) (x)
|
||||
# define xlate16_be(x) bswap_16(x)
|
||||
# define xlate32_be(x) bswap_32(x)
|
||||
# define xlate64_be(x) bswap_64(x)
|
||||
/* New clearer variants. */
|
||||
#define le16_to_cpu(x) (x)
|
||||
#define le32_to_cpu(x) (x)
|
||||
#define le64_to_cpu(x) (x)
|
||||
#define cpu_to_le16(x) (x)
|
||||
#define cpu_to_le32(x) (x)
|
||||
#define cpu_to_le64(x) (x)
|
||||
#define be16_to_cpu(x) bswap_16(x)
|
||||
#define be32_to_cpu(x) bswap_32(x)
|
||||
#define be64_to_cpu(x) bswap_64(x)
|
||||
#define cpu_to_be16(x) bswap_16(x)
|
||||
#define cpu_to_be32(x) bswap_32(x)
|
||||
#define cpu_to_be64(x) bswap_64(x)
|
||||
/* Old alternative variants. */
|
||||
#define xlate16(x) (x)
|
||||
#define xlate32(x) (x)
|
||||
#define xlate64(x) (x)
|
||||
#define xlate16_be(x) bswap_16(x)
|
||||
#define xlate32_be(x) bswap_32(x)
|
||||
#define xlate64_be(x) bswap_64(x)
|
||||
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
# define xlate16(x) bswap_16(x)
|
||||
# define xlate32(x) bswap_32(x)
|
||||
# define xlate64(x) bswap_64(x)
|
||||
# define xlate16_be(x) (x)
|
||||
# define xlate32_be(x) (x)
|
||||
# define xlate64_be(x) (x)
|
||||
/* New clearer variants. */
|
||||
#define le16_to_cpu(x) bswap_16(x)
|
||||
#define le32_to_cpu(x) bswap_32(x)
|
||||
#define le64_to_cpu(x) bswap_64(x)
|
||||
#define cpu_to_le16(x) bswap_16(x)
|
||||
#define cpu_to_le32(x) bswap_32(x)
|
||||
#define cpu_to_le64(x) bswap_64(x)
|
||||
#define be16_to_cpu(x) (x)
|
||||
#define be32_to_cpu(x) (x)
|
||||
#define be64_to_cpu(x) (x)
|
||||
#define cpu_to_be16(x) (x)
|
||||
#define cpu_to_be32(x) (x)
|
||||
#define cpu_to_be64(x) (x)
|
||||
/* Old alternative variants. */
|
||||
#define xlate16(x) bswap_16(x)
|
||||
#define xlate32(x) bswap_32(x)
|
||||
#define xlate64(x) bswap_64(x)
|
||||
#define xlate16_be(x) (x)
|
||||
#define xlate32_be(x) (x)
|
||||
#define xlate64_be(x) (x)
|
||||
|
||||
#else
|
||||
# include <asm/byteorder.h>
|
||||
# define xlate16(x) __cpu_to_le16((x))
|
||||
# define xlate32(x) __cpu_to_le32((x))
|
||||
# define xlate64(x) __cpu_to_le64((x))
|
||||
# define xlate16_be(x) __cpu_to_be16((x))
|
||||
# define xlate32_be(x) __cpu_to_be32((x))
|
||||
# define xlate64_be(x) __cpu_to_be64((x))
|
||||
#include <asm/byteorder.h>
|
||||
/* New clearer variants. */
|
||||
#define le16_to_cpu(x) __le16_to_cpu(x)
|
||||
#define le32_to_cpu(x) __le32_to_cpu(x)
|
||||
#define le64_to_cpu(x) __le64_to_cpu(x)
|
||||
#define cpu_to_le16(x) __cpu_to_le16(x)
|
||||
#define cpu_to_le32(x) __cpu_to_le32(x)
|
||||
#define cpu_to_le64(x) __cpu_to_le64(x)
|
||||
#define be16_to_cpu(x) __be16_to_cpu(x)
|
||||
#define be32_to_cpu(x) __be32_to_cpu(x)
|
||||
#define be64_to_cpu(x) __be64_to_cpu(x)
|
||||
#define cpu_to_be16(x) __cpu_to_be16(x)
|
||||
#define cpu_to_be32(x) __cpu_to_be32(x)
|
||||
#define cpu_to_be64(x) __cpu_to_be64(x)
|
||||
/* Old alternative variants. */
|
||||
#define xlate16(x) __cpu_to_le16(x)
|
||||
#define xlate32(x) __cpu_to_le32(x)
|
||||
#define xlate64(x) __cpu_to_le64(x)
|
||||
#define xlate16_be(x) __cpu_to_be16(x)
|
||||
#define xlate32_be(x) __cpu_to_be32(x)
|
||||
#define xlate64_be(x) __cpu_to_be64(x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -127,8 +127,9 @@ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \
|
||||
#define BIN 3
|
||||
#define SIZ 4
|
||||
#define PCT 5
|
||||
#define STR_LIST 6
|
||||
#define TIM 6
|
||||
#define SNUM 7 /* Signed Number */
|
||||
#define STR_LIST 8
|
||||
|
||||
#define FIELD_MODIFIABLE 0x00000001
|
||||
#define FIELD(type, strct, field_type, head, field, width, fn, id, desc, settable) \
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
#include "config.h"
|
||||
#include "str_list.h"
|
||||
#include "targets.h"
|
||||
@ -353,6 +352,7 @@ static int _raid_target_percent(void **target_state,
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pos ||
|
||||
(sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n",
|
||||
&numerator, &denominator, &i) != 2) ||
|
||||
|
@ -672,7 +672,7 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
|
||||
if (!(slog_dlid = build_dm_uuid(mem, rdev->slog, NULL)))
|
||||
return_0;
|
||||
} else if (rdev->slog_name &&
|
||||
sscanf(rdev->slog_name, "%" PRIu32, &slog_size) == 1) {
|
||||
sscanf(rdev->slog_name, FMTu32, &slog_size) == 1) {
|
||||
slog_flags = DM_CORELOG | DM_FORCESYNC;
|
||||
if (slog_size == 0) {
|
||||
log_error("Failed to use empty corelog size "
|
||||
|
@ -84,7 +84,8 @@ FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin and cach
|
||||
FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0)
|
||||
FIELD(LVS, lv, STR, "LProfile", lvid, 8, lvprofile, lv_profile, "Configuration profile attached to this LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0)
|
||||
FIELD(LVS, lv, STR, "Lock Args", lvid, 9, lvlockargs, lv_lockargs, "Lock args of the LV used by lvmlockd.", 0)
|
||||
FIELD(LVS, lv, TIM, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0)
|
||||
FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "Modules", lvid, 7, modules, lv_modules, "Kernel device-mapper modules required for this LV.", 0)
|
||||
|
||||
@ -143,6 +144,8 @@ FIELD(VGS, vg, SIZ, "VSize", cmd, 5, vgsize, vg_size, "Total size of VG in curre
|
||||
FIELD(VGS, vg, SIZ, "VFree", cmd, 5, vgfree, vg_free, "Total amount of free space in current units.", 0)
|
||||
FIELD(VGS, vg, STR, "SYS ID", cmd, 6, vgsystemid, vg_sysid, "System ID of the VG indicating which host owns it.", 0)
|
||||
FIELD(VGS, vg, STR, "System ID", cmd, 9, vgsystemid, vg_systemid, "System ID of the VG indicating which host owns it.", 0)
|
||||
FIELD(VGS, vg, STR, "Lock Type", cmd, 9, vglocktype, vg_locktype, "Lock type of the VG used by lvmlockd.", 0)
|
||||
FIELD(VGS, vg, STR, "Lock Args", cmd, 9, vglockargs, vg_lockargs, "Lock args of the VG used by lvmlockd.", 0)
|
||||
FIELD(VGS, vg, SIZ, "Ext", extent_size, 3, size32, vg_extent_size, "Size of Physical Extents in current units.", 0)
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, vg_extent_count, "Total number of Physical Extents.", 0)
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0)
|
||||
|
@ -342,7 +342,7 @@ GET_LV_NUM_PROPERTY_FN(metadata_percent, _metadata_percent(lv))
|
||||
#define _metadata_percent_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(lv_metadata_size, lv_metadata_size(lv) * SECTOR_SIZE)
|
||||
#define _lv_metadata_size_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_time, lv_time_dup(lv->vg->vgmem, lv))
|
||||
GET_LV_STR_PROPERTY_FN(lv_time, lv_time_dup(lv->vg->vgmem, lv, 0))
|
||||
#define _lv_time_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_host, lv_host_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_host_set prop_not_implemented_set
|
||||
@ -350,6 +350,8 @@ GET_LV_STR_PROPERTY_FN(lv_active, lv_active_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_active_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_profile, lv_profile_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_profile_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_lockargs, lv_lock_args_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_lockargs_set prop_not_implemented_set
|
||||
|
||||
/* VG */
|
||||
GET_VG_STR_PROPERTY_FN(vg_fmt, vg_fmt_dup(vg))
|
||||
@ -368,6 +370,10 @@ GET_VG_STR_PROPERTY_FN(vg_sysid, vg_system_id_dup(vg))
|
||||
#define _vg_sysid_set prop_not_implemented_set
|
||||
GET_VG_STR_PROPERTY_FN(vg_systemid, vg_system_id_dup(vg))
|
||||
#define _vg_systemid_set prop_not_implemented_set
|
||||
GET_VG_STR_PROPERTY_FN(vg_locktype, vg_lock_type_dup(vg))
|
||||
#define _vg_locktype_set prop_not_implemented_set
|
||||
GET_VG_STR_PROPERTY_FN(vg_lockargs, vg_lock_args_dup(vg))
|
||||
#define _vg_lockargs_set prop_not_implemented_set
|
||||
GET_VG_NUM_PROPERTY_FN(vg_extent_size, (SECTOR_SIZE * vg->extent_size))
|
||||
#define _vg_extent_size_set prop_not_implemented_set
|
||||
GET_VG_NUM_PROPERTY_FN(vg_extent_count, vg->extent_count)
|
||||
|
1136
lib/report/report.c
1136
lib/report/report.c
File diff suppressed because it is too large
Load Diff
@ -38,15 +38,15 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* TYPE_RESERVED_VALUE(type, reserved_value_id, description, value, reserved_name, ...)
|
||||
* FIELD_RESERVED_VALUE(field_id, reserved_value_id, description, value, reserved_name, ...)
|
||||
* TYPE_RESERVED_VALUE(type, flags, reserved_value_id, description, value, reserved_name, ...)
|
||||
* FIELD_RESERVED_VALUE(field_id, flags, reserved_value_id, description, value, reserved_name, ...)
|
||||
* FIELD_BINARY_RESERVED_VALUE(field_id, reserved_value_id, description, reserved_name for 1, ...)
|
||||
*/
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
/* Per-type reserved values usable for all fields of certain type. */
|
||||
TYPE_RESERVED_VALUE(NUM, num_undef_64, "Reserved value for undefined numeric value.", UINT64_C(-1), "-1", "unknown", "undefined", "undef")
|
||||
TYPE_RESERVED_VALUE(NUM, NOFLAG, num_undef_64, "Reserved value for undefined numeric value.", UINT64_C(-1), "-1", "unknown", "undefined", "undef")
|
||||
|
||||
/* Reserved values for PV fields */
|
||||
FIELD_RESERVED_BINARY_VALUE(pv_allocatable, pv_allocatable, "", "allocatable")
|
||||
@ -58,9 +58,9 @@ FIELD_RESERVED_BINARY_VALUE(vg_extendable, vg_extendable, "", "extendable")
|
||||
FIELD_RESERVED_BINARY_VALUE(vg_exported, vg_exported, "", "exported")
|
||||
FIELD_RESERVED_BINARY_VALUE(vg_partial, vg_partial, "", "partial")
|
||||
FIELD_RESERVED_BINARY_VALUE(vg_clustered, vg_clustered, "", "clustered")
|
||||
FIELD_RESERVED_VALUE(vg_permissions, vg_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
|
||||
FIELD_RESERVED_VALUE(vg_permissions, vg_permissions_r, "", "read-only", "read-only", "r", "ro")
|
||||
FIELD_RESERVED_VALUE(vg_mda_copies, vg_mda_copies_unmanaged, "", &GET_TYPE_RESERVED_VALUE(num_undef_64), "unmanaged")
|
||||
FIELD_RESERVED_VALUE(NAMED, vg_permissions, vg_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
|
||||
FIELD_RESERVED_VALUE(NAMED, vg_permissions, vg_permissions_r, "", "read-only", "read-only", "r", "ro")
|
||||
FIELD_RESERVED_VALUE(NOFLAG, vg_mda_copies, vg_mda_copies_unmanaged, "", &GET_TYPE_RESERVED_VALUE(num_undef_64), "unmanaged")
|
||||
|
||||
/* Reserved values for LV fields */
|
||||
FIELD_RESERVED_BINARY_VALUE(lv_initial_image_sync, lv_initial_image_sync, "", "initial image sync", "sync")
|
||||
@ -80,18 +80,19 @@ FIELD_RESERVED_BINARY_VALUE(lv_inactive_table, lv_inactive_table, "", "inactive
|
||||
FIELD_RESERVED_BINARY_VALUE(lv_device_open, lv_device_open, "", "open")
|
||||
FIELD_RESERVED_BINARY_VALUE(lv_skip_activation, lv_skip_activation, "", "skip activation", "skip")
|
||||
FIELD_RESERVED_BINARY_VALUE(zero, zero, "", "zero")
|
||||
FIELD_RESERVED_VALUE(lv_permissions, lv_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
|
||||
FIELD_RESERVED_VALUE(lv_permissions, lv_permissions_r, "", "read-only", "read-only", "r", "ro")
|
||||
FIELD_RESERVED_VALUE(lv_permissions, lv_permissions_r_override, "", "read-only-override", "read-only-override", "ro-override", "r-override", "R")
|
||||
FIELD_RESERVED_VALUE(lv_read_ahead, lv_read_ahead_auto, "", &_siz_max, "auto")
|
||||
FIELD_RESERVED_VALUE(lv_when_full, lv_when_full_error, "", "error", "error", "error when full", "error if no space")
|
||||
FIELD_RESERVED_VALUE(lv_when_full, lv_when_full_queue, "", "queue", "queue", "queue when full", "queue if no space")
|
||||
FIELD_RESERVED_VALUE(lv_when_full, lv_when_full_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
|
||||
FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_r, "", "read-only", "read-only", "r", "ro")
|
||||
FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_r_override, "", "read-only-override", "read-only-override", "ro-override", "r-override", "R")
|
||||
FIELD_RESERVED_VALUE(NOFLAG, lv_read_ahead, lv_read_ahead_auto, "", &_siz_max, "auto")
|
||||
FIELD_RESERVED_VALUE(NAMED, lv_when_full, lv_when_full_error, "", "error", "error", "error when full", "error if no space")
|
||||
FIELD_RESERVED_VALUE(NAMED, lv_when_full, lv_when_full_queue, "", "queue", "queue", "queue when full", "queue if no space")
|
||||
FIELD_RESERVED_VALUE(NOFLAG, lv_when_full, lv_when_full_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(NAMED | RANGE | FUZZY | DYNAMIC, lv_time, lv_time_fuzzy, "", lv_time_handler, NULL)
|
||||
|
||||
/* Reserved values for SEG fields */
|
||||
FIELD_RESERVED_VALUE(cache_policy, cache_policy_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(seg_monitor, seg_monitor_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(lv_health_status, health_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(NOFLAG, cache_policy, cache_policy_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(NOFLAG, seg_monitor, seg_monitor_undef, "", "", "", "undefined")
|
||||
FIELD_RESERVED_VALUE(NOFLAG, lv_health_status, health_undef, "", "", "", "undefined")
|
||||
/* TODO the following 2 need STR_LIST support for reserved values
|
||||
FIELD_RESERVED_VALUE(cache_settings, cache_settings_default, "", "default", "default")
|
||||
FIELD_RESERVED_VALUE(cache_settings, cache_settings_undef, "", "undefined", "undefined") */
|
||||
|
@ -294,7 +294,8 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_tree_node_add_thin_pool_target(node, len, seg->transaction_id,
|
||||
if (!dm_tree_node_add_thin_pool_target(node, len,
|
||||
seg->transaction_id,
|
||||
metadata_dlid, pool_dlid,
|
||||
seg->chunk_size, seg->low_water_mark,
|
||||
seg->zero_new_blocks ? 0 : 1))
|
||||
@ -344,7 +345,7 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
||||
*/
|
||||
if (!lv_thin_pool_transaction_id(seg->lv, &transaction_id))
|
||||
return_0; /* Thin pool should exist and work */
|
||||
if (transaction_id != seg->transaction_id) {
|
||||
if ((transaction_id + 1) != seg->transaction_id) {
|
||||
log_error("Can't create snapshot %s as origin %s is not suspended.",
|
||||
lmsg->u.lv->name, origin->name);
|
||||
return 0;
|
||||
@ -609,14 +610,18 @@ static int _thin_target_percent(void **target_state __attribute__((unused)),
|
||||
uint64_t *total_denominator)
|
||||
{
|
||||
struct dm_status_thin *s;
|
||||
uint64_t csize;
|
||||
|
||||
/* Status for thin device is in sectors */
|
||||
if (!dm_get_status_thin(mem, params, &s))
|
||||
return_0;
|
||||
|
||||
if (seg) {
|
||||
*percent = dm_make_percent(s->mapped_sectors, seg->lv->size);
|
||||
*total_denominator += seg->lv->size;
|
||||
/* Pool allocates whole chunk so round-up to nearest one */
|
||||
csize = first_seg(seg->pool_lv)->chunk_size;
|
||||
csize = ((seg->lv->size + csize - 1) / csize) * csize;
|
||||
*percent = dm_make_percent(s->mapped_sectors, csize);
|
||||
*total_denominator += csize;
|
||||
} else {
|
||||
/* No lv_segment info here */
|
||||
*percent = DM_PERCENT_INVALID;
|
||||
@ -645,8 +650,8 @@ static int _thin_target_present(struct cmd_context *cmd,
|
||||
{ 1, 4, THIN_FEATURE_BLOCK_SIZE, "block_size" },
|
||||
{ 1, 5, THIN_FEATURE_DISCARDS_NON_POWER_2, "discards_non_power_2" },
|
||||
{ 1, 10, THIN_FEATURE_METADATA_RESIZE, "metadata_resize" },
|
||||
{ 9, 11, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND, "external_origin_extend" },
|
||||
{ 1, 10, THIN_FEATURE_ERROR_IF_NO_SPACE, "error_if_no_space" },
|
||||
{ 1, 13, THIN_FEATURE_EXTERNAL_ORIGIN_EXTEND, "external_origin_extend" },
|
||||
};
|
||||
|
||||
static const char _lvmconf[] = "global/thin_disabled_features";
|
||||
@ -682,7 +687,7 @@ static int _thin_target_present(struct cmd_context *cmd,
|
||||
if (attributes) {
|
||||
if (!_feature_mask) {
|
||||
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
|
||||
if ((cn = find_config_tree_node(cmd, global_thin_disabled_features_CFG, NULL))) {
|
||||
if ((cn = find_config_tree_array(cmd, global_thin_disabled_features_CFG, NULL))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_error("Ignoring invalid string in config file %s.",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user