mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-29 16:23:49 +03:00
Compare commits
1 Commits
dev-mcsont
...
dev-mcsont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05716c2d8a |
47
Makefile.in
47
Makefile.in
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -15,8 +15,6 @@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
|
||||
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
|
||||
|
||||
@@ -93,44 +91,10 @@ cscope.out:
|
||||
all: cscope.out
|
||||
endif
|
||||
DISTCLEAN_TARGETS += cscope.out
|
||||
CLEAN_DIRS += autom4te.cache
|
||||
|
||||
check check_system check_cluster check_local check_lvmetad unit: all
|
||||
$(MAKE) -C test $(@)
|
||||
|
||||
conf.generate: tools
|
||||
|
||||
# how to use parenthesis in makefiles
|
||||
leftparen:=(
|
||||
LVM_VER := $(firstword $(subst $(leftparen), ,$(LVM_VERSION)))
|
||||
VER := LVM2.$(LVM_VER)
|
||||
# release file name
|
||||
FILE_VER := $(VER).tgz
|
||||
CLEAN_TARGETS += $(FILE_VER)
|
||||
CLEAN_DIRS += $(rpmbuilddir)
|
||||
|
||||
dist:
|
||||
@echo "Generating $(FILE_VER)";\
|
||||
(cd $(top_srcdir); git ls-tree -r HEAD --name-only | xargs tar --transform "s,^,$(VER)/," -c) | gzip >$(FILE_VER)
|
||||
|
||||
rpm: dist
|
||||
$(RM) -r $(rpmbuilddir)/SOURCES
|
||||
$(MKDIR_P) $(rpmbuilddir)/SOURCES
|
||||
$(LN_S) -f $(abs_top_builddir)/$(FILE_VER) $(rpmbuilddir)/SOURCES
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
|
||||
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
|
||||
DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
|
||||
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
|
||||
sed -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
|
||||
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
|
||||
-e "s,^\(Release:[^0-9%]*\)[0-9.]\+,\1 $$GIT_VER," \
|
||||
$(top_srcdir)/spec/source.inc >$(rpmbuilddir)/SOURCES/source.inc
|
||||
rpmbuild -v --define "_topdir $(rpmbuilddir)" -ba $(top_srcdir)/spec/lvm2.spec
|
||||
|
||||
generate: conf.generate
|
||||
$(MAKE) -C conf generate
|
||||
|
||||
install_system_dirs:
|
||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_SYS_DIR)
|
||||
$(INSTALL_ROOT_DIR) $(DESTDIR)$(DEFAULT_ARCHIVE_DIR)
|
||||
@@ -158,11 +122,8 @@ endif
|
||||
install_tmpfiles_configuration:
|
||||
$(MAKE) -C scripts install_tmpfiles_configuration
|
||||
|
||||
LCOV_TRACES = libdm.info lib.info liblvm.info tools.info \
|
||||
libdaemon/client.info libdaemon/server.info \
|
||||
daemons/clvmd.info daemons/dmeventd.info \
|
||||
daemons/lvmetad.info
|
||||
|
||||
LCOV_TRACES = libdm.info lib.info tools.info \
|
||||
daemons/dmeventd.info daemons/clvmd.info
|
||||
CLEAN_TARGETS += $(LCOV_TRACES)
|
||||
|
||||
ifneq ("$(LCOV)", "")
|
||||
@@ -191,7 +152,7 @@ lcov: $(LCOV_TRACES)
|
||||
$(RM) -r $(LCOV_REPORTS_DIR)
|
||||
$(MKDIR_P) $(LCOV_REPORTS_DIR)
|
||||
for i in $(LCOV_TRACES); do \
|
||||
test -s $$i -a $$(wc -w <$$i) -ge 100 && lc="$$lc $$i"; \
|
||||
test -s $$i && lc="$$lc $$i"; \
|
||||
done; \
|
||||
test -z "$$lc" || $(GENHTML) -p @abs_top_builddir@ \
|
||||
-o $(LCOV_REPORTS_DIR) $$lc
|
||||
|
||||
2
README
2
README
@@ -18,7 +18,7 @@ Mailing list for general discussion related to LVM2:
|
||||
|
||||
Mailing lists for LVM2 development, patches and commits:
|
||||
lvm-devel@redhat.com
|
||||
Subscribe from https://www.redhat.com/mailman/listinfo/lvm-devel
|
||||
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
|
||||
|
||||
lvm2-commits@lists.fedorahosted.org (Read-only archive of commits)
|
||||
Subscribe from https://fedorahosted.org/mailman/listinfo/lvm2-commits
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.99-git (2015-06-12)
|
||||
1.02.91-git (2014-09-01)
|
||||
|
||||
293
WHATS_NEW
293
WHATS_NEW
@@ -1,286 +1,6 @@
|
||||
Version 2.02.122 -
|
||||
=================================
|
||||
|
||||
Version 2.02.121 - 12th June 2015
|
||||
=================================
|
||||
Distinguish between on-disk and lvmetad versions of text metadata.
|
||||
Remove DL_LIBS from Makefiles for daemons that don't need them.
|
||||
Zero errno in before strtoul call in dmsetup if tested after the call.
|
||||
Zero errno in before strtoul call in lvmpolld.
|
||||
Fix a segfault in pvscan --cache --background command.
|
||||
Fix test for AREA_PV when checking for failed mirrors.
|
||||
Do not use --sysinit in lvm2-activation{-early,-net}.service if lvmpolld used.
|
||||
Maintain outdated PV info in lvmetad till all old metadata is gone from disk.
|
||||
Do not fail polling when poll LV not found (already finished or removed).
|
||||
Replace poll_get_copy_vg/lv fns with vg_read() and find_lv() in polldaemon.
|
||||
Close all device fds only in before sleep call in polldaemon.
|
||||
Simplify Makefile targets that generate exported symbols.
|
||||
Move various -D settings from Makefiles to configure.h.
|
||||
|
||||
Version 2.02.120 - 15th May 2015
|
||||
================================
|
||||
Make various adjustments to Makefile compilation flags.
|
||||
Add lvmpolld debug message class.
|
||||
Add lvmpolld client mode for querying running server instance for status info.
|
||||
Fix some libdaemon socket creation and reuse error paths.
|
||||
Daemons (libdaemon) support exit on idle also in non-systemd environment.
|
||||
Provide make dist and make rpm targets
|
||||
Configure lvm.conf for use_lvmetad and use_lvmpolld.
|
||||
Add lvpoll for cmdline communication with lvmpolld.
|
||||
Add lvmpolld acting as a free-standing version of polldaemon.
|
||||
Avoid repeated identical lvmetad VG lookups in commands processing all VGs.
|
||||
Handle switches to alternative duplicate PVs efficiently with lvmetad.
|
||||
Properly validate PV size for pvcreate --restorefile.
|
||||
Fix check if pvcreate wiped device (2.02.117).
|
||||
Fix storing of vgid when caching metadata (2.02.118).
|
||||
Fix recursive lvm-config man page. (2.02.119)
|
||||
Refactor polldaemon interfaces to poll every operation by VG/LV couple
|
||||
Skip wait after testing in _wait_for_single_lv when polling finished
|
||||
Return 'None' in python for empty string properties instead of crashing.
|
||||
Distinguish signed numerical property type in reports for lvm2app library.
|
||||
Reread raid completion status immediately when progress appears to be zero.
|
||||
lvm2app closes locking on lvm_quit().
|
||||
Configure detects /run or /var/run.
|
||||
Add missing newline in clvmd --help output.
|
||||
|
||||
Version 2.02.119 - 2nd May 2015
|
||||
===============================
|
||||
New LVM_LOG_FILE_EPOCH, LVM_EXPECTED_EXIT_STATUS env vars. Man page to follow.
|
||||
Remove detailed content from lvm.conf man page: use lvmconfig instead.
|
||||
Generate complete config files with lvmconfig or 'make generate'.
|
||||
Also display info on deprecated config with lvmconfig --withcomments.
|
||||
Display version since which config is deprecated in lvmconfig --withversions.
|
||||
Add --showdeprecated to lvmconfig to also display deprecated settings.
|
||||
Hide deprecated settings in lvmconfig output for all types but current,diff.
|
||||
Introduce support for exit on idle feature in libdaemon
|
||||
Add --showunsupported to lvmconfig to also display unsupported settings.
|
||||
Display unsupported settings for lvmconfig --type current,diff only by default
|
||||
Honour lvmconfig --ignoreunsupported and --ignoreadvanced for all --type.
|
||||
Make python bindings usable with python3 (and compatible with 2.6 & 2.7).
|
||||
Add lvmconfig -l|--list as shortcut for lvmconfig --type list --withsummary.
|
||||
Add lvmconfig --type list to display plain list of configuration settings.
|
||||
Introduce lvmconfig as the preferred form of 'lvm dumpconfig'.
|
||||
Add lv_ancestors and lv_descendants reporting fields.
|
||||
Add --ignorelocal option to dumpconfig to ignore the local section.
|
||||
Close connection to lvmetad after fork.
|
||||
Make lvchange able to resume background pvmove polling again.
|
||||
Split pvmove update metadata fn in an initial one and a subsequent one.
|
||||
Refactor shared pvmove and lvconvert code into new _poll files.
|
||||
Add --unconfigured option to dumpconfig to print strings unconfigured.
|
||||
Add --withsummary option to dumpconfig to print first line - summary comment.
|
||||
Use number of device holders to help choose between duplicate PVs.
|
||||
Try to make lvmetad and non-lvmetad duplicate PV handling as similar as poss.
|
||||
Issue warnings about duplicate PVs discovered by lvmetad.
|
||||
Track alternative devices with matching PVIDs in lvmetad.
|
||||
Check for lvm binary in blkdeactivate and skip LVM processing if not present.
|
||||
Add --enable-halvm and --disable-halvm options to lvmconf script.
|
||||
Add --services, --mirrorservice and --startstopservices option to lvmconf.
|
||||
Use proper default value of global/use_lvmetad when processing lvmconf script.
|
||||
Respect allocation/cling_tag_list during intial contiguous allocation.
|
||||
Add A_PARTITION_BY_TAGS set when allocated areas should not share tags.
|
||||
Make changes persist with python addTag/removeTag.
|
||||
Set correct vgid when updating cache when writing PV metadata.
|
||||
More efficient clvmd singlenode locking emulation.
|
||||
Reject lvcreate -m with raid4/5/6 to avoid unexpected layout.
|
||||
Don't skip invalidation of cached orphans if vg write lck is held (2.02.118).
|
||||
Log relevant PV tags when using cling allocation.
|
||||
Add str_list_add_list() to combine two lists.
|
||||
Fix LV processing with selection to always do the selection on initial state.
|
||||
Add internal LV_REMOVED LV status flag.
|
||||
|
||||
Version 2.02.118 - 23rd March 2015
|
||||
==================================
|
||||
Store metadata size + checksum in lvmcache and add struct lvmcache_vgsummary.
|
||||
Remove inaccessible clustered PVs from 'pvs -a'.
|
||||
Don't invalidate cached orphan information while global lock is held.
|
||||
Avoid rescan of all devices when requested pvscan for removed device.
|
||||
Measure configuration timestamps with nanoseconds when available.
|
||||
Disable lvchange of major and minor of pool LVs.
|
||||
Fix pvscan --cache to not scan and read ignored metadata areas on PVs.
|
||||
Add After=iscsi-shutdown.service to blk-availability.service systemd unit.
|
||||
Disallow vgconvert from changing metadata format when lvmetad is used.
|
||||
Don't do a full read of VG when creating a new VG with an existing name.
|
||||
Reduce amount of VG metadata parsing when looking for vgname on a PV.
|
||||
Avoid reparsing same metadata when reading same metadata from multiple PVs.
|
||||
Save extra device open/close when scanning device for size.
|
||||
Fix seg_monitor field to report status also for mirrors and thick snapshots.
|
||||
Replace LVM_WRITE with LVM_WRITE_LOCKED flags in metadata if system ID is set.
|
||||
Remove ACCESS_NEEDS_SYSTEM_ID VG status flag. (2.02.117)
|
||||
Enable system ID features.
|
||||
|
||||
Version 2.02.117 - 4th March 2015
|
||||
=================================
|
||||
Add CFG_DISABLED for new system ID config settings that must not yet be used.
|
||||
Preserve original format type field when processing backup files.
|
||||
Implement status action for lvm2-monitor initscript to display monitored LVs.
|
||||
Allow lvchange -p to change kernel state only if metadata state differs.
|
||||
Fix incorrect persistent .cache after report with label fields only (2.02.106).
|
||||
Reinstate PV tag recognition for pvs if reporting label fields only (2.02.105).
|
||||
Rescan devices before vgimport with lvmetad so exported VG is seen.
|
||||
Fix hang by adjusting cluster mirror regionsize, avoiding CPG msg limit.
|
||||
Do not crash when --cachepolicy is given without --cachesettings.
|
||||
Add NEEDS_FOREIGN_VGS flag to vgimport so --foreign is always supplied.
|
||||
Add --foreign to the 6 display and reporting tools and vgcfgbackup.
|
||||
Install /etc/lvm/lvmlocal.conf template with local section for systemid.
|
||||
Record creation_host_system_id in lvm2 metadata (never set yet).
|
||||
Reinstate recursive config file tag section processing. (2.02.99)
|
||||
Add 'lvm systemid' to display the current system ID (never set yet).
|
||||
Fix configure to properly recognize --with-default-raid10-segtype option.
|
||||
Do not refresh filters/rescan if no signature is wiped during pvcreate.
|
||||
Enforce none external dev info for wiping during pvcreate to avoid races.
|
||||
Add global/system_id_source and system_id_file to lvm.conf (disabled).
|
||||
Add support for VG system_id to control host access to VGs.
|
||||
Update vgextend to use process_each_vg.
|
||||
Add --ignoreskippedcluster to pvchange.
|
||||
Allow pvchange to modify several properties at once.
|
||||
Update pvchange to use process_each_pv.
|
||||
Fix pvs -a used with lvmetad to filter out devices unsuitable for PVs.
|
||||
Fix selection to recognize units for ba_start, vg_free and seg_start fields.
|
||||
Add support for -S/--select to vgexport and vgimport.
|
||||
Add support for -S/--select to vgdisplay, lvdisplay and pvdisplay without -C.
|
||||
Add support for -S/--select to vgremove and lvremove.
|
||||
Add support for -S/--select to vgchange,lvchange and pvchange.
|
||||
Add infrastructure to support selection for non-reporting tools.
|
||||
Add LVM_COMMAND_PROFILE env var to set default command profile name to use.
|
||||
Set CLOEXEC flag on file descriptors originating in libdaemon.
|
||||
|
||||
Version 2.02.116 - 30th January 2015
|
||||
====================================
|
||||
Deactivate unused thin pools activated with lvm2 pre-2.02.112 versions.
|
||||
Check lock holding LV when lvconverting stacked raid LV in cluster.
|
||||
Support udev external dev info for filters: PV min size, mpath, md, partition.
|
||||
Add fw_raid_component_detection lvm.conf option to enable FW raid detection.
|
||||
Add devices/external_device_info_source lvm.conf option ("none" by default).
|
||||
Scan pools in for_each_sub_lv() and add for_each_sub_lv_except_pools().
|
||||
Fix lvm2app lvm_lv_get_property return value for fields with info/status ioctl.
|
||||
Fix lvm2app regression in lvm_lv_get_attr causing unknown values (2.02.115).
|
||||
Set default cache_mode to writehrough when missing in metadata.
|
||||
Preserve chunk size with repair and metadata swap of a thin pool.
|
||||
Fix raid --splitmirror 1 functionality (2.02.112).
|
||||
Fix tree preload to handle splitting raid images.
|
||||
Do not support unpartitioned DASD devices.
|
||||
Improve config validation to check if setting with string value can be empty.
|
||||
|
||||
Version 2.02.115 - 21st January 2015
|
||||
====================================
|
||||
Report segment types without monitoring support as undefined.
|
||||
Support lvchange --errorwhenfull for thin pools.
|
||||
Improve the processing and reporting of duplicate PVs.
|
||||
Report lv_health_status and health attribute also for thin pool.
|
||||
Add lv_when_full reporting field.
|
||||
Add support for lvcreate --errorwhenfull y|n for thin pools.
|
||||
Fix lvconvert --repair to honour resilience requirement for segmented RAID LV.
|
||||
Filter out partitioned device-mapper devices as unsuitable for use as PVs.
|
||||
Also notify lvmetad about filtered device if using pvscan --cache DevicePath.
|
||||
Use LVM's own selection instead of awk expressions in clvmd startup scripts.
|
||||
Do not filter out snapshot origin LVs as unusable devices for an LVM stack.
|
||||
Fix incorrect rimage names when converting from mirror to raid1 LV (2.02.112).
|
||||
Introduce pvremove_many to avoid excessive metadata re-reading and messages.
|
||||
Check for cmirror availability during cluster mirror creation and activation.
|
||||
Add cache_policy and cache_settings reporting fields.
|
||||
Add missing recognition for --binary option with {pv,vg,lv}display -C.
|
||||
Fix vgimportclone to notify lvmetad about changes done if lvmetad is used.
|
||||
Fix vgimportclone to properly override config if it is missing in lvm.conf.
|
||||
Fix automatic use of configure --enable-udev-systemd-background-jobs.
|
||||
Correctly rename active split LV with -splitmirrors for raid1.
|
||||
Add report/compact_output to lvm.conf to enable/disable compact report output.
|
||||
Still restrict mirror region size to power of 2 when VG extent size is not.
|
||||
|
||||
Version 2.02.114 - 28th November 2014
|
||||
Version 2.02.112 -
|
||||
=====================================
|
||||
Release socket in daemon_close and protocol string in daemon_open error path.
|
||||
Add --cachepolicy and --cachesettings to lvcreate.
|
||||
Fix regression when parsing /dev/mapper dir (2.02.112).
|
||||
Fix missing rounding to 64KB when estimating optimal thin pool chunk size.
|
||||
Fix typo in clvmd initscript causing CLVMD_STOP_TIMEOUT var to be ignored.
|
||||
Fix size in pvresize "Resizing to ..." verbose msg to show proper result size.
|
||||
|
||||
Version 2.02.113 - 24th November 2014
|
||||
=====================================
|
||||
Add --cachepolicy and --cachesettings options to lvchange.
|
||||
Validate that converted volume and specified pool volume differ in lvconvert.
|
||||
Fix regression in vgscan --mknodes usage (2.02.112).
|
||||
Respect --prefix when setting CLMVD_PATH configure (2.02.89).
|
||||
Default to configure --enable-udev-systemd-background-jobs for systemd>=205.
|
||||
Fix ignore_vg() to properly react on various vg_read errors (2.02.112).
|
||||
Failed recovery returns FAILED_RECOVERY status flag for vg_read().
|
||||
Exit with non-zero status code when pvck encounters a problem.
|
||||
Fix clean_tree after activation/resume for cache target (2.02.112).
|
||||
|
||||
Version 2.02.112 - 11th November 2014
|
||||
=====================================
|
||||
Add cache_{read,write}_{hits,misses} reporting fields.
|
||||
Add cache_{total,used,dirty}_blocks reporting fields.
|
||||
Add _corig as reserved suffix.
|
||||
Reduce number of VG writes and commits when creating spare volumes.
|
||||
When remove_layer_from_lv() removes layer, restore subLV names.
|
||||
Cache-pool in use becomes invisible LV.
|
||||
Don't prompt for removal of _pmspare in VG without pool metadata LV.
|
||||
Deactivation of snapshot origin detects and deactivates left-over snapshots.
|
||||
Properly report error when taking snapshot of any cache type LV.
|
||||
Add basic thread debugging messages to dmeventd.
|
||||
Include threads being shutdown in dmeventd device registration responses.
|
||||
Inital support for external users of thin pools based on transaction_id.
|
||||
Report some basic percentage info for cache pools.
|
||||
Introduce size_mb_arg_with_percent() for advanced size arg reading.
|
||||
Add extra support for '.' as decimal point in size args.
|
||||
Add configure parameters for default segment type choices.
|
||||
Add global/sparse_segtype_default setting to use thin for --type sparse.
|
||||
Update and correct lvcreate and lvcovert man pages.
|
||||
Mark pools and snapshots as unzeroable volumes.
|
||||
Check for zeroing of volume after segment type is fully detected.
|
||||
Better support for persistent major and minor options with lvcreate.
|
||||
Refactor lvcreate towards more complete validation of all supported options.
|
||||
Support lvcreate --type linear.
|
||||
Improve _should_wipe_lv() to warn with message.
|
||||
Inform about temporarily created volumes only in verbose mode.
|
||||
Better support for --test mode with pool creation.
|
||||
Query lock holding LV when replacing and converting raid volumes.
|
||||
Add extra validate for locked lv within validate_lv_cache_create().
|
||||
Add internal lvseg_name() function.
|
||||
Skip use of lock files for virtual internal VG names.
|
||||
Fix selection on {vg,lv}_permissions fields to properly match selection criteria.
|
||||
Fix lv_permissions reporting to display read-only{-override} instead of blank.
|
||||
Fix liblvm2cmd and lvm shell to respect quotes around args in cmd line string.
|
||||
Permit extent sizes > 128KB that are not power of 2 with lvm2 format.
|
||||
Remove workaround for lvm2-monitor.service hang on stop if lvmetad stopped.
|
||||
Change vgremove to use process_each_lv_in_vg.
|
||||
Allow lvconvert --repair and --splitmirrors on internal LVs.
|
||||
Introduce WARN_ flags to control some metadata warning messages.
|
||||
Use process_each_pv in vgreduce.
|
||||
Refactor process_each_pv in toollib.
|
||||
Introduce single validation routine for pool chunk size.
|
||||
Support --yes like --force in vg/lvremove to skip y|n prompt.
|
||||
Support --yes with lvconvert --splitsnapshot.
|
||||
Fix detection of unsupported thin external lvconversions.
|
||||
Fix detection of unsupported cache and thin pool lvconversions.
|
||||
Fix detection of unsupported lvconversion of cache to snapshot.
|
||||
Improve code for creation of cache and cache pool volumes.
|
||||
Check cluster-wide (not local) active status before removing LV.
|
||||
Properly check if activation of removed cached LV really activated.
|
||||
lvremove cached LV removes cachepool (keep with lvconvert --splitcache).
|
||||
Always remove spare LV with last removed pool volume.
|
||||
Support lvconvert --splitcache and --uncache of cached LV.
|
||||
Option --cache has also shortcut -H (i.e. lvcreate -H).
|
||||
Refactor lvcreate code and better preserve --type argument.
|
||||
Refactor filter processing around lvmetad.
|
||||
Refactor process_each_lv in toollib.
|
||||
Refactor process_each_vg in toollib.
|
||||
Pools cannot be used as external origin.
|
||||
Use lv_update_and_reload() for snapshot reload.
|
||||
Don't print message in adjusted_mirror_region_size() in activation.
|
||||
Improve lv_update_and_reload() to find out proper lock holding LV.
|
||||
Improve search of LV in lv_ondisk().
|
||||
Do not scan sysfs in lv_check_not_in_use() when device is closed.
|
||||
Backup final metadata after resync of mirror/raid.
|
||||
Unify handling of --persistent option for lvcreate and lvchange.
|
||||
Validate major and minor numbers stored in metadata.
|
||||
Use -fPIE when linking -pie executables.
|
||||
Support DEBUG_MEMLOCK to trap unsupported mmap usage.
|
||||
Enable cache segment type by default.
|
||||
Ensure only supported volume types are used with cache segments.
|
||||
Fix inablility to specify cachemode when 'lvconvert'ing to cache-pool.
|
||||
Grab cluster lock for active LVs when setting clustered attribute.
|
||||
Disable vgchange of clustered attribute with any active LV in VG.
|
||||
Use va_copy to properly pass va_list through functions.
|
||||
Add function to detect rotational devices.
|
||||
Review internal checks for mirror/raid/pvmove volumes.
|
||||
@@ -288,17 +8,16 @@ Version 2.02.112 - 11th November 2014
|
||||
Fix cmirror endian conversions.
|
||||
Introduce lv_is_pvmove/locked/converting/merging macros.
|
||||
Avoid leaving linear logical volume when thin pool creation fails.
|
||||
Demote an error to a warning when devices known to lvmetad are filtered out.
|
||||
Re-order filter evaluation, making component filters global.
|
||||
Don't leak alloc_handle on raid target error path.
|
||||
Properly validate raid leg names.
|
||||
Archive metadata before starting their modification in raid target.
|
||||
Add missing vg_revert() in suspend_lv() raid and snapshot error path.
|
||||
Add missing vg_revert in suspend_lv() error path in raid target.
|
||||
Add missing backup of lvm2 metadata after some raid modifications.
|
||||
Use vg memory pool for extent allocation.
|
||||
Add allocation/physical_extent_size config option for default PE size of VGs.
|
||||
Demote an error to a warning when devices known to lvmetad are filtered out.
|
||||
Re-order filter evaluation, making component filters global.
|
||||
Fix logic that checks for full scan before iterating through devices.
|
||||
Introduce common code to modify metadata and reload updated LV.
|
||||
Introduce common code to modify metadate and reload updated LV.
|
||||
Fix rename of active snapshot volume in cluster.
|
||||
Make sure shared libraries are built with RELRO option.
|
||||
|
||||
|
||||
53
WHATS_NEW_DM
53
WHATS_NEW_DM
@@ -1,56 +1,5 @@
|
||||
Version 1.02.99 -
|
||||
================================
|
||||
Enhance error message when thin-pool message fails.
|
||||
|
||||
Version 1.02.98 - 12th June 2015
|
||||
================================
|
||||
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
|
||||
Use copy of errno made after each dm ioctl call in case errno changes later.
|
||||
|
||||
Version 1.02.97 - 15th May 2015
|
||||
===============================
|
||||
New dm_task_get_info(DM_1_02_97) supports internal_suspend state.
|
||||
New symbols are versioned and comes with versioned symbol name (DM_1_02_97).
|
||||
|
||||
Version 1.02.96 - 2nd May 2015
|
||||
==============================
|
||||
Fix selection to not match if using reserved value in criteria with >,<,>=,<.
|
||||
Fix selection to not match reserved values for size fields if using >,<,>=,<.
|
||||
Include uuid or device number in log message after ioctl failure.
|
||||
Add DM_INTERNAL_SUSPEND_FLAG to dm-ioctl.h.
|
||||
Install blkdeactivate script and its man page with make install_device-mapper.
|
||||
|
||||
Version 1.02.95 - 15th March 2015
|
||||
=================================
|
||||
Makefile regenerated.
|
||||
|
||||
Version 1.02.94 - 4th March 2015
|
||||
================================
|
||||
Add dm_report_object_is_selected for generalized interface for report/select.
|
||||
|
||||
Version 1.02.93 - 21st January 2015
|
||||
===================================
|
||||
Reduce severity of ioctl error message when dmeventd waitevent is interrupted.
|
||||
Report 'unknown version' when incompatible version numbers were not obtained.
|
||||
Report more info from thin pool status (out of data, metadata-ro, fail).
|
||||
Support error_if_no_space for thin pool target.
|
||||
Fix segfault while using selection with regex and unbuffered reporting.
|
||||
Add dm_report_compact_fields to remove empty fields from report output.
|
||||
Remove unimplemented dm_report_set_output_selection from libdevmapper.h.
|
||||
|
||||
Version 1.02.92 - 24th November 2014
|
||||
Version 1.02.91 -
|
||||
====================================
|
||||
Fix memory corruption with sorting empty string lists (1.02.86).
|
||||
Fix man dmsetup.8 syntax warning of Groff
|
||||
Accept unquoted strings and / in place of {} when parsing configs.
|
||||
|
||||
Version 1.02.91 - 11th November 2014
|
||||
====================================
|
||||
Update cache creation and dm_config_node to pass policy.
|
||||
Allow activation of any thin-pool if transaction_id supplied is 0.
|
||||
Don't print uninitialized stack bytes when non-root uses dm_check_version().
|
||||
Fix selection criteria to not match reserved values when using >, <, >=, <.
|
||||
Add DM_LIST_HEAD_INIT macro to libdevmapper.h.
|
||||
Fix dm_is_dm_major to not issue error about missing /proc lines for dm module.
|
||||
|
||||
Version 1.02.90 - 1st September 2014
|
||||
|
||||
@@ -37,10 +37,6 @@ AC_DEFUN([AC_TRY_CCFLAG],
|
||||
fi
|
||||
])
|
||||
|
||||
dnl AC_IF_YES([TEST-FOR-YES], [ACTION-IF-TRUE], [ACTION-IF-FALSE])
|
||||
dnl AS_IF() abstraction, checks shell variable for 'yes'
|
||||
AC_DEFUN([AC_IF_YES], [AS_IF([test $$1 = yes], [$2], [$3])])
|
||||
|
||||
dnl AC_TRY_LDFLAGS([LDFLAGS], [VAR], [ACTION-IF-WORKS], [ACTION-IF-FAILS])
|
||||
dnl check if $CC supports given ld flags
|
||||
|
||||
|
||||
4
aclocal.m4
vendored
4
aclocal.m4
vendored
@@ -1,6 +1,6 @@
|
||||
# generated automatically by aclocal 1.15 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.13.4 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
||||
@@ -17,37 +17,24 @@ top_builddir = @top_builddir@
|
||||
|
||||
CONFSRC=example.conf
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
install_conf: $(CONFSRC)
|
||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||
echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST)"; \
|
||||
$(INSTALL_WDATA) -D $< $(confdir)/$(CONFDEST); \
|
||||
fi
|
||||
|
||||
install_localconf: $(CONFLOCAL)
|
||||
@if [ ! -e $(confdir)/$(CONFLOCAL) ]; then \
|
||||
echo "$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL)"; \
|
||||
$(INSTALL_WDATA) -D $< $(confdir)/$(CONFLOCAL); \
|
||||
fi
|
||||
|
||||
install_profiles: $(PROFILES)
|
||||
$(INSTALL_DIR) $(DESTDIR)$(DEFAULT_PROFILE_DIR)
|
||||
$(INSTALL_DATA) $(PROFILES) $(DESTDIR)$(DEFAULT_PROFILE_DIR)/
|
||||
|
||||
install_lvm2: install_conf install_localconf install_profiles
|
||||
install_lvm2: install_conf install_profiles
|
||||
|
||||
install: install_lvm2
|
||||
|
||||
DISTCLEAN_TARGETS += $(CONFSRC) $(CONFLOCAL) $(PROFILE_TEMPLATES)
|
||||
DISTCLEAN_TARGETS += $(CONFSRC) $(PROFILE_TEMPLATES)
|
||||
|
||||
@@ -18,7 +18,6 @@ global {
|
||||
lvdisplay_shows_full_device_path=0
|
||||
}
|
||||
report {
|
||||
compact_output=0
|
||||
aligned=1
|
||||
buffered=1
|
||||
headings=1
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# This is an example configuration file for the LVM2 system.
|
||||
# It contains the default settings that would be used if there was no
|
||||
# @DEFAULT_SYS_DIR@/lvm.conf file.
|
||||
#
|
||||
# Refer to 'man lvm.conf' for further information including the file layout.
|
||||
#
|
||||
# Refer to 'man lvm.conf' for information about how settings configured in
|
||||
# this file are combined with built-in values and command line options to
|
||||
# arrive at the final values used by LVM.
|
||||
#
|
||||
# Refer to 'man lvmconfig' for information about displaying the built-in
|
||||
# and configured values used by LVM.
|
||||
#
|
||||
# If a default value is set in this file (not commented out), then a
|
||||
# new version of LVM using this file will continue using that value,
|
||||
# even if the new version of LVM changes the built-in default value.
|
||||
#
|
||||
# To put this file in a different directory and override @DEFAULT_SYS_DIR@ set
|
||||
# the environment variable LVM_SYSTEM_DIR before running the tools.
|
||||
#
|
||||
# N.B. Take care that each setting only appears once if uncommenting
|
||||
# example settings in this file.
|
||||
|
||||
2452
conf/example.conf.in
2452
conf/example.conf.in
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
# This is a local configuration file template for the LVM2 system
|
||||
# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
|
||||
#
|
||||
# Refer to 'man lvm.conf' for information about the file layout.
|
||||
#
|
||||
# To put this file in a different directory and override
|
||||
# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
|
||||
# running the tools.
|
||||
#
|
||||
# The lvmlocal.conf file is normally expected to contain only the
|
||||
# "local" section which contains settings that should not be shared or
|
||||
# repeated among different hosts. (But if other sections are present,
|
||||
# they *will* get processed. Settings in this file override equivalent
|
||||
# ones in lvm.conf and are in turn overridden by ones in any enabled
|
||||
# lvm_<tag>.conf files.)
|
||||
#
|
||||
# Please take care that each setting only appears once if uncommenting
|
||||
# example settings in this file and never copy this file between hosts.
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# This is a local configuration file template for the LVM2 system
|
||||
# which should be installed as @DEFAULT_SYS_DIR@/lvmlocal.conf .
|
||||
#
|
||||
# Refer to 'man lvm.conf' for information about the file layout.
|
||||
#
|
||||
# To put this file in a different directory and override
|
||||
# @DEFAULT_SYS_DIR@ set the environment variable LVM_SYSTEM_DIR before
|
||||
# running the tools.
|
||||
#
|
||||
# The lvmlocal.conf file is normally expected to contain only the
|
||||
# "local" section which contains settings that should not be shared or
|
||||
# repeated among different hosts. (But if other sections are present,
|
||||
# they *will* get processed. Settings in this file override equivalent
|
||||
# ones in lvm.conf and are in turn overridden by ones in any enabled
|
||||
# lvm_<tag>.conf files.)
|
||||
#
|
||||
# Please take care that each setting only appears once if uncommenting
|
||||
# example settings in this file and never copy this file between hosts.
|
||||
|
||||
|
||||
# Configuration section local.
|
||||
# LVM settings that are specific to the local host.
|
||||
local {
|
||||
|
||||
# Configuration option local/system_id.
|
||||
# Defines the local system ID for lvmlocal mode.
|
||||
# This is used when global/system_id_source is set
|
||||
# to 'lvmlocal' in the main configuration file,
|
||||
# e.g. lvm.conf.
|
||||
# When used, it must be set to a unique value
|
||||
# among all hosts sharing access to the storage,
|
||||
# e.g. a host name.
|
||||
# Example:
|
||||
# Set no system ID.
|
||||
# system_id = ""
|
||||
# Example:
|
||||
# Set the system_id to the string 'host1'.
|
||||
# system_id = "host1"
|
||||
# This configuration option does not have a default value defined.
|
||||
# system_id=""
|
||||
|
||||
# Configuration option local/extra_system_ids.
|
||||
# A list of extra VG system IDs the local host can access.
|
||||
# VGs with the system IDs listed here (in addition
|
||||
# to the host's own system ID) can be fully accessed
|
||||
# by the local host. (These are system IDs that the
|
||||
# host sees in VGs, not system IDs that identify the
|
||||
# local host, which is determined by system_id_source.)
|
||||
# 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=[]
|
||||
}
|
||||
@@ -16,7 +16,7 @@ allocation {
|
||||
thin_pool_zero=1
|
||||
thin_pool_discards="passdown"
|
||||
thin_pool_chunk_size_policy="generic"
|
||||
# thin_pool_chunk_size=128
|
||||
# thin_pool_chunk_size=64
|
||||
}
|
||||
activation {
|
||||
thin_pool_autoextend_threshold=100
|
||||
|
||||
341
configure.in
341
configure.in
@@ -1,6 +1,6 @@
|
||||
###############################################################################
|
||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
## Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
|
||||
##
|
||||
## This copyrighted material is made available to anyone wishing to use,
|
||||
## modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -26,9 +26,10 @@ AC_CONFIG_AUX_DIR(autoconf)
|
||||
dnl -- Get system type
|
||||
AC_CANONICAL_TARGET([])
|
||||
|
||||
AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
CFLAGS="$CFLAGS"
|
||||
COPTIMISE_FLAG="-O2"
|
||||
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
|
||||
ELDFLAGS="-Wl,--export-dynamic"
|
||||
# FIXME Generate list and use --dynamic-list=.dlopen.sym
|
||||
@@ -38,7 +39,6 @@ case "$host_os" in
|
||||
LIB_SUFFIX=so
|
||||
DEVMAPPER=yes
|
||||
LVMETAD=no
|
||||
LVMPOLLD=no
|
||||
ODIRECT=yes
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
@@ -48,6 +48,7 @@ case "$host_os" in
|
||||
;;
|
||||
darwin*)
|
||||
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
|
||||
COPTIMISE_FLAG="-O2"
|
||||
CLDFLAGS="$CLDFLAGS"
|
||||
ELDFLAGS=
|
||||
CLDWHOLEARCHIVE="-all_load"
|
||||
@@ -67,12 +68,7 @@ esac
|
||||
dnl -- Checks for programs.
|
||||
AC_PROG_SED
|
||||
AC_PROG_AWK
|
||||
save_CFLAGS=$CFLAGS
|
||||
save_CXXFLAGS=$CXXFLAGS
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
CFLAGS=$save_CFLAGS
|
||||
CXXFLAGS=$save_CXXFLAGS
|
||||
|
||||
dnl probably no longer needed in 2008, but...
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
@@ -177,7 +173,7 @@ dnl -- Setup the ownership of the files
|
||||
AC_MSG_CHECKING(file owner)
|
||||
AC_ARG_WITH(user,
|
||||
AC_HELP_STRING([--with-user=USER],
|
||||
[set the owner of installed files [USER=]]),
|
||||
[set the owner of installed files [[USER=]]]),
|
||||
OWNER=$withval)
|
||||
AC_MSG_RESULT($OWNER)
|
||||
test -n "$OWNER" && INSTALL="$INSTALL -o $OWNER"
|
||||
@@ -187,7 +183,7 @@ dnl -- Setup the group ownership of the files
|
||||
AC_MSG_CHECKING(group owner)
|
||||
AC_ARG_WITH(group,
|
||||
AC_HELP_STRING([--with-group=GROUP],
|
||||
[set the group owner of installed files [GROUP=]]),
|
||||
[set the group owner of installed files [[GROUP=]]]),
|
||||
GROUP=$withval)
|
||||
AC_MSG_RESULT($GROUP)
|
||||
test -n "$GROUP" && INSTALL="$INSTALL -g $GROUP"
|
||||
@@ -198,10 +194,9 @@ AC_MSG_CHECKING(device node uid)
|
||||
|
||||
AC_ARG_WITH(device-uid,
|
||||
AC_HELP_STRING([--with-device-uid=UID],
|
||||
[set the owner used for new device nodes [UID=0]]),
|
||||
[set the owner used for new device nodes [[UID=0]]]),
|
||||
DM_DEVICE_UID=$withval, DM_DEVICE_UID=0)
|
||||
AC_MSG_RESULT($DM_DEVICE_UID)
|
||||
AC_DEFINE_UNQUOTED([DM_DEVICE_UID], [$DM_DEVICE_UID], [Define default owner for device node])
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup device group ownership
|
||||
@@ -209,10 +204,9 @@ AC_MSG_CHECKING(device node gid)
|
||||
|
||||
AC_ARG_WITH(device-gid,
|
||||
AC_HELP_STRING([--with-device-gid=GID],
|
||||
[set the group used for new device nodes [GID=0]]),
|
||||
[set the group used for new device nodes [[GID=0]]]),
|
||||
DM_DEVICE_GID=$withval, DM_DEVICE_GID=0)
|
||||
AC_MSG_RESULT($DM_DEVICE_GID)
|
||||
AC_DEFINE_UNQUOTED([DM_DEVICE_GID], [$DM_DEVICE_GID], [Define default group for device node])
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup device mode
|
||||
@@ -220,15 +214,14 @@ AC_MSG_CHECKING(device node mode)
|
||||
|
||||
AC_ARG_WITH(device-mode,
|
||||
AC_HELP_STRING([--with-device-mode=MODE],
|
||||
[set the mode used for new device nodes [MODE=0600]]),
|
||||
[set the mode used for new device nodes [[MODE=0600]]]),
|
||||
DM_DEVICE_MODE=$withval, DM_DEVICE_MODE=0600)
|
||||
AC_MSG_RESULT($DM_DEVICE_MODE)
|
||||
AC_DEFINE_UNQUOTED([DM_DEVICE_MODE], [$DM_DEVICE_MODE], [Define default mode for device node])
|
||||
|
||||
AC_MSG_CHECKING(when to create device nodes)
|
||||
AC_ARG_WITH(device-nodes-on,
|
||||
AC_HELP_STRING([--with-device-nodes-on=ON],
|
||||
[create nodes on resume or create [ON=resume]]),
|
||||
[create nodes on resume or create [[ON=resume]]]),
|
||||
ADD_NODE=$withval, ADD_NODE=resume)
|
||||
case "$ADD_NODE" in
|
||||
resume) add_on=DM_ADD_NODE_ON_RESUME;;
|
||||
@@ -241,7 +234,7 @@ AC_DEFINE_UNQUOTED([DEFAULT_DM_ADD_NODE], $add_on, [Define default node creation
|
||||
AC_MSG_CHECKING(default name mangling)
|
||||
AC_ARG_WITH(default-name-mangling,
|
||||
AC_HELP_STRING([--with-default-name-mangling=MANGLING],
|
||||
[default name mangling: auto/none/hex [auto]]),
|
||||
[default name mangling: auto/none/hex [[MANGLING=auto]]]),
|
||||
MANGLING=$withval, MANGLING=auto)
|
||||
case "$MANGLING" in
|
||||
auto) mangling=DM_STRING_MANGLING_AUTO;;
|
||||
@@ -271,7 +264,8 @@ dnl -- format1 inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for lvm1 metadata)
|
||||
AC_ARG_WITH(lvm1,
|
||||
AC_HELP_STRING([--with-lvm1=TYPE],
|
||||
[LVM1 metadata support: internal/shared/none [internal]]),
|
||||
[LVM1 metadata support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
LVM1=$withval, LVM1=internal)
|
||||
|
||||
AC_MSG_RESULT($LVM1)
|
||||
@@ -288,7 +282,8 @@ dnl -- format_pool inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for GFS pool metadata)
|
||||
AC_ARG_WITH(pool,
|
||||
AC_HELP_STRING([--with-pool=TYPE],
|
||||
[GFS pool read-only support: internal/shared/none [internal]]),
|
||||
[GFS pool read-only support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
POOL=$withval, POOL=internal)
|
||||
AC_MSG_RESULT($POOL)
|
||||
|
||||
@@ -304,7 +299,8 @@ dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
AC_ARG_WITH(cluster,
|
||||
AC_HELP_STRING([--with-cluster=TYPE],
|
||||
[cluster LVM locking support: internal/shared/none [internal]]),
|
||||
[cluster LVM locking support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
CLUSTER=$withval)
|
||||
AC_MSG_RESULT($CLUSTER)
|
||||
|
||||
@@ -320,7 +316,8 @@ dnl -- snapshots inclusion type
|
||||
AC_MSG_CHECKING(whether to include snapshots)
|
||||
AC_ARG_WITH(snapshots,
|
||||
AC_HELP_STRING([--with-snapshots=TYPE],
|
||||
[snapshot support: internal/shared/none [internal]]),
|
||||
[snapshot support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
SNAPSHOTS=$withval, SNAPSHOTS=internal)
|
||||
AC_MSG_RESULT($SNAPSHOTS)
|
||||
|
||||
@@ -336,7 +333,8 @@ dnl -- mirrors inclusion type
|
||||
AC_MSG_CHECKING(whether to include mirrors)
|
||||
AC_ARG_WITH(mirrors,
|
||||
AC_HELP_STRING([--with-mirrors=TYPE],
|
||||
[mirror support: internal/shared/none [internal]]),
|
||||
[mirror support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
MIRRORS=$withval, MIRRORS=internal)
|
||||
AC_MSG_RESULT($MIRRORS)
|
||||
|
||||
@@ -352,39 +350,25 @@ dnl -- raid inclusion type
|
||||
AC_MSG_CHECKING(whether to include raid)
|
||||
AC_ARG_WITH(raid,
|
||||
AC_HELP_STRING([--with-raid=TYPE],
|
||||
[raid support: internal/shared/none [internal]]),
|
||||
[raid support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
RAID=$withval, RAID=internal)
|
||||
AC_MSG_RESULT($RAID)
|
||||
|
||||
AC_ARG_WITH(default-mirror-segtype,
|
||||
AC_HELP_STRING([--with-default-mirror-segtype=TYPE],
|
||||
[default mirror segtype: raid1/mirror [raid1]]),
|
||||
DEFAULT_MIRROR_SEGTYPE=$withval, DEFAULT_MIRROR_SEGTYPE="raid1")
|
||||
AC_ARG_WITH(default-raid10-segtype,
|
||||
AC_HELP_STRING([--with-default-raid10-segtype=TYPE],
|
||||
[default mirror segtype: raid10/mirror [raid10]]),
|
||||
DEFAULT_RAID10_SEGTYPE=$withval, DEFAULT_RAID10_SEGTYPE="raid10")
|
||||
case "$RAID" in
|
||||
none) test "$DEFAULT_MIRROR_SEGTYPE" = "raid1" && DEFAULT_MIRROR_SEGTYPE="mirror"
|
||||
test "$DEFAULT_RAID10_SEGTYPE" = "raid10" && DEFAULT_RAID10_SEGTYPE="mirror" ;;
|
||||
shared) ;;
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([RAID_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for raid.]) ;;
|
||||
*) AC_MSG_ERROR([--with-raid parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_MIRROR_SEGTYPE], ["$DEFAULT_MIRROR_SEGTYPE"],
|
||||
[Default segtype used for mirror volumes.])
|
||||
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_RAID10_SEGTYPE], ["$DEFAULT_RAID10_SEGTYPE"],
|
||||
[Default segtype used for raid10 volumes.])
|
||||
|
||||
################################################################################
|
||||
dnl -- asynchronous volume replicator inclusion type
|
||||
AC_MSG_CHECKING(whether to include replicators)
|
||||
AC_ARG_WITH(replicators,
|
||||
AC_HELP_STRING([--with-replicators=TYPE],
|
||||
[replicator support: internal/shared/none [none]]),
|
||||
[replicator support: internal/shared/none
|
||||
[[TYPE=none]]]),
|
||||
REPLICATORS=$withval, REPLICATORS=none)
|
||||
AC_MSG_RESULT($REPLICATORS)
|
||||
|
||||
@@ -395,49 +379,40 @@ case "$REPLICATORS" in
|
||||
*) AC_MSG_ERROR([--with-replicators parameter invalid ($REPLICATORS)]) ;;
|
||||
esac
|
||||
|
||||
|
||||
AC_ARG_WITH(default-sparse-segtype,
|
||||
AC_HELP_STRING([--with-default-sparse-segtype=TYPE],
|
||||
[default sparse segtype: thin/snapshot [thin]]),
|
||||
DEFAULT_SPARSE_SEGTYPE=$withval, DEFAULT_SPARSE_SEGTYPE="thin")
|
||||
|
||||
################################################################################
|
||||
dnl -- thin provisioning
|
||||
AC_MSG_CHECKING(whether to include thin provisioning)
|
||||
AC_ARG_WITH(thin,
|
||||
AC_HELP_STRING([--with-thin=TYPE],
|
||||
[thin provisioning support: internal/shared/none [internal]]),
|
||||
[thin provisioning support: internal/shared/none
|
||||
[[TYPE=internal]]]),
|
||||
THIN=$withval, THIN=internal)
|
||||
AC_ARG_WITH(thin-check,
|
||||
AC_HELP_STRING([--with-thin-check=PATH],
|
||||
[thin_check tool: [autodetect]]),
|
||||
[thin_check tool: [[autodetect]]]),
|
||||
THIN_CHECK_CMD=$withval, THIN_CHECK_CMD="autodetect")
|
||||
AC_ARG_WITH(thin-dump,
|
||||
AC_HELP_STRING([--with-thin-dump=PATH],
|
||||
[thin_dump tool: [autodetect]]),
|
||||
[thin_dump tool: [[autodetect]]]),
|
||||
THIN_DUMP_CMD=$withval, THIN_DUMP_CMD="autodetect")
|
||||
AC_ARG_WITH(thin-repair,
|
||||
AC_HELP_STRING([--with-thin-repair=PATH],
|
||||
[thin_repair tool: [autodetect]]),
|
||||
[thin_repair tool: [[autodetect]]]),
|
||||
THIN_REPAIR_CMD=$withval, THIN_REPAIR_CMD="autodetect")
|
||||
AC_ARG_WITH(thin-restore,
|
||||
AC_HELP_STRING([--with-thin-restore=PATH],
|
||||
[thin_restore tool: [autodetect]]),
|
||||
[thin_restore tool: [[autodetect]]]),
|
||||
THIN_RESTORE_CMD=$withval, THIN_RESTORE_CMD="autodetect")
|
||||
|
||||
AC_MSG_RESULT($THIN)
|
||||
|
||||
case "$THIN" in
|
||||
none) test "$DEFAULT_SPARSE_SEGTYPE" = "thin" && DEFAULT_SPARSE_SEGTYPE="snapshot" ;;
|
||||
shared) ;;
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([THIN_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for thin provisioning.]) ;;
|
||||
*) AC_MSG_ERROR([--with-thin parameter invalid ($THIN)]) ;;
|
||||
esac
|
||||
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_SPARSE_SEGTYPE], ["$DEFAULT_SPARSE_SEGTYPE"],
|
||||
[Default segtype used for sparse volumes.])
|
||||
|
||||
dnl -- thin_check needs-check flag
|
||||
AC_ARG_ENABLE(thin_check_needs_check,
|
||||
AC_HELP_STRING([--disable-thin_check_needs_check],
|
||||
@@ -499,16 +474,15 @@ case "$THIN" in
|
||||
THIN_CONFIGURE_WARN=y
|
||||
}
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether thin_check supports the needs-check flag])
|
||||
AC_MSG_RESULT([$THIN_CHECK_NEEDS_CHECK])
|
||||
if test "$THIN_CHECK_NEEDS_CHECK" = yes; then
|
||||
AC_DEFINE([THIN_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'thin_check' tool requires the --clear-needs-check-flag option])
|
||||
fi
|
||||
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_MSG_CHECKING([whether thin_check supports the needs-check flag])
|
||||
AC_MSG_RESULT([$THIN_CHECK_NEEDS_CHECK])
|
||||
if test "$THIN_CHECK_NEEDS_CHECK" = yes; then
|
||||
AC_DEFINE([THIN_CHECK_NEEDS_CHECK], 1, [Define to 1 if the external 'thin_check' tool requires the --clear-needs-check-flag option])
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED([THIN_CHECK_CMD], ["$THIN_CHECK_CMD"],
|
||||
[The path to 'thin_check', if available.])
|
||||
|
||||
@@ -526,23 +500,23 @@ dnl -- cache inclusion type
|
||||
AC_MSG_CHECKING(whether to include cache)
|
||||
AC_ARG_WITH(cache,
|
||||
AC_HELP_STRING([--with-cache=TYPE],
|
||||
[cache support: internal/shared/none [internal]]),
|
||||
CACHE=$withval, CACHE="internal")
|
||||
[cache support: internal/shared/none [[TYPE=none]]]),
|
||||
CACHE=$withval, CACHE="none")
|
||||
AC_ARG_WITH(cache-check,
|
||||
AC_HELP_STRING([--with-cache-check=PATH],
|
||||
[cache_check tool: [autodetect]]),
|
||||
[cache_check tool: [[autodetect]]]),
|
||||
CACHE_CHECK_CMD=$withval, CACHE_CHECK_CMD="autodetect")
|
||||
AC_ARG_WITH(cache-dump,
|
||||
AC_HELP_STRING([--with-cache-dump=PATH],
|
||||
[cache_dump tool: [autodetect]]),
|
||||
[cache_dump tool: [[autodetect]]]),
|
||||
CACHE_DUMP_CMD=$withval, CACHE_DUMP_CMD="autodetect")
|
||||
AC_ARG_WITH(cache-repair,
|
||||
AC_HELP_STRING([--with-cache-repair=PATH],
|
||||
[cache_repair tool: [autodetect]]),
|
||||
[cache_repair tool: [[autodetect]]]),
|
||||
CACHE_REPAIR_CMD=$withval, CACHE_REPAIR_CMD="autodetect")
|
||||
AC_ARG_WITH(cache-restore,
|
||||
AC_HELP_STRING([--with-cache-restore=PATH],
|
||||
[cache_restore tool: [autodetect]]),
|
||||
[cache_restore tool: [[autodetect]]]),
|
||||
CACHE_RESTORE_CMD=$withval, CACHE_RESTORE_CMD="autodetect")
|
||||
AC_MSG_RESULT($CACHE)
|
||||
|
||||
@@ -634,7 +608,7 @@ AC_ARG_ENABLE(ocf,
|
||||
AC_MSG_RESULT($OCF)
|
||||
AC_ARG_WITH(ocfdir,
|
||||
AC_HELP_STRING([--with-ocfdir=DIR],
|
||||
[install OCF files in [PREFIX/lib/ocf/resource.d/lvm2]]),
|
||||
[install OCF files in DIR [[PREFIX/lib/ocf/resource.d/lvm2]]]),
|
||||
OCFDIR=$withval, OCFDIR='${prefix}/lib/ocf/resource.d/lvm2')
|
||||
|
||||
################################################################################
|
||||
@@ -651,32 +625,28 @@ pkg_config_init() {
|
||||
}
|
||||
|
||||
################################################################################
|
||||
AC_MSG_CHECKING(for default run directory)
|
||||
RUN_DIR="/run"
|
||||
test -d "/run" || RUN_DIR="/var/run"
|
||||
AC_MSG_RESULT($RUN_DIR)
|
||||
dnl -- Set up pidfile and run directory
|
||||
AH_TEMPLATE(DEFAULT_PID_DIR)
|
||||
AC_ARG_WITH(default-pid-dir,
|
||||
AC_HELP_STRING([--with-default-pid-dir=PID_DIR],
|
||||
[Default directory to keep PID files in. [autodetect]]),
|
||||
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR=$RUN_DIR)
|
||||
[Default directory to keep PID files in. [[/var/run]]]),
|
||||
DEFAULT_PID_DIR="$withval", DEFAULT_PID_DIR="/var/run")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_PID_DIR, ["$DEFAULT_PID_DIR"],
|
||||
[Default directory to keep PID files in.])
|
||||
|
||||
AH_TEMPLATE(DEFAULT_DM_RUN_DIR, [Name of default DM run directory.])
|
||||
AC_ARG_WITH(default-dm-run-dir,
|
||||
AC_HELP_STRING([--with-default-dm-run-dir=DM_RUN_DIR],
|
||||
[ Default DM run directory. [autodetect]]),
|
||||
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR=$RUN_DIR)
|
||||
[ Default DM run directory. [[/var/run]]]),
|
||||
DEFAULT_DM_RUN_DIR="$withval", DEFAULT_DM_RUN_DIR="/var/run")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_DM_RUN_DIR, ["$DEFAULT_DM_RUN_DIR"],
|
||||
[Default DM run directory.])
|
||||
|
||||
AH_TEMPLATE(DEFAULT_RUN_DIR, [Name of default LVM run directory.])
|
||||
AC_ARG_WITH(default-run-dir,
|
||||
AC_HELP_STRING([--with-default-run-dir=RUN_DIR],
|
||||
[Default LVM run directory. [autodetect_run_dir/lvm]]),
|
||||
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="$RUN_DIR/lvm")
|
||||
[Default LVM run directory. [[/var/run/lvm]]]),
|
||||
DEFAULT_RUN_DIR="$withval", DEFAULT_RUN_DIR="/var/run/lvm")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||
[Default LVM run directory.])
|
||||
|
||||
@@ -691,7 +661,7 @@ AC_ARG_WITH(clvmd,
|
||||
* singlenode (localhost only)
|
||||
* all (autodetect)
|
||||
* none (disable build)
|
||||
[[none]]],
|
||||
[[TYPE=none]]],
|
||||
CLVMD=$withval, CLVMD=none)
|
||||
test "$CLVMD" = yes && CLVMD=all
|
||||
AC_MSG_RESULT($CLVMD)
|
||||
@@ -908,7 +878,7 @@ dnl -- clvmd pidfile
|
||||
if test "$CLVMD" != none; then
|
||||
AC_ARG_WITH(clvmd-pidfile,
|
||||
AC_HELP_STRING([--with-clvmd-pidfile=PATH],
|
||||
[clvmd pidfile [PID_DIR/clvmd.pid]]),
|
||||
[clvmd pidfile [[PID_DIR/clvmd.pid]]]),
|
||||
CLVMD_PIDFILE=$withval,
|
||||
CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid")
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"],
|
||||
@@ -931,7 +901,7 @@ dnl -- cmirrord pidfile
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_ARG_WITH(cmirrord-pidfile,
|
||||
AC_HELP_STRING([--with-cmirrord-pidfile=PATH],
|
||||
[cmirrord pidfile [PID_DIR/cmirrord.pid]]),
|
||||
[cmirrord pidfile [[PID_DIR/cmirrord.pid]]]),
|
||||
CMIRRORD_PIDFILE=$withval,
|
||||
CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid")
|
||||
AC_DEFINE_UNQUOTED(CMIRRORD_PIDFILE, ["$CMIRRORD_PIDFILE"],
|
||||
@@ -972,15 +942,13 @@ AC_TRY_CCFLAG([-Wjump-misses-init], [HAVE_WJUMP], [], [])
|
||||
AC_SUBST(HAVE_WJUMP)
|
||||
AC_TRY_CCFLAG([-Wclobbered], [HAVE_WCLOBBERED], [], [])
|
||||
AC_SUBST(HAVE_WCLOBBERED)
|
||||
AC_TRY_CCFLAG([-Wsync-nand], [HAVE_WSYNCNAND], [], [])
|
||||
AC_SUBST(HAVE_WSYNCNAND)
|
||||
|
||||
################################################################################
|
||||
dnl -- Override optimisation
|
||||
AC_MSG_CHECKING(for C optimisation flag)
|
||||
AC_ARG_WITH(optimisation,
|
||||
AC_HELP_STRING([--with-optimisation=OPT],
|
||||
[C optimisation flag [OPT=-O2]]),
|
||||
[C optimisation flag [[OPT=-O2]]]),
|
||||
COPTIMISE_FLAG=$withval)
|
||||
AC_MSG_RESULT($COPTIMISE_FLAG)
|
||||
|
||||
@@ -1035,16 +1003,12 @@ AC_ARG_ENABLE(valgrind_pool,
|
||||
VALGRIND_POOL=$enableval, VALGRIND_POOL=no)
|
||||
AC_MSG_RESULT($VALGRIND_POOL)
|
||||
|
||||
pkg_config_init
|
||||
PKG_CHECK_MODULES(VALGRIND, valgrind, [HAVE_VALGRIND=yes], [if test x$VALGRIND_POOL = xyes; then AC_MSG_ERROR(bailing out); fi])
|
||||
AC_SUBST(VALGRIND_CFLAGS)
|
||||
|
||||
if test x$HAVE_VALGRIND = xyes; then
|
||||
AC_DEFINE([HAVE_VALGRIND], 1, [valgrind.h found])
|
||||
fi
|
||||
|
||||
if test x$VALGRIND_POOL = xyes; then
|
||||
if test "$VALGRIND_POOL" = yes; then
|
||||
pkg_config_init
|
||||
PKG_CHECK_MODULES(VALGRIND, valgrind, [], [AC_MSG_ERROR(bailing out)])
|
||||
AC_DEFINE([VALGRIND_POOL], 1, [Enable a valgrind aware build of pool])
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(VALGRIND_CFLAGS)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
@@ -1072,65 +1036,16 @@ AC_MSG_RESULT($LVMETAD)
|
||||
BUILD_LVMETAD=$LVMETAD
|
||||
|
||||
if test "$BUILD_LVMETAD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmetad])
|
||||
AC_ARG_ENABLE(use_lvmetad,
|
||||
AC_HELP_STRING([--disable-use-lvmetad],
|
||||
[disable usage of LVM Metadata Daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMETAD=1 ;;
|
||||
*) DEFAULT_USE_LVMETAD=0 ;;
|
||||
esac], DEFAULT_USE_LVMETAD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMETAD)
|
||||
AC_DEFINE([LVMETAD_SUPPORT], 1, [Define to 1 to include code that uses lvmetad.])
|
||||
|
||||
AC_ARG_WITH(lvmetad-pidfile,
|
||||
AC_HELP_STRING([--with-lvmetad-pidfile=PATH],
|
||||
[lvmetad pidfile [PID_DIR/lvmetad.pid]]),
|
||||
[lvmetad pidfile [[PID_DIR/lvmetad.pid]]]),
|
||||
LVMETAD_PIDFILE=$withval,
|
||||
LVMETAD_PIDFILE="$DEFAULT_PID_DIR/lvmetad.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMETAD_PIDFILE, ["$LVMETAD_PIDFILE"],
|
||||
[Path to lvmetad pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMETAD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMETAD, [$DEFAULT_USE_LVMETAD],
|
||||
[Use lvmetad by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- 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
|
||||
|
||||
if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_MSG_CHECKING([defaults for use_lvmpolld])
|
||||
AC_ARG_ENABLE(use_lvmpolld,
|
||||
AC_HELP_STRING([--disable-use-lvmpolld],
|
||||
[disable usage of LVM Poll Daemon]),
|
||||
[case ${enableval} in
|
||||
yes) DEFAULT_USE_LVMPOLLD=1 ;;
|
||||
*) DEFAULT_USE_LVMPOLLD=0 ;;
|
||||
esac], DEFAULT_USE_LVMPOLLD=1)
|
||||
AC_MSG_RESULT($DEFAULT_USE_LVMPOLLD)
|
||||
AC_DEFINE([LVMPOLLD_SUPPORT], 1, [Define to 1 to include code that uses lvmpolld.])
|
||||
|
||||
AC_ARG_WITH(lvmpolld-pidfile,
|
||||
AC_HELP_STRING([--with-lvmpolld-pidfile=PATH],
|
||||
[lvmpolld pidfile [PID_DIR/lvmpolld.pid]]),
|
||||
LVMPOLLD_PIDFILE=$withval,
|
||||
LVMPOLLD_PIDFILE="$DEFAULT_PID_DIR/lvmpolld.pid")
|
||||
AC_DEFINE_UNQUOTED(LVMPOLLD_PIDFILE, ["$LVMPOLLD_PIDFILE"],
|
||||
[Path to lvmpolld pidfile.])
|
||||
else
|
||||
DEFAULT_USE_LVMPOLLD=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_USE_LVMPOLLD, [$DEFAULT_USE_LVMPOLLD],
|
||||
[Use lvmpolld by default.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable blkid wiping functionality
|
||||
@@ -1158,26 +1073,13 @@ fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
|
||||
dnl -- Requires systemd version 205 at least (including support for systemd-run)
|
||||
AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
|
||||
AC_ARG_ENABLE(udev-systemd-background-jobs,
|
||||
AC_HELP_STRING([--disable-udev-systemd-background-jobs],
|
||||
[disable udev-systemd protocol to instantiate a service for background job]),
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval,
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=maybe)
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval, UDEV_SYSTEMD_BACKGROUND_JOBS=yes)
|
||||
AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
|
||||
if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" != no; then
|
||||
pkg_config_init
|
||||
PKG_CHECK_MODULES(SYSTEMD, systemd >= 205,
|
||||
[test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe && UDEV_SYSTEMD_BACKGROUND_JOBS=yes],
|
||||
[if test "$UDEV_SYSTEMD_BACKGROUND_JOBS" = maybe; then
|
||||
UDEV_SYSTEMD_BACKGROUND_JOBS=no
|
||||
else
|
||||
AC_MSG_ERROR([bailing out... systemd >= 205 is required])
|
||||
fi])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable udev synchronisation
|
||||
AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
|
||||
@@ -1227,11 +1129,11 @@ AC_ARG_ENABLE(compat,
|
||||
[enable support for old device-mapper versions]),
|
||||
DM_COMPAT=$enableval, DM_COMPAT=no)
|
||||
|
||||
AS_IF([test "$DM_COMPAT" = yes],
|
||||
[AC_DEFINE([DM_COMPAT], 1, [Define to enable compat protocol])
|
||||
AC_MSG_ERROR([--enable-compat is not currently supported.
|
||||
if test "$DM_COMPAT" = yes; then
|
||||
AC_MSG_ERROR([--enable-compat is not currently supported.
|
||||
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
|
||||
ioctl protocol is supported.])])
|
||||
ioctl protocol is supported.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Compatible units suffix mode
|
||||
@@ -1251,8 +1153,6 @@ AC_ARG_ENABLE(ioctl,
|
||||
AC_HELP_STRING([--disable-ioctl],
|
||||
[disable ioctl calls to device-mapper in the kernel]),
|
||||
DM_IOCTLS=$enableval)
|
||||
AS_IF([test "$DM_IOCTLS" = yes],
|
||||
[AC_DEFINE([DM_IOCTLS], 1, [Define to enable ioctls calls to kernel])])
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable O_DIRECT
|
||||
@@ -1440,18 +1340,6 @@ if test "$REALTIME" = yes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Check if the system has struct stat st_ctim.
|
||||
AC_CACHE_CHECK([for struct stat has st_ctim.],
|
||||
[ac_cv_stat_st_ctim],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||
[#include <sys/stat.h>
|
||||
long bar(void) { struct stat s; return (long)(s.st_ctim.tv_sec + s.st_ctim.tv_nsec);}]
|
||||
)], [ac_cv_stat_st_ctim=yes], [ac_cv_stat_st_ctim=no])])
|
||||
|
||||
AC_IF_YES(ac_cv_stat_st_ctim,
|
||||
AC_DEFINE(HAVE_STAT_ST_CTIM, 1,
|
||||
[Define if struct stat has a field st_ctim with timespec for ctime]))
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for getopt
|
||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 if getopt_long is available.]))
|
||||
@@ -1511,51 +1399,48 @@ if test "$INTL" = yes; then
|
||||
# FIXME - Move this - can be device-mapper too
|
||||
INTL_PACKAGE="lvm2"
|
||||
AC_PATH_TOOL(MSGFMT, msgfmt)
|
||||
|
||||
AS_IF([test -z "$MSGFMT"], [AC_MSG_ERROR([msgfmt not found in path $PATH])])
|
||||
if [[ -z "$MSGFMT" ]]; then
|
||||
AC_MSG_ERROR([msgfmt not found in path $PATH])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(localedir,
|
||||
AC_HELP_STRING([--with-localedir=DIR],
|
||||
[locale-dependent data [DATAROOTDIR/locale]]),
|
||||
localedir=$withval, localedir=${localedir-'${datarootdir}/locale'})
|
||||
AC_DEFINE_UNQUOTED([INTL_PACKAGE], ["$INTL_PACKAGE"], [Internalization package])
|
||||
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
|
||||
AC_DEFINE_UNQUOTED([LOCALEDIR], ["$(eval echo $(eval echo $localedir))"], [Locale-dependent data])
|
||||
[translation files in DIR
|
||||
[[PREFIX/share/locale]]]),
|
||||
LOCALEDIR=$withval, LOCALEDIR='${prefix}/share/locale')
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- FIXME: need to switch to regular option here --sysconfdir
|
||||
AC_ARG_WITH(confdir,
|
||||
AC_HELP_STRING([--with-confdir=DIR],
|
||||
[configuration files in DIR [/etc]]),
|
||||
[configuration files in DIR [[/etc]]]),
|
||||
CONFDIR=$withval, CONFDIR='/etc')
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ETC_DIR, ["$CONFDIR"],
|
||||
[Default system configuration directory.])
|
||||
|
||||
AC_ARG_WITH(staticdir,
|
||||
AC_HELP_STRING([--with-staticdir=DIR],
|
||||
[static binaries in DIR [EPREFIX/sbin]]),
|
||||
[static binaries in DIR [[EPREFIX/sbin]]]),
|
||||
STATICDIR=$withval, STATICDIR='${exec_prefix}/sbin')
|
||||
|
||||
AC_ARG_WITH(usrlibdir,
|
||||
AC_HELP_STRING([--with-usrlibdir=DIR],
|
||||
[usrlib in DIR [PREFIX/lib]]),
|
||||
[usrlib in DIR [[PREFIX/lib]]]),
|
||||
usrlibdir=$withval, usrlibdir='${prefix}/lib')
|
||||
|
||||
AC_ARG_WITH(usrsbindir,
|
||||
AC_HELP_STRING([--with-usrsbindir=DIR],
|
||||
[usrsbin executables in DIR [PREFIX/sbin]]),
|
||||
[usrsbin executables in DIR [[PREFIX/sbin]]]),
|
||||
usrsbindir=$withval, usrsbindir='${prefix}/sbin')
|
||||
|
||||
################################################################################
|
||||
AC_ARG_WITH(udev_prefix,
|
||||
AC_HELP_STRING([--with-udev-prefix=UPREFIX],
|
||||
[install udev rule files in UPREFIX [EPREFIX]]),
|
||||
[install udev rule files in UPREFIX [[EPREFIX]]]),
|
||||
udev_prefix=$withval, udev_prefix='${exec_prefix}')
|
||||
|
||||
AC_ARG_WITH(udevdir,
|
||||
AC_HELP_STRING([--with-udevdir=DIR],
|
||||
[udev rules in DIR [UPREFIX/lib/udev/rules.d]]),
|
||||
[udev rules in DIR [[UPREFIX/lib/udev/rules.d]]]),
|
||||
udevdir=$withval, udevdir='${udev_prefix}/lib/udev/rules.d')
|
||||
|
||||
################################################################################
|
||||
@@ -1577,7 +1462,7 @@ test -z "$systemdutildir" && systemdutildir='${exec_prefix}/lib/systemd';
|
||||
################################################################################
|
||||
AC_ARG_WITH(tmpfilesdir,
|
||||
AC_HELP_STRING([--with-tmpfilesdir=DIR],
|
||||
[install configuration files for management of volatile files and directories in DIR [PREFIX/lib/tmpfiles.d]]),
|
||||
[install configuration files for management of volatile files and directories in DIR [[PREFIX/lib/tmpfiles.d]]]),
|
||||
tmpfilesdir=$withval, tmpfilesdir='${prefix}/lib/tmpfiles.d')
|
||||
################################################################################
|
||||
dnl -- Ensure additional headers required
|
||||
@@ -1629,8 +1514,8 @@ AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
clvmd_prefix=$ac_default_prefix
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
CLVMD_PATH="$clvmd_prefix/sbin/clvmd"
|
||||
test "$prefix" != NONE && clvmd_prefix=$prefix
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
fi
|
||||
|
||||
@@ -1639,7 +1524,7 @@ dnl -- dmeventd pidfile and executable path
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
AC_ARG_WITH(dmeventd-pidfile,
|
||||
AC_HELP_STRING([--with-dmeventd-pidfile=PATH],
|
||||
[dmeventd pidfile [PID_DIR/dmeventd.pid]]),
|
||||
[dmeventd pidfile [[PID_DIR/dmeventd.pid]]]),
|
||||
DMEVENTD_PIDFILE=$withval,
|
||||
DMEVENTD_PIDFILE="$DEFAULT_PID_DIR/dmeventd.pid")
|
||||
AC_DEFINE_UNQUOTED(DMEVENTD_PIDFILE, ["$DMEVENTD_PIDFILE"],
|
||||
@@ -1649,7 +1534,7 @@ fi
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
AC_ARG_WITH(dmeventd-path,
|
||||
AC_HELP_STRING([--with-dmeventd-path=PATH],
|
||||
[dmeventd path [EPREFIX/sbin/dmeventd]]),
|
||||
[dmeventd path [[EPREFIX/sbin/dmeventd]]]),
|
||||
DMEVENTD_PATH=$withval,
|
||||
DMEVENTD_PATH="$lvm_exec_prefix/sbin/dmeventd")
|
||||
AC_DEFINE_UNQUOTED(DMEVENTD_PATH, ["$DMEVENTD_PATH"],
|
||||
@@ -1661,42 +1546,42 @@ dnl -- various defaults
|
||||
dnl -- FIXME: need to switch to regular option here --sysconfdir
|
||||
AC_ARG_WITH(default-system-dir,
|
||||
AC_HELP_STRING([--with-default-system-dir=DIR],
|
||||
[default LVM system directory [/etc/lvm]]),
|
||||
[default LVM system directory [[/etc/lvm]]]),
|
||||
DEFAULT_SYS_DIR=$withval, DEFAULT_SYS_DIR="/etc/lvm")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_SYS_DIR, ["$DEFAULT_SYS_DIR"],
|
||||
[Path to LVM system directory.])
|
||||
|
||||
AC_ARG_WITH(default-profile-subdir,
|
||||
AC_HELP_STRING([--with-default-profile-subdir=SUBDIR],
|
||||
[default configuration profile subdir [profile]]),
|
||||
[default configuration profile subdir [[profile]]]),
|
||||
DEFAULT_PROFILE_SUBDIR=$withval, DEFAULT_PROFILE_SUBDIR=profile)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_PROFILE_SUBDIR, ["$DEFAULT_PROFILE_SUBDIR"],
|
||||
[Name of default configuration profile subdirectory.])
|
||||
|
||||
AC_ARG_WITH(default-archive-subdir,
|
||||
AC_HELP_STRING([--with-default-archive-subdir=SUBDIR],
|
||||
[default metadata archive subdir [archive]]),
|
||||
[default metadata archive subdir [[archive]]]),
|
||||
DEFAULT_ARCHIVE_SUBDIR=$withval, DEFAULT_ARCHIVE_SUBDIR=archive)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_ARCHIVE_SUBDIR, ["$DEFAULT_ARCHIVE_SUBDIR"],
|
||||
[Name of default metadata archive subdirectory.])
|
||||
|
||||
AC_ARG_WITH(default-backup-subdir,
|
||||
AC_HELP_STRING([--with-default-backup-subdir=SUBDIR],
|
||||
[default metadata backup subdir [backup]]),
|
||||
[default metadata backup subdir [[backup]]]),
|
||||
DEFAULT_BACKUP_SUBDIR=$withval, DEFAULT_BACKUP_SUBDIR=backup)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_BACKUP_SUBDIR, ["$DEFAULT_BACKUP_SUBDIR"],
|
||||
[Name of default metadata backup subdirectory.])
|
||||
|
||||
AC_ARG_WITH(default-cache-subdir,
|
||||
AC_HELP_STRING([--with-default-cache-subdir=SUBDIR],
|
||||
[default metadata cache subdir [cache]]),
|
||||
[default metadata cache subdir [[cache]]]),
|
||||
DEFAULT_CACHE_SUBDIR=$withval, DEFAULT_CACHE_SUBDIR=cache)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_CACHE_SUBDIR, ["$DEFAULT_CACHE_SUBDIR"],
|
||||
[Name of default metadata cache subdirectory.])
|
||||
|
||||
AC_ARG_WITH(default-locking-dir,
|
||||
AC_HELP_STRING([--with-default-locking-dir=DIR],
|
||||
[default locking directory [/var/lock/lvm]]),
|
||||
[default locking directory [[/var/lock/lvm]]]),
|
||||
DEFAULT_LOCK_DIR=$withval, DEFAULT_LOCK_DIR="/var/lock/lvm")
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
|
||||
[Name of default locking directory.])
|
||||
@@ -1705,7 +1590,7 @@ AC_DEFINE_UNQUOTED(DEFAULT_LOCK_DIR, ["$DEFAULT_LOCK_DIR"],
|
||||
dnl -- Setup default data alignment
|
||||
AC_ARG_WITH(default-data-alignment,
|
||||
AC_HELP_STRING([--with-default-data-alignment=NUM],
|
||||
[set the default data alignment in MiB [1]]),
|
||||
[set the default data alignment in MiB [[1]]]),
|
||||
DEFAULT_DATA_ALIGNMENT=$withval, DEFAULT_DATA_ALIGNMENT=1)
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_DATA_ALIGNMENT, [$DEFAULT_DATA_ALIGNMENT],
|
||||
[Default data alignment.])
|
||||
@@ -1715,7 +1600,7 @@ dnl -- which kernel interface to use (ioctl only)
|
||||
AC_MSG_CHECKING(for kernel interface choice)
|
||||
AC_ARG_WITH(interface,
|
||||
AC_HELP_STRING([--with-interface=IFACE],
|
||||
[choose kernel interface (ioctl) [ioctl]]),
|
||||
[choose kernel interface (ioctl) [[ioctl]]]),
|
||||
interface=$withval, interface=ioctl)
|
||||
test "$interface" != ioctl && AC_MSG_ERROR([--with-interface=ioctl required. fs no longer supported.])
|
||||
AC_MSG_RESULT($interface)
|
||||
@@ -1746,7 +1631,6 @@ AC_SUBST(BLKID_WIPING)
|
||||
AC_SUBST(BUILD_CMIRRORD)
|
||||
AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMETAD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
AC_SUBST(CACHE)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CFLOW_CMD)
|
||||
@@ -1770,27 +1654,27 @@ AC_SUBST(CPG_CFLAGS)
|
||||
AC_SUBST(CPG_LIBS)
|
||||
AC_SUBST(CSCOPE_CMD)
|
||||
AC_SUBST(DEBUG)
|
||||
AC_SUBST(DEFAULT_SYS_DIR)
|
||||
AC_SUBST(DEFAULT_ARCHIVE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_BACKUP_SUBDIR)
|
||||
AC_SUBST(DEFAULT_CACHE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_PID_DIR)
|
||||
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
|
||||
AC_SUBST(DEFAULT_RAID10_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
|
||||
AC_SUBST(DEFAULT_LOCK_DIR)
|
||||
AC_SUBST(DEFAULT_DM_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_PID_DIR)
|
||||
AC_SUBST(DEFAULT_RUN_DIR)
|
||||
AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
|
||||
AC_SUBST(DEFAULT_SYS_DIR)
|
||||
AC_SUBST(DEFAULT_USE_LVMETAD)
|
||||
AC_SUBST(DEFAULT_USE_LVMPOLLD)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
AC_SUBST(DLM_CFLAGS)
|
||||
AC_SUBST(DLM_LIBS)
|
||||
AC_SUBST(DL_LIBS)
|
||||
AC_SUBST(DMEVENTD)
|
||||
AC_SUBST(DMEVENTD_PATH)
|
||||
AC_SUBST(DM_COMPAT)
|
||||
AC_SUBST(DM_DEVICE_GID)
|
||||
AC_SUBST(DM_DEVICE_MODE)
|
||||
AC_SUBST(DM_DEVICE_UID)
|
||||
AC_SUBST(DM_IOCTLS)
|
||||
AC_SUBST(DM_LIB_VERSION)
|
||||
AC_SUBST(DM_LIB_PATCHLEVEL)
|
||||
AC_SUBST(ELDFLAGS)
|
||||
@@ -1798,12 +1682,13 @@ AC_SUBST(FSADM)
|
||||
AC_SUBST(BLKDEACTIVATE)
|
||||
AC_SUBST(HAVE_LIBDL)
|
||||
AC_SUBST(HAVE_REALTIME)
|
||||
AC_SUBST(HAVE_VALGRIND)
|
||||
AC_SUBST(INTL)
|
||||
AC_SUBST(INTL_PACKAGE)
|
||||
AC_SUBST(JOBS)
|
||||
AC_SUBST(LDDEPS)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LIB_SUFFIX)
|
||||
AC_SUBST(LOCALEDIR)
|
||||
AC_SUBST(LVM1)
|
||||
AC_SUBST(LVM1_FALLBACK)
|
||||
AC_SUBST(LVM_VERSION)
|
||||
@@ -1814,7 +1699,6 @@ AC_SUBST(LVM_PATCHLEVEL)
|
||||
AC_SUBST(LVM_PATH)
|
||||
AC_SUBST(LVM_RELEASE)
|
||||
AC_SUBST(LVM_RELEASE_DATE)
|
||||
AC_SUBST(localedir)
|
||||
AC_SUBST(MANGLING)
|
||||
AC_SUBST(MIRRORS)
|
||||
AC_SUBST(MSGFMT)
|
||||
@@ -1857,11 +1741,9 @@ AC_SUBST(UDEV_SYNC)
|
||||
AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
|
||||
AC_SUBST(UDEV_RULE_EXEC_DETECTION)
|
||||
AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMETAD_PIDFILE)
|
||||
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||
AC_SUBST(CLVMD_PIDFILE)
|
||||
AC_SUBST(CMIRRORD_PIDFILE)
|
||||
AC_SUBST(interface)
|
||||
@@ -1895,10 +1777,8 @@ daemons/dmeventd/plugins/mirror/Makefile
|
||||
daemons/dmeventd/plugins/snapshot/Makefile
|
||||
daemons/dmeventd/plugins/thin/Makefile
|
||||
daemons/lvmetad/Makefile
|
||||
daemons/lvmpolld/Makefile
|
||||
conf/Makefile
|
||||
conf/example.conf
|
||||
conf/lvmlocal.conf
|
||||
conf/command_profile_template.profile
|
||||
conf/metadata_profile_template.profile
|
||||
include/.symlinks
|
||||
@@ -1939,9 +1819,6 @@ scripts/lvm2_cmirrord_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_init_red_hat
|
||||
scripts/lvm2_lvmetad_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_systemd_red_hat.socket
|
||||
scripts/lvm2_lvmpolld_init_red_hat
|
||||
scripts/lvm2_lvmpolld_systemd_red_hat.service
|
||||
scripts/lvm2_lvmpolld_systemd_red_hat.socket
|
||||
scripts/lvm2_monitoring_init_red_hat
|
||||
scripts/lvm2_monitoring_systemd_red_hat.service
|
||||
scripts/lvm2_pvscan_systemd_red_hat@.service
|
||||
@@ -1958,14 +1835,10 @@ unit-tests/mm/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
AS_IF([test -n "$THIN_CONFIGURE_WARN"],
|
||||
[AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])])
|
||||
test -n "$THIN_CONFIGURE_WARN" && AC_MSG_WARN([Support for thin provisioning is limited since some thin provisioning tools are missing!])
|
||||
|
||||
AS_IF([test -n "$THIN_CHECK_VERSION_WARN"],
|
||||
[AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])])
|
||||
test -n "$THIN_CHECK_VERSION_WARN" && AC_MSG_WARN([You should also install thin_check vsn 0.3.2 (or later) to use lvm2 thin provisioning])
|
||||
|
||||
AS_IF([test -n "$CACHE_CONFIGURE_WARN"],
|
||||
[AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])])
|
||||
test -n "$CACHE_CONFIGURE_WARN" && AC_MSG_WARN([Support for cache is limited since some cache tools are missing!])
|
||||
|
||||
AS_IF([test "$ODIRECT" != yes],
|
||||
[AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])])
|
||||
test "$ODIRECT" = yes || AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
@@ -15,7 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad
|
||||
|
||||
ifneq ("@CLVMD@", "none")
|
||||
SUBDIRS += clvmd
|
||||
@@ -36,12 +36,8 @@ ifeq ("@BUILD_LVMETAD@", "yes")
|
||||
SUBDIRS += lvmetad
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
SUBDIRS += lvmpolld
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad
|
||||
endif
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
@@ -36,6 +36,10 @@ SOURCES = \
|
||||
lvm-functions.c \
|
||||
refresh_clvmd.c
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
DEFS += -DDEBUG
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-cman.c
|
||||
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
|
||||
|
||||
@@ -208,6 +208,8 @@ static int _lock_resource(const char *resource, int mode, int flags, int *lockid
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
|
||||
retry:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
if (flags & LCKF_CONVERT) {
|
||||
/* In real DLM, lock is identified only by lockid, resource is not used */
|
||||
@@ -267,14 +269,12 @@ retry:
|
||||
dm_list_add(head, &lck->list);
|
||||
}
|
||||
out:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Failed to lock resource %s\n", resource);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "lvm-version.h"
|
||||
#include "lvm-wrappers.h"
|
||||
#include "refresh_clvmd.h"
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
@@ -88,7 +89,7 @@ static debug_t debug = DEBUG_OFF;
|
||||
static int foreground_mode = 0;
|
||||
static pthread_t lvm_thread;
|
||||
/* Stack size 128KiB for thread, must be bigger then DEFAULT_RESERVED_STACK */
|
||||
static const size_t STACK_SIZE = 128 * 1024;
|
||||
static const size_t MIN_STACK_SIZE = 128 * 1024;
|
||||
static pthread_attr_t stack_attr;
|
||||
static int lvm_thread_exit = 0;
|
||||
static pthread_mutex_t lvm_thread_mutex;
|
||||
@@ -153,11 +154,16 @@ static if_type_t get_cluster_type(void);
|
||||
static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage: %s [options]\n"
|
||||
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
||||
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||
" -E<uuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -V Show version of clvmd\n"
|
||||
" -h Show this help information\n"
|
||||
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -E<lockuuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
||||
" -R Tell all running clvmds in the cluster to reload their device cache\n"
|
||||
" -S Restart clvmd, preserving exclusive locks\n"
|
||||
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
||||
" -t<secs> Command timeout (default 60 seconds)\n"
|
||||
" -T<secs> Startup timeout (default none)\n"
|
||||
" -I<cmgr> Cluster manager (default: auto)\n"
|
||||
" Available cluster managers: "
|
||||
#ifdef USE_COROSYNC
|
||||
@@ -172,12 +178,6 @@ static void usage(const char *prog, FILE *file)
|
||||
#ifdef USE_SINGLENODE
|
||||
"singlenode "
|
||||
#endif
|
||||
"\n"
|
||||
" -R Tell all running clvmds in the cluster to reload their device cache\n"
|
||||
" -S Restart clvmd, preserving exclusive locks\n"
|
||||
" -t<secs> Command timeout (default: 60 seconds)\n"
|
||||
" -T<secs> Startup timeout (default: 0 seconds)\n"
|
||||
" -V Show version of clvmd\n"
|
||||
"\n", prog);
|
||||
}
|
||||
|
||||
@@ -359,6 +359,7 @@ int main(int argc, char *argv[])
|
||||
int clusterwide_opt = 0;
|
||||
mode_t old_mask;
|
||||
int ret = 1;
|
||||
size_t stack_size;
|
||||
|
||||
struct option longopts[] = {
|
||||
{ "help", 0, 0, 'h' },
|
||||
@@ -515,8 +516,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Initialise the LVM thread variables */
|
||||
dm_list_init(&lvm_cmd_head);
|
||||
stack_size = 3 * lvm_getpagesize();
|
||||
stack_size = stack_size < MIN_STACK_SIZE ? MIN_STACK_SIZE : stack_size;
|
||||
if (pthread_attr_init(&stack_attr) ||
|
||||
pthread_attr_setstacksize(&stack_attr, STACK_SIZE)) {
|
||||
pthread_attr_setstacksize(&stack_attr, stack_size)) {
|
||||
log_sys_error("pthread_attr_init", "");
|
||||
exit(1);
|
||||
}
|
||||
@@ -900,10 +903,8 @@ static void main_loop(int cmd_timeout)
|
||||
ret = thisfd->callback(thisfd, buf, sizeof(buf),
|
||||
csid, &newfd);
|
||||
/* Ignore EAGAIN */
|
||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR)) {
|
||||
lastfd = thisfd;
|
||||
if (ret < 0 && (errno == EAGAIN || errno == EINTR))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Got error or EOF: Remove it from the list safely */
|
||||
if (ret <= 0) {
|
||||
@@ -1131,7 +1132,7 @@ static void dump_message(char *buf, int len)
|
||||
row[j] = buf[i];
|
||||
str[j] = (isprint(buf[i])) ? buf[i] : ' ';
|
||||
|
||||
if (i + 1 == len) {
|
||||
if ((j == 8) || (i + 1 == len)) {
|
||||
for (;j < 8; ++j) {
|
||||
row[j] = 0;
|
||||
str[j] = ' ';
|
||||
|
||||
@@ -136,7 +136,7 @@ static const char *decode_flags(unsigned char flags)
|
||||
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
||||
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
||||
flags & LCK_TEST_MODE ? "TEST|" : "",
|
||||
flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
|
||||
flags & LCK_CONVERT ? "CONVERT|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
||||
flags & LCK_REVERT_MODE ? "REVERT|" : "");
|
||||
|
||||
@@ -375,7 +375,7 @@ static int do_activate_lv(char *resource, unsigned char command, unsigned char l
|
||||
* of exclusive lock to shared one during activation.
|
||||
*/
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
|
||||
status = hold_lock(resource, mode, LCKF_NOQUEUE | (lock_flags & LCK_CONVERT ? LCKF_CONVERT:0));
|
||||
if (status) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
@@ -842,7 +842,7 @@ void lvm_do_backup(const char *vgname)
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, WARN_PV_READ, &consistent);
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 1, &consistent);
|
||||
|
||||
if (vg && consistent)
|
||||
check_current_backup(vg);
|
||||
|
||||
@@ -183,6 +183,7 @@ int clog_request_from_network(void *data, size_t data_len)
|
||||
{
|
||||
uint64_t *vp = data;
|
||||
uint64_t version = xlate64(vp[0]);
|
||||
uint64_t unconverted_version = vp[1];
|
||||
struct clog_request *rq = data;
|
||||
|
||||
switch (version) {
|
||||
|
||||
@@ -117,42 +117,6 @@ static int _foreground = 0;
|
||||
static int _restart = 0;
|
||||
static char **_initial_registrations = 0;
|
||||
|
||||
/* FIXME Make configurable at runtime */
|
||||
#ifdef DEBUG
|
||||
# define DEBUGLOG(fmt, args...) debuglog("[Thr %x]: " fmt, (int)pthread_self(), ## args)
|
||||
void debuglog(const char *fmt, ... ) __attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
void debuglog(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsyslog(LOG_DEBUG, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static const char *decode_cmd(uint32_t cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DM_EVENT_CMD_ACTIVE: return "ACTIVE";
|
||||
case DM_EVENT_CMD_REGISTER_FOR_EVENT: return "REGISTER_FOR_EVENT";
|
||||
case DM_EVENT_CMD_UNREGISTER_FOR_EVENT: return "UNREGISTER_FOR_EVENT";
|
||||
case DM_EVENT_CMD_GET_REGISTERED_DEVICE: return "GET_REGISTERED_DEVICE";
|
||||
case DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE: return "GET_NEXT_REGISTERED_DEVICE";
|
||||
case DM_EVENT_CMD_SET_TIMEOUT: return "SET_TIMEOUT";
|
||||
case DM_EVENT_CMD_GET_TIMEOUT: return "GET_TIMEOUT";
|
||||
case DM_EVENT_CMD_HELLO: return "HELLO";
|
||||
case DM_EVENT_CMD_DIE: return "DIE";
|
||||
case DM_EVENT_CMD_GET_STATUS: return "GET_STATUS";
|
||||
case DM_EVENT_CMD_GET_PARAMETERS: return "GET_PARAMETERS";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
# define DEBUGLOG(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Data kept about a DSO. */
|
||||
struct dso_data {
|
||||
struct dm_list list;
|
||||
@@ -574,7 +538,6 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
struct timespec timeout;
|
||||
time_t curr_time;
|
||||
|
||||
DEBUGLOG("Timeout thread starting.");
|
||||
timeout.tv_nsec = 0;
|
||||
pthread_cleanup_push(_exit_timeout, NULL);
|
||||
pthread_mutex_lock(&_timeout_mutex);
|
||||
@@ -586,7 +549,6 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
|
||||
if (thread->next_time <= curr_time) {
|
||||
thread->next_time = curr_time + thread->timeout;
|
||||
DEBUGLOG("Sending SIGALRM to Thr %x for timeout.", (int) thread->thread);
|
||||
pthread_kill(thread->thread, SIGALRM);
|
||||
}
|
||||
|
||||
@@ -598,7 +560,6 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
|
||||
&timeout);
|
||||
}
|
||||
|
||||
DEBUGLOG("Timeout thread finished.");
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return NULL;
|
||||
@@ -679,11 +640,9 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
|
||||
int ret = DM_WAIT_RETRY;
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
int ioctl_errno;
|
||||
|
||||
*task = 0;
|
||||
|
||||
DEBUGLOG("Preparing waitevent task for %s", thread->device.uuid);
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
|
||||
return DM_WAIT_RETRY;
|
||||
|
||||
@@ -702,37 +661,32 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
|
||||
if (!_in_event_counter++)
|
||||
dm_log_init(_no_intr_log);
|
||||
_unlock_mutex();
|
||||
|
||||
DEBUGLOG("Starting waitevent task for %s", thread->device.uuid);
|
||||
/*
|
||||
* This is so that you can break out of waiting on an event,
|
||||
* either for a timeout event, or to cancel the thread.
|
||||
*/
|
||||
set = _unblock_sigalrm();
|
||||
errno = 0;
|
||||
if (dm_task_run(dmt)) {
|
||||
thread->current_events |= DM_EVENT_DEVICE_ERROR;
|
||||
ret = DM_WAIT_INTR;
|
||||
|
||||
if ((ret = dm_task_get_info(dmt, &info)))
|
||||
thread->event_nr = info.event_nr;
|
||||
} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
|
||||
thread->current_events |= DM_EVENT_TIMEOUT;
|
||||
ret = DM_WAIT_INTR;
|
||||
} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {
|
||||
ret = DM_WAIT_FATAL;
|
||||
} else {
|
||||
ioctl_errno = dm_task_get_errno(dmt);
|
||||
if (thread->events & DM_EVENT_TIMEOUT && ioctl_errno == EINTR) {
|
||||
thread->current_events |= DM_EVENT_TIMEOUT;
|
||||
ret = DM_WAIT_INTR;
|
||||
} else if (thread->status == DM_THREAD_SHUTDOWN && ioctl_errno == EINTR)
|
||||
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
|
||||
errno, strerror(errno));
|
||||
if (errno == ENXIO) {
|
||||
syslog(LOG_ERR, "%s disappeared, detaching",
|
||||
thread->device.name);
|
||||
ret = DM_WAIT_FATAL;
|
||||
else {
|
||||
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
|
||||
ioctl_errno, strerror(ioctl_errno));
|
||||
if (ioctl_errno == ENXIO) {
|
||||
syslog(LOG_ERR, "%s disappeared, detaching",
|
||||
thread->device.name);
|
||||
ret = DM_WAIT_FATAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUGLOG("Completed waitevent task for %s", thread->device.uuid);
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &set, NULL);
|
||||
_lock_mutex();
|
||||
@@ -781,7 +735,6 @@ static void _monitor_unregister(void *arg)
|
||||
{
|
||||
struct thread_status *thread = arg, *thread_iter;
|
||||
|
||||
DEBUGLOG("_monitor_unregister thread cleanup handler running");
|
||||
if (!_do_unregister_device(thread))
|
||||
syslog(LOG_ERR, "%s: %s unregister failed\n", __func__,
|
||||
thread->device.name);
|
||||
@@ -807,7 +760,6 @@ static void _monitor_unregister(void *arg)
|
||||
_unlock_mutex();
|
||||
return;
|
||||
}
|
||||
DEBUGLOG("Marking Thr %x as DONE and unused.", (int)thread->thread);
|
||||
thread->status = DM_THREAD_DONE;
|
||||
UNLINK_THREAD(thread);
|
||||
LINK(thread, &_thread_registry_unused);
|
||||
@@ -911,7 +863,6 @@ static void *_monitor_thread(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGLOG("Finished _monitor_thread");
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return NULL;
|
||||
@@ -925,7 +876,6 @@ static int _create_thread(struct thread_status *thread)
|
||||
|
||||
static int _terminate_thread(struct thread_status *thread)
|
||||
{
|
||||
DEBUGLOG("Sending SIGALRM to terminate Thr %x.", (int)thread->thread);
|
||||
return pthread_kill(thread->thread, SIGALRM);
|
||||
}
|
||||
|
||||
@@ -1149,7 +1099,6 @@ static int _unregister_for_event(struct message_data *message_data)
|
||||
* unlink and terminate its monitoring thread.
|
||||
*/
|
||||
if (!thread->events) {
|
||||
DEBUGLOG("Marking Thr %x unused (no events).", (int)thread->thread);
|
||||
UNLINK_THREAD(thread);
|
||||
LINK(thread, &_thread_registry_unused);
|
||||
}
|
||||
@@ -1187,20 +1136,26 @@ static int _registered_device(struct message_data *message_data,
|
||||
}
|
||||
|
||||
static int _want_registered_device(char *dso_name, char *device_uuid,
|
||||
struct thread_status *thread)
|
||||
struct thread_status *thread)
|
||||
{
|
||||
/* If DSO names and device paths are equal. */
|
||||
if (dso_name && device_uuid)
|
||||
return !strcmp(dso_name, thread->dso_data->dso_name) &&
|
||||
!strcmp(device_uuid, thread->device.uuid);
|
||||
!strcmp(device_uuid, thread->device.uuid) &&
|
||||
(thread->status == DM_THREAD_RUNNING ||
|
||||
(thread->events & DM_EVENT_REGISTRATION_PENDING));
|
||||
|
||||
/* If DSO names are equal. */
|
||||
if (dso_name)
|
||||
return !strcmp(dso_name, thread->dso_data->dso_name);
|
||||
return !strcmp(dso_name, thread->dso_data->dso_name) &&
|
||||
(thread->status == DM_THREAD_RUNNING ||
|
||||
(thread->events & DM_EVENT_REGISTRATION_PENDING));
|
||||
|
||||
/* If device paths are equal. */
|
||||
if (device_uuid)
|
||||
return !strcmp(device_uuid, thread->device.uuid);
|
||||
return !strcmp(device_uuid, thread->device.uuid) &&
|
||||
(thread->status == DM_THREAD_RUNNING ||
|
||||
(thread->events & DM_EVENT_REGISTRATION_PENDING));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1228,18 +1183,6 @@ static int _get_registered_dev(struct message_data *message_data, int next)
|
||||
if (hit && !next)
|
||||
goto reg;
|
||||
|
||||
/*
|
||||
* If we didn't get a match, try the threads waiting to be deleted.
|
||||
* FIXME Do something similar if 'next' is set.
|
||||
*/
|
||||
if (!hit && !next)
|
||||
dm_list_iterate_items(thread, &_thread_registry_unused)
|
||||
if (_want_registered_device(message_data->dso_name,
|
||||
message_data->device_uuid, thread)) {
|
||||
hit = thread;
|
||||
goto reg;
|
||||
}
|
||||
|
||||
if (!hit)
|
||||
goto out;
|
||||
|
||||
@@ -1567,9 +1510,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
|
||||
@@ -1578,8 +1518,6 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
if (!_client_read(fifos, &msg))
|
||||
return;
|
||||
|
||||
DEBUGLOG("%s (0x%x) processing...", decode_cmd(msg.cmd), msg.cmd);
|
||||
|
||||
die = (msg.cmd == DM_EVENT_CMD_DIE) ? 1 : 0;
|
||||
|
||||
/* _do_process_request fills in msg (if memory allows for
|
||||
@@ -1591,8 +1529,6 @@ static void _process_request(struct dm_event_fifos *fifos)
|
||||
|
||||
dm_free(msg.data);
|
||||
|
||||
DEBUGLOG("%s (0x%x) completed.", decode_cmd(msg.cmd), msg.cmd);
|
||||
|
||||
if (die) {
|
||||
if (unlink(DMEVENTD_PIDFILE))
|
||||
perror(DMEVENTD_PIDFILE ": unlink failed");
|
||||
@@ -1641,8 +1577,10 @@ static void _cleanup_unused_threads(void)
|
||||
if (ret == ESRCH) {
|
||||
thread->status = DM_THREAD_DONE;
|
||||
} else if (ret) {
|
||||
syslog(LOG_ERR, "Unable to terminate thread: %s",
|
||||
strerror(ret));
|
||||
syslog(LOG_ERR,
|
||||
"Unable to terminate thread: %s\n",
|
||||
strerror(-ret));
|
||||
stack;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1657,7 +1595,6 @@ static void _cleanup_unused_threads(void)
|
||||
}
|
||||
|
||||
if (thread->status == DM_THREAD_DONE) {
|
||||
DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
|
||||
dm_list_del(l);
|
||||
_unlock_mutex();
|
||||
join_ret = pthread_join(thread->thread, NULL);
|
||||
@@ -1674,7 +1611,7 @@ static void _cleanup_unused_threads(void)
|
||||
|
||||
static void _sig_alarm(int signum __attribute__((unused)))
|
||||
{
|
||||
/* empty SIG_IGN */;
|
||||
pthread_testcancel();
|
||||
}
|
||||
|
||||
/* Init thread signal handling. */
|
||||
@@ -1997,8 +1934,8 @@ static void restart(void)
|
||||
|
||||
if (version < 1) {
|
||||
fprintf(stderr, "WARNING: The running dmeventd instance is too old.\n"
|
||||
"Protocol version %d (required: 1). Action cancelled.\n",
|
||||
version);
|
||||
"Protocol version %d (required: 1). Action cancelled.\n",
|
||||
version);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,8 +102,7 @@ int dmeventd_lvm2_init(void)
|
||||
goto out;
|
||||
|
||||
if (!_lvm_handle) {
|
||||
if (!getenv("LVM_LOG_FILE_EPOCH"))
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
|
||||
@@ -135,21 +135,11 @@ static int _remove_failed_devices(const char *device)
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvscan --cache", device))
|
||||
return -1;
|
||||
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Re-scan of mirror device %s failed.", device);
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device))
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
||||
|
||||
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
SOURCES = lvmetad-core.c
|
||||
SOURCES2 = testclient.c
|
||||
|
||||
TARGETS = lvmetad
|
||||
TARGETS = lvmetad lvmetad-testclient
|
||||
|
||||
.PHONY: install_lvmetad
|
||||
|
||||
@@ -39,7 +39,8 @@ CFLAGS += $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
lvmetad: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
|
||||
$(DL_LIBS) $(LVMLIBS) $(LIBS) -rdynamic
|
||||
|
||||
# TODO: No idea. No idea how to test either.
|
||||
#ifneq ("$(CFLOW_CMD)", "")
|
||||
|
||||
@@ -40,7 +40,6 @@ typedef struct {
|
||||
|
||||
struct dm_hash_table *vgid_to_metadata;
|
||||
struct dm_hash_table *vgid_to_vgname;
|
||||
struct dm_hash_table *vgid_to_outdated_pvs;
|
||||
struct dm_hash_table *vgname_to_vgid;
|
||||
struct dm_hash_table *pvid_to_vgid;
|
||||
struct {
|
||||
@@ -61,18 +60,17 @@ static void destroy_metadata_hashes(lvmetad_state *s)
|
||||
dm_hash_iterate(n, s->vgid_to_metadata)
|
||||
dm_config_destroy(dm_hash_get_data(s->vgid_to_metadata, n));
|
||||
|
||||
dm_hash_iterate(n, s->vgid_to_outdated_pvs)
|
||||
dm_config_destroy(dm_hash_get_data(s->vgid_to_outdated_pvs, n));
|
||||
|
||||
dm_hash_iterate(n, s->pvid_to_pvmeta)
|
||||
dm_config_destroy(dm_hash_get_data(s->pvid_to_pvmeta, n));
|
||||
|
||||
dm_hash_destroy(s->pvid_to_pvmeta);
|
||||
dm_hash_destroy(s->vgid_to_metadata);
|
||||
dm_hash_destroy(s->vgid_to_vgname);
|
||||
dm_hash_destroy(s->vgid_to_outdated_pvs);
|
||||
dm_hash_destroy(s->vgname_to_vgid);
|
||||
|
||||
dm_hash_iterate(n, s->device_to_pvid)
|
||||
dm_free(dm_hash_get_data(s->device_to_pvid, n));
|
||||
|
||||
dm_hash_destroy(s->device_to_pvid);
|
||||
dm_hash_destroy(s->pvid_to_vgid);
|
||||
}
|
||||
@@ -83,7 +81,6 @@ static void create_metadata_hashes(lvmetad_state *s)
|
||||
s->device_to_pvid = dm_hash_create(32);
|
||||
s->vgid_to_metadata = dm_hash_create(32);
|
||||
s->vgid_to_vgname = dm_hash_create(32);
|
||||
s->vgid_to_outdated_pvs = dm_hash_create(32);
|
||||
s->pvid_to_vgid = dm_hash_create(32);
|
||||
s->vgname_to_vgid = dm_hash_create(32);
|
||||
}
|
||||
@@ -426,75 +423,6 @@ bad:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvid)
|
||||
{
|
||||
struct dm_config_tree *pvmeta, *outdated_pvs;
|
||||
struct dm_config_node *list, *cft_vgid;
|
||||
struct dm_config_value *v;
|
||||
|
||||
lock_pvid_to_pvmeta(s);
|
||||
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
|
||||
/* if the MDA exists and is used, it will have ignore=0 set */
|
||||
if (!pvmeta ||
|
||||
(dm_config_find_int64(pvmeta->root, "pvmeta/mda0/ignore", 1) &&
|
||||
dm_config_find_int64(pvmeta->root, "pvmeta/mda1/ignore", 1)))
|
||||
return;
|
||||
|
||||
WARN(s, "PV %s has outdated metadata", pvid);
|
||||
|
||||
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
|
||||
if (!outdated_pvs) {
|
||||
if (!(outdated_pvs = dm_config_from_string("outdated_pvs/pv_list = []")) ||
|
||||
!(cft_vgid = make_text_node(outdated_pvs, "vgid", dm_pool_strdup(outdated_pvs->mem, vgid),
|
||||
outdated_pvs->root, NULL)))
|
||||
abort();
|
||||
if(!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
|
||||
abort();
|
||||
DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
|
||||
}
|
||||
|
||||
list = dm_config_find_node(outdated_pvs->root, "outdated_pvs/pv_list");
|
||||
v = list->v;
|
||||
while (v) {
|
||||
if (v->type != DM_CFG_EMPTY_ARRAY && !strcmp(v->v.str, pvid))
|
||||
return;
|
||||
v = v->next;
|
||||
}
|
||||
if (!(v = dm_config_create_value(outdated_pvs)))
|
||||
abort();
|
||||
v->type = DM_CFG_STRING;
|
||||
v->v.str = dm_pool_strdup(outdated_pvs->mem, pvid);
|
||||
v->next = list->v;
|
||||
list->v = v;
|
||||
}
|
||||
|
||||
static void chain_outdated_pvs(lvmetad_state *s, const char *vgid, struct dm_config_tree *metadata_cft, struct dm_config_node *metadata)
|
||||
{
|
||||
struct dm_config_tree *cft = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid), *pvmeta;
|
||||
struct dm_config_node *pv, *res, *out_pvs = cft ? dm_config_find_node(cft->root, "outdated_pvs/pv_list") : NULL;
|
||||
struct dm_config_value *pvs_v = out_pvs ? out_pvs->v : NULL;
|
||||
if (!pvs_v)
|
||||
return;
|
||||
if (!(res = make_config_node(metadata_cft, "outdated_pvs", metadata_cft->root, 0)))
|
||||
return; /* oops */
|
||||
res->sib = metadata->child;
|
||||
metadata->child = res;
|
||||
for (; pvs_v && pvs_v->type != DM_CFG_EMPTY_ARRAY; pvs_v = pvs_v->next) {
|
||||
pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvs_v->v.str);
|
||||
if (!pvmeta) {
|
||||
WARN(s, "metadata for PV %s not found", pvs_v->v.str);
|
||||
continue;
|
||||
}
|
||||
if (!(pv = dm_config_clone_node(metadata_cft, pvmeta->root, 0)))
|
||||
continue;
|
||||
pv->key = dm_config_find_str(pv, "pvmeta/id", NULL);
|
||||
pv->sib = res->child;
|
||||
res->child = pv;
|
||||
}
|
||||
}
|
||||
|
||||
static response vg_lookup(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_tree *cft;
|
||||
@@ -561,7 +489,6 @@ static response vg_lookup(lvmetad_state *s, request r)
|
||||
unlock_vg(s, uuid);
|
||||
|
||||
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
|
||||
chain_outdated_pvs(s, uuid, res.cft, n);
|
||||
|
||||
return res;
|
||||
bad:
|
||||
@@ -625,11 +552,9 @@ static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
|
||||
|
||||
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 };
|
||||
|
||||
/* You need to be holding the pvid_to_vgid lock already to call this. */
|
||||
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
||||
const char *vgid, int mode)
|
||||
const char *vgid, int nuke_empty)
|
||||
{
|
||||
struct dm_config_node *pv;
|
||||
struct dm_hash_table *to_check;
|
||||
@@ -649,14 +574,11 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
||||
if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
|
||||
continue;
|
||||
|
||||
if (mode == REMOVE_EMPTY &&
|
||||
if (nuke_empty &&
|
||||
(vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
|
||||
!dm_hash_insert(to_check, vgid_old, (void*) 1))
|
||||
goto out;
|
||||
|
||||
if (mode == MARK_OUTDATED)
|
||||
mark_outdated_pv(s, vgid, pvid);
|
||||
|
||||
if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
|
||||
goto out;
|
||||
|
||||
@@ -680,11 +602,10 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
|
||||
/* A pvid map lock needs to be held if update_pvids = 1. */
|
||||
static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
|
||||
{
|
||||
struct dm_config_tree *old, *outdated_pvs;
|
||||
struct dm_config_tree *old;
|
||||
const char *oldname;
|
||||
lock_vgid_to_metadata(s);
|
||||
old = dm_hash_lookup(s->vgid_to_metadata, vgid);
|
||||
outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
|
||||
oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
|
||||
|
||||
if (!old) {
|
||||
@@ -698,15 +619,12 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
|
||||
dm_hash_remove(s->vgid_to_metadata, vgid);
|
||||
dm_hash_remove(s->vgid_to_vgname, vgid);
|
||||
dm_hash_remove(s->vgname_to_vgid, oldname);
|
||||
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
|
||||
unlock_vgid_to_metadata(s);
|
||||
|
||||
if (update_pvids)
|
||||
/* FIXME: What should happen when update fails */
|
||||
update_pvid_to_vgid(s, old, "#orphan", 0);
|
||||
dm_config_destroy(old);
|
||||
if (outdated_pvs)
|
||||
dm_config_destroy(outdated_pvs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -750,7 +668,7 @@ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_p
|
||||
* this function, so they can be safely destroyed after update_metadata returns
|
||||
* (anything that might have been retained is copied). */
|
||||
static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
|
||||
struct dm_config_node *metadata, int64_t *oldseq, const char *pvid)
|
||||
struct dm_config_node *metadata, int64_t *oldseq)
|
||||
{
|
||||
struct dm_config_tree *cft = NULL;
|
||||
struct dm_config_tree *old;
|
||||
@@ -799,10 +717,6 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
|
||||
|
||||
if (seq < haveseq) {
|
||||
DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
|
||||
|
||||
if (pvid)
|
||||
mark_outdated_pv(s, dm_config_find_str(old->root, "metadata/id", NULL), pvid);
|
||||
|
||||
/* TODO: notify the client that their metadata is out of date? */
|
||||
retval = 1;
|
||||
goto out;
|
||||
@@ -825,8 +739,6 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
|
||||
|
||||
if (haveseq >= 0 && haveseq < seq) {
|
||||
INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
|
||||
if (oldseq)
|
||||
update_pvid_to_vgid(s, old, vgid, MARK_OUTDATED);
|
||||
/* temporarily orphan all of our PVs */
|
||||
update_pvid_to_vgid(s, old, "#orphan", 0);
|
||||
}
|
||||
@@ -861,46 +773,12 @@ out: /* FIXME: We should probably abort() on partial failures. */
|
||||
return retval;
|
||||
}
|
||||
|
||||
static dev_t device_remove(lvmetad_state *s, struct dm_config_tree *pvmeta, dev_t device)
|
||||
{
|
||||
struct dm_config_node *pvmeta_tmp;
|
||||
struct dm_config_value *v = NULL;
|
||||
dev_t alt_device = 0, prim_device = 0;
|
||||
|
||||
if ((pvmeta_tmp = dm_config_find_node(pvmeta->root, "pvmeta/devices_alternate")))
|
||||
v = pvmeta_tmp->v;
|
||||
|
||||
prim_device = dm_config_find_int64(pvmeta->root, "pvmeta/device", 0);
|
||||
|
||||
/* it is the primary device */
|
||||
if (device > 0 && device == prim_device && pvmeta_tmp && pvmeta_tmp->v)
|
||||
{
|
||||
alt_device = pvmeta_tmp->v->v.i;
|
||||
pvmeta_tmp->v = pvmeta_tmp->v->next;
|
||||
pvmeta_tmp = dm_config_find_node(pvmeta->root, "pvmeta/device");
|
||||
pvmeta_tmp->v->v.i = alt_device;
|
||||
} else if (device != prim_device)
|
||||
alt_device = prim_device;
|
||||
|
||||
/* it is an alternate device */
|
||||
if (device > 0 && v && v->v.i == device)
|
||||
pvmeta_tmp->v = v->next;
|
||||
else while (device > 0 && pvmeta_tmp && v) {
|
||||
if (v->next && v->next->v.i == device)
|
||||
v->next = v->next->next;
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
return alt_device;
|
||||
}
|
||||
|
||||
static response pv_gone(lvmetad_state *s, request r)
|
||||
{
|
||||
const char *pvid = daemon_request_str(r, "uuid", NULL);
|
||||
int64_t device = daemon_request_int(r, "device", 0);
|
||||
int64_t alt_device = 0;
|
||||
struct dm_config_tree *pvmeta;
|
||||
char *vgid;
|
||||
char *pvid_old, *vgid;
|
||||
|
||||
DEBUGLOG(s, "pv_gone: %s / %" PRIu64, pvid, device);
|
||||
|
||||
@@ -915,17 +793,15 @@ 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);
|
||||
pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
|
||||
vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
|
||||
|
||||
dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
|
||||
|
||||
if (!(alt_device = device_remove(s, pvmeta, device)))
|
||||
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
||||
|
||||
DEBUGLOG(s, "pv_gone alt_device = %" PRIu64, alt_device);
|
||||
|
||||
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
|
||||
dm_free(pvid_old);
|
||||
|
||||
if (vgid) {
|
||||
if (!(vgid = dm_strdup(vgid)))
|
||||
return reply_fail("out of memory");
|
||||
@@ -939,15 +815,9 @@ static response pv_gone(lvmetad_state *s, request r)
|
||||
if (!pvmeta)
|
||||
return reply_unknown("PVID does not exist");
|
||||
|
||||
if (!alt_device)
|
||||
dm_config_destroy(pvmeta);
|
||||
dm_config_destroy(pvmeta);
|
||||
|
||||
if (alt_device) {
|
||||
return daemon_reply_simple("OK",
|
||||
"device = %"PRId64, alt_device,
|
||||
NULL);
|
||||
} else
|
||||
return daemon_reply_simple("OK", NULL );
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
|
||||
static response pv_clear_all(lvmetad_state *s, request r)
|
||||
@@ -975,11 +845,11 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
const char *vgname = daemon_request_str(r, "vgname", NULL);
|
||||
const char *vgid = daemon_request_str(r, "metadata/id", NULL);
|
||||
const char *vgid_old = NULL;
|
||||
struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta"), *altdev = NULL;
|
||||
struct dm_config_value *altdev_v;
|
||||
struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta");
|
||||
uint64_t device, device_old_pvid = 0;
|
||||
struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL;
|
||||
char *old;
|
||||
char *pvid_dup;
|
||||
int complete = 0, orphan = 0;
|
||||
int64_t seqno = -1, seqno_old = -1, changed = 0;
|
||||
|
||||
@@ -991,8 +861,12 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
if (!dm_config_get_uint64(pvmeta, "pvmeta/device", &device))
|
||||
return reply_fail("need PV device number");
|
||||
|
||||
if (!(cft = dm_config_create()))
|
||||
if (!(cft = dm_config_create()) ||
|
||||
(!(pvid_dup = dm_strdup(pvid)))) {
|
||||
if (cft)
|
||||
dm_config_destroy(cft);
|
||||
return reply_fail("out of memory");
|
||||
}
|
||||
|
||||
lock_pvid_to_pvmeta(s);
|
||||
|
||||
@@ -1001,6 +875,7 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
|
||||
if ((old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device)))) {
|
||||
pvmeta_old_dev = dm_hash_lookup(s->pvid_to_pvmeta, old);
|
||||
dm_hash_remove(s->pvid_to_pvmeta, old);
|
||||
vgid_old = dm_hash_lookup(s->pvid_to_vgid, old);
|
||||
}
|
||||
|
||||
@@ -1010,69 +885,35 @@ static response pv_found(lvmetad_state *s, request r)
|
||||
if (!(cft->root = dm_config_clone_node(cft, pvmeta, 0)))
|
||||
goto out_of_mem;
|
||||
|
||||
pvid = dm_config_find_str(cft->root, "pvmeta/id", NULL);
|
||||
|
||||
if (!pvmeta_old_pvid || compare_config(pvmeta_old_pvid->root, cft->root))
|
||||
changed |= 1;
|
||||
|
||||
if (pvmeta_old_pvid && device != device_old_pvid) {
|
||||
DEBUGLOG(s, "PV %s duplicated on device %" PRIu64, pvid, device_old_pvid);
|
||||
DEBUGLOG(s, "pv %s no longer on device %" PRIu64, pvid, device_old_pvid);
|
||||
dm_free(dm_hash_lookup_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid)));
|
||||
dm_hash_remove_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid));
|
||||
if (!dm_hash_insert_binary(s->device_to_pvid, &device_old_pvid,
|
||||
sizeof(device_old_pvid), (void*)pvid))
|
||||
goto out_of_mem;
|
||||
if ((altdev = dm_config_find_node(pvmeta_old_pvid->root, "pvmeta/devices_alternate"))) {
|
||||
altdev = dm_config_clone_node(cft, altdev, 0);
|
||||
chain_node(altdev, cft->root, 0);
|
||||
} else
|
||||
if (!(altdev = make_config_node(cft, "devices_alternate", cft->root, 0)))
|
||||
goto out_of_mem;
|
||||
altdev_v = altdev->v;
|
||||
while (1) {
|
||||
if (altdev_v && altdev_v->v.i == device_old_pvid)
|
||||
break;
|
||||
if (altdev_v)
|
||||
altdev_v = altdev_v->next;
|
||||
if (!altdev_v) {
|
||||
if (!(altdev_v = dm_config_create_value(cft)))
|
||||
goto out_of_mem;
|
||||
altdev_v->next = altdev->v;
|
||||
altdev->v = altdev_v;
|
||||
altdev->v->v.i = device_old_pvid;
|
||||
break;
|
||||
}
|
||||
};
|
||||
altdev_v = altdev->v;
|
||||
while (altdev_v) {
|
||||
if (altdev_v->next && altdev_v->next->v.i == device)
|
||||
altdev_v->next = altdev_v->next->next;
|
||||
altdev_v = altdev_v->next;
|
||||
}
|
||||
changed |= 1;
|
||||
}
|
||||
|
||||
if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) ||
|
||||
!dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid)) {
|
||||
!dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) {
|
||||
dm_hash_remove(s->pvid_to_pvmeta, pvid);
|
||||
out_of_mem:
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
dm_config_destroy(cft);
|
||||
dm_free(pvid_dup);
|
||||
dm_free(old);
|
||||
return reply_fail("out of memory");
|
||||
}
|
||||
|
||||
unlock_pvid_to_pvmeta(s);
|
||||
|
||||
dm_free(old);
|
||||
|
||||
if (pvmeta_old_pvid)
|
||||
dm_config_destroy(pvmeta_old_pvid);
|
||||
if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid) {
|
||||
dev_t d = dm_config_find_int64(pvmeta_old_dev->root, "pvmeta/device", 0);
|
||||
WARN(s, "pv_found: stray device %"PRId64, d);
|
||||
if (!device_remove(s, pvmeta_old_dev, device)) {
|
||||
dm_hash_remove(s->pvid_to_pvmeta, old);
|
||||
dm_config_destroy(pvmeta_old_dev);
|
||||
}
|
||||
}
|
||||
if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid)
|
||||
dm_config_destroy(pvmeta_old_dev);
|
||||
|
||||
if (metadata) {
|
||||
if (!vgid)
|
||||
@@ -1083,7 +924,7 @@ out_of_mem:
|
||||
if (daemon_request_int(r, "metadata/seqno", -1) < 0)
|
||||
return reply_fail("need VG seqno");
|
||||
|
||||
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old, pvid))
|
||||
if (!update_metadata(s, vgname, vgid, metadata, &seqno_old))
|
||||
return reply_fail("metadata update failed");
|
||||
changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1));
|
||||
} else {
|
||||
@@ -1131,21 +972,6 @@ out_of_mem:
|
||||
NULL);
|
||||
}
|
||||
|
||||
static response vg_clear_outdated_pvs(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_tree *outdated_pvs;
|
||||
const char *vgid = daemon_request_str(r, "vgid", NULL);
|
||||
|
||||
if (!vgid)
|
||||
return reply_fail("need VG UUID");
|
||||
|
||||
if ((outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid))) {
|
||||
dm_config_destroy(outdated_pvs);
|
||||
dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
|
||||
}
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
}
|
||||
|
||||
static response vg_update(lvmetad_state *s, request r)
|
||||
{
|
||||
struct dm_config_node *metadata = dm_config_find_node(r.cft->root, "metadata");
|
||||
@@ -1161,7 +987,7 @@ static response vg_update(lvmetad_state *s, request r)
|
||||
|
||||
/* TODO defer metadata update here; add a separate vg_commit
|
||||
* call; if client does not commit, die */
|
||||
if (!update_metadata(s, vgname, vgid, metadata, NULL, NULL))
|
||||
if (!update_metadata(s, vgname, vgid, metadata, NULL))
|
||||
return reply_fail("metadata update failed");
|
||||
}
|
||||
return daemon_reply_simple("OK", NULL);
|
||||
@@ -1209,7 +1035,7 @@ static void _dump_pairs(struct buffer *buf, struct dm_hash_table *ht, const char
|
||||
*val = dm_hash_get_data(ht, n);
|
||||
buffer_append(buf, " ");
|
||||
if (int_key)
|
||||
(void) dm_asprintf(&append, "%d = \"%s\"", *(const int*)key, val);
|
||||
(void) dm_asprintf(&append, "%d = \"%s\"", *(int*)key, val);
|
||||
else
|
||||
(void) dm_asprintf(&append, "%s = \"%s\"", key, val);
|
||||
if (append)
|
||||
@@ -1242,9 +1068,6 @@ static response dump(lvmetad_state *s)
|
||||
buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
|
||||
_dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
|
||||
|
||||
buffer_append(b, "\n# VGID to outdated PVs mapping\n\n");
|
||||
_dump_cft(b, s->vgid_to_outdated_pvs, "outdated_pvs/vgid");
|
||||
|
||||
buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
|
||||
_dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);
|
||||
|
||||
@@ -1304,9 +1127,6 @@ static response handler(daemon_state s, client_handle h, request r)
|
||||
if (!strcmp(rq, "vg_update"))
|
||||
return vg_update(state, r);
|
||||
|
||||
if (!strcmp(rq, "vg_clear_outdated_pvs"))
|
||||
return vg_clear_outdated_pvs(state, r);
|
||||
|
||||
if (!strcmp(rq, "vg_remove"))
|
||||
return vg_remove(state, r);
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ void _dump_vg(daemon_handle h, const char *uuid)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
daemon_handle h = lvmetad_open();
|
||||
/* FIXME Missing error path */
|
||||
|
||||
if (argc > 1) {
|
||||
int i;
|
||||
@@ -115,7 +114,6 @@ int main(int argc, char **argv) {
|
||||
scan(h, argv[i]);
|
||||
}
|
||||
destroy_toolcontext(cmd);
|
||||
/* FIXME Missing lvmetad_close() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -124,6 +122,6 @@ int main(int argc, char **argv) {
|
||||
_dump_vg(h, vgid);
|
||||
_pv_add(h, uuid3, NULL);
|
||||
|
||||
daemon_close(h); /* FIXME lvmetad_close? */
|
||||
daemon_close(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2014-2015 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU Lesser General Public License v.2.1.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
|
||||
|
||||
TARGETS = lvmpolld
|
||||
|
||||
.PHONY: install_lvmpolld
|
||||
|
||||
CFLOW_LIST = $(SOURCES)
|
||||
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
CFLOW_TARGET = lvmpolld
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/libdaemon/server
|
||||
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
|
||||
|
||||
LIBS += $(PTHREAD_LIBS)
|
||||
|
||||
LDFLAGS += -L$(top_builddir)/libdaemon/server $(DAEMON_LDFLAGS)
|
||||
CLDFLAGS += -L$(top_builddir)/libdaemon/server
|
||||
CFLAGS += $(DAEMON_CFLAGS)
|
||||
|
||||
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
|
||||
$(top_builddir)/libdaemon/server/libdaemonserver.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LVMLIBS) $(LIBS)
|
||||
|
||||
install_lvmpolld: lvmpolld
|
||||
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
|
||||
|
||||
install_lvm2: install_lvmpolld
|
||||
|
||||
install: install_lvm2
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lvmpolld-common.h"
|
||||
|
||||
/* extract this info from autoconf/automake files */
|
||||
#define LVPOLL_CMD "lvpoll"
|
||||
|
||||
#define MIN_ARGV_SIZE 8
|
||||
|
||||
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
|
||||
[CONVERT] = LVMPD_REQ_CONVERT,
|
||||
[MERGE] = LVMPD_REQ_MERGE,
|
||||
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN };
|
||||
|
||||
const char *polling_op(enum poll_type type)
|
||||
{
|
||||
return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
|
||||
}
|
||||
|
||||
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
|
||||
{
|
||||
const char **newargv = *cmdargv;
|
||||
|
||||
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
|
||||
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
|
||||
if (!newargv)
|
||||
return 0;
|
||||
*cmdargv = newargv;
|
||||
}
|
||||
|
||||
*(*cmdargv + (*ind)++) = str;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
|
||||
{
|
||||
unsigned i = 0;
|
||||
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
|
||||
if (!cmd_argv)
|
||||
return NULL;
|
||||
|
||||
/* path to lvm2 binary */
|
||||
if (!add_to_cmd_arr(&cmd_argv, lvm_binary, &i))
|
||||
goto err;
|
||||
|
||||
/* cmd to execute */
|
||||
if (!add_to_cmd_arr(&cmd_argv, LVPOLL_CMD, &i))
|
||||
goto err;
|
||||
|
||||
/* transfer internal polling interval */
|
||||
if (pdlv->sinterval &&
|
||||
(!add_to_cmd_arr(&cmd_argv, "--interval", &i) ||
|
||||
!add_to_cmd_arr(&cmd_argv, pdlv->sinterval, &i)))
|
||||
goto err;
|
||||
|
||||
/* pass abort param */
|
||||
if (abort_polling &&
|
||||
!add_to_cmd_arr(&cmd_argv, "--abort", &i))
|
||||
goto err;
|
||||
|
||||
/* pass handle-missing-pvs. used by mirror polling operation */
|
||||
if (handle_missing_pvs &&
|
||||
!add_to_cmd_arr(&cmd_argv, "--handlemissingpvs", &i))
|
||||
goto err;
|
||||
|
||||
/* one of: "convert", "pvmove", "merge", "merge_thin" */
|
||||
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
|
||||
!add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
|
||||
goto err;
|
||||
|
||||
/* vg/lv name */
|
||||
if (!add_to_cmd_arr(&cmd_argv, pdlv->lvname, &i))
|
||||
goto err;
|
||||
|
||||
/* disable metadata backup */
|
||||
if (!add_to_cmd_arr(&cmd_argv, "-An", &i))
|
||||
goto err;
|
||||
|
||||
/* terminating NULL */
|
||||
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
|
||||
goto err;
|
||||
|
||||
return cmd_argv;
|
||||
err:
|
||||
dm_free(cmd_argv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: in fact exclude should be va list */
|
||||
static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
|
||||
{
|
||||
const char * const* tmp = (const char * const*) environ;
|
||||
|
||||
if (!tmp)
|
||||
return 0;
|
||||
|
||||
while (*tmp) {
|
||||
if (strncmp(*tmp, exclude, strlen(exclude)) && !add_to_cmd_arr(cmd_envp, *tmp, i))
|
||||
return 0;
|
||||
tmp++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
unsigned i = 0;
|
||||
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
|
||||
|
||||
if (!cmd_envp)
|
||||
return NULL;
|
||||
|
||||
/* copy whole environment from lvmpolld, exclude LVM_SYSTEM_DIR if set */
|
||||
if (!copy_env(&cmd_envp, &i, "LVM_SYSTEM_DIR="))
|
||||
goto err;
|
||||
|
||||
/* Add per client LVM_SYSTEM_DIR variable if set */
|
||||
if (*pdlv->lvm_system_dir_env && !add_to_cmd_arr(&cmd_envp, pdlv->lvm_system_dir_env, &i))
|
||||
goto err;
|
||||
|
||||
/* terminating NULL */
|
||||
if (!add_to_cmd_arr(&cmd_envp, NULL, &i))
|
||||
goto err;
|
||||
|
||||
return cmd_envp;
|
||||
err:
|
||||
dm_free(cmd_envp);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_LVMPOLLD_CMD_UTILS_H
|
||||
#define _LVM_LVMPOLLD_CMD_UTILS_H
|
||||
|
||||
#include "lvmpolld-data-utils.h"
|
||||
|
||||
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort, unsigned handle_missing_pvs);
|
||||
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv);
|
||||
|
||||
const char *polling_op(enum poll_type);
|
||||
|
||||
#endif /* _LVM_LVMPOLLD_CMD_UTILS_H */
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file must be included first by every lvmpolld source file.
|
||||
*/
|
||||
#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 "lvmpolld-cmd-utils.h"
|
||||
#include "lvmpolld-protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif /* _LVM_LVMPOLLD_COMMON_H */
|
||||
@@ -1,984 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lvmpolld-common.h"
|
||||
|
||||
#include "lvm-version.h"
|
||||
#include "daemon-server.h"
|
||||
#include "daemon-log.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <wait.h>
|
||||
|
||||
#define LVMPOLLD_SOCKET DEFAULT_RUN_DIR "/lvmpolld.socket"
|
||||
|
||||
#define PD_LOG_PREFIX "LVMPOLLD"
|
||||
#define LVM2_LOG_PREFIX "\tLVPOLL"
|
||||
|
||||
/* predefined reason for response = "failed" case */
|
||||
#define REASON_REQ_NOT_IMPLEMENTED "request not implemented"
|
||||
#define REASON_MISSING_LVID "request requires lvid set"
|
||||
#define REASON_MISSING_LVNAME "request requires lvname set"
|
||||
#define REASON_MISSING_VGNAME "request requires vgname set"
|
||||
#define REASON_POLLING_FAILED "polling of lvm command failed"
|
||||
#define REASON_ILLEGAL_ABORT_REQUEST "abort only supported with PVMOVE polling operation"
|
||||
#define REASON_DIFFERENT_OPERATION_IN_PROGRESS "Different operation on LV already in progress"
|
||||
#define REASON_INVALID_INTERVAL "request requires interval set"
|
||||
#define REASON_ENOMEM "not enough memory"
|
||||
|
||||
struct lvmpolld_state {
|
||||
daemon_idle *idle;
|
||||
log_state *log;
|
||||
const char *log_config;
|
||||
const char *lvm_binary;
|
||||
|
||||
struct lvmpolld_store *id_to_pdlv_abort;
|
||||
struct lvmpolld_store *id_to_pdlv_poll;
|
||||
};
|
||||
|
||||
static pthread_key_t key;
|
||||
|
||||
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
|
||||
{
|
||||
#ifdef _GNU_SOURCE
|
||||
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
|
||||
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
|
||||
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
|
||||
#else
|
||||
# warning "Can't decide proper strerror_r implementation. lvmpolld will not issue specific system error messages"
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage:\n"
|
||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path] [-B path] [-p path] [-t secs]\n"
|
||||
"%s --dump [-s path]\n"
|
||||
" -V|--version Show version info\n"
|
||||
" -h|--help Show this help information\n"
|
||||
" -f|--foreground Don't fork, run in the foreground\n"
|
||||
" --dump Dump full lvmpolld state\n"
|
||||
" -l|--log Logging message level (-l {all|wire|debug})\n"
|
||||
" -p|--pidfile Set path to the pidfile\n"
|
||||
" -s|--socket Set path to the communication socket\n"
|
||||
" -B|--binary Path to lvm2 binary\n"
|
||||
" -t|--timeout Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog, prog);
|
||||
}
|
||||
|
||||
static int _init(struct daemon_state *s)
|
||||
{
|
||||
struct lvmpolld_state *ls = s->private;
|
||||
ls->log = s->log;
|
||||
|
||||
if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1))
|
||||
return 0;
|
||||
|
||||
if (pthread_key_create(&key, lvmpolld_thread_data_destroy)) {
|
||||
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to create pthread key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ls->id_to_pdlv_poll = pdst_init("polling");
|
||||
ls->id_to_pdlv_abort = pdst_init("abort");
|
||||
|
||||
if (!ls->id_to_pdlv_poll || !ls->id_to_pdlv_abort) {
|
||||
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to allocate internal data structures");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ls->lvm_binary = ls->lvm_binary ?: LVM_PATH;
|
||||
|
||||
if (access(ls->lvm_binary, X_OK)) {
|
||||
FATAL(ls, "%s: %s %s", PD_LOG_PREFIX, "Execute access rights denied on", ls->lvm_binary);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ls->idle)
|
||||
ls->idle->is_idle = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _lvmpolld_stores_lock(struct lvmpolld_state *ls)
|
||||
{
|
||||
pdst_lock(ls->id_to_pdlv_poll);
|
||||
pdst_lock(ls->id_to_pdlv_abort);
|
||||
}
|
||||
|
||||
static void _lvmpolld_stores_unlock(struct lvmpolld_state *ls)
|
||||
{
|
||||
pdst_unlock(ls->id_to_pdlv_abort);
|
||||
pdst_unlock(ls->id_to_pdlv_poll);
|
||||
}
|
||||
|
||||
static void _lvmpolld_global_lock(struct lvmpolld_state *ls)
|
||||
{
|
||||
_lvmpolld_stores_lock(ls);
|
||||
|
||||
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_poll);
|
||||
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_abort);
|
||||
}
|
||||
|
||||
static void _lvmpolld_global_unlock(struct lvmpolld_state *ls)
|
||||
{
|
||||
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_abort);
|
||||
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_poll);
|
||||
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
}
|
||||
|
||||
static int _fini(struct daemon_state *s)
|
||||
{
|
||||
int done;
|
||||
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
|
||||
struct lvmpolld_state *ls = s->private;
|
||||
|
||||
DEBUGLOG(s, "fini");
|
||||
|
||||
DEBUGLOG(s, "sending cancel requests");
|
||||
|
||||
_lvmpolld_global_lock(ls);
|
||||
pdst_locked_send_cancel(ls->id_to_pdlv_poll);
|
||||
pdst_locked_send_cancel(ls->id_to_pdlv_abort);
|
||||
_lvmpolld_global_unlock(ls);
|
||||
|
||||
DEBUGLOG(s, "waiting for background threads to finish");
|
||||
|
||||
while(1) {
|
||||
_lvmpolld_stores_lock(ls);
|
||||
done = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
|
||||
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
if (done)
|
||||
break;
|
||||
nanosleep(&t, NULL);
|
||||
}
|
||||
|
||||
DEBUGLOG(s, "destroying internal data structures");
|
||||
|
||||
_lvmpolld_stores_lock(ls);
|
||||
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_poll);
|
||||
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_abort);
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
|
||||
pdst_destroy(ls->id_to_pdlv_poll);
|
||||
pdst_destroy(ls->id_to_pdlv_abort);
|
||||
|
||||
pthread_key_delete(key);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static response reply(const char *res, const char *reason)
|
||||
{
|
||||
return daemon_reply_simple(res, "reason = %s", reason, NULL);
|
||||
}
|
||||
|
||||
static int read_single_line(struct lvmpolld_thread_data *data, int err)
|
||||
{
|
||||
ssize_t r = getline(&data->line, &data->line_size, err ? data->ferr : data->fout);
|
||||
|
||||
if (r > 0 && *(data->line + r - 1) == '\n')
|
||||
*(data->line + r - 1) = '\0';
|
||||
|
||||
return (r > 0);
|
||||
}
|
||||
|
||||
static void update_idle_state(struct lvmpolld_state *ls)
|
||||
{
|
||||
if (!ls->idle)
|
||||
return;
|
||||
|
||||
_lvmpolld_stores_lock(ls);
|
||||
|
||||
ls->idle->is_idle = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
|
||||
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
|
||||
|
||||
_lvmpolld_stores_unlock(ls);
|
||||
|
||||
DEBUGLOG(ls, "%s: %s %s%s", PD_LOG_PREFIX, "daemon is", ls->idle->is_idle ? "" : "not ", "idle");
|
||||
}
|
||||
|
||||
/* make this configurable */
|
||||
#define MAX_TIMEOUT 2
|
||||
|
||||
static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data *data)
|
||||
{
|
||||
int ch_stat, r, err = 1, fds_count = 2, timeout = 0;
|
||||
pid_t pid;
|
||||
struct lvmpolld_cmd_stat cmd_state = { .retcode = -1, .signal = 0 };
|
||||
struct pollfd fds[] = { { .fd = data->outpipe[0], .events = POLLIN },
|
||||
{ .fd = data->errpipe[0], .events = POLLIN } };
|
||||
|
||||
if (!(data->fout = fdopen(data->outpipe[0], "r")) || !(data->ferr = fdopen(data->errpipe[0], "r"))) {
|
||||
ERROR(pdlv->ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to open file stream",
|
||||
errno, _strerror_r(errno, data));
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
|
||||
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
|
||||
if (r < 0) {
|
||||
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
|
||||
PD_LOG_PREFIX, "poll() for LVM2 cmd", pdlv->cmd_pid,
|
||||
errno, _strerror_r(errno, data));
|
||||
goto out;
|
||||
} else if (!r) {
|
||||
timeout++;
|
||||
|
||||
WARN(pdlv->ls, "%s: %s (PID %d) %s", PD_LOG_PREFIX,
|
||||
"polling for output of the lvm cmd", pdlv->cmd_pid,
|
||||
"has timed out");
|
||||
|
||||
if (timeout > MAX_TIMEOUT) {
|
||||
ERROR(pdlv->ls, "%s: %s (PID %d) (no output for %d seconds)",
|
||||
PD_LOG_PREFIX,
|
||||
"LVM2 cmd is unresponsive too long",
|
||||
pdlv->cmd_pid,
|
||||
timeout * pdlv_get_timeout(pdlv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
continue; /* while(1) */
|
||||
}
|
||||
|
||||
timeout = 0;
|
||||
|
||||
/* handle the command's STDOUT */
|
||||
if (fds[0].revents & POLLIN) {
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught input data in STDOUT");
|
||||
|
||||
assert(read_single_line(data, 0)); /* may block indef. anyway */
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||
pdlv->cmd_pid, "STDOUT", data->line);
|
||||
} else if (fds[0].revents) {
|
||||
if (fds[0].revents & POLLHUP)
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught POLLHUP");
|
||||
else
|
||||
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
|
||||
|
||||
fds[0].fd = -1;
|
||||
fds_count--;
|
||||
}
|
||||
|
||||
/* handle the command's STDERR */
|
||||
if (fds[1].revents & POLLIN) {
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
|
||||
"caught input data in STDERR");
|
||||
|
||||
assert(read_single_line(data, 1)); /* may block indef. anyway */
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
|
||||
pdlv->cmd_pid, "STDERR", data->line);
|
||||
} else if (fds[1].revents) {
|
||||
if (fds[1].revents & POLLHUP)
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught err POLLHUP");
|
||||
else
|
||||
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
|
||||
|
||||
fds[1].fd = -1;
|
||||
fds_count--;
|
||||
}
|
||||
|
||||
do {
|
||||
/*
|
||||
* fds_count == 0 means polling reached EOF
|
||||
* or received error on both descriptors.
|
||||
* In such case, just wait for command to finish
|
||||
*/
|
||||
pid = waitpid(pdlv->cmd_pid, &ch_stat, fds_count ? WNOHANG : 0);
|
||||
} while (pid < 0 && errno == EINTR);
|
||||
|
||||
if (pid) {
|
||||
if (pid < 0) {
|
||||
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
|
||||
PD_LOG_PREFIX, "waitpid() for lvm2 cmd",
|
||||
pdlv->cmd_pid, errno,
|
||||
_strerror_r(errno, data));
|
||||
goto out;
|
||||
}
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "child exited");
|
||||
break;
|
||||
}
|
||||
} /* while(1) */
|
||||
|
||||
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "about to collect remaining lines");
|
||||
if (fds[0].fd >= 0)
|
||||
while (read_single_line(data, 0)) {
|
||||
assert(r > 0);
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDOUT", data->line);
|
||||
}
|
||||
if (fds[1].fd >= 0)
|
||||
while (read_single_line(data, 1)) {
|
||||
assert(r > 0);
|
||||
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDERR", data->line);
|
||||
}
|
||||
|
||||
if (WIFEXITED(ch_stat)) {
|
||||
INFO(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
|
||||
"lvm2 cmd", pdlv->cmd_pid, "exited with", WEXITSTATUS(ch_stat));
|
||||
cmd_state.retcode = WEXITSTATUS(ch_stat);
|
||||
} else if (WIFSIGNALED(ch_stat)) {
|
||||
WARN(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
|
||||
"lvm2 cmd", pdlv->cmd_pid, "got terminated by signal",
|
||||
WTERMSIG(ch_stat));
|
||||
cmd_state.signal = WTERMSIG(ch_stat);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
if (!err)
|
||||
pdlv_set_cmd_state(pdlv, &cmd_state);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
|
||||
{
|
||||
const char * const* tmp = ptr;
|
||||
|
||||
if (!tmp)
|
||||
return;
|
||||
|
||||
while (*tmp) {
|
||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, *tmp);
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
|
||||
static void *fork_and_poll(void *args)
|
||||
{
|
||||
int outfd, errfd, state;
|
||||
struct lvmpolld_thread_data *data;
|
||||
pid_t r;
|
||||
|
||||
int error = 1;
|
||||
struct lvmpolld_lv *pdlv = (struct lvmpolld_lv *) args;
|
||||
struct lvmpolld_state *ls = pdlv->ls;
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
||||
data = lvmpolld_thread_data_constructor(pdlv);
|
||||
pthread_setspecific(key, data);
|
||||
pthread_setcancelstate(state, &state);
|
||||
|
||||
if (!data) {
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Failed to initialize per-thread data");
|
||||
goto err;
|
||||
}
|
||||
|
||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
|
||||
debug_print(ls, pdlv->cmdargv);
|
||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
|
||||
|
||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd environment variables:");
|
||||
debug_print(ls, pdlv->cmdenvp);
|
||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
|
||||
|
||||
outfd = data->outpipe[1];
|
||||
errfd = data->errpipe[1];
|
||||
|
||||
r = fork();
|
||||
if (!r) {
|
||||
/* child */
|
||||
/* !!! Do not touch any posix thread primitives !!! */
|
||||
|
||||
if ((dup2(outfd, STDOUT_FILENO ) != STDOUT_FILENO) ||
|
||||
(dup2(errfd, STDERR_FILENO ) != STDERR_FILENO))
|
||||
_exit(LVMPD_RET_DUP_FAILED);
|
||||
|
||||
execve(*(pdlv->cmdargv), (char *const *)pdlv->cmdargv, (char *const *)pdlv->cmdenvp);
|
||||
|
||||
_exit(LVMPD_RET_EXC_FAILED);
|
||||
} else {
|
||||
/* parent */
|
||||
if (r == -1) {
|
||||
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "fork failed",
|
||||
errno, _strerror_r(errno, data));
|
||||
goto err;
|
||||
}
|
||||
|
||||
INFO(ls, "%s: LVM2 cmd \"%s\" (PID: %d)", PD_LOG_PREFIX, *(pdlv->cmdargv), r);
|
||||
|
||||
pdlv->cmd_pid = r;
|
||||
|
||||
/* failure to close write end of any pipe will result in broken polling */
|
||||
if (close(data->outpipe[1])) {
|
||||
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of pipe",
|
||||
errno, _strerror_r(errno, data));
|
||||
goto err;
|
||||
}
|
||||
data->outpipe[1] = -1;
|
||||
|
||||
if (close(data->errpipe[1])) {
|
||||
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of err pipe",
|
||||
errno, _strerror_r(errno, data));
|
||||
goto err;
|
||||
}
|
||||
data->errpipe[1] = -1;
|
||||
|
||||
error = poll_for_output(pdlv, data);
|
||||
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "polling for lvpoll output has finished");
|
||||
}
|
||||
|
||||
err:
|
||||
r = 0;
|
||||
|
||||
pdst_lock(pdlv->pdst);
|
||||
|
||||
if (error) {
|
||||
/* last reader is responsible for pdlv cleanup */
|
||||
r = pdlv->cmd_pid;
|
||||
pdlv_set_error(pdlv, 1);
|
||||
}
|
||||
|
||||
pdlv_set_polling_finished(pdlv, 1);
|
||||
if (data)
|
||||
data->pdlv = NULL;
|
||||
|
||||
pdst_locked_dec(pdlv->pdst);
|
||||
|
||||
pdst_unlock(pdlv->pdst);
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
|
||||
lvmpolld_thread_data_destroy(data);
|
||||
pthread_setspecific(key, NULL);
|
||||
pthread_setcancelstate(state, &state);
|
||||
|
||||
update_idle_state(ls);
|
||||
|
||||
/*
|
||||
* This is unfortunate case where we
|
||||
* know nothing about state of lvm cmd and
|
||||
* (eventually) ongoing progress.
|
||||
*
|
||||
* harvest zombies
|
||||
*/
|
||||
if (r)
|
||||
while(waitpid(r, NULL, 0) < 0 && errno == EINTR);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static response progress_info(client_handle h, struct lvmpolld_state *ls, request req)
|
||||
{
|
||||
char *id;
|
||||
struct lvmpolld_lv *pdlv;
|
||||
struct lvmpolld_store *pdst;
|
||||
struct lvmpolld_lv_state st;
|
||||
response r;
|
||||
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
|
||||
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||
|
||||
if (!lvid)
|
||||
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
|
||||
|
||||
id = construct_id(sysdir, lvid);
|
||||
if (!id) {
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "progress_info request failed to construct ID.");
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
|
||||
DEBUGLOG(ls, "%s: %s: %s", PD_LOG_PREFIX, "ID", id);
|
||||
|
||||
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
|
||||
|
||||
pdst_lock(pdst);
|
||||
|
||||
pdlv = pdst_locked_lookup(pdst, id);
|
||||
if (pdlv) {
|
||||
/*
|
||||
* with store lock held, I'm the only reader accessing the pdlv
|
||||
*/
|
||||
st = pdlv_get_status(pdlv);
|
||||
|
||||
if (st.error || st.polling_finished) {
|
||||
INFO(ls, "%s: %s %s", PD_LOG_PREFIX,
|
||||
"Polling finished. Removing related data structure for LV",
|
||||
lvid);
|
||||
pdst_locked_remove(pdst, id);
|
||||
pdlv_destroy(pdlv);
|
||||
}
|
||||
}
|
||||
/* pdlv must not be dereferenced from now on */
|
||||
|
||||
pdst_unlock(pdst);
|
||||
|
||||
dm_free(id);
|
||||
|
||||
if (pdlv) {
|
||||
if (st.error)
|
||||
return reply(LVMPD_RESP_FAILED, REASON_POLLING_FAILED);
|
||||
|
||||
if (st.polling_finished)
|
||||
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
|
||||
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
|
||||
LVMPD_PARM_VALUE " = %d", st.cmd_state.signal ?: st.cmd_state.retcode,
|
||||
NULL);
|
||||
else
|
||||
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
|
||||
}
|
||||
else
|
||||
r = daemon_reply_simple(LVMPD_RESP_NOT_FOUND, NULL);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls,
|
||||
struct lvmpolld_store *pdst,
|
||||
const char *interval, const char *id,
|
||||
const char *vgname, const char *lvname,
|
||||
const char *sysdir, enum poll_type type,
|
||||
unsigned abort_polling, unsigned uinterval)
|
||||
{
|
||||
const char **cmdargv, **cmdenvp;
|
||||
struct lvmpolld_lv *pdlv;
|
||||
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
|
||||
|
||||
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
|
||||
interval, uinterval, pdst);
|
||||
|
||||
if (!pdlv) {
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmdargv = cmdargv_ctr(pdlv, pdlv->ls->lvm_binary, abort_polling, handle_missing_pvs);
|
||||
if (!cmdargv) {
|
||||
pdlv_destroy(pdlv);
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd arguments for lvpoll command");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmdenvp = cmdenvp_ctr(pdlv);
|
||||
if (!cmdenvp) {
|
||||
pdlv_destroy(pdlv);
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd environment for lvpoll command");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdlv->cmdargv = cmdargv;
|
||||
pdlv->cmdenvp = cmdenvp;
|
||||
|
||||
return pdlv;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
r = pthread_create(&pdlv->tid, &attr, fork_and_poll, (void *)pdlv);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return !r;
|
||||
}
|
||||
|
||||
static response poll_init(client_handle h, struct lvmpolld_state *ls, request req, enum poll_type type)
|
||||
{
|
||||
char *id;
|
||||
struct lvmpolld_lv *pdlv;
|
||||
struct lvmpolld_store *pdst;
|
||||
unsigned uinterval;
|
||||
|
||||
const char *interval = daemon_request_str(req, LVMPD_PARM_INTERVAL, NULL);
|
||||
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
|
||||
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
|
||||
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
|
||||
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
|
||||
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
|
||||
|
||||
assert(type < POLL_TYPE_MAX);
|
||||
|
||||
if (abort_polling && type != PVMOVE)
|
||||
return reply(LVMPD_RESP_EINVAL, REASON_ILLEGAL_ABORT_REQUEST);
|
||||
|
||||
if (!interval || strpbrk(interval, "-") || sscanf(interval, "%u", &uinterval) != 1)
|
||||
return reply(LVMPD_RESP_EINVAL, REASON_INVALID_INTERVAL);
|
||||
|
||||
if (!lvname)
|
||||
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVNAME);
|
||||
|
||||
if (!lvid)
|
||||
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
|
||||
|
||||
if (!vgname)
|
||||
return reply(LVMPD_RESP_FAILED, REASON_MISSING_VGNAME);
|
||||
|
||||
id = construct_id(sysdir, lvid);
|
||||
if (!id) {
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "poll_init request failed to construct ID.");
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
|
||||
DEBUGLOG(ls, "%s: %s=%s", PD_LOG_PREFIX, "ID", id);
|
||||
|
||||
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
|
||||
|
||||
pdst_lock(pdst);
|
||||
|
||||
pdlv = pdst_locked_lookup(pdst, id);
|
||||
if (pdlv && pdlv_get_polling_finished(pdlv)) {
|
||||
WARN(ls, "%s: %s %s", PD_LOG_PREFIX, "Force removal of uncollected info for LV",
|
||||
lvid);
|
||||
/*
|
||||
* lvmpolld has to remove uncollected results in this case.
|
||||
* otherwise it would have to refuse request for new polling
|
||||
* lv with same id.
|
||||
*/
|
||||
pdst_locked_remove(pdst, id);
|
||||
pdlv_destroy(pdlv);
|
||||
pdlv = NULL;
|
||||
}
|
||||
|
||||
if (pdlv) {
|
||||
if (!pdlv_is_type(pdlv, type)) {
|
||||
pdst_unlock(pdst);
|
||||
ERROR(ls, "%s: %s '%s': expected: %s, requested: %s",
|
||||
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
|
||||
id,
|
||||
polling_op(pdlv_get_type(pdlv)), polling_op(type));
|
||||
dm_free(id);
|
||||
return reply(LVMPD_RESP_EINVAL,
|
||||
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
|
||||
}
|
||||
pdlv->init_rq_count++; /* safe. protected by store lock */
|
||||
} else {
|
||||
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
|
||||
lvname, sysdir, type, abort_polling, 2 * uinterval);
|
||||
if (!pdlv) {
|
||||
pdst_unlock(pdst);
|
||||
dm_free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
if (!pdst_locked_insert(pdst, id, pdlv)) {
|
||||
pdlv_destroy(pdlv);
|
||||
pdst_unlock(pdst);
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
|
||||
dm_free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
if (!spawn_detached_thread(pdlv)) {
|
||||
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to spawn detached monitoring thread");
|
||||
pdst_locked_remove(pdst, id);
|
||||
pdlv_destroy(pdlv);
|
||||
pdst_unlock(pdst);
|
||||
dm_free(id);
|
||||
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
|
||||
}
|
||||
|
||||
pdst_locked_inc(pdst);
|
||||
if (ls->idle)
|
||||
ls->idle->is_idle = 0;
|
||||
}
|
||||
|
||||
pdst_unlock(pdst);
|
||||
|
||||
dm_free(id);
|
||||
|
||||
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
|
||||
}
|
||||
|
||||
static response dump_state(client_handle h, struct lvmpolld_state *ls, request r)
|
||||
{
|
||||
response res = { 0 };
|
||||
struct buffer *b = &res.buffer;
|
||||
|
||||
buffer_init(b);
|
||||
|
||||
_lvmpolld_global_lock(ls);
|
||||
|
||||
buffer_append(b, "# Registered polling operations\n\n");
|
||||
buffer_append(b, "poll {\n");
|
||||
pdst_locked_dump(ls->id_to_pdlv_poll, b);
|
||||
buffer_append(b, "}\n\n");
|
||||
|
||||
buffer_append(b, "# Registered abort operations\n\n");
|
||||
buffer_append(b, "abort {\n");
|
||||
pdst_locked_dump(ls->id_to_pdlv_abort, b);
|
||||
buffer_append(b, "}");
|
||||
|
||||
_lvmpolld_global_unlock(ls);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static response _handler(struct daemon_state s, client_handle h, request r)
|
||||
{
|
||||
struct lvmpolld_state *ls = s.private;
|
||||
const char *rq = daemon_request_str(r, "request", "NONE");
|
||||
|
||||
if (!strcmp(rq, LVMPD_REQ_PVMOVE))
|
||||
return poll_init(h, ls, r, PVMOVE);
|
||||
else if (!strcmp(rq, LVMPD_REQ_CONVERT))
|
||||
return poll_init(h, ls, r, CONVERT);
|
||||
else if (!strcmp(rq, LVMPD_REQ_MERGE))
|
||||
return poll_init(h, ls, r, MERGE);
|
||||
else if (!strcmp(rq, LVMPD_REQ_MERGE_THIN))
|
||||
return poll_init(h, ls, r, MERGE_THIN);
|
||||
else if (!strcmp(rq, LVMPD_REQ_PROGRESS))
|
||||
return progress_info(h, ls, r);
|
||||
else if (!strcmp(rq, LVMPD_REQ_DUMP))
|
||||
return dump_state(h, ls, r);
|
||||
else
|
||||
return reply(LVMPD_RESP_EINVAL, REASON_REQ_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(str, &endptr, 10);
|
||||
if (errno || *endptr || l >= UINT_MAX)
|
||||
return 0;
|
||||
|
||||
*max_timeouts = (unsigned) l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Client functionality */
|
||||
typedef int (*action_fn_t) (void *args);
|
||||
|
||||
struct log_line_baton {
|
||||
const char *prefix;
|
||||
};
|
||||
|
||||
daemon_handle _lvmpolld = { .error = 0 };
|
||||
|
||||
static daemon_handle _lvmpolld_open(const char *socket)
|
||||
{
|
||||
daemon_info lvmpolld_info = {
|
||||
.path = "lvmpolld",
|
||||
.socket = socket ?: DEFAULT_RUN_DIR "/lvmpolld.socket",
|
||||
.protocol = LVMPOLLD_PROTOCOL,
|
||||
.protocol_version = LVMPOLLD_PROTOCOL_VERSION
|
||||
};
|
||||
|
||||
return daemon_open(lvmpolld_info);
|
||||
}
|
||||
|
||||
static void _log_line(const char *line, void *baton) {
|
||||
struct log_line_baton *b = baton;
|
||||
fprintf(stdout, "%s%s\n", b->prefix, line);
|
||||
}
|
||||
|
||||
static int printout_raw_response(const char *prefix, const char *msg)
|
||||
{
|
||||
struct log_line_baton b = { .prefix = prefix };
|
||||
char *buf;
|
||||
char *pos;
|
||||
|
||||
buf = dm_strdup(msg);
|
||||
pos = buf;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
while (pos) {
|
||||
char *next = strchr(pos, '\n');
|
||||
if (next)
|
||||
*next = 0;
|
||||
_log_line(pos, &b);
|
||||
pos = next ? next + 1 : 0;
|
||||
}
|
||||
dm_free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* place all action implementations below */
|
||||
|
||||
static int action_dump(void *args __attribute__((unused)))
|
||||
{
|
||||
daemon_request req;
|
||||
daemon_reply repl;
|
||||
int r = 0;
|
||||
|
||||
req = daemon_request_make(LVMPD_REQ_DUMP);
|
||||
if (!req.cft) {
|
||||
fprintf(stderr, "Failed to create lvmpolld " LVMPD_REQ_DUMP " request.\n");
|
||||
goto out_req;
|
||||
}
|
||||
|
||||
repl = daemon_send(_lvmpolld, req);
|
||||
if (repl.error) {
|
||||
fprintf(stderr, "Failed to send a request or receive response.\n");
|
||||
goto out_rep;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is dumb copy & paste from libdaemon log routines.
|
||||
*/
|
||||
if (!printout_raw_response(" ", repl.buffer.mem)) {
|
||||
fprintf(stderr, "Failed to print out the response.\n");
|
||||
goto out_rep;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out_rep:
|
||||
daemon_reply_destroy(repl);
|
||||
out_req:
|
||||
daemon_request_destroy(req);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
enum action_index {
|
||||
ACTION_DUMP = 0,
|
||||
ACTION_MAX /* keep at the end */
|
||||
};
|
||||
|
||||
static const action_fn_t actions[ACTION_MAX] = { [ACTION_DUMP] = action_dump };
|
||||
|
||||
static int _make_action(enum action_index idx, void *args)
|
||||
{
|
||||
return idx < ACTION_MAX ? actions[idx](args) : 0;
|
||||
}
|
||||
|
||||
static int _lvmpolld_client(const char *socket, unsigned action)
|
||||
{
|
||||
int r;
|
||||
|
||||
_lvmpolld = _lvmpolld_open(socket);
|
||||
|
||||
if (_lvmpolld.error || _lvmpolld.socket_fd < 0) {
|
||||
fprintf(stderr, "Failed to establish connection with lvmpolld.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = _make_action(action, NULL);
|
||||
|
||||
daemon_close(_lvmpolld);
|
||||
|
||||
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int action_idx = ACTION_MAX;
|
||||
static struct option long_options[] = {
|
||||
/* Have actions always at the beginning of the array. */
|
||||
{"dump", no_argument, &action_idx, ACTION_DUMP }, /* or an option_index ? */
|
||||
|
||||
/* other options */
|
||||
{"binary", required_argument, 0, 'B' },
|
||||
{"foreground", no_argument, 0, 'f' },
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{"log", required_argument, 0, 'l' },
|
||||
{"pidfile", required_argument, 0, 'p' },
|
||||
{"socket", required_argument, 0, 's' },
|
||||
{"timeout", required_argument, 0, 't' },
|
||||
{"version", no_argument, 0, 'V' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
int client = 0, server = 0;
|
||||
unsigned action = ACTION_MAX;
|
||||
struct timeval timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
struct lvmpolld_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
.daemon_fini = _fini,
|
||||
.daemon_init = _init,
|
||||
.handler = _handler,
|
||||
.name = "lvmpolld",
|
||||
.pidfile = getenv("LVM_LVMPOLLD_PIDFILE") ?: LVMPOLLD_PIDFILE,
|
||||
.private = &ls,
|
||||
.protocol = LVMPOLLD_PROTOCOL,
|
||||
.protocol_version = LVMPOLLD_PROTOCOL_VERSION,
|
||||
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "fhVl:p:s:B:t:", long_options, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 0 :
|
||||
if (action < ACTION_MAX) {
|
||||
fprintf(stderr, "Can't perform more actions. Action already requested: %s\n",
|
||||
long_options[action].name);
|
||||
_usage(argv[0], stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
action = action_idx;
|
||||
client = 1;
|
||||
break;
|
||||
case '?':
|
||||
_usage(argv[0], stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
case 'B': /* --binary */
|
||||
ls.lvm_binary = optarg;
|
||||
server = 1;
|
||||
break;
|
||||
case 'V': /* --version */
|
||||
printf("lvmpolld version: " LVM_VERSION "\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'f': /* --foreground */
|
||||
s.foreground = 1;
|
||||
server = 1;
|
||||
break;
|
||||
case 'h': /* --help */
|
||||
_usage(argv[0], stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l': /* --log */
|
||||
ls.log_config = optarg;
|
||||
server = 1;
|
||||
break;
|
||||
case 'p': /* --pidfile */
|
||||
s.pidfile = optarg;
|
||||
server = 1;
|
||||
break;
|
||||
case 's': /* --socket */
|
||||
s.socket_path = optarg;
|
||||
break;
|
||||
case 't': /* --timeout in seconds */
|
||||
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||
fprintf(stderr, "Invalid value of timeout parameter.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* 0 equals to wait indefinitely */
|
||||
if (di.max_timeouts)
|
||||
s.idle = ls.idle = &di;
|
||||
server = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (client && server) {
|
||||
fprintf(stderr, "Invalid combination of client and server parameters.\n\n");
|
||||
_usage(argv[0], stdout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (client)
|
||||
return _lvmpolld_client(s.socket_path, action);
|
||||
|
||||
/* Server */
|
||||
daemon_start(s);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lvmpolld-common.h"
|
||||
|
||||
#include "config-util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
static char *_construct_full_lvname(const char *vgname, const char *lvname)
|
||||
{
|
||||
char *name;
|
||||
size_t l;
|
||||
|
||||
l = strlen(vgname) + strlen(lvname) + 2; /* vg/lv and \0 */
|
||||
name = (char *) dm_malloc(l * sizeof(char));
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (dm_snprintf(name, l, "%s/%s", vgname, lvname) < 0) {
|
||||
dm_free(name);
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static char *_construct_lvm_system_dir_env(const char *sysdir)
|
||||
{
|
||||
/*
|
||||
* Store either "LVM_SYSTEM_DIR=/path/to..."
|
||||
* - or -
|
||||
* just single char to store NULL byte
|
||||
*/
|
||||
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
|
||||
char *env = (char *) dm_malloc(l * sizeof(char));
|
||||
|
||||
if (!env)
|
||||
return NULL;
|
||||
|
||||
*env = '\0';
|
||||
|
||||
if (sysdir && dm_snprintf(env, l, "LVM_SYSTEM_DIR=%s", sysdir) < 0) {
|
||||
dm_free(env);
|
||||
env = NULL;
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
static const char *_get_lvid(const char *lvmpolld_id, const char *sysdir)
|
||||
{
|
||||
return lvmpolld_id ? (lvmpolld_id + (sysdir ? strlen(sysdir) : 0)) : NULL;
|
||||
}
|
||||
|
||||
char *construct_id(const char *sysdir, const char *uuid)
|
||||
{
|
||||
char *id;
|
||||
int r;
|
||||
size_t l;
|
||||
|
||||
l = strlen(uuid) + (sysdir ? strlen(sysdir) : 0) + 1;
|
||||
id = (char *) dm_malloc(l * sizeof(char));
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
r = sysdir ? dm_snprintf(id, l, "%s%s", sysdir, uuid) :
|
||||
dm_snprintf(id, l, "%s", uuid);
|
||||
|
||||
if (r < 0) {
|
||||
dm_free(id);
|
||||
id = NULL;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
const char *vgname, const char *lvname,
|
||||
const char *sysdir, enum poll_type type,
|
||||
const char *sinterval, unsigned pdtimeout,
|
||||
struct lvmpolld_store *pdst)
|
||||
{
|
||||
char *lvmpolld_id = dm_strdup(id), /* copy */
|
||||
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
|
||||
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
|
||||
|
||||
struct lvmpolld_lv tmp = {
|
||||
.ls = ls,
|
||||
.type = type,
|
||||
.lvmpolld_id = lvmpolld_id,
|
||||
.lvid = _get_lvid(lvmpolld_id, sysdir),
|
||||
.lvname = full_lvname,
|
||||
.lvm_system_dir_env = lvm_system_dir_env,
|
||||
.sinterval = dm_strdup(sinterval), /* copy */
|
||||
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
|
||||
.cmd_state = { .retcode = -1, .signal = 0 },
|
||||
.pdst = pdst,
|
||||
.init_rq_count = 1
|
||||
}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
|
||||
|
||||
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
|
||||
goto err;
|
||||
|
||||
memcpy(pdlv, &tmp, sizeof(*pdlv));
|
||||
|
||||
if (pthread_mutex_init(&pdlv->lock, NULL))
|
||||
goto err;
|
||||
|
||||
return pdlv;
|
||||
|
||||
err:
|
||||
dm_free((void *)full_lvname);
|
||||
dm_free((void *)lvmpolld_id);
|
||||
dm_free((void *)lvm_system_dir_env);
|
||||
dm_free((void *)tmp.sinterval);
|
||||
dm_free((void *)pdlv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pdlv_destroy(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
dm_free((void *)pdlv->lvmpolld_id);
|
||||
dm_free((void *)pdlv->lvname);
|
||||
dm_free((void *)pdlv->sinterval);
|
||||
dm_free((void *)pdlv->lvm_system_dir_env);
|
||||
dm_free((void *)pdlv->cmdargv);
|
||||
dm_free((void *)pdlv->cmdenvp);
|
||||
|
||||
pthread_mutex_destroy(&pdlv->lock);
|
||||
|
||||
dm_free((void *)pdlv);
|
||||
}
|
||||
|
||||
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
unsigned ret;
|
||||
|
||||
pdlv_lock(pdlv);
|
||||
ret = pdlv->polling_finished;
|
||||
pdlv_unlock(pdlv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
struct lvmpolld_lv_state r;
|
||||
|
||||
pdlv_lock(pdlv);
|
||||
r.error = pdlv_locked_error(pdlv);
|
||||
r.polling_finished = pdlv_locked_polling_finished(pdlv);
|
||||
r.cmd_state = pdlv_locked_cmd_state(pdlv);
|
||||
pdlv_unlock(pdlv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state)
|
||||
{
|
||||
pdlv_lock(pdlv);
|
||||
pdlv->cmd_state = *cmd_state;
|
||||
pdlv_unlock(pdlv);
|
||||
}
|
||||
|
||||
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error)
|
||||
{
|
||||
pdlv_lock(pdlv);
|
||||
pdlv->error = error;
|
||||
pdlv_unlock(pdlv);
|
||||
}
|
||||
|
||||
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
|
||||
{
|
||||
pdlv_lock(pdlv);
|
||||
pdlv->polling_finished = finished;
|
||||
pdlv_unlock(pdlv);
|
||||
}
|
||||
|
||||
struct lvmpolld_store *pdst_init(const char *name)
|
||||
{
|
||||
struct lvmpolld_store *pdst = (struct lvmpolld_store *) dm_malloc(sizeof(struct lvmpolld_store));
|
||||
if (!pdst)
|
||||
return NULL;
|
||||
|
||||
pdst->store = dm_hash_create(32);
|
||||
if (!pdst->store)
|
||||
goto err_hash;
|
||||
if (pthread_mutex_init(&pdst->lock, NULL))
|
||||
goto err_mutex;
|
||||
|
||||
pdst->name = name;
|
||||
pdst->active_polling_count = 0;
|
||||
|
||||
return pdst;
|
||||
|
||||
err_mutex:
|
||||
dm_hash_destroy(pdst->store);
|
||||
err_hash:
|
||||
dm_free(pdst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pdst_destroy(struct lvmpolld_store *pdst)
|
||||
{
|
||||
if (!pdst)
|
||||
return;
|
||||
|
||||
dm_hash_destroy(pdst->store);
|
||||
pthread_mutex_destroy(&pdst->lock);
|
||||
dm_free(pdst);
|
||||
}
|
||||
|
||||
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
|
||||
dm_hash_iterate(n, pdst->store)
|
||||
pdlv_lock(dm_hash_get_data(pdst->store, n));
|
||||
}
|
||||
|
||||
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
|
||||
dm_hash_iterate(n, pdst->store)
|
||||
pdlv_unlock(dm_hash_get_data(pdst->store, n));
|
||||
}
|
||||
|
||||
static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
char tmp[1024];
|
||||
const struct lvmpolld_cmd_stat *cmd_state = &pdlv->cmd_state;
|
||||
|
||||
/* pdlv-section { */
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t%s {\n", pdlv->lvmpolld_id) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvid=\"%s\"\n", pdlv->lvid) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\ttype=\"%s\"\n", polling_op(pdlv->type)) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvname=\"%s\"\n", pdlv->lvname) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvmpolld_internal_timeout=%d\n", pdlv->pdtimeout) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_interval=\"%s\"\n", pdlv->sinterval ?: "<undefined>") > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tLVM_SYSTEM_DIR=\"%s\"\n",
|
||||
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + strlen("LVM_SYSTEM_DIR=")) : "<undefined>")) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_pid=%d\n", pdlv->cmd_pid) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
|
||||
/* lvm_commmand-section { */
|
||||
buffer_append(buff, "\t\tlvm_command {\n");
|
||||
if (cmd_state->retcode == -1 && !cmd_state->signal)
|
||||
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
|
||||
else {
|
||||
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_FINISHED "\"\n");
|
||||
if (dm_snprintf(tmp, sizeof(tmp), "\t\t\treason=\"%s\"\n\t\t\tvalue=%d\n",
|
||||
(cmd_state->signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE),
|
||||
(cmd_state->signal ?: cmd_state->retcode)) > 0)
|
||||
buffer_append(buff, tmp);
|
||||
}
|
||||
buffer_append(buff, "\t\t}\n");
|
||||
/* } lvm_commmand-section */
|
||||
|
||||
buffer_append(buff, "\t}\n");
|
||||
/* } pdlv-section */
|
||||
}
|
||||
|
||||
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
|
||||
dm_hash_iterate(n, pdst->store)
|
||||
_pdlv_locked_dump(buff, dm_hash_get_data(pdst->store, n));
|
||||
}
|
||||
|
||||
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst)
|
||||
{
|
||||
struct lvmpolld_lv *pdlv;
|
||||
struct dm_hash_node *n;
|
||||
|
||||
dm_hash_iterate(n, pdst->store) {
|
||||
pdlv = dm_hash_get_data(pdst->store, n);
|
||||
if (!pdlv_locked_polling_finished(pdlv))
|
||||
pthread_cancel(pdlv->tid);
|
||||
}
|
||||
}
|
||||
|
||||
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
|
||||
dm_hash_iterate(n, pdst->store)
|
||||
pdlv_destroy(dm_hash_get_data(pdst->store, n));
|
||||
}
|
||||
|
||||
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) dm_malloc(sizeof(struct lvmpolld_thread_data));
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
data->pdlv = NULL;
|
||||
data->line = NULL;
|
||||
data->fout = data->ferr = NULL;
|
||||
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
|
||||
|
||||
if (pipe(data->outpipe) || pipe(data->errpipe)) {
|
||||
lvmpolld_thread_data_destroy(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fcntl(data->outpipe[0], F_SETFD, FD_CLOEXEC) ||
|
||||
fcntl(data->outpipe[1], F_SETFD, FD_CLOEXEC) ||
|
||||
fcntl(data->errpipe[0], F_SETFD, FD_CLOEXEC) ||
|
||||
fcntl(data->errpipe[1], F_SETFD, FD_CLOEXEC)) {
|
||||
lvmpolld_thread_data_destroy(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->pdlv = pdlv;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void lvmpolld_thread_data_destroy(void *thread_private)
|
||||
{
|
||||
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) thread_private;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->pdlv) {
|
||||
pdst_lock(data->pdlv->pdst);
|
||||
/*
|
||||
* FIXME: skip this step if lvmpolld is activated
|
||||
* by systemd.
|
||||
*/
|
||||
if (!pdlv_get_polling_finished(data->pdlv))
|
||||
kill(data->pdlv->cmd_pid, SIGTERM);
|
||||
pdlv_set_polling_finished(data->pdlv, 1);
|
||||
pdst_locked_dec(data->pdlv->pdst);
|
||||
pdst_unlock(data->pdlv->pdst);
|
||||
}
|
||||
|
||||
dm_free(data->line);
|
||||
|
||||
if (data->fout && !fclose(data->fout))
|
||||
data->outpipe[0] = -1;
|
||||
|
||||
if (data->ferr && !fclose(data->ferr))
|
||||
data->errpipe[0] = -1;
|
||||
|
||||
if (data->outpipe[0] >= 0)
|
||||
close(data->outpipe[0]);
|
||||
|
||||
if (data->outpipe[1] >= 0)
|
||||
close(data->outpipe[1]);
|
||||
|
||||
if (data->errpipe[0] >= 0)
|
||||
close(data->errpipe[0]);
|
||||
|
||||
if (data->errpipe[1] >= 0)
|
||||
close(data->errpipe[1]);
|
||||
|
||||
dm_free(data);
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
|
||||
#define _LVM_LVMPOLLD_DATA_UTILS_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct buffer;
|
||||
struct lvmpolld_state;
|
||||
|
||||
enum poll_type {
|
||||
PVMOVE = 0,
|
||||
CONVERT,
|
||||
MERGE,
|
||||
MERGE_THIN,
|
||||
POLL_TYPE_MAX
|
||||
};
|
||||
|
||||
struct lvmpolld_cmd_stat {
|
||||
int retcode;
|
||||
int signal;
|
||||
};
|
||||
|
||||
struct lvmpolld_store {
|
||||
pthread_mutex_t lock;
|
||||
void *store;
|
||||
const char *name;
|
||||
unsigned active_polling_count;
|
||||
};
|
||||
|
||||
struct lvmpolld_lv {
|
||||
/*
|
||||
* accessing following vars doesn't
|
||||
* require struct lvmpolld_lv lock
|
||||
*/
|
||||
struct lvmpolld_state *const ls;
|
||||
const enum poll_type type;
|
||||
const char *const lvid;
|
||||
const char *const lvmpolld_id;
|
||||
const char *const lvname; /* full vg/lv name */
|
||||
const unsigned pdtimeout; /* in seconds */
|
||||
const char *const sinterval;
|
||||
const char *const lvm_system_dir_env;
|
||||
struct lvmpolld_store *const pdst;
|
||||
const char *const *cmdargv;
|
||||
const char *const *cmdenvp;
|
||||
|
||||
/* only used by write */
|
||||
pid_t cmd_pid;
|
||||
pthread_t tid;
|
||||
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/* block of shared variables protected by lock */
|
||||
struct lvmpolld_cmd_stat cmd_state;
|
||||
unsigned init_rq_count; /* for debuging purposes only */
|
||||
unsigned polling_finished:1; /* no more updates */
|
||||
unsigned error:1; /* unrecoverable error occured in lvmpolld */
|
||||
};
|
||||
|
||||
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
|
||||
|
||||
/* TODO: replace with configuration option */
|
||||
#define MIN_POLLING_TIMEOUT 60
|
||||
|
||||
struct lvmpolld_lv_state {
|
||||
unsigned error:1;
|
||||
unsigned polling_finished:1;
|
||||
struct lvmpolld_cmd_stat cmd_state;
|
||||
};
|
||||
|
||||
struct lvmpolld_thread_data {
|
||||
char *line;
|
||||
size_t line_size;
|
||||
int outpipe[2];
|
||||
int errpipe[2];
|
||||
FILE *fout;
|
||||
FILE *ferr;
|
||||
char buf[1024];
|
||||
struct lvmpolld_lv *pdlv;
|
||||
};
|
||||
|
||||
char *construct_id(const char *sysdir, const char *lvid);
|
||||
|
||||
/* LVMPOLLD_LV_T section */
|
||||
|
||||
/* only call with appropriate struct lvmpolld_store lock held */
|
||||
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
|
||||
const char *vgname, const char *lvname,
|
||||
const char *sysdir, enum poll_type type,
|
||||
const char *sinterval, unsigned pdtimeout,
|
||||
struct lvmpolld_store *pdst);
|
||||
|
||||
/* only call with appropriate struct lvmpolld_store lock held */
|
||||
void pdlv_destroy(struct lvmpolld_lv *pdlv);
|
||||
|
||||
static inline void pdlv_lock(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
pthread_mutex_lock(&pdlv->lock);
|
||||
}
|
||||
|
||||
static inline void pdlv_unlock(struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
pthread_mutex_unlock(&pdlv->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* no struct lvmpolld_lv lock required section
|
||||
*/
|
||||
static inline int pdlv_is_type(const struct lvmpolld_lv *pdlv, enum poll_type type)
|
||||
{
|
||||
return pdlv->type == type;
|
||||
}
|
||||
|
||||
static inline unsigned pdlv_get_timeout(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
return pdlv->pdtimeout;
|
||||
}
|
||||
|
||||
static inline enum poll_type pdlv_get_type(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
return pdlv->type;
|
||||
}
|
||||
|
||||
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv);
|
||||
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv);
|
||||
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state);
|
||||
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error);
|
||||
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished);
|
||||
|
||||
/*
|
||||
* struct lvmpolld_lv lock required section
|
||||
*/
|
||||
static inline struct lvmpolld_cmd_stat pdlv_locked_cmd_state(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
return pdlv->cmd_state;
|
||||
}
|
||||
|
||||
static inline int pdlv_locked_polling_finished(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
return pdlv->polling_finished;
|
||||
}
|
||||
|
||||
static inline unsigned pdlv_locked_error(const struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
return pdlv->error;
|
||||
}
|
||||
|
||||
/* struct lvmpolld_store manipulation routines */
|
||||
|
||||
struct lvmpolld_store *pdst_init(const char *name);
|
||||
void pdst_destroy(struct lvmpolld_store *pdst);
|
||||
|
||||
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff);
|
||||
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst);
|
||||
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst);
|
||||
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst);
|
||||
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst);
|
||||
|
||||
static inline void pdst_lock(struct lvmpolld_store *pdst)
|
||||
{
|
||||
pthread_mutex_lock(&pdst->lock);
|
||||
}
|
||||
|
||||
static inline void pdst_unlock(struct lvmpolld_store *pdst)
|
||||
{
|
||||
pthread_mutex_unlock(&pdst->lock);
|
||||
}
|
||||
|
||||
static inline void pdst_locked_inc(struct lvmpolld_store *pdst)
|
||||
{
|
||||
pdst->active_polling_count++;
|
||||
}
|
||||
|
||||
static inline void pdst_locked_dec(struct lvmpolld_store *pdst)
|
||||
{
|
||||
pdst->active_polling_count--;
|
||||
}
|
||||
|
||||
static inline unsigned pdst_locked_get_active_count(const struct lvmpolld_store *pdst)
|
||||
{
|
||||
return pdst->active_polling_count;
|
||||
}
|
||||
|
||||
static inline int pdst_locked_insert(struct lvmpolld_store *pdst, const char *key, struct lvmpolld_lv *pdlv)
|
||||
{
|
||||
return dm_hash_insert(pdst->store, key, pdlv);
|
||||
}
|
||||
|
||||
static inline struct lvmpolld_lv *pdst_locked_lookup(struct lvmpolld_store *pdst, const char *key)
|
||||
{
|
||||
return dm_hash_lookup(pdst->store, key);
|
||||
}
|
||||
|
||||
static inline void pdst_locked_remove(struct lvmpolld_store *pdst, const char *key)
|
||||
{
|
||||
dm_hash_remove(pdst->store, key);
|
||||
}
|
||||
|
||||
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv);
|
||||
void lvmpolld_thread_data_destroy(void *thread_private);
|
||||
|
||||
#endif /* _LVM_LVMPOLLD_DATA_UTILS_H */
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_LVMPOLLD_PROTOCOL_H
|
||||
#define _LVM_LVMPOLLD_PROTOCOL_H
|
||||
|
||||
#include "polling_ops.h"
|
||||
|
||||
#define LVMPOLLD_PROTOCOL "lvmpolld"
|
||||
#define LVMPOLLD_PROTOCOL_VERSION 1
|
||||
|
||||
#define LVMPD_REQ_CONVERT CONVERT_POLL
|
||||
#define LVMPD_REQ_DUMP "dump"
|
||||
#define LVMPD_REQ_MERGE MERGE_POLL
|
||||
#define LVMPD_REQ_MERGE_THIN MERGE_THIN_POLL
|
||||
#define LVMPD_REQ_PROGRESS "progress_info"
|
||||
#define LVMPD_REQ_PVMOVE PVMOVE_POLL
|
||||
|
||||
#define LVMPD_PARM_ABORT "abort"
|
||||
#define LVMPD_PARM_HANDLE_MISSING_PVS "handle_missing_pvs"
|
||||
#define LVMPD_PARM_INTERVAL "interval"
|
||||
#define LVMPD_PARM_LVID "lvid"
|
||||
#define LVMPD_PARM_LVNAME "lvname"
|
||||
#define LVMPD_PARM_SYSDIR "sysdir"
|
||||
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
|
||||
#define LVMPD_PARM_VGNAME "vgname"
|
||||
|
||||
#define LVMPD_RESP_FAILED "failed"
|
||||
#define LVMPD_RESP_FINISHED "finished"
|
||||
#define LVMPD_RESP_IN_PROGRESS "in_progress"
|
||||
#define LVMPD_RESP_EINVAL "invalid"
|
||||
#define LVMPD_RESP_NOT_FOUND "not_found"
|
||||
#define LVMPD_RESP_OK "OK"
|
||||
|
||||
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
|
||||
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating singal */
|
||||
|
||||
#define LVMPD_RET_DUP_FAILED 100
|
||||
#define LVMPD_RET_EXC_FAILED 101
|
||||
|
||||
#endif /* _LVM_LVMPOLLD_PROTOCOL_H */
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_TOOL_POLLING_OPS_H
|
||||
#define _LVM_TOOL_POLLING_OPS_H
|
||||
|
||||
/* this file is also part of lvmpolld protocol */
|
||||
|
||||
#define PVMOVE_POLL "pvmove"
|
||||
#define CONVERT_POLL "convert"
|
||||
#define MERGE_POLL "merge"
|
||||
#define MERGE_THIN_POLL "merge_thin"
|
||||
|
||||
#endif /* _LVM_TOOL_POLLING_OPS_H */
|
||||
@@ -1,86 +0,0 @@
|
||||
Q: Why should lvmetad cache foreign VGs?
|
||||
A: It's the most useful behavior in the "steady state".
|
||||
|
||||
How to arrive at that conclusion.
|
||||
Four code configurations to consider, each in two different circumstances.
|
||||
|
||||
configurations:
|
||||
|
||||
1. lvm not using lvmetad
|
||||
2. lvm using lvmetad and lvmlockd
|
||||
3. lvm using lvmetad, and lvmetad does not cache foreign VGs
|
||||
(Not currently implemented.)
|
||||
4. lvm using lvmetad, and lvmetad caches foreign VGs
|
||||
|
||||
circumstances:
|
||||
|
||||
A. steady state: PVs are not added or removed to/from foreign VGs
|
||||
B. transient state: PVs are added or removed to/from foreign VGs
|
||||
|
||||
combinations:
|
||||
|
||||
1.A. A PV is correctly shown in the foreign VG.
|
||||
1.B. A PV is correctly shown in the foreign VG.
|
||||
|
||||
The most accurate representation, at the cost of always scanning disks.
|
||||
|
||||
|
||||
2.A. A PV is correctly shown in the foreign VG.
|
||||
2.B. A PV is correctly shown in the foreign VG.
|
||||
|
||||
The most accurate representation, at the cost of using lvmlockd.
|
||||
|
||||
|
||||
3.A. A PV in a foreign VG is shown as unused.
|
||||
3.B. A PV in a foreign VG is shown as unused.
|
||||
|
||||
If lvmetad ignores foreign VGs and does not cache them, the PVs in the
|
||||
foreign VGs appear to be unused. This largely defeats the purpose of
|
||||
system_id, which is meant to treat VGs/PVs as foreign instead of free
|
||||
(albeit imperfectly, see below.)
|
||||
|
||||
|
||||
4.A. A PV is correctly shown in the foreign VG.
|
||||
4.B. A PV is not correctly shown in the foreign VG.
|
||||
|
||||
This avoids the cost of always scanning disks, and avoids the cost of
|
||||
using lvmlockd. The steady state 4.A. is an improvement over the steady
|
||||
state 3.A. When the steady state is the common case, this is a big
|
||||
advantage. When the steady state is *not* the common case, the foreign VG
|
||||
concept is not as useful (if shared devices are this dynamic, lvmlockd
|
||||
should be considered.)
|
||||
|
||||
The limitations related to the transient state 4.B. are explained in
|
||||
lvmsystemid(7), along with how to handle it. The specific inaccuracies
|
||||
possible in 4.B. are:
|
||||
|
||||
. PV is shown as belonging to a foreign VG, but is actually unused.
|
||||
. PV is shown as unused, but actually belongs to a foreign VG.
|
||||
|
||||
To resolve the inaccuracies in the transient state (4.B.), and return the
|
||||
system to an accurate steady state (4.A.), the disks need to be scanned,
|
||||
which updates lvmetad. The scanning/updating is a manual step, i.e.
|
||||
running 'pvscan --cache', which by definition scans disks and updates
|
||||
lvmetad.
|
||||
|
||||
--
|
||||
|
||||
The --foreign command line option for report/display commands
|
||||
(vgs/lvs/pvs/vgdisplay/lvdisplay/pvdisplay) is not directly related to
|
||||
whether or not lvmetad caches foreign VGs.
|
||||
|
||||
By default, foreign VGs are silently ignored and not printed by these
|
||||
commands. However, when the --foreign option is used, these commands do
|
||||
produce output about foreign VGs.
|
||||
|
||||
(When --foreign is not used, and the command specifically requests a
|
||||
foreign VG by name, an error is produced about not accessing foreign VGs,
|
||||
and the foreign VG is not displayed.)
|
||||
|
||||
The decision to report/display foreign VGs or not is independent of
|
||||
whether lvmetad is caching those VGs. When lvmetad is caching the foreign
|
||||
VG, a report/display command run with --foreign will scan disks to read
|
||||
the foreign VG and give the most up to date version of it (the copy of the
|
||||
foreign VG in lvmetad may be out of date due to changes to the VG by the
|
||||
foreign host.)
|
||||
|
||||
@@ -30,48 +30,28 @@ multiqueue
|
||||
|
||||
This policy is the default.
|
||||
|
||||
The multiqueue policy has three sets of 16 queues: one set for entries
|
||||
waiting for the cache and another two for those in the cache (a set for
|
||||
clean entries and a set for dirty entries).
|
||||
|
||||
The multiqueue policy has two sets of 16 queues: one set for entries
|
||||
waiting for the cache and another one for those in the cache.
|
||||
Cache entries in the queues are aged based on logical time. Entry into
|
||||
the cache is based on variable thresholds and queue selection is based
|
||||
on hit count on entry. The policy aims to take different cache miss
|
||||
costs into account and to adjust to varying load patterns automatically.
|
||||
|
||||
Message and constructor argument pairs are:
|
||||
'sequential_threshold <#nr_sequential_ios>'
|
||||
'random_threshold <#nr_random_ios>'
|
||||
'read_promote_adjustment <value>'
|
||||
'write_promote_adjustment <value>'
|
||||
'discard_promote_adjustment <value>'
|
||||
'sequential_threshold <#nr_sequential_ios>' and
|
||||
'random_threshold <#nr_random_ios>'.
|
||||
|
||||
The sequential threshold indicates the number of contiguous I/Os
|
||||
required before a stream is treated as sequential. Once a stream is
|
||||
considered sequential it will bypass the cache. The random threshold
|
||||
required before a stream is treated as sequential. The random threshold
|
||||
is the number of intervening non-contiguous I/Os that must be seen
|
||||
before the stream is treated as random again.
|
||||
|
||||
The sequential and random thresholds default to 512 and 4 respectively.
|
||||
|
||||
Large, sequential I/Os are probably better left on the origin device
|
||||
since spindles tend to have good sequential I/O bandwidth. The
|
||||
io_tracker counts contiguous I/Os to try to spot when the I/O is in one
|
||||
of these sequential modes. But there are use-cases for wanting to
|
||||
promote sequential blocks to the cache (e.g. fast application startup).
|
||||
If sequential threshold is set to 0 the sequential I/O detection is
|
||||
disabled and sequential I/O will no longer implicitly bypass the cache.
|
||||
Setting the random threshold to 0 does _not_ disable the random I/O
|
||||
stream detection.
|
||||
|
||||
Internally the mq policy determines a promotion threshold. If the hit
|
||||
count of a block not in the cache goes above this threshold it gets
|
||||
promoted to the cache. The read, write and discard promote adjustment
|
||||
tunables allow you to tweak the promotion threshold by adding a small
|
||||
value based on the io type. They default to 4, 8 and 1 respectively.
|
||||
If you're trying to quickly warm a new cache device you may wish to
|
||||
reduce these to encourage promotion. Remember to switch them back to
|
||||
their defaults after the cache fills though.
|
||||
Large, sequential ios are probably better left on the origin device
|
||||
since spindles tend to have good bandwidth. The io_tracker counts
|
||||
contiguous I/Os to try to spot when the io is in one of these sequential
|
||||
modes.
|
||||
|
||||
cleaner
|
||||
-------
|
||||
|
||||
@@ -50,16 +50,14 @@ other parameters detailed later):
|
||||
which are dirty, and extra hints for use by the policy object.
|
||||
This information could be put on the cache device, but having it
|
||||
separate allows the volume manager to configure it differently,
|
||||
e.g. as a mirror for extra robustness. This metadata device may only
|
||||
be used by a single cache device.
|
||||
e.g. as a mirror for extra robustness.
|
||||
|
||||
Fixed block size
|
||||
----------------
|
||||
|
||||
The origin is divided up into blocks of a fixed size. This block size
|
||||
is configurable when you first create the cache. Typically we've been
|
||||
using block sizes of 256KB - 1024KB. The block size must be between 64
|
||||
(32KB) and 2097152 (1GB) and a multiple of 64 (32KB).
|
||||
using block sizes of 256k - 1024k.
|
||||
|
||||
Having a fixed block size simplifies the target a lot. But it is
|
||||
something of a compromise. For instance, a small part of a block may be
|
||||
@@ -68,11 +66,10 @@ So large block sizes are bad because they waste cache space. And small
|
||||
block sizes are bad because they increase the amount of metadata (both
|
||||
in core and on disk).
|
||||
|
||||
Cache operating modes
|
||||
---------------------
|
||||
Writeback/writethrough
|
||||
----------------------
|
||||
|
||||
The cache has three operating modes: writeback, writethrough and
|
||||
passthrough.
|
||||
The cache has two modes, writeback and writethrough.
|
||||
|
||||
If writeback, the default, is selected then a write to a block that is
|
||||
cached will go only to the cache and the block will be marked dirty in
|
||||
@@ -82,38 +79,15 @@ If writethrough is selected then a write to a cached block will not
|
||||
complete until it has hit both the origin and cache devices. Clean
|
||||
blocks should remain clean.
|
||||
|
||||
If passthrough is selected, useful when the cache contents are not known
|
||||
to be coherent with the origin device, then all reads are served from
|
||||
the origin device (all reads miss the cache) and all writes are
|
||||
forwarded to the origin device; additionally, write hits cause cache
|
||||
block invalidates. To enable passthrough mode the cache must be clean.
|
||||
Passthrough mode allows a cache device to be activated without having to
|
||||
worry about coherency. Coherency that exists is maintained, although
|
||||
the cache will gradually cool as writes take place. If the coherency of
|
||||
the cache can later be verified, or established through use of the
|
||||
"invalidate_cblocks" message, the cache device can be transitioned to
|
||||
writethrough or writeback mode while still warm. Otherwise, the cache
|
||||
contents can be discarded prior to transitioning to the desired
|
||||
operating mode.
|
||||
|
||||
A simple cleaner policy is provided, which will clean (write back) all
|
||||
dirty blocks in a cache. Useful for decommissioning a cache or when
|
||||
shrinking a cache. Shrinking the cache's fast device requires all cache
|
||||
blocks, in the area of the cache being removed, to be clean. If the
|
||||
area being removed from the cache still contains dirty blocks the resize
|
||||
will fail. Care must be taken to never reduce the volume used for the
|
||||
cache's fast device until the cache is clean. This is of particular
|
||||
importance if writeback mode is used. Writethrough and passthrough
|
||||
modes already maintain a clean cache. Future support to partially clean
|
||||
the cache, above a specified threshold, will allow for keeping the cache
|
||||
warm and in writeback mode during resize.
|
||||
dirty blocks in a cache. Useful for decommissioning a cache.
|
||||
|
||||
Migration throttling
|
||||
--------------------
|
||||
|
||||
Migrating data between the origin and cache device uses bandwidth.
|
||||
The user can set a throttle to prevent more than a certain amount of
|
||||
migration occurring at any one time. Currently we're not taking any
|
||||
migration occuring at any one time. Currently we're not taking any
|
||||
account of normal io traffic going to the devices. More work needs
|
||||
doing here to avoid migrating during those peak io moments.
|
||||
|
||||
@@ -124,11 +98,12 @@ the default being 204800 sectors (or 100MB).
|
||||
Updating on-disk metadata
|
||||
-------------------------
|
||||
|
||||
On-disk metadata is committed every time a FLUSH or FUA bio is written.
|
||||
If no such requests are made then commits will occur every second. This
|
||||
means the cache behaves like a physical disk that has a volatile write
|
||||
cache. If power is lost you may lose some recent writes. The metadata
|
||||
should always be consistent in spite of any crash.
|
||||
On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
|
||||
written. If no such requests are made then commits will occur every
|
||||
second. This means the cache behaves like a physical disk that has a
|
||||
write cache (the same is true of the thin-provisioning target). If
|
||||
power is lost you may lose some recent writes. The metadata should
|
||||
always be consistent in spite of any crash.
|
||||
|
||||
The 'dirty' state for a cache block changes far too frequently for us
|
||||
to keep updating it on the fly. So we treat it as a hint. In normal
|
||||
@@ -184,7 +159,7 @@ Constructor
|
||||
block size : cache unit size in sectors
|
||||
|
||||
#feature args : number of feature arguments passed
|
||||
feature args : writethrough or passthrough (The default is writeback.)
|
||||
feature args : writethrough. (The default is writeback.)
|
||||
|
||||
policy : the replacement policy to use
|
||||
#policy args : an even number of arguments corresponding to
|
||||
@@ -200,13 +175,6 @@ Optional feature arguments are:
|
||||
back cache block contents later for performance reasons,
|
||||
so they may differ from the corresponding origin blocks.
|
||||
|
||||
passthrough : a degraded mode useful for various cache coherency
|
||||
situations (e.g., rolling back snapshots of
|
||||
underlying storage). Reads and writes always go to
|
||||
the origin. If a write goes to a cached origin
|
||||
block, then the cache block is invalidated.
|
||||
To enable passthrough mode the cache must be clean.
|
||||
|
||||
A policy called 'default' is always registered. This is an alias for
|
||||
the policy we currently think is giving best all round performance.
|
||||
|
||||
@@ -216,43 +184,36 @@ the characteristics of a specific policy, always request it by name.
|
||||
Status
|
||||
------
|
||||
|
||||
<metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
<cache block size> <#used cache blocks>/<#total cache blocks>
|
||||
<#read hits> <#read misses> <#write hits> <#write misses>
|
||||
<#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||
<#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||
<#used metadata blocks>/<#total metadata blocks> <#read hits> <#read misses>
|
||||
<#write hits> <#write misses> <#demotions> <#promotions> <#blocks in cache>
|
||||
<#dirty> <#features> <features>* <#core args> <core args>* <#policy args>
|
||||
<policy args>*
|
||||
|
||||
metadata block size : Fixed block size for each metadata block in
|
||||
sectors
|
||||
#used metadata blocks : Number of metadata blocks used
|
||||
#total metadata blocks : Total number of metadata blocks
|
||||
cache block size : Configurable block size for the cache device
|
||||
in sectors
|
||||
#used cache blocks : Number of blocks resident in the cache
|
||||
#total cache blocks : Total number of cache blocks
|
||||
#read hits : Number of times a READ bio has been mapped
|
||||
#used metadata blocks : Number of metadata blocks used
|
||||
#total metadata blocks : Total number of metadata blocks
|
||||
#read hits : Number of times a READ bio has been mapped
|
||||
to the cache
|
||||
#read misses : Number of times a READ bio has been mapped
|
||||
#read misses : Number of times a READ bio has been mapped
|
||||
to the origin
|
||||
#write hits : Number of times a WRITE bio has been mapped
|
||||
#write hits : Number of times a WRITE bio has been mapped
|
||||
to the cache
|
||||
#write misses : Number of times a WRITE bio has been
|
||||
#write misses : Number of times a WRITE bio has been
|
||||
mapped to the origin
|
||||
#demotions : Number of times a block has been removed
|
||||
#demotions : Number of times a block has been removed
|
||||
from the cache
|
||||
#promotions : Number of times a block has been moved to
|
||||
#promotions : Number of times a block has been moved to
|
||||
the cache
|
||||
#dirty : Number of blocks in the cache that differ
|
||||
#blocks in cache : Number of blocks resident in the cache
|
||||
#dirty : Number of blocks in the cache that differ
|
||||
from the origin
|
||||
#feature args : Number of feature args to follow
|
||||
feature args : 'writethrough' (optional)
|
||||
#core args : Number of core arguments (must be even)
|
||||
core args : Key/value pairs for tuning the core
|
||||
#feature args : Number of feature args to follow
|
||||
feature args : 'writethrough' (optional)
|
||||
#core args : Number of core arguments (must be even)
|
||||
core args : Key/value pairs for tuning the core
|
||||
e.g. migration_threshold
|
||||
policy name : Name of the policy
|
||||
#policy args : Number of policy arguments to follow (must be even)
|
||||
policy args : Key/value pairs
|
||||
e.g. sequential_threshold
|
||||
#policy args : Number of policy arguments to follow (must be even)
|
||||
policy args : Key/value pairs
|
||||
e.g. 'sequential_threshold 1024
|
||||
|
||||
Messages
|
||||
--------
|
||||
@@ -268,28 +229,12 @@ The message format is:
|
||||
E.g.
|
||||
dmsetup message my_cache 0 sequential_threshold 1024
|
||||
|
||||
|
||||
Invalidation is removing an entry from the cache without writing it
|
||||
back. Cache blocks can be invalidated via the invalidate_cblocks
|
||||
message, which takes an arbitrary number of cblock ranges. Each cblock
|
||||
range's end value is "one past the end", meaning 5-10 expresses a range
|
||||
of values from 5 to 9. Each cblock must be expressed as a decimal
|
||||
value, in the future a variant message that takes cblock ranges
|
||||
expressed in hexidecimal may be needed to better support efficient
|
||||
invalidation of larger caches. The cache must be in passthrough mode
|
||||
when invalidate_cblocks is used.
|
||||
|
||||
invalidate_cblocks [<cblock>|<cblock begin>-<cblock end>]*
|
||||
|
||||
E.g.
|
||||
dmsetup message my_cache 0 invalidate_cblocks 2345 3456-4567 5678-6789
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
The test suite can be found here:
|
||||
|
||||
https://github.com/jthornber/device-mapper-test-suite
|
||||
https://github.com/jthornber/thinp-test-suite
|
||||
|
||||
dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \
|
||||
/dev/mapper/ssd /dev/mapper/origin 512 1 writeback default 0'
|
||||
|
||||
@@ -4,15 +4,12 @@ dm-crypt
|
||||
Device-Mapper's "crypt" target provides transparent encryption of block devices
|
||||
using the kernel crypto API.
|
||||
|
||||
For a more detailed description of supported parameters see:
|
||||
https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
|
||||
|
||||
Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||
<offset> [<#opt_params> <opt_params>]
|
||||
|
||||
<cipher>
|
||||
Encryption cipher and an optional IV generation mode.
|
||||
(In format cipher[:keycount]-chainmode-ivmode[:ivopts]).
|
||||
(In format cipher[:keycount]-chainmode-ivopts:ivmode).
|
||||
Examples:
|
||||
des
|
||||
aes-cbc-essiv:sha256
|
||||
@@ -22,11 +19,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||
|
||||
<key>
|
||||
Key used for encryption. It is encoded as a hexadecimal number.
|
||||
You can only use key sizes that are valid for the selected cipher
|
||||
in combination with the selected iv mode.
|
||||
Note that for some iv modes the key string can contain additional
|
||||
keys (for example IV seed) so the key contains more parts concatenated
|
||||
into a single string.
|
||||
You can only use key sizes that are valid for the selected cipher.
|
||||
|
||||
<keycount>
|
||||
Multi-key compatibility mode. You can define <keycount> keys and
|
||||
@@ -51,7 +44,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
|
||||
Otherwise #opt_params is the number of following arguments.
|
||||
|
||||
Example of optional parameters section:
|
||||
3 allow_discards same_cpu_crypt submit_from_crypt_cpus
|
||||
1 allow_discards
|
||||
|
||||
allow_discards
|
||||
Block discard requests (a.k.a. TRIM) are passed through the crypt device.
|
||||
@@ -63,24 +56,11 @@ allow_discards
|
||||
used space etc.) if the discarded blocks can be located easily on the
|
||||
device later.
|
||||
|
||||
same_cpu_crypt
|
||||
Perform encryption using the same cpu that IO was submitted on.
|
||||
The default is to use an unbound workqueue so that encryption work
|
||||
is automatically balanced between available CPUs.
|
||||
|
||||
submit_from_crypt_cpus
|
||||
Disable offloading writes to a separate thread after encryption.
|
||||
There are some situations where offloading write bios from the
|
||||
encryption threads to a single thread degrades performance
|
||||
significantly. The default is to offload write bios to the same
|
||||
thread because it benefits CFQ to have writes submitted using the
|
||||
same context.
|
||||
|
||||
Example scripts
|
||||
===============
|
||||
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
|
||||
encryption with dm-crypt using the 'cryptsetup' utility, see
|
||||
https://gitlab.com/cryptsetup/cryptsetup
|
||||
http://code.google.com/p/cryptsetup/
|
||||
|
||||
[[
|
||||
#!/bin/sh
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
dm-era is a target that behaves similar to the linear target. In
|
||||
addition it keeps track of which blocks were written within a user
|
||||
defined period of time called an 'era'. Each era target instance
|
||||
maintains the current era as a monotonically increasing 32-bit
|
||||
counter.
|
||||
|
||||
Use cases include tracking changed blocks for backup software, and
|
||||
partially invalidating the contents of a cache to restore cache
|
||||
coherency after rolling back a vendor snapshot.
|
||||
|
||||
Constructor
|
||||
===========
|
||||
|
||||
era <metadata dev> <origin dev> <block size>
|
||||
|
||||
metadata dev : fast device holding the persistent metadata
|
||||
origin dev : device holding data blocks that may change
|
||||
block size : block size of origin data device, granularity that is
|
||||
tracked by the target
|
||||
|
||||
Messages
|
||||
========
|
||||
|
||||
None of the dm messages take any arguments.
|
||||
|
||||
checkpoint
|
||||
----------
|
||||
|
||||
Possibly move to a new era. You shouldn't assume the era has
|
||||
incremented. After sending this message, you should check the
|
||||
current era via the status line.
|
||||
|
||||
take_metadata_snap
|
||||
------------------
|
||||
|
||||
Create a clone of the metadata, to allow a userland process to read it.
|
||||
|
||||
drop_metadata_snap
|
||||
------------------
|
||||
|
||||
Drop the metadata snapshot.
|
||||
|
||||
Status
|
||||
======
|
||||
|
||||
<metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
<current era> <held metadata root | '-'>
|
||||
|
||||
metadata block size : Fixed block size for each metadata block in
|
||||
sectors
|
||||
#used metadata blocks : Number of metadata blocks used
|
||||
#total metadata blocks : Total number of metadata blocks
|
||||
current era : The current era
|
||||
held metadata root : The location, in blocks, of the metadata root
|
||||
that has been 'held' for userspace read
|
||||
access. '-' indicates there is no held root
|
||||
|
||||
Detailed use case
|
||||
=================
|
||||
|
||||
The scenario of invalidating a cache when rolling back a vendor
|
||||
snapshot was the primary use case when developing this target:
|
||||
|
||||
Taking a vendor snapshot
|
||||
------------------------
|
||||
|
||||
- Send a checkpoint message to the era target
|
||||
- Make a note of the current era in its status line
|
||||
- Take vendor snapshot (the era and snapshot should be forever
|
||||
associated now).
|
||||
|
||||
Rolling back to an vendor snapshot
|
||||
----------------------------------
|
||||
|
||||
- Cache enters passthrough mode (see: dm-cache's docs in cache.txt)
|
||||
- Rollback vendor storage
|
||||
- Take metadata snapshot
|
||||
- Ascertain which blocks have been written since the snapshot was taken
|
||||
by checking each block's era
|
||||
- Invalidate those blocks in the caching software
|
||||
- Cache returns to writeback/writethrough mode
|
||||
|
||||
Memory usage
|
||||
============
|
||||
|
||||
The target uses a bitset to record writes in the current era. It also
|
||||
has a spare bitset ready for switching over to a new era. Other than
|
||||
that it uses a few 4k blocks for updating metadata.
|
||||
|
||||
(4 * nr_blocks) bytes + buffers
|
||||
|
||||
Resilience
|
||||
==========
|
||||
|
||||
Metadata is updated on disk before a write to a previously unwritten
|
||||
block is performed. As such dm-era should not be effected by a hard
|
||||
crash such as power failure.
|
||||
|
||||
Userland tools
|
||||
==============
|
||||
|
||||
Userland tools are found in the increasingly poorly named
|
||||
thin-provisioning-tools project:
|
||||
|
||||
https://github.com/jthornber/thin-provisioning-tools
|
||||
@@ -1,140 +0,0 @@
|
||||
dm-log-writes
|
||||
=============
|
||||
|
||||
This target takes 2 devices, one to pass all IO to normally, and one to log all
|
||||
of the write operations to. This is intended for file system developers wishing
|
||||
to verify the integrity of metadata or data as the file system is written to.
|
||||
There is a log_write_entry written for every WRITE request and the target is
|
||||
able to take arbitrary data from userspace to insert into the log. The data
|
||||
that is in the WRITE requests is copied into the log to make the replay happen
|
||||
exactly as it happened originally.
|
||||
|
||||
Log Ordering
|
||||
============
|
||||
|
||||
We log things in order of completion once we are sure the write is no longer in
|
||||
cache. This means that normal WRITE requests are not actually logged until the
|
||||
next REQ_FLUSH request. This is to make it easier for userspace to replay the
|
||||
log in a way that correlates to what is on disk and not what is in cache, to
|
||||
make it easier to detect improper waiting/flushing.
|
||||
|
||||
This works by attaching all WRITE requests to a list once the write completes.
|
||||
Once we see a REQ_FLUSH request we splice this list onto the request and once
|
||||
the FLUSH request completes we log all of the WRITEs and then the FLUSH. Only
|
||||
completed WRITEs, at the time the REQ_FLUSH is issued, are added in order to
|
||||
simulate the worst case scenario with regard to power failures. Consider the
|
||||
following example (W means write, C means complete):
|
||||
|
||||
W1,W2,W3,C3,C2,Wflush,C1,Cflush
|
||||
|
||||
The log would show the following
|
||||
|
||||
W3,W2,flush,W1....
|
||||
|
||||
Again this is to simulate what is actually on disk, this allows us to detect
|
||||
cases where a power failure at a particular point in time would create an
|
||||
inconsistent file system.
|
||||
|
||||
Any REQ_FUA requests bypass this flushing mechanism and are logged as soon as
|
||||
they complete as those requests will obviously bypass the device cache.
|
||||
|
||||
Any REQ_DISCARD requests are treated like WRITE requests. Otherwise we would
|
||||
have all the DISCARD requests, and then the WRITE requests and then the FLUSH
|
||||
request. Consider the following example:
|
||||
|
||||
WRITE block 1, DISCARD block 1, FLUSH
|
||||
|
||||
If we logged DISCARD when it completed, the replay would look like this
|
||||
|
||||
DISCARD 1, WRITE 1, FLUSH
|
||||
|
||||
which isn't quite what happened and wouldn't be caught during the log replay.
|
||||
|
||||
Target interface
|
||||
================
|
||||
|
||||
i) Constructor
|
||||
|
||||
log-writes <dev_path> <log_dev_path>
|
||||
|
||||
dev_path : Device that all of the IO will go to normally.
|
||||
log_dev_path : Device where the log entries are written to.
|
||||
|
||||
ii) Status
|
||||
|
||||
<#logged entries> <highest allocated sector>
|
||||
|
||||
#logged entries : Number of logged entries
|
||||
highest allocated sector : Highest allocated sector
|
||||
|
||||
iii) Messages
|
||||
|
||||
mark <description>
|
||||
|
||||
You can use a dmsetup message to set an arbitrary mark in a log.
|
||||
For example say you want to fsck a file system after every
|
||||
write, but first you need to replay up to the mkfs to make sure
|
||||
we're fsck'ing something reasonable, you would do something like
|
||||
this:
|
||||
|
||||
mkfs.btrfs -f /dev/mapper/log
|
||||
dmsetup message log 0 mark mkfs
|
||||
<run test>
|
||||
|
||||
This would allow you to replay the log up to the mkfs mark and
|
||||
then replay from that point on doing the fsck check in the
|
||||
interval that you want.
|
||||
|
||||
Every log has a mark at the end labeled "dm-log-writes-end".
|
||||
|
||||
Userspace component
|
||||
===================
|
||||
|
||||
There is a userspace tool that will replay the log for you in various ways.
|
||||
It can be found here: https://github.com/josefbacik/log-writes
|
||||
|
||||
Example usage
|
||||
=============
|
||||
|
||||
Say you want to test fsync on your file system. You would do something like
|
||||
this:
|
||||
|
||||
TABLE="0 $(blockdev --getsz /dev/sdb) log-writes /dev/sdb /dev/sdc"
|
||||
dmsetup create log --table "$TABLE"
|
||||
mkfs.btrfs -f /dev/mapper/log
|
||||
dmsetup message log 0 mark mkfs
|
||||
|
||||
mount /dev/mapper/log /mnt/btrfs-test
|
||||
<some test that does fsync at the end>
|
||||
dmsetup message log 0 mark fsync
|
||||
md5sum /mnt/btrfs-test/foo
|
||||
umount /mnt/btrfs-test
|
||||
|
||||
dmsetup remove log
|
||||
replay-log --log /dev/sdc --replay /dev/sdb --end-mark fsync
|
||||
mount /dev/sdb /mnt/btrfs-test
|
||||
md5sum /mnt/btrfs-test/foo
|
||||
<verify md5sum's are correct>
|
||||
|
||||
Another option is to do a complicated file system operation and verify the file
|
||||
system is consistent during the entire operation. You could do this with:
|
||||
|
||||
TABLE="0 $(blockdev --getsz /dev/sdb) log-writes /dev/sdb /dev/sdc"
|
||||
dmsetup create log --table "$TABLE"
|
||||
mkfs.btrfs -f /dev/mapper/log
|
||||
dmsetup message log 0 mark mkfs
|
||||
|
||||
mount /dev/mapper/log /mnt/btrfs-test
|
||||
<fsstress to dirty the fs>
|
||||
btrfs filesystem balance /mnt/btrfs-test
|
||||
umount /mnt/btrfs-test
|
||||
dmsetup remove log
|
||||
|
||||
replay-log --log /dev/sdc --replay /dev/sdb --end-mark mkfs
|
||||
btrfsck /dev/sdb
|
||||
replay-log --log /dev/sdc --replay /dev/sdb --start-mark mkfs \
|
||||
--fsck "btrfsck /dev/sdb" --check fua
|
||||
|
||||
And that will replay the log until it sees a FUA request, run the fsck command
|
||||
and if the fsck passes it will replay to the next FUA, until it is completed or
|
||||
the fsck command exists abnormally.
|
||||
@@ -222,5 +222,3 @@ Version History
|
||||
1.4.2 Add RAID10 "far" and "offset" algorithm support.
|
||||
1.5.0 Add message interface to allow manipulation of the sync_action.
|
||||
New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
|
||||
1.5.1 Add ability to restore transiently failed devices on resume.
|
||||
1.5.2 'mismatch_cnt' is zero unless [last_]sync_action is "check".
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
DM statistics
|
||||
=============
|
||||
|
||||
Device Mapper supports the collection of I/O statistics on user-defined
|
||||
regions of a DM device. If no regions are defined no statistics are
|
||||
collected so there isn't any performance impact. Only bio-based DM
|
||||
devices are currently supported.
|
||||
|
||||
Each user-defined region specifies a starting sector, length and step.
|
||||
Individual statistics will be collected for each step-sized area within
|
||||
the range specified.
|
||||
|
||||
The I/O statistics counters for each step-sized area of a region are
|
||||
in the same format as /sys/block/*/stat or /proc/diskstats (see:
|
||||
Documentation/iostats.txt). But two extra counters (12 and 13) are
|
||||
provided: total time spent reading and writing in milliseconds. All
|
||||
these counters may be accessed by sending the @stats_print message to
|
||||
the appropriate DM device via dmsetup.
|
||||
|
||||
Each region has a corresponding unique identifier, which we call a
|
||||
region_id, that is assigned when the region is created. The region_id
|
||||
must be supplied when querying statistics about the region, deleting the
|
||||
region, etc. Unique region_ids enable multiple userspace programs to
|
||||
request and process statistics for the same DM device without stepping
|
||||
on each other's data.
|
||||
|
||||
The creation of DM statistics will allocate memory via kmalloc or
|
||||
fallback to using vmalloc space. At most, 1/4 of the overall system
|
||||
memory may be allocated by DM statistics. The admin can see how much
|
||||
memory is used by reading
|
||||
/sys/module/dm_mod/parameters/stats_current_allocated_bytes
|
||||
|
||||
Messages
|
||||
========
|
||||
|
||||
@stats_create <range> <step> [<program_id> [<aux_data>]]
|
||||
|
||||
Create a new region and return the region_id.
|
||||
|
||||
<range>
|
||||
"-" - whole device
|
||||
"<start_sector>+<length>" - a range of <length> 512-byte sectors
|
||||
starting with <start_sector>.
|
||||
|
||||
<step>
|
||||
"<area_size>" - the range is subdivided into areas each containing
|
||||
<area_size> sectors.
|
||||
"/<number_of_areas>" - the range is subdivided into the specified
|
||||
number of areas.
|
||||
|
||||
<program_id>
|
||||
An optional parameter. A name that uniquely identifies
|
||||
the userspace owner of the range. This groups ranges together
|
||||
so that userspace programs can identify the ranges they
|
||||
created and ignore those created by others.
|
||||
The kernel returns this string back in the output of
|
||||
@stats_list message, but it doesn't use it for anything else.
|
||||
|
||||
<aux_data>
|
||||
An optional parameter. A word that provides auxiliary data
|
||||
that is useful to the client program that created the range.
|
||||
The kernel returns this string back in the output of
|
||||
@stats_list message, but it doesn't use this value for anything.
|
||||
|
||||
@stats_delete <region_id>
|
||||
|
||||
Delete the region with the specified id.
|
||||
|
||||
<region_id>
|
||||
region_id returned from @stats_create
|
||||
|
||||
@stats_clear <region_id>
|
||||
|
||||
Clear all the counters except the in-flight i/o counters.
|
||||
|
||||
<region_id>
|
||||
region_id returned from @stats_create
|
||||
|
||||
@stats_list [<program_id>]
|
||||
|
||||
List all regions registered with @stats_create.
|
||||
|
||||
<program_id>
|
||||
An optional parameter.
|
||||
If this parameter is specified, only matching regions
|
||||
are returned.
|
||||
If it is not specified, all regions are returned.
|
||||
|
||||
Output format:
|
||||
<region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
|
||||
|
||||
@stats_print <region_id> [<starting_line> <number_of_lines>]
|
||||
|
||||
Print counters for each step-sized area of a region.
|
||||
|
||||
<region_id>
|
||||
region_id returned from @stats_create
|
||||
|
||||
<starting_line>
|
||||
The index of the starting line in the output.
|
||||
If omitted, all lines are returned.
|
||||
|
||||
<number_of_lines>
|
||||
The number of lines to include in the output.
|
||||
If omitted, all lines are returned.
|
||||
|
||||
Output format for each step-sized area of a region:
|
||||
|
||||
<start_sector>+<length> counters
|
||||
|
||||
The first 11 counters have the same meaning as
|
||||
/sys/block/*/stat or /proc/diskstats.
|
||||
|
||||
Please refer to Documentation/iostats.txt for details.
|
||||
|
||||
1. the number of reads completed
|
||||
2. the number of reads merged
|
||||
3. the number of sectors read
|
||||
4. the number of milliseconds spent reading
|
||||
5. the number of writes completed
|
||||
6. the number of writes merged
|
||||
7. the number of sectors written
|
||||
8. the number of milliseconds spent writing
|
||||
9. the number of I/Os currently in progress
|
||||
10. the number of milliseconds spent doing I/Os
|
||||
11. the weighted number of milliseconds spent doing I/Os
|
||||
|
||||
Additional counters:
|
||||
12. the total time spent reading in milliseconds
|
||||
13. the total time spent writing in milliseconds
|
||||
|
||||
@stats_print_clear <region_id> [<starting_line> <number_of_lines>]
|
||||
|
||||
Atomically print and then clear all the counters except the
|
||||
in-flight i/o counters. Useful when the client consuming the
|
||||
statistics does not want to lose any statistics (those updated
|
||||
between printing and clearing).
|
||||
|
||||
<region_id>
|
||||
region_id returned from @stats_create
|
||||
|
||||
<starting_line>
|
||||
The index of the starting line in the output.
|
||||
If omitted, all lines are printed and then cleared.
|
||||
|
||||
<number_of_lines>
|
||||
The number of lines to process.
|
||||
If omitted, all lines are printed and then cleared.
|
||||
|
||||
@stats_set_aux <region_id> <aux_data>
|
||||
|
||||
Store auxiliary data aux_data for the specified region.
|
||||
|
||||
<region_id>
|
||||
region_id returned from @stats_create
|
||||
|
||||
<aux_data>
|
||||
The string that identifies data which is useful to the client
|
||||
program that created the range. The kernel returns this
|
||||
string back in the output of @stats_list message, but it
|
||||
doesn't use this value for anything.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Subdivide the DM device 'vol' into 100 pieces and start collecting
|
||||
statistics on them:
|
||||
|
||||
dmsetup message vol 0 @stats_create - /100
|
||||
|
||||
Set the auxillary data string to "foo bar baz" (the escape for each
|
||||
space must also be escaped, otherwise the shell will consume them):
|
||||
|
||||
dmsetup message vol 0 @stats_set_aux 0 foo\\ bar\\ baz
|
||||
|
||||
List the statistics:
|
||||
|
||||
dmsetup message vol 0 @stats_list
|
||||
|
||||
Print the statistics:
|
||||
|
||||
dmsetup message vol 0 @stats_print 0
|
||||
|
||||
Delete the statistics:
|
||||
|
||||
dmsetup message vol 0 @stats_delete 0
|
||||
@@ -1,138 +0,0 @@
|
||||
dm-switch
|
||||
=========
|
||||
|
||||
The device-mapper switch target creates a device that supports an
|
||||
arbitrary mapping of fixed-size regions of I/O across a fixed set of
|
||||
paths. The path used for any specific region can be switched
|
||||
dynamically by sending the target a message.
|
||||
|
||||
It maps I/O to underlying block devices efficiently when there is a large
|
||||
number of fixed-sized address regions but there is no simple pattern
|
||||
that would allow for a compact representation of the mapping such as
|
||||
dm-stripe.
|
||||
|
||||
Background
|
||||
----------
|
||||
|
||||
Dell EqualLogic and some other iSCSI storage arrays use a distributed
|
||||
frameless architecture. In this architecture, the storage group
|
||||
consists of a number of distinct storage arrays ("members") each having
|
||||
independent controllers, disk storage and network adapters. When a LUN
|
||||
is created it is spread across multiple members. The details of the
|
||||
spreading are hidden from initiators connected to this storage system.
|
||||
The storage group exposes a single target discovery portal, no matter
|
||||
how many members are being used. When iSCSI sessions are created, each
|
||||
session is connected to an eth port on a single member. Data to a LUN
|
||||
can be sent on any iSCSI session, and if the blocks being accessed are
|
||||
stored on another member the I/O will be forwarded as required. This
|
||||
forwarding is invisible to the initiator. The storage layout is also
|
||||
dynamic, and the blocks stored on disk may be moved from member to
|
||||
member as needed to balance the load.
|
||||
|
||||
This architecture simplifies the management and configuration of both
|
||||
the storage group and initiators. In a multipathing configuration, it
|
||||
is possible to set up multiple iSCSI sessions to use multiple network
|
||||
interfaces on both the host and target to take advantage of the
|
||||
increased network bandwidth. An initiator could use a simple round
|
||||
robin algorithm to send I/O across all paths and let the storage array
|
||||
members forward it as necessary, but there is a performance advantage to
|
||||
sending data directly to the correct member.
|
||||
|
||||
A device-mapper table already lets you map different regions of a
|
||||
device onto different targets. However in this architecture the LUN is
|
||||
spread with an address region size on the order of 10s of MBs, which
|
||||
means the resulting table could have more than a million entries and
|
||||
consume far too much memory.
|
||||
|
||||
Using this device-mapper switch target we can now build a two-layer
|
||||
device hierarchy:
|
||||
|
||||
Upper Tier - Determine which array member the I/O should be sent to.
|
||||
Lower Tier - Load balance amongst paths to a particular member.
|
||||
|
||||
The lower tier consists of a single dm multipath device for each member.
|
||||
Each of these multipath devices contains the set of paths directly to
|
||||
the array member in one priority group, and leverages existing path
|
||||
selectors to load balance amongst these paths. We also build a
|
||||
non-preferred priority group containing paths to other array members for
|
||||
failover reasons.
|
||||
|
||||
The upper tier consists of a single dm-switch device. This device uses
|
||||
a bitmap to look up the location of the I/O and choose the appropriate
|
||||
lower tier device to route the I/O. By using a bitmap we are able to
|
||||
use 4 bits for each address range in a 16 member group (which is very
|
||||
large for us). This is a much denser representation than the dm table
|
||||
b-tree can achieve.
|
||||
|
||||
Construction Parameters
|
||||
=======================
|
||||
|
||||
<num_paths> <region_size> <num_optional_args> [<optional_args>...]
|
||||
[<dev_path> <offset>]+
|
||||
|
||||
<num_paths>
|
||||
The number of paths across which to distribute the I/O.
|
||||
|
||||
<region_size>
|
||||
The number of 512-byte sectors in a region. Each region can be redirected
|
||||
to any of the available paths.
|
||||
|
||||
<num_optional_args>
|
||||
The number of optional arguments. Currently, no optional arguments
|
||||
are supported and so this must be zero.
|
||||
|
||||
<dev_path>
|
||||
The block device that represents a specific path to the device.
|
||||
|
||||
<offset>
|
||||
The offset of the start of data on the specific <dev_path> (in units
|
||||
of 512-byte sectors). This number is added to the sector number when
|
||||
forwarding the request to the specific path. Typically it is zero.
|
||||
|
||||
Messages
|
||||
========
|
||||
|
||||
set_region_mappings <index>:<path_nr> [<index>]:<path_nr> [<index>]:<path_nr>...
|
||||
|
||||
Modify the region table by specifying which regions are redirected to
|
||||
which paths.
|
||||
|
||||
<index>
|
||||
The region number (region size was specified in constructor parameters).
|
||||
If index is omitted, the next region (previous index + 1) is used.
|
||||
Expressed in hexadecimal (WITHOUT any prefix like 0x).
|
||||
|
||||
<path_nr>
|
||||
The path number in the range 0 ... (<num_paths> - 1).
|
||||
Expressed in hexadecimal (WITHOUT any prefix like 0x).
|
||||
|
||||
R<n>,<m>
|
||||
This parameter allows repetitive patterns to be loaded quickly. <n> and <m>
|
||||
are hexadecimal numbers. The last <n> mappings are repeated in the next <m>
|
||||
slots.
|
||||
|
||||
Status
|
||||
======
|
||||
|
||||
No status line is reported.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
Assume that you have volumes vg1/switch0 vg1/switch1 vg1/switch2 with
|
||||
the same size.
|
||||
|
||||
Create a switch device with 64kB region size:
|
||||
dmsetup create switch --table "0 `blockdev --getsize /dev/vg1/switch0`
|
||||
switch 3 128 0 /dev/vg1/switch0 0 /dev/vg1/switch1 0 /dev/vg1/switch2 0"
|
||||
|
||||
Set mappings for the first 7 entries to point to devices switch0, switch1,
|
||||
switch2, switch0, switch1, switch2, switch1:
|
||||
dmsetup message switch 0 set_region_mappings 0:0 :1 :2 :0 :1 :2 :1
|
||||
|
||||
Set repetitive mapping. This command:
|
||||
dmsetup message switch 0 set_region_mappings 1000:1 :2 R2,10
|
||||
is equivalent to:
|
||||
dmsetup message switch 0 set_region_mappings 1000:1 :2 :1 :2 :1 :2 :1 :2 \
|
||||
:1 :2 :1 :2 :1 :2 :1 :2 :1 :2
|
||||
|
||||
@@ -99,14 +99,13 @@ Using an existing pool device
|
||||
$data_block_size $low_water_mark"
|
||||
|
||||
$data_block_size gives the smallest unit of disk space that can be
|
||||
allocated at a time expressed in units of 512-byte sectors.
|
||||
$data_block_size must be between 128 (64KB) and 2097152 (1GB) and a
|
||||
multiple of 128 (64KB). $data_block_size cannot be changed after the
|
||||
thin-pool is created. People primarily interested in thin provisioning
|
||||
may want to use a value such as 1024 (512KB). People doing lots of
|
||||
snapshotting may want a smaller value such as 128 (64KB). If you are
|
||||
not zeroing newly-allocated data, a larger $data_block_size in the
|
||||
region of 256000 (128MB) is suggested.
|
||||
allocated at a time expressed in units of 512-byte sectors. People
|
||||
primarily interested in thin provisioning may want to use a value such
|
||||
as 1024 (512KB). People doing lots of snapshotting may want a smaller value
|
||||
such as 128 (64KB). If you are not zeroing newly-allocated data,
|
||||
a larger $data_block_size in the region of 256000 (128MB) is suggested.
|
||||
$data_block_size must be the same for the lifetime of the
|
||||
metadata device.
|
||||
|
||||
$low_water_mark is expressed in blocks of size $data_block_size. If
|
||||
free space on the data device drops below this level then a dm event
|
||||
@@ -116,35 +115,6 @@ Resuming a device with a new table itself triggers an event so the
|
||||
userspace daemon can use this to detect a situation where a new table
|
||||
already exceeds the threshold.
|
||||
|
||||
A low water mark for the metadata device is maintained in the kernel and
|
||||
will trigger a dm event if free space on the metadata device drops below
|
||||
it.
|
||||
|
||||
Updating on-disk metadata
|
||||
-------------------------
|
||||
|
||||
On-disk metadata is committed every time a FLUSH or FUA bio is written.
|
||||
If no such requests are made then commits will occur every second. This
|
||||
means the thin-provisioning target behaves like a physical disk that has
|
||||
a volatile write cache. If power is lost you may lose some recent
|
||||
writes. The metadata should always be consistent in spite of any crash.
|
||||
|
||||
If data space is exhausted the pool will either error or queue IO
|
||||
according to the configuration (see: error_if_no_space). If metadata
|
||||
space is exhausted or a metadata operation fails: the pool will error IO
|
||||
until the pool is taken offline and repair is performed to 1) fix any
|
||||
potential inconsistencies and 2) clear the flag that imposes repair.
|
||||
Once the pool's metadata device is repaired it may be resized, which
|
||||
will allow the pool to return to normal operation. Note that if a pool
|
||||
is flagged as needing repair, the pool's data and metadata devices
|
||||
cannot be resized until repair is performed. It should also be noted
|
||||
that when the pool's metadata space is exhausted the current metadata
|
||||
transaction is aborted. Given that the pool will cache IO whose
|
||||
completion may have already been acknowledged to upper IO layers
|
||||
(e.g. filesystem) it is strongly suggested that consistency checks
|
||||
(e.g. fsck) be performed on those layers when repair of the pool is
|
||||
required.
|
||||
|
||||
Thin provisioning
|
||||
-----------------
|
||||
|
||||
@@ -264,8 +234,6 @@ i) Constructor
|
||||
read_only: Don't allow any changes to be made to the pool
|
||||
metadata.
|
||||
|
||||
error_if_no_space: Error IOs, instead of queueing, if no space.
|
||||
|
||||
Data block size must be between 64KB (128 sectors) and 1GB
|
||||
(2097152 sectors) inclusive.
|
||||
|
||||
@@ -287,9 +255,10 @@ ii) Status
|
||||
should register for the event and then check the target's status.
|
||||
|
||||
held metadata root:
|
||||
The location, in blocks, of the metadata root that has been
|
||||
The location, in sectors, of the metadata root that has been
|
||||
'held' for userspace read access. '-' indicates there is no
|
||||
held root.
|
||||
held root. This feature is not yet implemented so '-' is
|
||||
always returned.
|
||||
|
||||
discard_passdown|no_discard_passdown
|
||||
Whether or not discards are actually being passed down to the
|
||||
@@ -306,14 +275,6 @@ ii) Status
|
||||
contain the string 'Fail'. The userspace recovery tools
|
||||
should then be used.
|
||||
|
||||
error_if_no_space|queue_if_no_space
|
||||
If the pool runs out of data or metadata space, the pool will
|
||||
either queue or error the IO destined to the data device. The
|
||||
default is to queue the IO until more space is added or the
|
||||
'no_space_timeout' expires. The 'no_space_timeout' dm-thin-pool
|
||||
module parameter can be used to change this timeout -- it
|
||||
defaults to 60 seconds but may be disabled using a value of 0.
|
||||
|
||||
iii) Messages
|
||||
|
||||
create_thin <dev id>
|
||||
@@ -380,6 +341,9 @@ then you'll have no access to blocks mapped beyond the end. If you
|
||||
load a target that is bigger than before, then extra blocks will be
|
||||
provisioned as and when needed.
|
||||
|
||||
If you wish to reduce the size of your thin device and potentially
|
||||
regain some space then send the 'trim' message to the pool.
|
||||
|
||||
ii) Status
|
||||
|
||||
<nr mapped sectors> <highest mapped sector>
|
||||
|
||||
@@ -11,7 +11,6 @@ Construction Parameters
|
||||
<data_block_size> <hash_block_size>
|
||||
<num_data_blocks> <hash_start_block>
|
||||
<algorithm> <digest> <salt>
|
||||
[<#opt_params> <opt_params>]
|
||||
|
||||
<version>
|
||||
This is the type of the on-disk hash format.
|
||||
@@ -63,22 +62,6 @@ Construction Parameters
|
||||
<salt>
|
||||
The hexadecimal encoding of the salt value.
|
||||
|
||||
<#opt_params>
|
||||
Number of optional parameters. If there are no optional parameters,
|
||||
the optional paramaters section can be skipped or #opt_params can be zero.
|
||||
Otherwise #opt_params is the number of following arguments.
|
||||
|
||||
Example of optional parameters section:
|
||||
1 ignore_corruption
|
||||
|
||||
ignore_corruption
|
||||
Log corrupted blocks, but allow read operations to proceed normally.
|
||||
|
||||
restart_on_corruption
|
||||
Restart the system when a corrupted block is discovered. This option is
|
||||
not compatible with ignore_corruption and requires user space support to
|
||||
avoid restart loops.
|
||||
|
||||
Theory of operation
|
||||
===================
|
||||
|
||||
@@ -142,7 +125,7 @@ block boundary) are the hash blocks which are stored a depth at a time
|
||||
|
||||
The full specification of kernel parameters and on-disk metadata format
|
||||
is available at the cryptsetup project's wiki page
|
||||
https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
|
||||
http://code.google.com/p/cryptsetup/wiki/DMVerity
|
||||
|
||||
Status
|
||||
======
|
||||
@@ -159,7 +142,7 @@ Set up a device:
|
||||
|
||||
A command line tool veritysetup is available to compute or verify
|
||||
the hash tree or activate the kernel device. This is available from
|
||||
the cryptsetup upstream repository https://gitlab.com/cryptsetup/cryptsetup/
|
||||
the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
|
||||
(as a libcryptsetup extension).
|
||||
|
||||
Create hash on the device:
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
LVM poll daemon overview
|
||||
========================
|
||||
|
||||
(last updated: 2015-05-09)
|
||||
|
||||
LVM poll daemon (lvmpolld) is the alternative for lvm2 classical polling
|
||||
mechanisms. The motivation behind new lvmpolld was to create persistent
|
||||
system service that would be more durable and transparent. It's suited
|
||||
particularly for any systemd enabled distribution.
|
||||
|
||||
Before lvmpolld any background polling process originating in a lvm2 command
|
||||
initiated inside cgroup of a systemd service could get killed if the main
|
||||
process (service) exited in such cgroup. That could lead to premature termination
|
||||
of such lvm2 polling process.
|
||||
|
||||
Also without lvmpolld there were no means to detect a particular polling process
|
||||
suited for monitoring of specific operation is already in-progress and therefore
|
||||
it's not desirable to start next one with exactly same task. lvmpolld is able to
|
||||
detect such duplicate requests and not spawn such redundant process.
|
||||
|
||||
lvmpolld is primarily targeted for systems with systemd as init process. For systems
|
||||
without systemd there's no need to install lvmpolld because there is no issue
|
||||
with observation described in second paragraph. You can still benefit from
|
||||
avoiding duplicate polling process being spawned, but without systemd lvmpolld
|
||||
can't easily be run on-demand (activated by a socket maintained by systemd).
|
||||
|
||||
lvmpolld implement shutdown on idle and can shutdown automatically when idle
|
||||
for requested time. 60 second is recommended default here. This behaviour can be
|
||||
turned off if found useless.
|
||||
|
||||
Data structures
|
||||
---------------
|
||||
|
||||
a) Logical Volume (struct lvmpolld_lv)
|
||||
|
||||
Each operation is identified by LV. Internal identifier within lvmpolld
|
||||
is full LV uuid (vg_uuid+lv_uuid) prefixed with LVM_SYSTEM_DIR if set by client.
|
||||
|
||||
such full identifier may look like:
|
||||
|
||||
"/etc/lvm/lvm.confWFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
|
||||
|
||||
or without LVM_SYSTEM_DIR being set explicitly:
|
||||
|
||||
"WFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
|
||||
|
||||
|
||||
LV carries various metadata about polling operation. The most significant are:
|
||||
|
||||
VG name
|
||||
LV name
|
||||
polling interval (usually --interval passed to lvm2 command or default from lvm2
|
||||
configuration)
|
||||
operation type (one of: pvmove, convert, merge, thin_merge)
|
||||
LVM_SYSTEM_DIR (if set, this is also passed among environment variables of lvpoll
|
||||
command spawned by lvmpolld)
|
||||
|
||||
b) LV stores (struct lvmpolld_store)
|
||||
|
||||
lvmpolld uses two stores for Logical volumes (struct lvmpolld_lv). One store for polling
|
||||
operations in-progress. These operations are as of now: PV move, mirror up-conversion,
|
||||
classical snapshot merge, thin snapshot merge.
|
||||
|
||||
The second store is suited only for pvmove --abort operations in-progress. Both
|
||||
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
|
||||
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
|
||||
guaranteed by lvm2 locking mechanism).
|
||||
|
||||
Locking order
|
||||
-------------
|
||||
|
||||
There are two types of locks in lvmpolld. Each store has own store lock and each LV has
|
||||
own lv lock.
|
||||
|
||||
Locking order is:
|
||||
1) store lock
|
||||
2) LV lock
|
||||
|
||||
Each LV has to be inside a store. When daemon requires to take both locks it has
|
||||
to take a store lock first and LV lock has to be taken afterwards (after the
|
||||
appropriate store lock where the LV is being stored :))
|
||||
@@ -1,8 +1,6 @@
|
||||
@top_srcdir@/daemons/clvmd/clvm.h
|
||||
@top_srcdir@/daemons/dmeventd/libdevmapper-event.h
|
||||
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
|
||||
@top_srcdir@/daemons/lvmpolld/lvmpolld-protocol.h
|
||||
@top_srcdir@/daemons/lvmpolld/polling_ops.h
|
||||
@top_srcdir@/liblvm/lvm2app.h
|
||||
@top_srcdir@/lib/activate/activate.h
|
||||
@top_srcdir@/lib/activate/targets.h
|
||||
@@ -15,7 +13,6 @@
|
||||
@top_srcdir@/lib/datastruct/btree.h
|
||||
@top_srcdir@/lib/datastruct/str_list.h
|
||||
@top_srcdir@/lib/device/dev-cache.h
|
||||
@top_srcdir@/lib/device/dev-ext-udev-constants.h
|
||||
@top_srcdir@/lib/device/dev-type.h
|
||||
@top_srcdir@/lib/device/device.h
|
||||
@top_srcdir@/lib/device/device-types.h
|
||||
@@ -31,8 +28,6 @@
|
||||
@top_srcdir@/lib/locking/locking.h
|
||||
@top_srcdir@/lib/log/log.h
|
||||
@top_srcdir@/lib/log/lvm-logging.h
|
||||
@top_srcdir@/lib/lvmpolld/lvmpolld-client.h
|
||||
@top_srcdir@/lib/lvmpolld/polldaemon.h
|
||||
@top_srcdir@/lib/metadata/lv.h
|
||||
@top_srcdir@/lib/metadata/lv_alloc.h
|
||||
@top_srcdir@/lib/metadata/metadata.h
|
||||
|
||||
@@ -20,12 +20,8 @@ include $(top_builddir)/make.tmpl
|
||||
|
||||
all: .symlinks_created
|
||||
|
||||
LINKS := $(shell find . -maxdepth 1 -type l)
|
||||
|
||||
.symlinks_created: .symlinks
|
||||
ifneq (,$(firstword $(LINKS)))
|
||||
$(RM) $(LINKS)
|
||||
endif
|
||||
.symlinks_created: .symlinks
|
||||
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
|
||||
for i in `cat $<`; do $(LN_S) $$i ; done
|
||||
touch $@
|
||||
|
||||
@@ -35,5 +31,5 @@ device-mapper: all
|
||||
|
||||
cflow: all
|
||||
|
||||
DISTCLEAN_TARGETS += .symlinks
|
||||
CLEAN_TARGETS += $(LINKS) .include_symlinks .symlinks_created
|
||||
DISTCLEAN_TARGETS += $(shell find . -maxdepth 1 -type l)
|
||||
DISTCLEAN_TARGETS += .include_symlinks .symlinks_created .symlinks
|
||||
|
||||
@@ -56,7 +56,6 @@ SOURCES =\
|
||||
datastruct/btree.c \
|
||||
datastruct/str_list.c \
|
||||
device/dev-cache.c \
|
||||
device/dev-ext.c \
|
||||
device/dev-io.c \
|
||||
device/dev-md.c \
|
||||
device/dev-swap.c \
|
||||
@@ -70,11 +69,9 @@ SOURCES =\
|
||||
filters/filter-regex.c \
|
||||
filters/filter-sysfs.c \
|
||||
filters/filter-md.c \
|
||||
filters/filter-fwraid.c \
|
||||
filters/filter-mpath.c \
|
||||
filters/filter-partitioned.c \
|
||||
filters/filter-type.c \
|
||||
filters/filter-usable.c \
|
||||
format_text/archive.c \
|
||||
format_text/archiver.c \
|
||||
format_text/export.c \
|
||||
@@ -196,11 +193,6 @@ ifeq ("@BUILD_LVMETAD@", "yes")
|
||||
cache/lvmetad.c
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
SOURCES +=\
|
||||
lvmpolld/lvmpolld-client.c
|
||||
endif
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
|
||||
LIBS += -ldevmapper-event
|
||||
@@ -227,7 +219,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS) $(VALGRIND_CFLAGS)
|
||||
CFLAGS += $(BLKID_CFLAGS) $(UDEV_CFLAGS)
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
||||
|
||||
@@ -108,13 +108,13 @@ int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_passes_volumes_filter(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
static int _lv_passes_volumes_filter(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const struct dm_config_node *cn, const int cfg_id)
|
||||
{
|
||||
const struct dm_config_value *cv;
|
||||
const char *str;
|
||||
static char config_path[PATH_MAX];
|
||||
size_t len = strlen(lv->vg->name);
|
||||
static char path[PATH_MAX];
|
||||
|
||||
config_def_get_path(config_path, sizeof(config_path), cfg_id);
|
||||
log_verbose("%s configuration setting defined: "
|
||||
@@ -125,23 +125,24 @@ static int _lv_passes_volumes_filter(struct cmd_context *cmd, const struct logic
|
||||
if (cv->type == DM_CFG_EMPTY_ARRAY)
|
||||
goto out;
|
||||
if (cv->type != DM_CFG_STRING) {
|
||||
log_print_unless_silent("Ignoring invalid string in config file %s.",
|
||||
config_path);
|
||||
log_error("Ignoring invalid string in config file %s",
|
||||
config_path);
|
||||
continue;
|
||||
}
|
||||
str = cv->v.str;
|
||||
if (!*str) {
|
||||
log_print_unless_silent("Ignoring empty string in config file %s.",
|
||||
config_path);
|
||||
log_error("Ignoring empty string in config file %s",
|
||||
config_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* Tag? */
|
||||
if (*str == '@') {
|
||||
str++;
|
||||
if (!*str) {
|
||||
log_print_unless_silent("Ignoring empty tag in config file %s",
|
||||
config_path);
|
||||
log_error("Ignoring empty tag in config file "
|
||||
"%s", config_path);
|
||||
continue;
|
||||
}
|
||||
/* If any host tag matches any LV or VG tag, activate */
|
||||
@@ -160,12 +161,21 @@ static int _lv_passes_volumes_filter(struct cmd_context *cmd, const struct logic
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If supplied name is vgname[/lvname] */
|
||||
if ((strncmp(str, lv->vg->name, len) == 0) &&
|
||||
(!str[len] ||
|
||||
((str[len] == '/') &&
|
||||
!strcmp(str + len + 1, lv->name))))
|
||||
if (!strchr(str, '/')) {
|
||||
/* vgname supplied */
|
||||
if (!strcmp(str, lv->vg->name))
|
||||
return 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
/* vgname/lvname */
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
|
||||
lv->name) < 0) {
|
||||
log_error("dm_snprintf error from %s/%s", lv->vg->name,
|
||||
lv->name);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(path, str))
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -238,23 +248,8 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
const struct lv_segment *lv_seg, int use_layer,
|
||||
struct lv_with_info_and_seg_status *status,
|
||||
int with_open_count, int with_read_ahead)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
|
||||
int use_layer, struct lv_seg_status *lv_seg_status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
struct lv_status_cache **status)
|
||||
{
|
||||
}
|
||||
int lv_check_not_in_use(const struct logical_volume *lv)
|
||||
int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvinfo *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -333,35 +328,35 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
|
||||
}
|
||||
*******/
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive,
|
||||
const struct logical_volume *ondisk_lv, const struct logical_volume *incore_lv)
|
||||
struct logical_volume *ondisk_lv, struct logical_volume *incore_lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, const struct logical_volume *lv)
|
||||
int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only,
|
||||
unsigned exclusive, unsigned revert, const struct logical_volume *lv)
|
||||
unsigned exclusive, unsigned revert, struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv)
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv, const struct logical_volume *lv)
|
||||
int *activate_lv, struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, int noscan,
|
||||
int temporary, const struct logical_volume *lv)
|
||||
int temporary, struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv)
|
||||
int noscan, int temporary, struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -410,7 +405,7 @@ int lv_check_transient(struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const struct lv_activate_opts *laopts, int monitor)
|
||||
{
|
||||
return 1;
|
||||
@@ -427,11 +422,11 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int device_is_usable(struct device *dev, struct dev_usable_check_params check)
|
||||
int device_is_usable(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lv_has_target_type(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
|
||||
const char *layer, const char *target_type)
|
||||
{
|
||||
return 0;
|
||||
@@ -463,7 +458,7 @@ int activation(void)
|
||||
}
|
||||
|
||||
static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv)
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
@@ -492,7 +487,7 @@ static int _passes_activation_filter(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
static int _passes_readonly_filter(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv)
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
@@ -599,7 +594,7 @@ int module_present(struct cmd_context *cmd, const char *target_name)
|
||||
int ret = 0;
|
||||
#ifdef MODPROBE_CMD
|
||||
char module[128];
|
||||
const char *argv[] = { MODPROBE_CMD, module, NULL };
|
||||
const char *argv[3];
|
||||
|
||||
if (dm_snprintf(module, sizeof(module), "dm-%s", target_name) < 0) {
|
||||
log_error("module_present module name too long: %s",
|
||||
@@ -607,6 +602,10 @@ int module_present(struct cmd_context *cmd, const char *target_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
argv[0] = MODPROBE_CMD;
|
||||
argv[1] = module;
|
||||
argv[2] = NULL;
|
||||
|
||||
ret = exec_cmd(cmd, argv, NULL, 0);
|
||||
#endif
|
||||
return ret;
|
||||
@@ -633,14 +632,17 @@ int target_present(struct cmd_context *cmd, const char *target_name,
|
||||
return target_version(target_name, &maj, &min, &patchlevel);
|
||||
}
|
||||
|
||||
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int use_layer, struct lvinfo *info,
|
||||
const struct lv_segment *seg,
|
||||
struct lv_seg_status *seg_status,
|
||||
int with_open_count, int with_read_ahead)
|
||||
/*
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
|
||||
*/
|
||||
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
|
||||
struct lvinfo *info, int with_open_count, int with_read_ahead)
|
||||
{
|
||||
struct dm_info dminfo;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
/*
|
||||
* If open_count info is requested and we have to be sure our own udev
|
||||
* transactions are finished
|
||||
@@ -654,23 +656,10 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
|
||||
}
|
||||
|
||||
/* New thin-pool has no layer, but -tpool suffix needs to be queried */
|
||||
if (!use_layer && lv_is_new_thin_pool(lv)) {
|
||||
/* Check if there isn't existing old thin pool mapping in the table */
|
||||
if (!dev_manager_info(cmd->mem, lv, NULL, 0, 0, &dminfo, NULL, NULL))
|
||||
return_0;
|
||||
if (!dminfo.exists)
|
||||
use_layer = 1;
|
||||
}
|
||||
|
||||
if (seg_status)
|
||||
seg_status->seg = seg;
|
||||
|
||||
if (!dev_manager_info(cmd->mem, lv,
|
||||
if (!dev_manager_info(lv->vg->cmd->mem, lv,
|
||||
(use_layer) ? lv_layer(lv) : NULL,
|
||||
with_open_count, with_read_ahead,
|
||||
&dminfo, (info) ? &info->read_ahead : NULL,
|
||||
seg_status))
|
||||
&dminfo, (info) ? &info->read_ahead : NULL))
|
||||
return_0;
|
||||
|
||||
if (!info)
|
||||
@@ -688,19 +677,6 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
|
||||
*/
|
||||
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
|
||||
struct lvinfo *info, int with_open_count, int with_read_ahead)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
return _lv_info(cmd, lv, use_layer, info, NULL, NULL, with_open_count, with_read_ahead);
|
||||
}
|
||||
|
||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
struct lvinfo *info, int with_open_count, int with_read_ahead)
|
||||
{
|
||||
@@ -716,67 +692,26 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if lv_seg_status structure populated,
|
||||
* else 0 on failure or if device not active locally.
|
||||
*/
|
||||
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
|
||||
int use_layer, struct lv_seg_status *lv_seg_status)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
return _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, lv_seg_status, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if lv_with_info_and_seg_status structure populated,
|
||||
* else 0 on failure or if device not active locally.
|
||||
*
|
||||
* This is the same as calling lv_info and lv_status,
|
||||
* but* it's done in one go with one ioctl if possible! ]
|
||||
*/
|
||||
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
const struct lv_segment *lv_seg, int use_layer,
|
||||
struct lv_with_info_and_seg_status *status,
|
||||
int with_open_count, int with_read_ahead)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (lv == lv_seg->lv)
|
||||
return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
|
||||
with_open_count, with_read_ahead);
|
||||
|
||||
/*
|
||||
* If the info is requested for an LV and segment
|
||||
* status for segment that belong to another LV,
|
||||
* we need to acquire info and status separately!
|
||||
*/
|
||||
return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
|
||||
_lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
|
||||
}
|
||||
|
||||
#define OPEN_COUNT_CHECK_RETRIES 25
|
||||
#define OPEN_COUNT_CHECK_USLEEP_DELAY 200000
|
||||
|
||||
int lv_check_not_in_use(const struct logical_volume *lv)
|
||||
int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvinfo *info)
|
||||
{
|
||||
struct lvinfo info;
|
||||
unsigned int open_count_check_retries;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) || !info.exists || !info.open_count)
|
||||
if (!info->exists)
|
||||
return 1;
|
||||
|
||||
/* If sysfs is not used, use open_count information only. */
|
||||
if (dm_sysfs_dir()) {
|
||||
if (dm_device_has_holders(info.major, info.minor)) {
|
||||
if (dm_device_has_holders(info->major, info->minor)) {
|
||||
log_error("Logical volume %s/%s is used by another device.",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_device_has_mounted_fs(info.major, info.minor)) {
|
||||
if (dm_device_has_mounted_fs(info->major, info->minor)) {
|
||||
log_error("Logical volume %s/%s contains a filesystem in use.",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
@@ -784,7 +719,7 @@ int lv_check_not_in_use(const struct logical_volume *lv)
|
||||
}
|
||||
|
||||
open_count_check_retries = retry_deactivation() ? OPEN_COUNT_CHECK_RETRIES : 1;
|
||||
while (info.open_count > 0 && open_count_check_retries--) {
|
||||
while (info->open_count > 0 && open_count_check_retries--) {
|
||||
if (!open_count_check_retries) {
|
||||
log_error("Logical volume %s/%s in use.",
|
||||
lv->vg->name, lv->name);
|
||||
@@ -794,7 +729,7 @@ int lv_check_not_in_use(const struct logical_volume *lv)
|
||||
usleep(OPEN_COUNT_CHECK_USLEEP_DELAY);
|
||||
log_debug_activation("Retrying open_count check for %s/%s.",
|
||||
lv->vg->name, lv->name);
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0)) {
|
||||
if (!lv_info(cmd, lv, 0, info, 1, 0)) {
|
||||
stack; /* device dissappeared? */
|
||||
break;
|
||||
}
|
||||
@@ -870,6 +805,7 @@ int lv_mirror_percent(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
|
||||
log_debug_activation("Checking mirror percent for LV %s/%s", lv->vg->name, lv->name);
|
||||
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
@@ -1048,42 +984,158 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return dm_status_cache for cache volume, accept also cache pool
|
||||
*
|
||||
* As there are too many variable for cache volumes, and it hard
|
||||
* to make good API - so let's obtain dm_status_cache and return
|
||||
* all info we have - user just has to release struct after its use.
|
||||
*/
|
||||
int lv_cache_status(const struct logical_volume *cache_lv,
|
||||
struct lv_status_cache **status)
|
||||
int lv_cache_block_info(struct logical_volume *lv,
|
||||
uint32_t *chunk_size, uint64_t *dirty_count,
|
||||
uint64_t *used_count, uint64_t *total_count)
|
||||
{
|
||||
struct dev_manager *dm;
|
||||
struct lv_segment *cache_seg;
|
||||
struct logical_volume *cache_lv;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_cache *status;
|
||||
|
||||
if (lv_is_cache_pool(cache_lv) && !dm_list_empty(&cache_lv->segs_using_this_lv)) {
|
||||
if (!(cache_seg = get_only_segment_using_this_lv(cache_lv)))
|
||||
/* The user is free to choose which args they are interested in */
|
||||
if (chunk_size)
|
||||
*chunk_size = 0;
|
||||
if (dirty_count)
|
||||
*dirty_count = 0;
|
||||
if (used_count)
|
||||
*used_count = 0;
|
||||
if (total_count)
|
||||
*total_count = 0;
|
||||
|
||||
if (lv_is_cache(lv))
|
||||
cache_lv = lv;
|
||||
else if (lv_is_cache_pool(lv)) {
|
||||
if (dm_list_empty(&lv->segs_using_this_lv)) {
|
||||
//FIXME: Ok to return value not sourced from kernel?
|
||||
// This could be valuable - esp for 'lvs' output
|
||||
log_error(INTERNAL_ERROR "Unable to get block info"
|
||||
" of unlinked cache_pool, %s", lv->name);
|
||||
//FIXME: ... because we could do this:
|
||||
if (chunk_size)
|
||||
*chunk_size = first_seg(lv)->chunk_size;
|
||||
/* Unlinked cache_pools have 0 dirty & used blocks */
|
||||
if (total_count) {
|
||||
*total_count = lv->size; /* in sectors */
|
||||
*total_count /= first_seg(lv)->chunk_size;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!(cache_seg = get_only_segment_using_this_lv(lv)))
|
||||
return_0;
|
||||
cache_lv = cache_seg->lv;
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR
|
||||
"Unable to get block info of non-cache LV, %s",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_pending_delete(cache_lv))
|
||||
return 0;
|
||||
|
||||
if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0))
|
||||
return 0;
|
||||
return_0;
|
||||
|
||||
log_debug_activation("Checking cache status for LV %s.",
|
||||
display_lvname(cache_lv));
|
||||
log_debug_activation("Checking cache block info for LV %s/%s",
|
||||
cache_lv->vg->name, cache_lv->name);
|
||||
|
||||
if (!(dm = dev_manager_create(cache_lv->vg->cmd, cache_lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_cache_status(dm, cache_lv, status)) {
|
||||
if (!dev_manager_cache_status(dm, cache_lv, &status)) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
/* User has to call dm_pool_destroy(status->mem)! */
|
||||
|
||||
if (chunk_size)
|
||||
*chunk_size = status->block_size;
|
||||
if (dirty_count)
|
||||
*dirty_count = status->dirty_blocks;
|
||||
if (used_count)
|
||||
*used_count = status->used_blocks;
|
||||
if (total_count)
|
||||
*total_count = status->total_blocks;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_cache_policy_info(struct logical_volume *lv,
|
||||
const char **policy_name, int *policy_argc,
|
||||
const char ***policy_argv)
|
||||
{
|
||||
int i;
|
||||
struct lv_segment *cache_seg;
|
||||
struct logical_volume *cache_lv;
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_cache *status;
|
||||
struct dm_pool *mem = lv->vg->cmd->mem;
|
||||
|
||||
/* The user is free to choose which args they are interested in */
|
||||
if (policy_name)
|
||||
*policy_name = NULL;
|
||||
if (policy_argc)
|
||||
*policy_argc = 0;
|
||||
if (policy_argv)
|
||||
*policy_argv = NULL;
|
||||
|
||||
if (lv_is_cache(lv))
|
||||
cache_lv = lv;
|
||||
else if (lv_is_cache_pool(lv)) {
|
||||
if (dm_list_empty(&lv->segs_using_this_lv)) {
|
||||
//FIXME: Ok to return value not sourced from kernel?
|
||||
log_error(INTERNAL_ERROR "Unable to get policy info"
|
||||
" of unlinked cache_pool, %s", lv->name);
|
||||
//FIXME: ... because we could do this:
|
||||
if (policy_name)
|
||||
*policy_name = first_seg(lv)->policy_name;
|
||||
if (policy_argc)
|
||||
*policy_argc = first_seg(lv)->policy_argc;
|
||||
if (policy_argv)
|
||||
*policy_argv = first_seg(lv)->policy_argv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!(cache_seg = get_only_segment_using_this_lv(lv)))
|
||||
return_0;
|
||||
cache_lv = cache_seg->lv;
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR
|
||||
"Unable to get policy info of non-cache LV, %s",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0))
|
||||
return_0;
|
||||
|
||||
log_debug_activation("Checking cache policy for LV %s/%s",
|
||||
cache_lv->vg->name, cache_lv->name);
|
||||
|
||||
if (!(dm = dev_manager_create(cache_lv->vg->cmd, cache_lv->vg->name, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_manager_cache_status(dm, cache_lv, &status)) {
|
||||
dev_manager_destroy(dm);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (policy_name &&
|
||||
!(*policy_name = dm_pool_strdup(mem, status->policy_name)))
|
||||
return_0;
|
||||
if (policy_argc)
|
||||
*policy_argc = status->policy_argc;
|
||||
if (policy_argv) {
|
||||
if (!(*policy_argv =
|
||||
dm_pool_zalloc(mem, sizeof(char *) * status->policy_argc)))
|
||||
return_0;
|
||||
for (i = 0; i < status->policy_argc; ++i)
|
||||
if (!((*policy_argv)[i] =
|
||||
dm_pool_strdup(mem, status->policy_argv[i])))
|
||||
return_0;
|
||||
}
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1098,7 +1150,7 @@ int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin %sdata percent for LV %s/%s",
|
||||
@@ -1124,7 +1176,7 @@ int lv_thin_percent(const struct logical_volume *lv,
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin percent for LV %s/%s",
|
||||
@@ -1151,7 +1203,7 @@ int lv_thin_pool_transaction_id(const struct logical_volume *lv,
|
||||
struct dev_manager *dm;
|
||||
struct dm_status_thin_pool *status;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking thin percent for LV %s/%s",
|
||||
@@ -1175,7 +1227,7 @@ int lv_thin_device_id(const struct logical_volume *lv, uint32_t *device_id)
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!lv_info(lv->vg->cmd, lv, 0, NULL, 0, 0))
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_debug_activation("Checking device id for LV %s/%s",
|
||||
@@ -1204,7 +1256,7 @@ static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
return info.exists;
|
||||
}
|
||||
|
||||
static int _lv_open_count(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
static int _lv_open_count(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
struct lvinfo info;
|
||||
|
||||
@@ -1216,7 +1268,7 @@ static int _lv_open_count(struct cmd_context *cmd, const struct logical_volume *
|
||||
return info.open_count;
|
||||
}
|
||||
|
||||
static int _lv_activate_lv(const struct logical_volume *lv, struct lv_activate_opts *laopts)
|
||||
static int _lv_activate_lv(struct logical_volume *lv, struct lv_activate_opts *laopts)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -1231,7 +1283,7 @@ static int _lv_activate_lv(const struct logical_volume *lv, struct lv_activate_o
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_preload(const struct logical_volume *lv, struct lv_activate_opts *laopts,
|
||||
static int _lv_preload(struct logical_volume *lv, struct lv_activate_opts *laopts,
|
||||
int *flush_required)
|
||||
{
|
||||
int r = 0;
|
||||
@@ -1253,7 +1305,7 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_deactivate(const struct logical_volume *lv)
|
||||
static int _lv_deactivate(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
@@ -1268,7 +1320,7 @@ static int _lv_deactivate(const struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_suspend_lv(const struct logical_volume *lv, struct lv_activate_opts *laopts,
|
||||
static int _lv_suspend_lv(struct logical_volume *lv, struct lv_activate_opts *laopts,
|
||||
int lockfs, int flush_required)
|
||||
{
|
||||
int r;
|
||||
@@ -1486,7 +1538,7 @@ char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath)
|
||||
return path;
|
||||
}
|
||||
|
||||
static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
static char *_build_target_uuid(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
const char *layer;
|
||||
|
||||
@@ -1501,7 +1553,7 @@ static char *_build_target_uuid(struct cmd_context *cmd, const struct logical_vo
|
||||
}
|
||||
|
||||
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
|
||||
const struct logical_volume *lv, int *pending)
|
||||
struct logical_volume *lv, int *pending)
|
||||
{
|
||||
char *uuid;
|
||||
enum dm_event_mask evmask = 0;
|
||||
@@ -1533,7 +1585,7 @@ int target_registered_with_dmeventd(struct cmd_context *cmd, const char *dso,
|
||||
return evmask;
|
||||
}
|
||||
|
||||
int target_register_events(struct cmd_context *cmd, const char *dso, const struct logical_volume *lv,
|
||||
int target_register_events(struct cmd_context *cmd, const char *dso, struct logical_volume *lv,
|
||||
int evmask __attribute__((unused)), int set, int timeout)
|
||||
{
|
||||
char *uuid;
|
||||
@@ -1569,7 +1621,7 @@ int target_register_events(struct cmd_context *cmd, const char *dso, const struc
|
||||
* Returns 0 if an attempt to (un)monitor the device failed.
|
||||
* Returns 1 otherwise.
|
||||
*/
|
||||
int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const struct lv_activate_opts *laopts, int monitor)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
@@ -1621,11 +1673,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
* In case of a snapshot device, we monitor lv->snapshot->lv,
|
||||
* not the actual LV itself.
|
||||
*/
|
||||
if (lv_is_cow(lv) && (laopts->no_merging || !lv_is_merging_cow(lv))) {
|
||||
if (!(r = monitor_dev_for_events(cmd, lv->snapshot->lv, NULL, monitor)))
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
if (lv_is_cow(lv) && (laopts->no_merging || !lv_is_merging_cow(lv)))
|
||||
return monitor_dev_for_events(cmd, lv->snapshot->lv, NULL, monitor);
|
||||
|
||||
/*
|
||||
* In case this LV is a snapshot origin, we instead monitor
|
||||
@@ -1635,10 +1684,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
if (!laopts->origin_only && lv_is_origin(lv))
|
||||
dm_list_iterate_safe(snh, snht, &lv->snapshot_segs)
|
||||
if (!monitor_dev_for_events(cmd, dm_list_struct_base(snh,
|
||||
struct lv_segment, origin_list)->cow, NULL, monitor)) {
|
||||
stack;
|
||||
struct lv_segment, origin_list)->cow, NULL, monitor))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the volume is mirrored and its log is also mirrored, monitor
|
||||
@@ -1647,10 +1694,8 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
if ((seg = first_seg(lv)) != NULL && seg->log_lv != NULL &&
|
||||
(log_seg = first_seg(seg->log_lv)) != NULL &&
|
||||
seg_is_mirrored(log_seg))
|
||||
if (!monitor_dev_for_events(cmd, seg->log_lv, NULL, monitor)) {
|
||||
stack;
|
||||
if (!monitor_dev_for_events(cmd, seg->log_lv, NULL, monitor))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
/* Recurse for AREA_LV */
|
||||
@@ -1673,16 +1718,12 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
*/
|
||||
if (seg->pool_lv &&
|
||||
!monitor_dev_for_events(cmd, seg->pool_lv,
|
||||
(!monitor) ? laopts : NULL, monitor)) {
|
||||
stack;
|
||||
(!monitor) ? laopts : NULL, monitor))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (seg->metadata_lv &&
|
||||
!monitor_dev_for_events(cmd, seg->metadata_lv, NULL, monitor)) {
|
||||
stack;
|
||||
!monitor_dev_for_events(cmd, seg->metadata_lv, NULL, monitor))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!seg_monitored(seg) ||
|
||||
(seg->status & PVMOVE) ||
|
||||
@@ -1728,7 +1769,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
|
||||
/* Check [un]monitor results */
|
||||
/* Try a couple times if pending, but not forever... */
|
||||
for (i = 0; i < 40; i++) {
|
||||
for (i = 0; i < 10; i++) {
|
||||
pending = 0;
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
if (pending ||
|
||||
@@ -1738,7 +1779,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
lv->vg->name, lv->name, monitor ? "" : "un");
|
||||
else
|
||||
break;
|
||||
usleep(10000 * i);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (r)
|
||||
@@ -1755,7 +1796,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
}
|
||||
|
||||
struct detached_lv_data {
|
||||
const struct logical_volume *lv_pre;
|
||||
struct logical_volume *lv_pre;
|
||||
struct lv_activate_opts *laopts;
|
||||
int *flush_required;
|
||||
};
|
||||
@@ -1765,22 +1806,8 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data)
|
||||
struct detached_lv_data *detached = data;
|
||||
struct lv_list *lvl_pre;
|
||||
|
||||
/* Check and preload removed raid image leg or metadata */
|
||||
if (lv_is_raid_image(lv)) {
|
||||
if ((lvl_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) &&
|
||||
!lv_is_raid_image(lvl_pre->lv) && lv_is_active(lv) &&
|
||||
!_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required))
|
||||
return_0;
|
||||
} else if (lv_is_raid_metadata(lv)) {
|
||||
if ((lvl_pre = find_lv_in_vg_by_lvid(detached->lv_pre->vg, &lv->lvid)) &&
|
||||
!lv_is_raid_metadata(lvl_pre->lv) && lv_is_active(lv) &&
|
||||
!_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if ((lvl_pre = find_lv_in_vg(detached->lv_pre->vg, lv->name))) {
|
||||
if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) &&
|
||||
(!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) &&
|
||||
if (lv_is_visible(lvl_pre->lv) && lv_is_active(lv) && (!lv_is_cow(lv) || !lv_is_cow(lvl_pre->lv)) &&
|
||||
!_lv_preload(lvl_pre->lv, detached->laopts, detached->flush_required))
|
||||
return_0;
|
||||
}
|
||||
@@ -1790,11 +1817,9 @@ static int _preload_detached_lv(struct logical_volume *lv, void *data)
|
||||
|
||||
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct lv_activate_opts *laopts, int error_if_not_suspended,
|
||||
const struct logical_volume *ondisk_lv, const struct logical_volume *incore_lv)
|
||||
struct logical_volume *ondisk_lv, struct logical_volume *incore_lv)
|
||||
{
|
||||
const struct logical_volume *pvmove_lv = NULL;
|
||||
const struct logical_volume *ondisk_lv_to_free = NULL;
|
||||
const struct logical_volume *incore_lv_to_free = NULL;
|
||||
struct logical_volume *pvmove_lv = NULL, *ondisk_lv_to_free = NULL, *incore_lv_to_free = NULL;
|
||||
struct lv_list *lvl_pre;
|
||||
struct seg_list *sl;
|
||||
struct lv_segment *snap_seg;
|
||||
@@ -1878,7 +1903,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
detached.laopts = laopts;
|
||||
detached.flush_required = &flush_required;
|
||||
|
||||
if (!for_each_sub_lv((struct logical_volume *)ondisk_lv, &_preload_detached_lv, &detached))
|
||||
if (!for_each_sub_lv(ondisk_lv, &_preload_detached_lv, &detached))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
@@ -1961,8 +1986,7 @@ out:
|
||||
*
|
||||
* Returns success if the device is not active
|
||||
*/
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive,
|
||||
const struct logical_volume *ondisk_lv, const struct logical_volume *incore_lv)
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive, struct logical_volume *ondisk_lv, struct logical_volume *incore_lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = {
|
||||
.origin_only = origin_only,
|
||||
@@ -1982,9 +2006,9 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
|
||||
|
||||
static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct lv_activate_opts *laopts, int error_if_not_active,
|
||||
const struct logical_volume *lv)
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct logical_volume *lv_to_free = NULL;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
int messages_only = 0;
|
||||
@@ -2010,9 +2034,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
|
||||
log_debug_activation("Resuming LV %s/%s%s%s%s.", lv->vg->name, lv->name,
|
||||
error_if_not_active ? "" : " if active",
|
||||
laopts->origin_only ?
|
||||
(lv_is_thin_pool(lv) ? " pool only" :
|
||||
lv_is_thin_volume(lv) ? " thin only" : " without snapshots") : "",
|
||||
laopts->origin_only ? " without snapshots" : "",
|
||||
laopts->revert ? " (reverting)" : "");
|
||||
|
||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||
@@ -2057,7 +2079,7 @@ out:
|
||||
*/
|
||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
|
||||
unsigned origin_only, unsigned exclusive,
|
||||
unsigned revert, const struct logical_volume *lv)
|
||||
unsigned revert, struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = {
|
||||
.origin_only = origin_only,
|
||||
@@ -2068,21 +2090,22 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
|
||||
return _lv_resume(cmd, lvid_s, &laopts, 0, lv);
|
||||
}
|
||||
|
||||
int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only,
|
||||
const struct logical_volume *lv)
|
||||
int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = { .origin_only = origin_only, };
|
||||
|
||||
return _lv_resume(cmd, lvid_s, &laopts, 1, lv);
|
||||
}
|
||||
|
||||
static int _lv_has_open_snapshots(const struct logical_volume *lv)
|
||||
static int _lv_has_open_snapshots(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *snap_seg;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs, origin_list)
|
||||
if (!lv_check_not_in_use(snap_seg->cow))
|
||||
if (!lv_info(lv->vg->cmd, snap_seg->cow, 0, &info, 1, 0) ||
|
||||
!lv_check_not_in_use(lv->vg->cmd, snap_seg->cow, &info))
|
||||
r++;
|
||||
|
||||
if (r)
|
||||
@@ -2092,12 +2115,11 @@ static int _lv_has_open_snapshots(const struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv)
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct logical_volume *lv_to_free = NULL;
|
||||
struct lvinfo info;
|
||||
static const struct lv_activate_opts laopts = { .skip_in_use = 1 };
|
||||
struct dm_list *snh;
|
||||
int r = 0;
|
||||
|
||||
if (!activation())
|
||||
@@ -2114,29 +2136,17 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
|
||||
log_debug_activation("Deactivating %s/%s.", lv->vg->name, lv->name);
|
||||
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0))
|
||||
if (!lv_info(cmd, lv, 0, &info, 1, 0))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists) {
|
||||
r = 1;
|
||||
/* Check attached snapshot segments are also inactive */
|
||||
dm_list_iterate(snh, &lv->snapshot_segs) {
|
||||
if (!lv_info(cmd, dm_list_struct_base(snh, struct lv_segment, origin_list)->cow,
|
||||
0, &info, 0, 0))
|
||||
goto_out;
|
||||
if (info.exists) {
|
||||
r = 0; /* Snapshot left in table? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r)
|
||||
goto out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lv_is_visible(lv) || lv_is_virtual_origin(lv) ||
|
||||
lv_is_merging_thin_snapshot(lv)) {
|
||||
if (!lv_check_not_in_use(lv))
|
||||
if (!lv_check_not_in_use(cmd, lv, &info))
|
||||
goto_out;
|
||||
|
||||
if (lv_is_origin(lv) && _lv_has_open_snapshots(lv))
|
||||
@@ -2153,12 +2163,8 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
r = _lv_deactivate(lv);
|
||||
critical_section_dec(cmd, "deactivated");
|
||||
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists) {
|
||||
/* Turn into log_error, but we do not log error */
|
||||
log_debug_activation("Deactivated volume is still %s present.",
|
||||
display_lvname(lv));
|
||||
if (!lv_info(cmd, lv, 0, &info, 0, 0) || info.exists)
|
||||
r = 0;
|
||||
}
|
||||
out:
|
||||
if (lv_to_free) {
|
||||
lv_release_replicator_vgs(lv_to_free);
|
||||
@@ -2170,9 +2176,9 @@ out:
|
||||
|
||||
/* Test if LV passes filter */
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv, const struct logical_volume *lv)
|
||||
int *activate_lv, struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct logical_volume *lv_to_free = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (!activation()) {
|
||||
@@ -2199,9 +2205,9 @@ out:
|
||||
|
||||
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct lv_activate_opts *laopts, int filter,
|
||||
const struct logical_volume *lv)
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct logical_volume *lv_to_free = NULL;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
@@ -2240,16 +2246,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if cmirrord is running for clustered mirrors.
|
||||
*/
|
||||
if (!laopts->exclusive && vg_is_clustered(lv->vg) &&
|
||||
lv_is_mirror(lv) && !lv_is_raid(lv) &&
|
||||
!cluster_mirror_is_available(lv->vg->cmd)) {
|
||||
log_error("Shared cluster mirrors are not available.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Activating '%s'.", lv->name);
|
||||
r = 1;
|
||||
@@ -2274,7 +2270,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (info.exists && !info.suspended && info.live_table &&
|
||||
(info.read_only == read_only_lv(lv, laopts))) {
|
||||
r = 1;
|
||||
log_debug_activation("Volume is already active.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2302,7 +2297,7 @@ out:
|
||||
|
||||
/* Activate LV */
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv)
|
||||
int noscan, int temporary, struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = { .exclusive = exclusive,
|
||||
.noscan = noscan,
|
||||
@@ -2316,7 +2311,7 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
|
||||
/* Activate LV only if it passes filter */
|
||||
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv)
|
||||
int noscan, int temporary, struct logical_volume *lv)
|
||||
{
|
||||
struct lv_activate_opts laopts = { .exclusive = exclusive,
|
||||
.noscan = noscan,
|
||||
|
||||
@@ -30,37 +30,6 @@ struct lvinfo {
|
||||
uint32_t read_ahead;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SEG_STATUS_NONE,
|
||||
SEG_STATUS_CACHE,
|
||||
SEG_STATUS_RAID,
|
||||
SEG_STATUS_SNAPSHOT,
|
||||
SEG_STATUS_THIN,
|
||||
SEG_STATUS_THIN_POOL,
|
||||
SEG_STATUS_UNKNOWN
|
||||
} lv_seg_status_type_t;
|
||||
|
||||
struct lv_seg_status {
|
||||
struct dm_pool *mem; /* input */
|
||||
const struct lv_segment *seg; /* input */
|
||||
lv_seg_status_type_t type; /* output */
|
||||
union {
|
||||
struct dm_status_cache *cache;
|
||||
struct dm_status_raid *raid;
|
||||
struct dm_status_snapshot *snapshot;
|
||||
struct dm_status_thin *thin;
|
||||
struct dm_status_thin_pool *thin_pool;
|
||||
};
|
||||
};
|
||||
|
||||
struct lv_with_info_and_seg_status {
|
||||
const struct logical_volume *lv; /* input */
|
||||
int info_ok;
|
||||
struct lvinfo info; /* output */
|
||||
int seg_part_of_lv; /* output */
|
||||
struct lv_seg_status seg_status; /* input/output, see lv_seg_status */
|
||||
};
|
||||
|
||||
struct lv_activate_opts {
|
||||
int exclusive;
|
||||
int origin_only;
|
||||
@@ -105,54 +74,34 @@ void activation_release(void);
|
||||
void activation_exit(void);
|
||||
|
||||
/* int lv_suspend(struct cmd_context *cmd, const char *lvid_s); */
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive,
|
||||
const struct logical_volume *lv_ondisk, const struct logical_volume *lv_incore);
|
||||
int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, const struct logical_volume *lv);
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, unsigned exclusive, struct logical_volume *lv_ondisk, struct logical_volume *lv_incore);
|
||||
int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, struct logical_volume *lv);
|
||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
|
||||
unsigned origin_only, unsigned exclusive, unsigned revert, const struct logical_volume *lv);
|
||||
unsigned origin_only, unsigned exclusive, unsigned revert, struct logical_volume *lv);
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv);
|
||||
int noscan, int temporary, struct logical_volume *lv);
|
||||
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
|
||||
int noscan, int temporary, const struct logical_volume *lv);
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logical_volume *lv);
|
||||
int noscan, int temporary, struct logical_volume *lv);
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, struct logical_volume *lv);
|
||||
|
||||
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Returns 1 if info structure has been populated, else 0 on failure.
|
||||
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
|
||||
* Returns 1 if info structure has been populated, else 0.
|
||||
*/
|
||||
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_layer,
|
||||
struct lvinfo *info, int with_open_count, int with_read_ahead);
|
||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
struct lvinfo *info, int with_open_count, int with_read_ahead);
|
||||
|
||||
/*
|
||||
* Returns 1 if lv_seg_status structure has been populated,
|
||||
* else 0 on failure or if device not active locally.
|
||||
*/
|
||||
int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
|
||||
int use_layer, struct lv_seg_status *lv_seg_status);
|
||||
|
||||
/*
|
||||
* Returns 1 if lv_info_and_seg_status structure has been populated,
|
||||
* else 0 on failure or if device not active locally.
|
||||
*
|
||||
* lv_info_with_seg_status is the same as calling lv_info and then lv_status,
|
||||
* but this fn tries to do that with one ioctl if possible.
|
||||
*/
|
||||
int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
const struct lv_segment *lv_seg, int use_layer,
|
||||
struct lv_with_info_and_seg_status *status,
|
||||
int with_open_count, int with_read_ahead);
|
||||
|
||||
int lv_check_not_in_use(const struct logical_volume *lv);
|
||||
int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvinfo *info);
|
||||
|
||||
/*
|
||||
* Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.
|
||||
*/
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv, const struct logical_volume *lv);
|
||||
int *activate_lv, struct logical_volume *lv);
|
||||
/*
|
||||
* Checks against the auto_activation_volume_list and
|
||||
* returns 1 if the LV should be activated, 0 otherwise.
|
||||
@@ -171,8 +120,12 @@ int lv_raid_dev_health(const struct logical_volume *lv, char **dev_health);
|
||||
int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt);
|
||||
int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action);
|
||||
int lv_raid_message(const struct logical_volume *lv, const char *msg);
|
||||
int lv_cache_status(const struct logical_volume *lv,
|
||||
struct lv_status_cache **status);
|
||||
int lv_cache_block_info(struct logical_volume *lv,
|
||||
uint32_t *chunk_size, uint64_t *dirty_count,
|
||||
uint64_t *used_count, uint64_t *total_count);
|
||||
int lv_cache_policy_info(struct logical_volume *lv,
|
||||
const char **policy_name, int *policy_argc,
|
||||
const char ***policy_argv);
|
||||
int lv_thin_pool_percent(const struct logical_volume *lv, int metadata,
|
||||
dm_percent_t *percent);
|
||||
int lv_thin_percent(const struct logical_volume *lv, int mapped,
|
||||
@@ -194,18 +147,18 @@ int lv_is_active_exclusive(const struct logical_volume *lv);
|
||||
int lv_is_active_exclusive_locally(const struct logical_volume *lv);
|
||||
int lv_is_active_exclusive_remotely(const struct logical_volume *lv);
|
||||
|
||||
int lv_has_target_type(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
|
||||
const char *layer, const char *target_type);
|
||||
|
||||
int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const struct lv_activate_opts *laopts, int do_reg);
|
||||
|
||||
#ifdef DMEVENTD
|
||||
# include "libdevmapper-event.h"
|
||||
char *get_monitor_dso_path(struct cmd_context *cmd, const char *libpath);
|
||||
int target_registered_with_dmeventd(struct cmd_context *cmd, const char *libpath,
|
||||
const struct logical_volume *lv, int *pending);
|
||||
int target_register_events(struct cmd_context *cmd, const char *dso, const struct logical_volume *lv,
|
||||
struct logical_volume *lv, int *pending);
|
||||
int target_register_events(struct cmd_context *cmd, const char *dso, struct logical_volume *lv,
|
||||
int evmask __attribute__((unused)), int set, int timeout);
|
||||
#endif
|
||||
|
||||
@@ -219,19 +172,18 @@ int add_linear_area_to_dtree(struct dm_tree_node *node, uint64_t size,
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg);
|
||||
|
||||
struct dev_usable_check_params {
|
||||
unsigned int check_empty:1;
|
||||
unsigned int check_blocked:1;
|
||||
unsigned int check_suspended:1;
|
||||
unsigned int check_error_target:1;
|
||||
unsigned int check_reserved:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns 1 if mapped device is not suspended, blocked or
|
||||
* is using a reserved name.
|
||||
*/
|
||||
int device_is_usable(struct device *dev, struct dev_usable_check_params check);
|
||||
int device_is_usable(struct device *dev);
|
||||
|
||||
/*
|
||||
* Returns 1 if the device is suspended or blocking.
|
||||
* (Does not perform check on the LV name of the device.)
|
||||
* N.B. This is !device_is_usable() without the name check.
|
||||
*/
|
||||
int device_is_suspended_or_blocking(struct device *dev);
|
||||
|
||||
/*
|
||||
* Declaration moved here from fs.h to keep header fs.h hidden
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,9 +25,8 @@ struct cmd_context;
|
||||
struct dev_manager;
|
||||
struct dm_info;
|
||||
struct device;
|
||||
struct lv_seg_status;
|
||||
|
||||
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts);
|
||||
int read_only_lv(struct logical_volume *lv, struct lv_activate_opts *laopts);
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
@@ -48,8 +47,7 @@ void dev_manager_exit(void);
|
||||
int dev_manager_info(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
const char *layer,
|
||||
int with_open_count, int with_read_ahead,
|
||||
struct dm_info *dminfo, uint32_t *read_ahead,
|
||||
struct lv_seg_status *seg_status);
|
||||
struct dm_info *info, uint32_t *read_ahead);
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
dm_percent_t *percent);
|
||||
@@ -64,7 +62,7 @@ int dev_manager_raid_message(struct dev_manager *dm,
|
||||
const char *msg);
|
||||
int dev_manager_cache_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_status_cache **status);
|
||||
struct dm_status_cache **status);
|
||||
int dev_manager_thin_pool_status(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
struct dm_status_thin_pool **status,
|
||||
@@ -78,14 +76,14 @@ int dev_manager_thin_percent(struct dev_manager *dm,
|
||||
int dev_manager_thin_device_id(struct dev_manager *dm,
|
||||
const struct logical_volume *lv,
|
||||
uint32_t *device_id);
|
||||
int dev_manager_suspend(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts, int lockfs, int flush_required);
|
||||
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts);
|
||||
int dev_manager_preload(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts, int *flush_required);
|
||||
int dev_manager_deactivate(struct dev_manager *dm, const struct logical_volume *lv);
|
||||
int dev_manager_transient(struct dev_manager *dm, const struct logical_volume *lv) __attribute__((nonnull(1, 2)));
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_transient(struct dev_manager *dm, struct logical_volume *lv) __attribute__((nonnull(1, 2)));
|
||||
|
||||
int dev_manager_mknodes(const struct logical_volume *lv);
|
||||
|
||||
|
||||
@@ -468,8 +468,8 @@ int fs_del_lv_byname(const char *dev_dir, const char *vg_name,
|
||||
return _fs_op(FS_DEL, dev_dir, vg_name, lv_name, "", "", check_udev);
|
||||
}
|
||||
|
||||
int fs_rename_lv(const struct logical_volume *lv, const char *dev,
|
||||
const char *old_vgname, const char *old_lvname)
|
||||
int fs_rename_lv(struct logical_volume *lv, const char *dev,
|
||||
const char *old_vgname, const char *old_lvname)
|
||||
{
|
||||
if (strcmp(old_vgname, lv->vg->name)) {
|
||||
return
|
||||
|
||||
@@ -27,7 +27,7 @@ int fs_add_lv(const struct logical_volume *lv, const char *dev);
|
||||
int fs_del_lv(const struct logical_volume *lv);
|
||||
int fs_del_lv_byname(const char *dev_dir, const char *vg_name,
|
||||
const char *lv_name, int check_udev);
|
||||
int fs_rename_lv(const struct logical_volume *lv, const char *dev,
|
||||
int fs_rename_lv(struct logical_volume *lv, const char *dev,
|
||||
const char *old_vgname, const char *old_lvname);
|
||||
/* void fs_unlock(void); moved to activate.h */
|
||||
uint32_t fs_get_cookie(void);
|
||||
|
||||
464
lib/cache/lvmcache.c
vendored
464
lib/cache/lvmcache.c
vendored
@@ -56,8 +56,6 @@ struct lvmcache_vginfo {
|
||||
char _padding[7];
|
||||
struct lvmcache_vginfo *next; /* Another VG with same name? */
|
||||
char *creation_host;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
size_t vgmetadata_size;
|
||||
char *vgmetadata; /* Copy of VG metadata as format_text string */
|
||||
struct dm_config_tree *cft; /* Config tree created from vgmetadata */
|
||||
@@ -67,7 +65,6 @@ struct lvmcache_vginfo {
|
||||
unsigned vg_use_count; /* Counter of vg reusage */
|
||||
unsigned precommitted; /* Is vgmetadata live or precommitted? */
|
||||
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
|
||||
unsigned preferred_duplicates; /* preferred duplicate pvs have been set */
|
||||
};
|
||||
|
||||
static struct dm_hash_table *_pvid_hash = NULL;
|
||||
@@ -79,7 +76,6 @@ static int _scanning_in_progress = 0;
|
||||
static int _has_scanned = 0;
|
||||
static int _vgs_locked = 0;
|
||||
static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */
|
||||
static int _found_duplicate_pvs = 0; /* If we never see a duplicate PV we can skip checking for them later. */
|
||||
|
||||
int lvmcache_init(void)
|
||||
{
|
||||
@@ -116,47 +112,6 @@ int lvmcache_init(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Once PV info has been populated in lvmcache and
|
||||
* lvmcache has chosen preferred duplicate devices,
|
||||
* set this flag so that lvmcache will not try to
|
||||
* compare and choose preferred duplicate devices
|
||||
* again (which may result in different preferred
|
||||
* devices.) PV info can be populated in lvmcache
|
||||
* multiple times, each time causing lvmcache to
|
||||
* compare the duplicate devices, so we need to
|
||||
* record that the comparison/preferences have
|
||||
* already been done, so the preferrences from the
|
||||
* first time through are not changed.
|
||||
*
|
||||
* This is something of a hack to work around the
|
||||
* fact that the code isn't really designed to
|
||||
* handle duplicate PVs, and the fact that lvmetad
|
||||
* has its own way of picking a preferred duplicate
|
||||
* and lvmcache has another way based on having
|
||||
* more information than lvmetad does.
|
||||
*
|
||||
* If we come up with a better overall method to
|
||||
* handle duplicate PVs, then this can probably be
|
||||
* removed.
|
||||
*
|
||||
* FIXME: if we want to make lvmetad work with clvmd,
|
||||
* then this may need to be changed to set
|
||||
* preferred_duplicates back to 0.
|
||||
*/
|
||||
|
||||
void lvmcache_set_preferred_duplicates(const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
vginfo->preferred_duplicates = 1;
|
||||
}
|
||||
|
||||
void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
|
||||
{
|
||||
if (!lvmetad_active() || _has_scanned)
|
||||
@@ -329,9 +284,6 @@ void lvmcache_commit_metadata(const char *vgname)
|
||||
|
||||
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
||||
{
|
||||
if (lvmcache_vgname_is_locked(VG_GLOBAL) && !vg_write_lock_held())
|
||||
return;
|
||||
|
||||
/* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
|
||||
if (!strcmp(vgname, VG_ORPHANS)) {
|
||||
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
|
||||
@@ -340,7 +292,7 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
||||
|
||||
/* Indicate that PVs could now be missing from the cache */
|
||||
init_full_scan_done(0);
|
||||
} else
|
||||
} else if (!lvmcache_vgname_is_locked(VG_GLOBAL))
|
||||
_drop_metadata(vgname, drop_precommitted);
|
||||
}
|
||||
|
||||
@@ -415,10 +367,10 @@ void lvmcache_lock_vgname(const char *vgname, int read_only __attribute__((unuse
|
||||
if (!dm_hash_insert(_lock_hash, vgname, (void *) 1))
|
||||
log_error("Cache locking failure for %s", vgname);
|
||||
|
||||
if (strcmp(vgname, VG_GLOBAL)) {
|
||||
_update_cache_lock_state(vgname, 1);
|
||||
_update_cache_lock_state(vgname, 1);
|
||||
|
||||
if (strcmp(vgname, VG_GLOBAL))
|
||||
_vgs_locked++;
|
||||
}
|
||||
}
|
||||
|
||||
int lvmcache_vgname_is_locked(const char *vgname)
|
||||
@@ -435,8 +387,7 @@ void lvmcache_unlock_vgname(const char *vgname)
|
||||
log_error(INTERNAL_ERROR "Attempt to unlock unlocked VG %s.",
|
||||
vgname);
|
||||
|
||||
if (strcmp(vgname, VG_GLOBAL))
|
||||
_update_cache_lock_state(vgname, 0);
|
||||
_update_cache_lock_state(vgname, 0);
|
||||
|
||||
dm_hash_remove(_lock_hash, vgname);
|
||||
|
||||
@@ -450,16 +401,6 @@ int lvmcache_vgs_locked(void)
|
||||
return _vgs_locked;
|
||||
}
|
||||
|
||||
/*
|
||||
* When lvmcache sees a duplicate PV, this is set.
|
||||
* process_each_pv() can avoid searching for duplicates
|
||||
* by checking this and seeing that no duplicate PVs exist.
|
||||
*/
|
||||
int lvmcache_found_duplicate_pvs(void)
|
||||
{
|
||||
return _found_duplicate_pvs;
|
||||
}
|
||||
|
||||
static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
|
||||
struct lvmcache_info *info)
|
||||
{
|
||||
@@ -752,10 +693,10 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (full_scan == 2 && (cmd->full_filter && !cmd->full_filter->use_count) && !refresh_filters(cmd))
|
||||
if (full_scan == 2 && (cmd->filter && !cmd->filter->use_count) && !refresh_filters(cmd))
|
||||
goto_out;
|
||||
|
||||
if (!cmd->full_filter || !(iter = dev_iter_create(cmd->full_filter, (full_scan == 2) ? 1 : 0))) {
|
||||
if (!cmd->filter || !(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
|
||||
log_error("dev_iter creation failed");
|
||||
goto out;
|
||||
}
|
||||
@@ -778,8 +719,8 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
* device cache for the benefit of short-lived processes.
|
||||
*/
|
||||
if (full_scan == 2 && cmd->is_long_lived &&
|
||||
cmd->dump_filter && cmd->full_filter && cmd->full_filter->dump &&
|
||||
!cmd->full_filter->dump(cmd->full_filter, 0))
|
||||
cmd->dump_filter && cmd->filter && cmd->filter->dump &&
|
||||
!cmd->filter->dump(cmd->filter, 0))
|
||||
stack;
|
||||
|
||||
r = 1;
|
||||
@@ -905,37 +846,6 @@ int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo
|
||||
}
|
||||
// #endif
|
||||
|
||||
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
|
||||
struct dm_list *vgnameids)
|
||||
{
|
||||
struct vgnameid_list *vgnl;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
lvmcache_label_scan(cmd, 0);
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
if (!include_internal && is_orphan_vg(vginfo->vgname))
|
||||
continue;
|
||||
|
||||
if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {
|
||||
log_error("vgnameid_list allocation failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vgnl->vgid = dm_pool_strdup(cmd->mem, vginfo->vgid);
|
||||
vgnl->vg_name = dm_pool_strdup(cmd->mem, vginfo->vgname);
|
||||
|
||||
if (!vgnl->vgid || !vgnl->vg_name) {
|
||||
log_error("vgnameid_list member allocation failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_add(vgnameids, &vgnl->list);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
|
||||
int include_internal)
|
||||
{
|
||||
@@ -1481,26 +1391,6 @@ static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstat
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvmcache_update_vg_mda_info(struct lvmcache_info *info, uint32_t mda_checksum,
|
||||
size_t mda_size)
|
||||
{
|
||||
if (!info || !info->vginfo || !mda_size)
|
||||
return 1;
|
||||
|
||||
if (info->vginfo->mda_checksum == mda_checksum || info->vginfo->mda_size == mda_size)
|
||||
return 1;
|
||||
|
||||
info->vginfo->mda_checksum = mda_checksum;
|
||||
info->vginfo->mda_size = mda_size;
|
||||
|
||||
/* FIXME Add checksum index */
|
||||
|
||||
log_debug_cache("lvmcache: %s: VG %s: Stored metadata checksum %" PRIu32 " with size %" PRIsize_t ".",
|
||||
dev_name(info->dev), info->vginfo->vgname, mda_checksum, mda_size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
|
||||
{
|
||||
if (!_lock_hash && !lvmcache_init()) {
|
||||
@@ -1511,11 +1401,10 @@ int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
|
||||
return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
|
||||
}
|
||||
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary)
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *creation_host)
|
||||
{
|
||||
const char *vgname = vgsummary->vgname;
|
||||
const char *vgid = (char *)&vgsummary->vgid;
|
||||
|
||||
if (!vgname && !info->vginfo) {
|
||||
log_error(INTERNAL_ERROR "NULL vgname handed to cache");
|
||||
/* FIXME Remove this */
|
||||
@@ -1543,11 +1432,10 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
|
||||
if (!is_orphan_vg(vgname))
|
||||
info->status &= ~CACHE_INVALID;
|
||||
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
|
||||
vgsummary->creation_host, info->fmt) ||
|
||||
if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
|
||||
creation_host, info->fmt) ||
|
||||
!_lvmcache_update_vgid(info, info->vginfo, vgid) ||
|
||||
!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host) ||
|
||||
!_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
|
||||
!_lvmcache_update_vgstatus(info, vgstatus, creation_host))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -1558,11 +1446,6 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
struct lvmcache_vgsummary vgsummary = {
|
||||
.vgname = vg->name,
|
||||
.vgstatus = vg->status,
|
||||
.vgid = vg->id
|
||||
};
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
@@ -1570,7 +1453,9 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||
if ((info = lvmcache_info_from_pvid(pvid_s, 0)) &&
|
||||
!lvmcache_update_vgname_and_id(info, &vgsummary))
|
||||
!lvmcache_update_vgname_and_id(info, vg->name,
|
||||
(char *) &vg->id,
|
||||
vg->status, NULL))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -1581,85 +1466,6 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace pv->dev with dev so that dev will appear for reporting.
|
||||
*/
|
||||
|
||||
void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct device *dev)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
|
||||
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
if (!(info = lvmcache_info_from_pvid(pvid_s, 0)))
|
||||
return;
|
||||
|
||||
info->dev = dev;
|
||||
info->label->dev = dev;
|
||||
pv->dev = dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can see multiple different devices with the
|
||||
* same pvid, i.e. duplicates.
|
||||
*
|
||||
* There may be different reasons for seeing two
|
||||
* devices with the same pvid:
|
||||
* - multipath showing two paths to the same thing
|
||||
* - one device copied to another, e.g. with dd,
|
||||
* also referred to as cloned devices.
|
||||
* - a "subsystem" taking a device and creating
|
||||
* another device of its own that represents the
|
||||
* underlying device it is using, e.g. using dm
|
||||
* to create an identity mapping of a PV.
|
||||
*
|
||||
* Given duplicate devices, we have to choose one
|
||||
* of them to be the "preferred" dev, i.e. the one
|
||||
* that will be referenced in lvmcache, by pv->dev.
|
||||
* We can keep the existing dev, that's currently
|
||||
* used in lvmcache, or we can replace the existing
|
||||
* dev with the new duplicate.
|
||||
*
|
||||
* Regardless of which device is preferred, we need
|
||||
* to print messages explaining which devices were
|
||||
* found so that a user can sort out for themselves
|
||||
* what has happened if the preferred device is not
|
||||
* the one they are interested in.
|
||||
*
|
||||
* If a user wants to use the non-preferred device,
|
||||
* they will need to filter out the device that
|
||||
* lvm is preferring.
|
||||
*
|
||||
* The dev_subsystem calls check if the major number
|
||||
* of the dev is part of a subsystem like DM/MD/DRBD.
|
||||
* A dev that's part of a subsystem is preferred over a
|
||||
* duplicate of that dev that is not part of a
|
||||
* subsystem.
|
||||
*
|
||||
* The has_holders calls check if the device is being
|
||||
* used by another, and prefers one that's being used.
|
||||
*
|
||||
* FIXME: why do we prefer a device without holders
|
||||
* over a device with holders? We should understand
|
||||
* the reason for that choice.
|
||||
*
|
||||
* FIXME: there may be other reasons to prefer one
|
||||
* device over another:
|
||||
*
|
||||
* . are there other use/open counts we could check
|
||||
* beyond the holders?
|
||||
*
|
||||
* . check if either is bad/usable and prefer
|
||||
* the good one?
|
||||
*
|
||||
* . prefer the one with smaller minor number?
|
||||
* Might avoid disturbing things due to a new
|
||||
* transient duplicate?
|
||||
*/
|
||||
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid,
|
||||
@@ -1670,14 +1476,6 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
struct label *label;
|
||||
struct lvmcache_info *existing, *info;
|
||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
struct lvmcache_vgsummary vgsummary = {
|
||||
.vgname = vgname,
|
||||
.vgstatus = vgstatus,
|
||||
};
|
||||
|
||||
/* N.B. vgid is not NUL-terminated when called from _text_pv_write */
|
||||
if (vgid)
|
||||
strncpy((char *)&vgsummary.vgid, vgid, sizeof(vgsummary.vgid));
|
||||
|
||||
if (!_vgname_hash && !lvmcache_init()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
@@ -1707,168 +1505,49 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
lvmcache_del_bas(info);
|
||||
} else {
|
||||
if (existing->dev != dev) {
|
||||
int old_in_subsystem = 0;
|
||||
int new_in_subsystem = 0;
|
||||
int old_is_dm = 0;
|
||||
int new_is_dm = 0;
|
||||
int old_has_holders = 0;
|
||||
int new_has_holders = 0;
|
||||
|
||||
/*
|
||||
* Here are different devices with the same pvid:
|
||||
* duplicates. See comment above.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This flag tells the process_each_pv code to search
|
||||
* the devices list for duplicates, so that devices
|
||||
* can be processed together with their duplicates
|
||||
* (while processing the VG, rather than reporting
|
||||
* pv->dev under the VG, and its duplicate outside
|
||||
* the VG context.)
|
||||
*/
|
||||
_found_duplicate_pvs = 1;
|
||||
|
||||
/*
|
||||
* The new dev may not have pvid set.
|
||||
* The process_each_pv code needs to have the pvid
|
||||
* set in each device to detect that the devices
|
||||
* are duplicates.
|
||||
*/
|
||||
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
|
||||
|
||||
/*
|
||||
* Now decide if we are going to ignore the new
|
||||
* device, or replace the existing/old device in
|
||||
* lvmcache with the new one.
|
||||
*/
|
||||
old_in_subsystem = dev_subsystem_part_major(dt, existing->dev);
|
||||
new_in_subsystem = dev_subsystem_part_major(dt, dev);
|
||||
|
||||
old_is_dm = dm_is_dm_major(MAJOR(existing->dev->dev));
|
||||
new_is_dm = dm_is_dm_major(MAJOR(dev->dev));
|
||||
|
||||
old_has_holders = dm_device_has_holders(MAJOR(existing->dev->dev), MINOR(existing->dev->dev));
|
||||
new_has_holders = dm_device_has_holders(MAJOR(dev->dev), MINOR(dev->dev));
|
||||
|
||||
if (old_has_holders && new_has_holders) {
|
||||
/*
|
||||
* This is not a selection of old or new, but
|
||||
* just a warning to be aware of.
|
||||
*/
|
||||
log_warn("WARNING: duplicate PV %s is being used from both devices %s and %s",
|
||||
pvid_s,
|
||||
dev_name(existing->dev),
|
||||
dev_name(dev));
|
||||
}
|
||||
|
||||
if (existing->vginfo->preferred_duplicates) {
|
||||
/*
|
||||
* The preferred duplicate devs have already
|
||||
* been chosen during a previous populating of
|
||||
* lvmcache, so just use the existing preferences.
|
||||
*/
|
||||
log_verbose("Found duplicate PV %s: using existing dev %s",
|
||||
pvid_s,
|
||||
dev_name(existing->dev));
|
||||
/* Is the existing entry a duplicate pvid e.g. md ? */
|
||||
if (dev_subsystem_part_major(dt, existing->dev) &&
|
||||
!dev_subsystem_part_major(dt, dev)) {
|
||||
log_very_verbose("Ignoring duplicate PV %s on "
|
||||
"%s - using %s %s",
|
||||
pvid, dev_name(dev),
|
||||
dev_subsystem_name(dt, existing->dev),
|
||||
dev_name(existing->dev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (old_in_subsystem && !new_in_subsystem) {
|
||||
/* Use old, ignore new. */
|
||||
log_warn("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(existing->dev),
|
||||
dev_name(dev));
|
||||
log_warn("Using duplicate PV %s from subsystem %s, ignoring %s",
|
||||
dev_name(existing->dev),
|
||||
dev_subsystem_name(dt, existing->dev),
|
||||
dev_name(dev));
|
||||
} else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
||||
!dm_is_dm_major(MAJOR(dev->dev))) {
|
||||
log_very_verbose("Ignoring duplicate PV %s on "
|
||||
"%s - using dm %s",
|
||||
pvid, dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
return NULL;
|
||||
|
||||
} else if (!old_in_subsystem && new_in_subsystem) {
|
||||
/* Use new, replace old. */
|
||||
log_warn("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
log_warn("Using duplicate PV %s from subsystem %s, replacing %s",
|
||||
dev_name(dev),
|
||||
dev_subsystem_name(dt, dev),
|
||||
dev_name(existing->dev));
|
||||
|
||||
} else if (old_has_holders && !new_has_holders) {
|
||||
/* Use new, replace old. */
|
||||
/* FIXME: why choose the one without olders? */
|
||||
log_warn("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
log_warn("Using duplicate PV %s without holders, replacing %s",
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
|
||||
} else if (!old_has_holders && new_has_holders) {
|
||||
/* Use old, ignore new. */
|
||||
log_warn("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(existing->dev),
|
||||
dev_name(dev));
|
||||
log_warn("Using duplicate PV %s without holders, ignoring %s",
|
||||
dev_name(existing->dev),
|
||||
dev_name(dev));
|
||||
return NULL;
|
||||
|
||||
} else if (old_is_dm && new_is_dm) {
|
||||
/* Use new, replace old. */
|
||||
/* FIXME: why choose the new instead of the old? */
|
||||
log_warn("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
log_warn("Using duplicate PV %s which is last seen, replacing %s",
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
|
||||
} else if (!strcmp(pvid_s, existing->dev->pvid)) {
|
||||
/* No criteria to use for preferring old or new. */
|
||||
/* FIXME: why choose the new instead of the old? */
|
||||
/* FIXME: a transient duplicate would be a reason
|
||||
* to select the old instead of the new. */
|
||||
log_warn("Found duplicate PV %s: using %s not %s",
|
||||
pvid_s,
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
log_warn("Using duplicate PV %s which is last seen, replacing %s",
|
||||
dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The new dev is the same as the existing dev.
|
||||
*
|
||||
* FIXME: Why can't we just return NULL here if the
|
||||
* device already exists? Things don't seem to work
|
||||
* if we do that for some reason.
|
||||
*/
|
||||
log_verbose("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
} else if (!dev_subsystem_part_major(dt, existing->dev) &&
|
||||
dev_subsystem_part_major(dt, dev))
|
||||
log_very_verbose("Duplicate PV %s on %s - "
|
||||
"using %s %s", pvid,
|
||||
dev_name(existing->dev),
|
||||
dev_subsystem_name(dt, existing->dev),
|
||||
dev_name(dev));
|
||||
else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
||||
dm_is_dm_major(MAJOR(dev->dev)))
|
||||
log_very_verbose("Duplicate PV %s on %s - "
|
||||
"using dm %s", pvid,
|
||||
dev_name(existing->dev),
|
||||
dev_name(dev));
|
||||
/* FIXME If both dm, check dependencies */
|
||||
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
|
||||
//dm_is_dm_major(MAJOR(dev->dev)))
|
||||
//
|
||||
else if (!strcmp(pvid_s, existing->dev->pvid))
|
||||
log_error("Found duplicate PV %s: using %s not "
|
||||
"%s", pvid, dev_name(dev),
|
||||
dev_name(existing->dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: when could this ever happen?
|
||||
* If this does happen, identify when/why here, and
|
||||
* if not, remove this code.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch over to new preferred device.
|
||||
*/
|
||||
if (strcmp(pvid_s, existing->dev->pvid))
|
||||
log_debug_cache("Updating pvid cache to %s (%s) from %s (%s)",
|
||||
pvid_s, dev_name(dev),
|
||||
existing->dev->pvid, dev_name(existing->dev));
|
||||
/* Switch over to new preferred device */
|
||||
existing->dev = dev;
|
||||
info = existing;
|
||||
/* Has labeller changed? */
|
||||
@@ -1893,7 +1572,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
|
||||
if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
|
||||
if (!existing) {
|
||||
dm_hash_remove(_pvid_hash, pvid_s);
|
||||
strcpy(info->dev->pvid, "");
|
||||
@@ -2302,28 +1981,3 @@ uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info)
|
||||
const struct format_type *lvmcache_fmt(struct lvmcache_info *info) {
|
||||
return info->fmt;
|
||||
}
|
||||
|
||||
int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
if (!vgsummary->mda_size)
|
||||
return 0;
|
||||
|
||||
/* FIXME Index the checksums */
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
if (vgsummary->mda_checksum == vginfo->mda_checksum &&
|
||||
vgsummary->mda_size == vginfo->mda_size &&
|
||||
!is_orphan_vg(vginfo->vgname)) {
|
||||
vgsummary->vgname = vginfo->vgname;
|
||||
vgsummary->creation_host = vginfo->creation_host;
|
||||
vgsummary->vgstatus = vginfo->status;
|
||||
/* vginfo->vgid has 1 extra byte then vgsummary->vgid */
|
||||
memcpy(&vgsummary->vgid, vginfo->vgid, sizeof(vgsummary->vgid));
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
23
lib/cache/lvmcache.h
vendored
23
lib/cache/lvmcache.h
vendored
@@ -39,15 +39,6 @@ struct disk_locn;
|
||||
|
||||
struct lvmcache_vginfo;
|
||||
|
||||
struct lvmcache_vgsummary {
|
||||
const char *vgname;
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
char *creation_host;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
};
|
||||
|
||||
int lvmcache_init(void);
|
||||
void lvmcache_allow_reads_with_lvmetad(void);
|
||||
|
||||
@@ -67,7 +58,8 @@ void lvmcache_del(struct lvmcache_info *info);
|
||||
|
||||
/* Update things */
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
const char *vgname, const char *vgid,
|
||||
uint32_t vgstatus, const char *hostname);
|
||||
int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted);
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||
@@ -76,7 +68,6 @@ int lvmcache_verify_lock_order(const char *vgname);
|
||||
|
||||
/* Queries */
|
||||
const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels);
|
||||
int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary);
|
||||
|
||||
/* Decrement and test if there are still vg holders in vginfo. */
|
||||
int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo);
|
||||
@@ -107,9 +98,6 @@ struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd,
|
||||
struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
|
||||
int include_internal);
|
||||
|
||||
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
|
||||
struct dm_list *vgnameids);
|
||||
|
||||
/* Returns list of struct dm_str_list containing pool-allocated copy of pvids */
|
||||
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid);
|
||||
@@ -169,11 +157,4 @@ unsigned lvmcache_mda_count(struct lvmcache_info *info);
|
||||
int lvmcache_vgid_is_cached(const char *vgid);
|
||||
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
|
||||
|
||||
void lvmcache_replace_dev(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct device *dev);
|
||||
|
||||
int lvmcache_found_duplicate_pvs(void);
|
||||
|
||||
void lvmcache_set_preferred_duplicates(const char *vgid);
|
||||
|
||||
#endif
|
||||
|
||||
237
lib/cache/lvmetad.c
vendored
237
lib/cache/lvmetad.c
vendored
@@ -39,6 +39,7 @@ void lvmetad_disconnect(void)
|
||||
if (_lvmetad_connected)
|
||||
daemon_close(_lvmetad);
|
||||
_lvmetad_connected = 0;
|
||||
_lvmetad_cmd = NULL;
|
||||
}
|
||||
|
||||
void lvmetad_init(struct cmd_context *cmd)
|
||||
@@ -46,10 +47,6 @@ void lvmetad_init(struct cmd_context *cmd)
|
||||
if (!_lvmetad_use && !access(getenv("LVM_LVMETAD_PIDFILE") ? : LVMETAD_PIDFILE, F_OK))
|
||||
log_warn("WARNING: lvmetad is running but disabled."
|
||||
" Restart lvmetad before enabling it!");
|
||||
|
||||
if (_lvmetad_connected)
|
||||
log_debug(INTERNAL_ERROR "Refreshing lvmetad global handle while connection with the daemon is active");
|
||||
|
||||
_lvmetad_cmd = cmd;
|
||||
}
|
||||
|
||||
@@ -101,13 +98,11 @@ int lvmetad_active(void)
|
||||
return _lvmetad_connected;
|
||||
}
|
||||
|
||||
void lvmetad_set_active(struct cmd_context *cmd, int active)
|
||||
void lvmetad_set_active(int active)
|
||||
{
|
||||
_lvmetad_use = active;
|
||||
if (!active && lvmetad_active())
|
||||
lvmetad_disconnect();
|
||||
if (cmd && !refresh_filters(cmd))
|
||||
stack;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -139,9 +134,6 @@ void lvmetad_set_socket(const char *sock)
|
||||
_lvmetad_socket = sock;
|
||||
}
|
||||
|
||||
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
|
||||
int ignore_obsolete);
|
||||
|
||||
static daemon_reply _lvmetad_send(const char *id, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -189,7 +181,7 @@ retry:
|
||||
max_remaining_sleep_times--; /* Sleep once before rescanning the first time, then 5 times each time after that. */
|
||||
} else {
|
||||
/* If the re-scan fails here, we try again later. */
|
||||
(void) _lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL, 0);
|
||||
(void) lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL);
|
||||
num_rescans++;
|
||||
max_remaining_sleep_times = 5;
|
||||
}
|
||||
@@ -268,21 +260,19 @@ static int _read_mda(struct lvmcache_info *info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
struct dm_config_node *cn,
|
||||
struct format_type *fmt, dev_t fallback)
|
||||
static struct lvmcache_info *_pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
struct dm_config_node *cn,
|
||||
dev_t fallback)
|
||||
{
|
||||
struct device *dev, *dev_alternate, *dev_alternate_cache = NULL;
|
||||
struct label *label;
|
||||
struct device *dev;
|
||||
struct id pvid, vgid;
|
||||
char mda_id[32];
|
||||
char da_id[32];
|
||||
int i = 0;
|
||||
struct dm_config_node *mda, *da;
|
||||
struct dm_config_node *alt_devices = dm_config_find_node(cn->child, "devices_alternate");
|
||||
struct dm_config_value *alt_device = NULL;
|
||||
struct dm_config_node *mda = NULL;
|
||||
struct dm_config_node *da = NULL;
|
||||
uint64_t offset, size;
|
||||
struct lvmcache_info *info, *info_alternate;
|
||||
struct lvmcache_info *info;
|
||||
const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL),
|
||||
*vgid_txt = dm_config_find_str(cn->child, "vgid", NULL),
|
||||
*vgname = dm_config_find_str(cn->child, "vgname", NULL),
|
||||
@@ -291,12 +281,11 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
uint64_t devsize = dm_config_find_int64(cn->child, "dev_size", 0),
|
||||
label_sector = dm_config_find_int64(cn->child, "label_sector", 0);
|
||||
|
||||
if (!fmt && fmt_name)
|
||||
fmt = get_format_by_name(cmd, fmt_name);
|
||||
struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL;
|
||||
|
||||
if (!fmt) {
|
||||
log_error("PV %s not recognised. Is the device missing?", pvid_txt);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = dev_cache_get_by_devt(devt, cmd->filter);
|
||||
@@ -304,18 +293,22 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
dev = dev_cache_get_by_devt(fallback, cmd->filter);
|
||||
|
||||
if (!dev) {
|
||||
log_warn("WARNING: Device for PV %s not found or rejected by a filter.", pvid_txt);
|
||||
return 0;
|
||||
dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter);
|
||||
if (!dev)
|
||||
log_error("No device found for PV %s.", pvid_txt);
|
||||
else
|
||||
log_warn("WARNING: Device %s for PV %s rejected by a filter.", dev_name(dev), pvid_txt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) {
|
||||
log_error("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vgid_txt) {
|
||||
if (!id_read_format(&vgid, vgid_txt))
|
||||
return_0;
|
||||
return_NULL;
|
||||
} else
|
||||
strcpy((char*)&vgid, fmt->orphan_vg_name);
|
||||
|
||||
@@ -324,7 +317,7 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
|
||||
if (!(info = lvmcache_add(fmt->labeller, (const char *)&pvid, dev,
|
||||
vgname, (const char *)&vgid, 0)))
|
||||
return_0;
|
||||
return_NULL;
|
||||
|
||||
lvmcache_get_label(info)->sector = label_sector;
|
||||
lvmcache_get_label(info)->dev = dev;
|
||||
@@ -365,53 +358,7 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd,
|
||||
++i;
|
||||
} while (da);
|
||||
|
||||
if (alt_devices)
|
||||
alt_device = alt_devices->v;
|
||||
|
||||
while (alt_device) {
|
||||
dev_alternate = dev_cache_get_by_devt(alt_device->v.i, cmd->filter);
|
||||
if (dev_alternate) {
|
||||
if ((info_alternate = lvmcache_add(fmt->labeller, (const char *)&pvid, dev_alternate,
|
||||
vgname, (const char *)&vgid, 0))) {
|
||||
dev_alternate_cache = dev_alternate;
|
||||
info = info_alternate;
|
||||
lvmcache_get_label(info)->dev = dev_alternate;
|
||||
}
|
||||
} else {
|
||||
log_warn("Duplicate of PV %s dev %s exists on unknown device %"PRId64 ":%" PRId64,
|
||||
pvid_txt, dev_name(dev), MAJOR(alt_device->v.i), MINOR(alt_device->v.i));
|
||||
}
|
||||
alt_device = alt_device->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update lvmcache with the info about the alternate device by
|
||||
* reading its label, which should update lvmcache.
|
||||
*/
|
||||
if (dev_alternate_cache) {
|
||||
if (!label_read(dev_alternate_cache, &label, 0)) {
|
||||
log_warn("No PV label found on duplicate device %s.", dev_name(dev_alternate_cache));
|
||||
}
|
||||
}
|
||||
|
||||
lvmcache_set_preferred_duplicates((const char *)&vgid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_update_struct_pv(struct physical_volume *pv, struct format_instance *fid)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
if ((info = lvmcache_info_from_pvid((const char *)&pv->id, 0))) {
|
||||
pv->label_sector = lvmcache_get_label(info)->sector;
|
||||
pv->dev = lvmcache_device(info);
|
||||
if (!pv->dev)
|
||||
pv->status |= MISSING_PV;
|
||||
if (!lvmcache_fid_add_mdas_pv(info, fid))
|
||||
return_0;
|
||||
pv->fid = fid;
|
||||
} else
|
||||
pv->status |= MISSING_PV; /* probably missing */
|
||||
return 1;
|
||||
return info;
|
||||
}
|
||||
|
||||
struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
|
||||
@@ -428,6 +375,7 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
struct format_type *fmt;
|
||||
struct dm_config_node *pvcn;
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!lvmetad_active())
|
||||
return NULL;
|
||||
@@ -476,28 +424,24 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
|
||||
if ((pvcn = dm_config_find_node(top, "metadata/physical_volumes")))
|
||||
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
|
||||
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
|
||||
|
||||
if ((pvcn = dm_config_find_node(top, "metadata/outdated_pvs")))
|
||||
for (pvcn = pvcn->child; pvcn; pvcn = pvcn->sib)
|
||||
_pv_populate_lvmcache(cmd, pvcn, fmt, 0);
|
||||
_pv_populate_lvmcache(cmd, pvcn, 0);
|
||||
|
||||
top->key = name;
|
||||
if (!(vg = import_vg_from_lvmetad_config_tree(reply.cft, fid)))
|
||||
if (!(vg = import_vg_from_config_tree(reply.cft, fid)))
|
||||
goto_out;
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
}
|
||||
if ((info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
|
||||
pvl->pv->label_sector = lvmcache_get_label(info)->sector;
|
||||
pvl->pv->dev = lvmcache_device(info);
|
||||
if (!pvl->pv->dev)
|
||||
pvl->pv->status |= MISSING_PV;
|
||||
if (!lvmcache_fid_add_mdas_pv(info, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
}
|
||||
} else
|
||||
pvl->pv->status |= MISSING_PV; /* probably missing */
|
||||
}
|
||||
|
||||
lvmcache_update_vg(vg, 0);
|
||||
@@ -631,7 +575,7 @@ int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid, int *found)
|
||||
|
||||
if (!(cn = dm_config_find_node(reply.cft->root, "physical_volume")))
|
||||
goto_out;
|
||||
else if (!_pv_populate_lvmcache(cmd, cn, NULL, 0))
|
||||
else if (!_pv_populate_lvmcache(cmd, cn, 0))
|
||||
goto_out;
|
||||
|
||||
out_success:
|
||||
@@ -661,7 +605,7 @@ int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *f
|
||||
goto out_success;
|
||||
|
||||
cn = dm_config_find_node(reply.cft->root, "physical_volume");
|
||||
if (!cn || !_pv_populate_lvmcache(cmd, cn, NULL, dev->dev))
|
||||
if (!cn || !_pv_populate_lvmcache(cmd, cn, dev->dev))
|
||||
goto_out;
|
||||
|
||||
out_success:
|
||||
@@ -689,63 +633,13 @@ int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
|
||||
|
||||
if ((cn = dm_config_find_node(reply.cft->root, "physical_volumes")))
|
||||
for (cn = cn->child; cn; cn = cn->sib)
|
||||
_pv_populate_lvmcache(cmd, cn, NULL, 0);
|
||||
_pv_populate_lvmcache(cmd, cn, 0);
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids)
|
||||
{
|
||||
struct vgnameid_list *vgnl;
|
||||
struct id vgid;
|
||||
const char *vgid_txt;
|
||||
const char *vg_name;
|
||||
daemon_reply reply;
|
||||
struct dm_config_node *cn;
|
||||
|
||||
log_debug_lvmetad("Asking lvmetad for complete list of known VG ids/names");
|
||||
reply = _lvmetad_send("vg_list", NULL);
|
||||
if (!_lvmetad_handle_reply(reply, "list VGs", "", NULL)) {
|
||||
daemon_reply_destroy(reply);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if ((cn = dm_config_find_node(reply.cft->root, "volume_groups"))) {
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
vgid_txt = cn->key;
|
||||
if (!id_read_format(&vgid, vgid_txt)) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) {
|
||||
log_error("vgnameid_list allocation failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vg_name = dm_config_find_str(cn->child, "name", NULL))) {
|
||||
log_error("vg_list no name found.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vgnl->vgid = dm_pool_strdup(cmd->mem, (char *)&vgid);
|
||||
vgnl->vg_name = dm_pool_strdup(cmd->mem, vg_name);
|
||||
|
||||
if (!vgnl->vgid || !vgnl->vg_name) {
|
||||
log_error("vgnameid_list member allocation failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_add(vgnameids, &vgnl->list);
|
||||
}
|
||||
}
|
||||
|
||||
daemon_reply_destroy(reply);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
|
||||
{
|
||||
struct volume_group *tmp;
|
||||
@@ -999,9 +893,7 @@ struct _lvmetad_pvscan_baton {
|
||||
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);
|
||||
struct volume_group *this = mda->ops->vg_read(b->fid, "", mda, 1);
|
||||
|
||||
/* FIXME Also ensure contents match etc. */
|
||||
if (!b->vg || this->seqno > b->vg->seqno)
|
||||
@@ -1013,7 +905,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
activation_handler handler, int ignore_obsolete)
|
||||
activation_handler handler)
|
||||
{
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
@@ -1042,16 +934,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
goto_bad;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
if (ignore_obsolete)
|
||||
log_warn("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
else
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
|
||||
if (ignore_obsolete)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1064,7 +949,7 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
* can scan further devices.
|
||||
*/
|
||||
if (!baton.vg && !(baton.fid->fmt->features & FMT_MDAS))
|
||||
baton.vg = ((struct metadata_area *) dm_list_first(&baton.fid->metadata_areas_in_use))->ops->vg_read(baton.fid, lvmcache_vgname_from_info(info), NULL, NULL, NULL, 1);
|
||||
baton.vg = ((struct metadata_area *) dm_list_first(&baton.fid->metadata_areas_in_use))->ops->vg_read(baton.fid, lvmcache_vgname_from_info(info), NULL, 1);
|
||||
|
||||
if (!baton.vg)
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
@@ -1090,8 +975,7 @@ bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
|
||||
int ignore_obsolete)
|
||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
@@ -1133,7 +1017,7 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
|
||||
stack;
|
||||
break;
|
||||
}
|
||||
if (!lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete))
|
||||
if (!lvmetad_pvscan_single(cmd, dev, handler))
|
||||
r = 0;
|
||||
}
|
||||
|
||||
@@ -1148,32 +1032,3 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
|
||||
return r;
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler)
|
||||
{
|
||||
return _lvmetad_pvscan_all_devs(cmd, handler, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME Implement this function, skipping PVs known to belong to local or clustered,
|
||||
* non-exported VGs.
|
||||
*/
|
||||
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
32
lib/cache/lvmetad.h
vendored
32
lib/cache/lvmetad.h
vendored
@@ -29,14 +29,15 @@ typedef int (*activation_handler) (struct cmd_context *cmd,
|
||||
|
||||
#ifdef LVMETAD_SUPPORT
|
||||
/*
|
||||
* Sets up a global handle for our process.
|
||||
* Initialise the communication with lvmetad. Normally called by
|
||||
* lvmcache_init. Sets up a global handle for our process.
|
||||
*/
|
||||
void lvmetad_init(struct cmd_context *);
|
||||
|
||||
/*
|
||||
* Override the use of lvmetad for retrieving scan results and metadata.
|
||||
*/
|
||||
void lvmetad_set_active(struct cmd_context *, int);
|
||||
void lvmetad_set_active(int);
|
||||
|
||||
/*
|
||||
* Configure the socket that lvmetad_init will use to connect to the daemon.
|
||||
@@ -58,9 +59,7 @@ int lvmetad_socket_present(void);
|
||||
|
||||
/*
|
||||
* Check whether lvmetad is active (where active means both that it is running
|
||||
* and that we have a working connection with it). It opens new connection
|
||||
* with lvmetad in the process when lvmetad is supposed to be used and the
|
||||
* connection is not open yet.
|
||||
* and that we have a working connection with it).
|
||||
*/
|
||||
int lvmetad_active(void);
|
||||
|
||||
@@ -71,9 +70,8 @@ int lvmetad_active(void);
|
||||
void lvmetad_connect_or_warn(void);
|
||||
|
||||
/*
|
||||
* Drop connection to lvmetad. A subsequent lvmetad_connect_or_warn or
|
||||
* lvmetad_active will re-establish the connection (possibly at a
|
||||
* different socket path).
|
||||
* Drop connection to lvmetad. A subsequent lvmetad_init() will re-establish
|
||||
* the connection (possibly at a different socket path).
|
||||
*/
|
||||
void lvmetad_disconnect(void);
|
||||
|
||||
@@ -144,12 +142,6 @@ int lvmetad_pv_lookup_by_dev(struct cmd_context *cmd, struct device *dev, int *f
|
||||
*/
|
||||
int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd);
|
||||
|
||||
/*
|
||||
* Request a list of vgid/vgname pairs for all VGs known to lvmetad.
|
||||
* Does not do vg_lookup's on each VG, and does not populate lvmcache.
|
||||
*/
|
||||
int lvmetad_get_vgnameids(struct cmd_context *cmd, struct dm_list *vgnameids);
|
||||
|
||||
/*
|
||||
* Find a VG by its ID or its name in the lvmetad cache. Gives NULL if the VG is
|
||||
* not found.
|
||||
@@ -161,18 +153,15 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
|
||||
* Scan a single device and update lvmetad with the result(s).
|
||||
*/
|
||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
activation_handler handler, int ignore_obsolete);
|
||||
activation_handler handler);
|
||||
|
||||
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);
|
||||
|
||||
# else /* LVMETAD_SUPPORT */
|
||||
|
||||
# define lvmetad_init(cmd) do { } while (0)
|
||||
# define lvmetad_disconnect() do { } while (0)
|
||||
# define lvmetad_set_active(cmd, a) do { } while (0)
|
||||
# define lvmetad_set_active(a) do { } while (0)
|
||||
# define lvmetad_set_socket(a) do { } while (0)
|
||||
# define lvmetad_used() (0)
|
||||
# define lvmetad_socket_present() (0)
|
||||
@@ -189,12 +178,9 @@ int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
|
||||
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
|
||||
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
||||
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
||||
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
|
||||
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
|
||||
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
|
||||
# define lvmetad_pvscan_single(cmd, dev, handler) (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)
|
||||
|
||||
# endif /* LVMETAD_SUPPORT */
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "text_export.h"
|
||||
#include "config.h"
|
||||
#include "str_list.h"
|
||||
#include "targets.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
#include "metadata.h"
|
||||
@@ -30,13 +31,20 @@
|
||||
dm_config_parent_name(sn), seg->lv->name), 0;
|
||||
|
||||
|
||||
static const char *_name(const struct lv_segment *seg)
|
||||
{
|
||||
return seg->segtype->name;
|
||||
}
|
||||
|
||||
static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
const struct dm_config_node *sn,
|
||||
struct dm_hash_table *pv_hash __attribute__((unused)))
|
||||
{
|
||||
uint32_t chunk_size;
|
||||
struct logical_volume *data_lv, *meta_lv;
|
||||
const char *str = NULL;
|
||||
struct dm_pool *mem = seg->lv->vg->vgmem;
|
||||
char *argv_str;
|
||||
struct dm_pool *mem = seg->lv->vg->vgmem; //FIXME: what mempool should be used?
|
||||
|
||||
if (!dm_config_has_node(sn, "data"))
|
||||
return SEG_LOG_ERROR("Cache data not specified in");
|
||||
@@ -44,7 +52,7 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("Cache data must be a string in");
|
||||
if (!(data_lv = find_lv(seg->lv->vg, str)))
|
||||
return SEG_LOG_ERROR("Unknown logical volume %s specified for "
|
||||
"cache data in", str);
|
||||
"cache data in", str);
|
||||
|
||||
if (!dm_config_has_node(sn, "metadata"))
|
||||
return SEG_LOG_ERROR("Cache metadata not specified in");
|
||||
@@ -52,64 +60,101 @@ static int _cache_pool_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("Cache metadata must be a string in");
|
||||
if (!(meta_lv = find_lv(seg->lv->vg, str)))
|
||||
return SEG_LOG_ERROR("Unknown logical volume %s specified for "
|
||||
"cache metadata in", str);
|
||||
"cache metadata in", str);
|
||||
|
||||
if (!dm_config_get_uint32(sn, "chunk_size", &seg->chunk_size))
|
||||
if (!dm_config_get_uint32(sn, "chunk_size", &chunk_size))
|
||||
return SEG_LOG_ERROR("Couldn't read cache chunk_size in");
|
||||
|
||||
/*
|
||||
* Read in features:
|
||||
* cache_mode = {passthrough|writethrough|writeback}
|
||||
* cache_mode = {writethrough|writeback}
|
||||
*
|
||||
* 'cache_mode' does not have to be present.
|
||||
*/
|
||||
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 (!get_cache_mode(str, &seg->feature_flags))
|
||||
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:
|
||||
* policy_settings {
|
||||
* migration_threshold=2048
|
||||
* sequention_threashold=100
|
||||
* random_threashold=200
|
||||
* read_promote_adjustment=10
|
||||
* write_promote_adjustment=20
|
||||
* discard_promote_adjustment=40
|
||||
* Read in core arguments (these are key/value pairs)
|
||||
* core_argc = <# args>
|
||||
* core_argv = "[<key> <value>]..."
|
||||
*
|
||||
* <key> = <value>
|
||||
* <key> = <value>
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* If the policy is not present, default policy is used.
|
||||
* 'core_argc' does not have to be present. If it is not present,
|
||||
* any other core_* fields are ignored. If it is present, then
|
||||
* 'core_argv' must be present - even if they are
|
||||
* 'core_argc = 0' and 'core_argv = ""'.
|
||||
*/
|
||||
if ((sn = dm_config_find_node(sn, "policy_settings"))) {
|
||||
if (sn->v)
|
||||
return SEG_LOG_ERROR("policy_settings must be a section in");
|
||||
if (dm_config_has_node(sn, "core_argc")) {
|
||||
if (!dm_config_has_node(sn, "core_argv"))
|
||||
return SEG_LOG_ERROR("not all core arguments defined in");
|
||||
|
||||
if (!(seg->policy_settings = dm_config_clone_node_with_mem(mem, sn, 0)))
|
||||
if (!dm_config_get_uint32(sn, "core_argc", &seg->core_argc))
|
||||
return SEG_LOG_ERROR("Unable to read core_argc in");
|
||||
|
||||
str = dm_config_find_str(sn, "core_argv", NULL);
|
||||
if ((str && !seg->core_argc) || (!str && seg->core_argc))
|
||||
return SEG_LOG_ERROR("core_argc and core_argv do"
|
||||
" not match in");
|
||||
|
||||
if (!(seg->core_argv =
|
||||
dm_pool_alloc(mem, sizeof(char *) * seg->core_argc)))
|
||||
return_0;
|
||||
if (str &&
|
||||
(!(argv_str = dm_pool_strdup(mem, str)) ||
|
||||
((int)seg->core_argc != dm_split_words(argv_str, seg->core_argc,
|
||||
0, (char **) seg->core_argv))))
|
||||
return SEG_LOG_ERROR("core_argc and core_argv do"
|
||||
" not match in");
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in policy:
|
||||
* policy_name = "<policy_name>"
|
||||
* policy_argc = <# args>
|
||||
* policy_argv = "[<key> <value>]..."
|
||||
*
|
||||
* 'policy_name' does not have to be present. If it is not present,
|
||||
* any other policy_* fields are ignored. If it is present, then
|
||||
* the other policy_* fields must be present - even if they are
|
||||
* 'policy_argc = 0' and 'policy_argv = ""'.
|
||||
*/
|
||||
if (dm_config_has_node(sn, "policy_name")) {
|
||||
if (!dm_config_has_node(sn, "policy_argc") ||
|
||||
!dm_config_has_node(sn, "policy_argv"))
|
||||
return SEG_LOG_ERROR("not all policy arguments defined in");
|
||||
if (!(str = dm_config_find_str(sn, "policy_name", NULL)))
|
||||
return SEG_LOG_ERROR("policy_name must be a string in");
|
||||
seg->policy_name = dm_pool_strdup(mem, str);
|
||||
|
||||
if (!dm_config_get_uint32(sn, "policy_argc", &seg->policy_argc))
|
||||
return SEG_LOG_ERROR("Unable to read policy_argc in");
|
||||
|
||||
str = dm_config_find_str(sn, "policy_argv", NULL);
|
||||
if ((str && !seg->policy_argc) || (!str && seg->policy_argc))
|
||||
return SEG_LOG_ERROR("policy_argc and policy_argv do"
|
||||
" not match in");
|
||||
|
||||
if (!(seg->policy_argv =
|
||||
dm_pool_alloc(mem, sizeof(char *) * seg->policy_argc)))
|
||||
return_0;
|
||||
if (str &&
|
||||
(!(argv_str = dm_pool_strdup(mem, str)) ||
|
||||
((int)seg->policy_argc != dm_split_words(argv_str,
|
||||
seg->policy_argc,
|
||||
0, (char **) seg->policy_argv))))
|
||||
return SEG_LOG_ERROR("policy_argc and policy_argv do"
|
||||
" not match in");
|
||||
}
|
||||
|
||||
if (!attach_pool_data_lv(seg, data_lv))
|
||||
return_0;
|
||||
if (!attach_pool_metadata_lv(seg, meta_lv))
|
||||
return_0;
|
||||
seg->chunk_size = chunk_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -125,26 +170,43 @@ static int _cache_pool_text_import_area_count(const struct dm_config_node *sn,
|
||||
static int _cache_pool_text_export(const struct lv_segment *seg,
|
||||
struct formatter *f)
|
||||
{
|
||||
const char *cache_mode;
|
||||
|
||||
if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
|
||||
return_0;
|
||||
unsigned i;
|
||||
char buf[256]; //FIXME: IS THERE AN 'outf' THAT DOESN'T DO NEWLINE?!?
|
||||
uint32_t feature_flags = seg->feature_flags;
|
||||
|
||||
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)
|
||||
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);
|
||||
if (feature_flags) {
|
||||
if (feature_flags & DM_CACHE_FEATURE_WRITETHROUGH) {
|
||||
outf(f, "cache_mode = \"writethrough\"");
|
||||
feature_flags &= ~DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
} else if (feature_flags & DM_CACHE_FEATURE_WRITEBACK) {
|
||||
outf(f, "cache_mode = \"writeback\"");
|
||||
feature_flags &= ~DM_CACHE_FEATURE_WRITEBACK;
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "Unknown feature flags "
|
||||
"in cache_pool segment for %s", seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
out_config_node(f, seg->policy_settings);
|
||||
}
|
||||
|
||||
if (seg->core_argc) {
|
||||
outf(f, "core_argc = %u", seg->core_argc);
|
||||
outf(f, "core_argv = \"");
|
||||
for (i = 0; i < seg->core_argc; i++)
|
||||
outf(f, "%s%s", i ? " " : "", seg->core_argv[i]);
|
||||
outf(f, "\"");
|
||||
}
|
||||
|
||||
if (seg->policy_name) {
|
||||
outf(f, "policy_name = \"%s\"", seg->policy_name);
|
||||
outf(f, "policy_argc = %u", seg->policy_argc);
|
||||
buf[0] = '\0';
|
||||
for (i = 0; i < seg->policy_argc; i++)
|
||||
sprintf(buf, "%s%s", i ? " " : "", seg->policy_argv[i]);
|
||||
outf(f, "policy_argv = \"%s\"", buf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -200,6 +262,7 @@ static int _modules_needed(struct dm_pool *mem,
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
static struct segtype_handler _cache_pool_ops = {
|
||||
.name = _name,
|
||||
.text_import = _cache_pool_text_import,
|
||||
.text_import_area_count = _cache_pool_text_import_area_count,
|
||||
.text_export = _cache_pool_text_export,
|
||||
@@ -217,7 +280,7 @@ static int _cache_text_import(struct lv_segment *seg,
|
||||
struct dm_hash_table *pv_hash __attribute__((unused)))
|
||||
{
|
||||
struct logical_volume *pool_lv, *origin_lv;
|
||||
const char *name;
|
||||
const char *name = NULL;
|
||||
|
||||
if (!dm_config_has_node(sn, "cache_pool"))
|
||||
return SEG_LOG_ERROR("cache_pool not specified in");
|
||||
@@ -225,7 +288,7 @@ static int _cache_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("cache_pool must be a string in");
|
||||
if (!(pool_lv = find_lv(seg->lv->vg, name)))
|
||||
return SEG_LOG_ERROR("Unknown logical volume %s specified for "
|
||||
"cache_pool in", name);
|
||||
"cache_pool in", name);
|
||||
|
||||
if (!dm_config_has_node(sn, "origin"))
|
||||
return SEG_LOG_ERROR("Cache origin not specified in");
|
||||
@@ -233,17 +296,10 @@ static int _cache_text_import(struct lv_segment *seg,
|
||||
return SEG_LOG_ERROR("Cache origin must be a string in");
|
||||
if (!(origin_lv = find_lv(seg->lv->vg, name)))
|
||||
return SEG_LOG_ERROR("Unknown logical volume %s specified for "
|
||||
"cache origin in", name);
|
||||
"cache origin in", name);
|
||||
|
||||
if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
|
||||
return_0;
|
||||
|
||||
seg->cleaner_policy = 0;
|
||||
if (dm_config_has_node(sn, "cleaner") &&
|
||||
!dm_config_get_uint32(sn, "cleaner", &seg->cleaner_policy))
|
||||
return SEG_LOG_ERROR("Could not read cache cleaner in");
|
||||
|
||||
seg->lv->status |= strstr(seg->lv->name, "_corig") ? LV_PENDING_DELETE : 0;
|
||||
|
||||
if (!attach_pool_lv(seg, pool_lv, NULL, NULL))
|
||||
return_0;
|
||||
|
||||
@@ -266,9 +322,6 @@ static int _cache_text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
outf(f, "cache_pool = \"%s\"", seg->pool_lv->name);
|
||||
outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name);
|
||||
|
||||
if (seg->cleaner_policy)
|
||||
outf(f, "cleaner = 1");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -282,16 +335,9 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
struct dm_tree_node *node, uint64_t len,
|
||||
uint32_t *pvmove_mirror_count __attribute__((unused)))
|
||||
{
|
||||
struct lv_segment *cache_pool_seg;
|
||||
struct lv_segment *cache_pool_seg = first_seg(seg->pool_lv);
|
||||
char *metadata_uuid, *data_uuid, *origin_uuid;
|
||||
|
||||
if (!seg->pool_lv || !seg_is_cache(seg)) {
|
||||
log_error(INTERNAL_ERROR "Passed segment is not cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cache_pool_seg = first_seg(seg->pool_lv);
|
||||
|
||||
if (!(metadata_uuid = build_dm_uuid(mem, cache_pool_seg->metadata_lv, NULL)))
|
||||
return_0;
|
||||
|
||||
@@ -302,20 +348,24 @@ static int _cache_add_target_line(struct dev_manager *dm,
|
||||
return_0;
|
||||
|
||||
if (!dm_tree_node_add_cache_target(node, len,
|
||||
cache_pool_seg->feature_flags,
|
||||
metadata_uuid,
|
||||
data_uuid,
|
||||
origin_uuid,
|
||||
seg->cleaner_policy ? "cleaner" : cache_pool_seg->policy_name,
|
||||
seg->cleaner_policy ? NULL : cache_pool_seg->policy_settings,
|
||||
cache_pool_seg->chunk_size))
|
||||
cache_pool_seg->chunk_size,
|
||||
cache_pool_seg->feature_flags,
|
||||
cache_pool_seg->core_argc,
|
||||
cache_pool_seg->core_argv,
|
||||
cache_pool_seg->policy_name,
|
||||
cache_pool_seg->policy_argc,
|
||||
cache_pool_seg->policy_argv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
return add_areas_line(dm, seg, node, 0u, seg->area_count);
|
||||
}
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
static struct segtype_handler _cache_ops = {
|
||||
.name = _name,
|
||||
.text_import = _cache_text_import,
|
||||
.text_import_area_count = _cache_text_import_area_count,
|
||||
.text_export = _cache_text_export,
|
||||
@@ -345,10 +395,12 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
log_error("Failed to allocate memory for cache_pool segtype");
|
||||
return 0;
|
||||
}
|
||||
segtype->cmd = cmd;
|
||||
|
||||
segtype->name = "cache-pool";
|
||||
segtype->flags = SEG_CACHE_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->flags = SEG_CACHE_POOL;
|
||||
segtype->ops = &_cache_pool_ops;
|
||||
segtype->private = NULL;
|
||||
|
||||
if (!lvm_register_segtype(seglib, segtype))
|
||||
return_0;
|
||||
@@ -359,10 +411,12 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
log_error("Failed to allocate memory for cache segtype");
|
||||
return 0;
|
||||
}
|
||||
segtype->cmd = cmd;
|
||||
|
||||
segtype->name = "cache";
|
||||
segtype->flags = SEG_CACHE | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->flags = SEG_CACHE;
|
||||
segtype->ops = &_cache_ops;
|
||||
segtype->private = NULL;
|
||||
|
||||
if (!lvm_register_segtype(seglib, segtype))
|
||||
return_0;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "lvmcache.h"
|
||||
#include "lvmetad.h"
|
||||
#include "archiver.h"
|
||||
#include "lvmpolld-client.h"
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
#include "sharedlib.h"
|
||||
@@ -56,128 +55,6 @@
|
||||
|
||||
static const size_t linebuffer_size = 4096;
|
||||
|
||||
/*
|
||||
* Copy the input string, removing invalid characters.
|
||||
*/
|
||||
const char *system_id_from_string(struct cmd_context *cmd, const char *str)
|
||||
{
|
||||
char *system_id;
|
||||
|
||||
if (!str || !*str) {
|
||||
log_warn("WARNING: Empty system ID supplied.");
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!(system_id = dm_pool_zalloc(cmd->libmem, strlen(str) + 1))) {
|
||||
log_warn("WARNING: Failed to allocate system ID.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy_systemid_chars(str, system_id);
|
||||
|
||||
if (!*system_id) {
|
||||
log_warn("WARNING: Invalid system ID format: %s", str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strncmp(system_id, "localhost", 9)) {
|
||||
log_warn("WARNING: system ID may not begin with the string \"localhost\".");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return system_id;
|
||||
}
|
||||
|
||||
static const char *_read_system_id_from_file(struct cmd_context *cmd, const char *file)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t line_size;
|
||||
char *start, *end;
|
||||
const char *system_id = NULL;
|
||||
FILE *fp;
|
||||
|
||||
if (!file || !strlen(file) || !file[0])
|
||||
return_NULL;
|
||||
|
||||
if (!(fp = fopen(file, "r"))) {
|
||||
log_warn("WARNING: %s: fopen failed: %s", file, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (getline(&line, &line_size, fp) > 0) {
|
||||
start = line;
|
||||
|
||||
/* Ignore leading whitespace */
|
||||
while (*start && isspace(*start))
|
||||
start++;
|
||||
|
||||
/* Ignore rest of line after # */
|
||||
if (!*start || *start == '#')
|
||||
continue;
|
||||
|
||||
if (system_id && *system_id) {
|
||||
log_warn("WARNING: Ignoring extra line(s) in system ID file %s.", file);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Remove any comments from end of line */
|
||||
for (end = start; *end; end++)
|
||||
if (*end == '#') {
|
||||
*end = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
system_id = system_id_from_string(cmd, start);
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
|
||||
return system_id;
|
||||
}
|
||||
|
||||
static const char *_system_id_from_source(struct cmd_context *cmd, const char *source)
|
||||
{
|
||||
char filebuf[PATH_MAX];
|
||||
const char *file;
|
||||
const char *etc_str;
|
||||
const char *str;
|
||||
const char *system_id = NULL;
|
||||
|
||||
if (!strcasecmp(source, "uname")) {
|
||||
if (cmd->hostname)
|
||||
system_id = system_id_from_string(cmd, cmd->hostname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* lvm.conf and lvmlocal.conf are merged into one config tree */
|
||||
if (!strcasecmp(source, "lvmlocal")) {
|
||||
if ((str = find_config_tree_str(cmd, local_system_id_CFG, NULL)))
|
||||
system_id = system_id_from_string(cmd, str);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strcasecmp(source, "machineid") || !strcasecmp(source, "machine-id")) {
|
||||
etc_str = find_config_tree_str(cmd, global_etc_CFG, NULL);
|
||||
if (dm_snprintf(filebuf, sizeof(filebuf), "%s/machine-id", etc_str) != -1)
|
||||
system_id = _read_system_id_from_file(cmd, filebuf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strcasecmp(source, "file")) {
|
||||
file = find_config_tree_str(cmd, global_system_id_file_CFG, NULL);
|
||||
system_id = _read_system_id_from_file(cmd, file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_warn("WARNING: Unrecognised system_id_source \"%s\".", source);
|
||||
|
||||
out:
|
||||
return system_id;
|
||||
}
|
||||
|
||||
static int _get_env_vars(struct cmd_context *cmd)
|
||||
{
|
||||
const char *e;
|
||||
@@ -274,8 +151,6 @@ static int _parse_debug_classes(struct cmd_context *cmd)
|
||||
debug_classes |= LOG_CLASS_CACHE;
|
||||
else if (!strcasecmp(cv->v.str, "locking"))
|
||||
debug_classes |= LOG_CLASS_LOCKING;
|
||||
else if (!strcasecmp(cv->v.str, "lvmpolld"))
|
||||
debug_classes |= LOG_CLASS_LVMPOLLD;
|
||||
else
|
||||
log_verbose("Unrecognised value for log/debug_classes: %s", cv->v.str);
|
||||
}
|
||||
@@ -413,8 +288,7 @@ static int _check_config(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int process_profilable_config(struct cmd_context *cmd)
|
||||
{
|
||||
int process_profilable_config(struct cmd_context *cmd) {
|
||||
if (!(cmd->default_settings.unit_factor =
|
||||
dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL),
|
||||
&cmd->default_settings.unit_type, 1, NULL))) {
|
||||
@@ -430,55 +304,15 @@ int process_profilable_config(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_system_id(struct cmd_context *cmd)
|
||||
{
|
||||
const char *source, *system_id;
|
||||
int local_set = 0;
|
||||
|
||||
cmd->system_id = NULL;
|
||||
cmd->unknown_system_id = 0;
|
||||
|
||||
system_id = find_config_tree_str_allow_empty(cmd, local_system_id_CFG, NULL);
|
||||
if (system_id && *system_id)
|
||||
local_set = 1;
|
||||
|
||||
source = find_config_tree_str(cmd, global_system_id_source_CFG, NULL);
|
||||
if (!source)
|
||||
source = "none";
|
||||
|
||||
/* Defining local system_id but not using it is probably a config mistake. */
|
||||
if (local_set && strcmp(source, "lvmlocal"))
|
||||
log_warn("WARNING: local/system_id is set, so should global/system_id_source be \"lvmlocal\" not \"%s\"?", source);
|
||||
|
||||
if (!strcmp(source, "none"))
|
||||
return 1;
|
||||
|
||||
if ((system_id = _system_id_from_source(cmd, source)) && *system_id) {
|
||||
cmd->system_id = system_id;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The source failed to resolve a system_id. In this case allow
|
||||
* VGs with no system_id to be accessed, but not VGs with a system_id.
|
||||
*/
|
||||
log_warn("WARNING: No system ID found from system_id_source %s.", source);
|
||||
cmd->unknown_system_id = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
const char *dev_ext_info_src;
|
||||
const char *read_ahead;
|
||||
struct stat st;
|
||||
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];
|
||||
|
||||
@@ -506,16 +340,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return_0;
|
||||
#endif
|
||||
|
||||
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
|
||||
if (!strcmp(dev_ext_info_src, "none"))
|
||||
init_external_device_info_source(DEV_EXT_NONE);
|
||||
else if (!strcmp(dev_ext_info_src, "udev"))
|
||||
init_external_device_info_source(DEV_EXT_UDEV);
|
||||
else {
|
||||
log_error("Invalid external device info source specification.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* proc dir */
|
||||
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
|
||||
@@ -622,7 +446,6 @@ static int _process_config(struct cmd_context *cmd)
|
||||
(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)
|
||||
@@ -640,22 +463,12 @@ static int _process_config(struct cmd_context *cmd)
|
||||
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);
|
||||
lvmetad_set_active(0);
|
||||
} else
|
||||
lvmetad_set_active(NULL, find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL));
|
||||
lvmetad_set_active(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;
|
||||
}
|
||||
|
||||
@@ -713,12 +526,11 @@ static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
|
||||
const char *tag;
|
||||
int passes;
|
||||
|
||||
/* Access tags section directly */
|
||||
if (!(tn = find_config_node(cmd, cft, tags_CFG_SECTION)) || !tn->child)
|
||||
if (!(tn = find_config_tree_node(cmd, tags_CFG_SECTION, NULL)) || !tn->child)
|
||||
return 1;
|
||||
|
||||
/* NB hosttags 0 when already 1 intentionally does not delete the tag */
|
||||
if (!cmd->hosttags && find_config_bool(cmd, cft, tags_hosttags_CFG)) {
|
||||
if (!cmd->hosttags && find_config_tree_bool(cmd, tags_hosttags_CFG, NULL)) {
|
||||
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
||||
if (!_set_tag(cmd, cmd->hostname))
|
||||
return_0;
|
||||
@@ -749,7 +561,7 @@ static int _init_tags(struct cmd_context *cmd, struct dm_config_tree *cft)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _load_config_file(struct cmd_context *cmd, const char *tag, int local)
|
||||
static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
{
|
||||
static char config_file[PATH_MAX] = "";
|
||||
const char *filler = "";
|
||||
@@ -757,10 +569,6 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag, int local
|
||||
|
||||
if (*tag)
|
||||
filler = "_";
|
||||
else if (local) {
|
||||
filler = "";
|
||||
tag = "local";
|
||||
}
|
||||
|
||||
if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||
cmd->system_dir, filler, tag) < 0) {
|
||||
@@ -788,9 +596,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag, int local
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and read lvm.conf.
|
||||
*/
|
||||
/* Find and read first config file */
|
||||
static int _init_lvm_conf(struct cmd_context *cmd)
|
||||
{
|
||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||
@@ -802,7 +608,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_load_config_file(cmd, "", 0))
|
||||
if (!_load_config_file(cmd, ""))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -815,7 +621,7 @@ static int _init_tag_configs(struct cmd_context *cmd)
|
||||
|
||||
/* Tag list may grow while inside this loop */
|
||||
dm_list_iterate_items(sl, &cmd->tags) {
|
||||
if (!_load_config_file(cmd, sl->str, 0))
|
||||
if (!_load_config_file(cmd, sl->str))
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -1029,9 +835,9 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAX_FILTERS 8
|
||||
#define MAX_FILTERS 6
|
||||
|
||||
static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
{
|
||||
int nr_filt = 0;
|
||||
const struct dm_config_node *cn;
|
||||
@@ -1070,15 +876,6 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/* usable device filter. Required. */
|
||||
if (!(filters[nr_filt] = usable_filter_create(cmd->dev_types,
|
||||
lvmetad_used() ? FILTER_MODE_PRE_LVMETAD
|
||||
: FILTER_MODE_NO_LVMETAD))) {
|
||||
log_error("Failed to create usabled device filter");
|
||||
goto bad;
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/* mpath component filter. Optional, non-critical. */
|
||||
if (find_config_tree_bool(cmd, devices_multipath_component_detection_CFG, NULL)) {
|
||||
if ((filters[nr_filt] = mpath_filter_create(cmd->dev_types)))
|
||||
@@ -1099,14 +896,7 @@ static struct dev_filter *_init_lvmetad_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* firmware raid filter. Optional, non-critical. */
|
||||
if (find_config_tree_bool(cmd, devices_fw_raid_component_detection_CFG, NULL)) {
|
||||
init_fwraid_filtering(1);
|
||||
if ((filters[nr_filt] = fwraid_filter_create(cmd->dev_types)))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
if (!(composite = composite_filter_create(nr_filt, 1, filters)))
|
||||
if (!(composite = composite_filter_create(nr_filt, filters)))
|
||||
goto_bad;
|
||||
|
||||
return composite;
|
||||
@@ -1118,99 +908,39 @@ bad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The way the filtering is initialized depends on whether lvmetad is uesd or not.
|
||||
*
|
||||
* If lvmetad is used, there are three filter chains:
|
||||
*
|
||||
* - cmd->lvmetad_filter - the lvmetad filter chain used when scanning devs for lvmetad update:
|
||||
* sysfs filter -> global regex filter -> type filter ->
|
||||
* usable device filter(FILTER_MODE_PRE_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter ->
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
* - cmd->filter - the filter chain used for lvmetad responses:
|
||||
* persistent filter -> usable device filter(FILTER_MODE_POST_LVMETAD) ->
|
||||
* regex filter
|
||||
*
|
||||
* - cmd->full_filter - the filter chain used for all the remaining situations:
|
||||
* lvmetad_filter -> filter
|
||||
*
|
||||
* If lvmetad isnot used, there's just one filter chain:
|
||||
*
|
||||
* - cmd->filter == cmd->full_filter:
|
||||
* persistent filter -> regex filter -> sysfs filter ->
|
||||
* global regex filter -> type filter ->
|
||||
* usable device filter(FILTER_MODE_NO_LVMETAD) ->
|
||||
* mpath component filter -> partitioned filter ->
|
||||
* md component filter -> fw raid filter
|
||||
*
|
||||
*/
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
struct dev_filter *filter = NULL, *filter_components[2] = {0};
|
||||
struct dev_filter *f3 = NULL, *f4 = NULL, *toplevel_components[2] = { 0 };
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
struct timespec ts, cts;
|
||||
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
cmd->lvmetad_filter = _init_lvmetad_filter_chain(cmd);
|
||||
if (!cmd->lvmetad_filter)
|
||||
if (!(cmd->lvmetad_filter = _init_filter_components(cmd)))
|
||||
goto_bad;
|
||||
|
||||
init_ignore_suspended_devices(find_config_tree_bool(cmd, devices_ignore_suspended_devices_CFG, NULL));
|
||||
init_ignore_lvm_mirrors(find_config_tree_bool(cmd, devices_ignore_lvm_mirrors_CFG, NULL));
|
||||
|
||||
/*
|
||||
* If lvmetad is used, there's a separation between pre-lvmetad filter chain
|
||||
* ("cmd->lvmetad_filter") applied only if scanning for lvmetad update and
|
||||
* post-lvmetad filter chain ("filter") applied on each lvmetad response.
|
||||
* However, if lvmetad is not used, these two chains are not separated
|
||||
* and we use exactly one filter chain during device scanning ("filter"
|
||||
* that includes also "cmd->lvmetad_filter" chain).
|
||||
*/
|
||||
/* filter component 0 */
|
||||
if (lvmetad_used()) {
|
||||
if (!(filter_components[0] = usable_filter_create(cmd->dev_types, FILTER_MODE_POST_LVMETAD))) {
|
||||
log_verbose("Failed to create usable device filter.");
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
cmd->lvmetad_filter = NULL;
|
||||
}
|
||||
|
||||
/* filter component 1 */
|
||||
if ((cn = find_config_tree_node(cmd, devices_filter_CFG, NULL))) {
|
||||
if (!(filter_components[1] = regex_filter_create(cn->v)))
|
||||
if (!(f3 = regex_filter_create(cn->v)))
|
||||
goto_bad;
|
||||
/* we have two filter components - create composite filter */
|
||||
if (!(filter = composite_filter_create(2, 0, filter_components)))
|
||||
toplevel_components[0] = cmd->lvmetad_filter;
|
||||
toplevel_components[1] = f3;
|
||||
if (!(f4 = composite_filter_create(2, toplevel_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
/* we have only one filter component - no need to create composite filter */
|
||||
filter = filter_components[0];
|
||||
f4 = cmd->lvmetad_filter;
|
||||
|
||||
if (!(dev_cache = find_config_tree_str(cmd, devices_cache_CFG, NULL)))
|
||||
goto_bad;
|
||||
|
||||
if (!(filter = persistent_filter_create(cmd->dev_types, filter, dev_cache))) {
|
||||
if (!(cmd->filter = persistent_filter_create(cmd->dev_types, f4, dev_cache))) {
|
||||
log_verbose("Failed to create persistent device filter.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
cmd->filter = filter;
|
||||
|
||||
if (lvmetad_used()) {
|
||||
filter_components[0] = cmd->lvmetad_filter;
|
||||
filter_components[1] = cmd->filter;
|
||||
if (!(cmd->full_filter = composite_filter_create(2, 0, filter_components)))
|
||||
goto_bad;
|
||||
} else
|
||||
cmd->full_filter = filter;
|
||||
|
||||
/* Should we ever dump persistent filter state? */
|
||||
if (find_config_tree_bool(cmd, devices_write_cache_state_CFG, NULL))
|
||||
cmd->dump_filter = 1;
|
||||
@@ -1225,38 +955,22 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
|
||||
*/
|
||||
if (!find_config_tree_bool(cmd, global_use_lvmetad_CFG, NULL) &&
|
||||
load_persistent_cache && !cmd->is_long_lived &&
|
||||
!stat(dev_cache, &st)) {
|
||||
lvm_stat_ctim(&ts, &st);
|
||||
cts = config_file_timestamp(cmd->cft);
|
||||
if (timespeccmp(&ts, &cts, >) &&
|
||||
!persistent_filter_load(cmd->filter, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
}
|
||||
!stat(dev_cache, &st) &&
|
||||
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(cmd->filter, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
if (!filter) {
|
||||
/*
|
||||
* composite filter not created - destroy
|
||||
* each component directly
|
||||
*/
|
||||
if (filter_components[0])
|
||||
filter_components[0]->destroy(filter_components[0]);
|
||||
if (filter_components[1])
|
||||
filter_components[1]->destroy(filter_components[1]);
|
||||
} else {
|
||||
/*
|
||||
* composite filter created - destroy it - this
|
||||
* will also destroy any of its components
|
||||
*/
|
||||
filter->destroy(filter);
|
||||
if (f4) /* kills both f3 and cmd->lvmetad_filter */
|
||||
f4->destroy(f4);
|
||||
else {
|
||||
if (f3)
|
||||
f3->destroy(f3);
|
||||
if (cmd->lvmetad_filter)
|
||||
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
|
||||
}
|
||||
|
||||
/* if lvmetad is used, the cmd->lvmetad_filter is separate */
|
||||
if (cmd->lvmetad_filter)
|
||||
cmd->lvmetad_filter->destroy(cmd->lvmetad_filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1379,6 +1093,7 @@ int lvm_register_segtype(struct segtype_library *seglib,
|
||||
struct segment_type *segtype2;
|
||||
|
||||
segtype->library = seglib->lib;
|
||||
segtype->cmd = seglib->cmd;
|
||||
|
||||
dm_list_iterate_items(segtype2, &seglib->cmd->segtypes) {
|
||||
if (strcmp(segtype2->name, segtype->name))
|
||||
@@ -1422,7 +1137,7 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
init_striped_segtype,
|
||||
init_zero_segtype,
|
||||
init_error_segtype,
|
||||
/* disabled until needed init_free_segtype, */
|
||||
init_free_segtype,
|
||||
#ifdef SNAPSHOT_INTERNAL
|
||||
init_snapshot_segtype,
|
||||
#endif
|
||||
@@ -1755,10 +1470,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (!_init_tags(cmd, cmd->cft))
|
||||
goto_out;
|
||||
|
||||
/* Load lvmlocal.conf */
|
||||
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
|
||||
goto_out;
|
||||
|
||||
if (!_init_tag_configs(cmd))
|
||||
goto_out;
|
||||
|
||||
@@ -1870,19 +1581,17 @@ static void _destroy_dev_types(struct cmd_context *cmd)
|
||||
cmd->dev_types = NULL;
|
||||
}
|
||||
|
||||
static void _destroy_filters(struct cmd_context *cmd)
|
||||
{
|
||||
if (cmd->full_filter) {
|
||||
cmd->full_filter->destroy(cmd->full_filter);
|
||||
cmd->lvmetad_filter = cmd->filter = cmd->full_filter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int refresh_filters(struct cmd_context *cmd)
|
||||
{
|
||||
int r, saved_ignore_suspended_devices = ignore_suspended_devices();
|
||||
|
||||
_destroy_filters(cmd);
|
||||
if (cmd->filter) {
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
cmd->filter = NULL;
|
||||
}
|
||||
|
||||
cmd->lvmetad_filter = NULL;
|
||||
|
||||
if (!(r = _init_filters(cmd, 0)))
|
||||
stack;
|
||||
|
||||
@@ -1912,8 +1621,10 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
_destroy_filters(cmd);
|
||||
|
||||
if (cmd->filter) {
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
cmd->filter = NULL;
|
||||
}
|
||||
if (!dev_cache_exit())
|
||||
stack;
|
||||
_destroy_dev_types(cmd);
|
||||
@@ -1963,10 +1674,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_tags(cmd, cft_tmp))
|
||||
return_0;
|
||||
|
||||
/* Load lvmlocal.conf */
|
||||
if (*cmd->system_dir && !_load_config_file(cmd, "", 1))
|
||||
return_0;
|
||||
|
||||
/* Doesn't change cmd->cft */
|
||||
if (!_init_tag_configs(cmd))
|
||||
return_0;
|
||||
@@ -2030,7 +1737,8 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
label_exit();
|
||||
_destroy_segtypes(&cmd->segtypes);
|
||||
_destroy_formats(cmd, &cmd->formats);
|
||||
_destroy_filters(cmd);
|
||||
if (cmd->filter)
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
if (cmd->mem)
|
||||
dm_pool_destroy(cmd->mem);
|
||||
dev_cache_exit();
|
||||
@@ -2077,7 +1785,6 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
|
||||
lvmetad_release_token();
|
||||
lvmetad_disconnect();
|
||||
lvmpolld_disconnect();
|
||||
|
||||
release_log_memory();
|
||||
activation_exit();
|
||||
|
||||
@@ -71,7 +71,6 @@ struct cmd_context {
|
||||
|
||||
struct dm_list formats; /* Available formats */
|
||||
struct dm_list segtypes; /* Available segment types */
|
||||
const char *system_id;
|
||||
const char *hostname;
|
||||
const char *kernel_vsn;
|
||||
|
||||
@@ -96,29 +95,10 @@ struct cmd_context {
|
||||
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;
|
||||
|
||||
/*
|
||||
* Use of filters depends on whether lvmetad is used or not:
|
||||
*
|
||||
* - if lvmetad is used:
|
||||
* - cmd->lvmetad_filter used when scanning devices for lvmetad
|
||||
* - cmd->filter used when processing lvmetad responses
|
||||
* - cmd->full_filter used for remaining situations
|
||||
*
|
||||
* - if lvmetad is not used:
|
||||
* - cmd->lvmetad_filter is NULL
|
||||
* - cmd->filter == cmd->full_filter used for all situations
|
||||
*
|
||||
*/
|
||||
struct dev_filter *lvmetad_filter;
|
||||
struct dev_filter *filter;
|
||||
struct dev_filter *full_filter;
|
||||
struct dev_filter *lvmetad_filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
|
||||
struct dm_list config_files; /* master lvm config + any existing tag configs */
|
||||
@@ -165,6 +145,4 @@ int init_lvmcache_orphans(struct cmd_context *cmd);
|
||||
|
||||
struct format_type *get_format_by_name(struct cmd_context *cmd, const char *format);
|
||||
|
||||
const char *system_id_from_string(struct cmd_context *cmd, const char *str);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ struct config_file {
|
||||
|
||||
struct config_source {
|
||||
config_source_t type;
|
||||
struct timespec timestamp;
|
||||
time_t timestamp;
|
||||
union {
|
||||
struct config_file *file;
|
||||
struct config_file *profile;
|
||||
@@ -65,11 +65,11 @@ struct config_source {
|
||||
* Map each ID to respective definition of the configuration item.
|
||||
*/
|
||||
static struct cfg_def_item _cfg_def_items[CFG_COUNT + 1] = {
|
||||
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, {0}, deprecated_since_version, deprecation_comment, comment},
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, {.v_UNCONFIGURED = unconfigured_value}, deprecated_since_version, deprecation_comment, comment},
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, {.v_UNCONFIGURED = unconfigured_value}, deprecated_since_version, deprecation_comment, comment},
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, {.fn_UNCONFIGURED = get_default_unconfigured_##id}, deprecated_since_version, deprecation_comment, comment},
|
||||
#define cfg_section(id, name, parent, flags, since_version, comment) {id, parent, name, CFG_TYPE_SECTION, {0}, flags, since_version, comment},
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, comment) {id, parent, name, type, {.v_##type = default_value}, flags, since_version, comment},
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, comment) {id, parent, name, type, {.fn_##type = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, comment},
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.v_CFG_TYPE_STRING = default_value}, flags, since_version, comment},
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, comment) {id, parent, name, CFG_TYPE_ARRAY | types, {.fn_CFG_TYPE_STRING = get_default_##id}, flags | CFG_DEFAULT_RUN_TIME, since_version, comment},
|
||||
#include "config_settings.h"
|
||||
#undef cfg_section
|
||||
#undef cfg
|
||||
@@ -173,7 +173,7 @@ int config_file_check(struct dm_config_tree *cft, const char **filename, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvm_stat_ctim(&cs->timestamp, info);
|
||||
cs->timestamp = info->st_ctime;
|
||||
cf->exists = 1;
|
||||
cf->st_size = info->st_size;
|
||||
|
||||
@@ -193,7 +193,6 @@ int config_file_changed(struct dm_config_tree *cft)
|
||||
struct config_source *cs = dm_config_get_custom(cft);
|
||||
struct config_file *cf;
|
||||
struct stat info;
|
||||
struct timespec ts;
|
||||
|
||||
if (cs->type != CONFIG_FILE) {
|
||||
log_error(INTERNAL_ERROR "config_file_changed: expected file config source, "
|
||||
@@ -227,9 +226,7 @@ int config_file_changed(struct dm_config_tree *cft)
|
||||
}
|
||||
|
||||
/* Unchanged? */
|
||||
lvm_stat_ctim(&ts, &info);
|
||||
if ((timespeccmp(&cs->timestamp, &ts, ==)) &&
|
||||
cf->st_size == info.st_size)
|
||||
if (cs->timestamp == info.st_ctime && cf->st_size == info.st_size)
|
||||
return 0;
|
||||
|
||||
reload:
|
||||
@@ -481,15 +478,9 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When checksum_only is set, the checksum of buffer is only matched
|
||||
* and function avoids parsing of mda into config tree which
|
||||
* remains unmodified and should not be used.
|
||||
*/
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
int checksum_only)
|
||||
checksum_fn_t checksum_fn, uint32_t checksum)
|
||||
{
|
||||
char *fb, *fe;
|
||||
int r = 0;
|
||||
@@ -538,11 +529,9 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!checksum_only) {
|
||||
fe = fb + size + size2;
|
||||
if (!dm_config_parse(cft, fb, fe))
|
||||
goto_out;
|
||||
}
|
||||
fe = fb + size + size2;
|
||||
if (!dm_config_parse(cft, fb, fe))
|
||||
goto_out;
|
||||
|
||||
r = 1;
|
||||
|
||||
@@ -586,7 +575,7 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
}
|
||||
|
||||
r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0, 0);
|
||||
(checksum_fn_t) NULL, 0);
|
||||
|
||||
if (!cf->keep_open) {
|
||||
if (!dev_close(cf->dev))
|
||||
@@ -597,14 +586,13 @@ int config_file_read(struct dm_config_tree *cft)
|
||||
return r;
|
||||
}
|
||||
|
||||
struct timespec config_file_timestamp(struct dm_config_tree *cft)
|
||||
time_t config_file_timestamp(struct dm_config_tree *cft)
|
||||
{
|
||||
struct config_source *cs = dm_config_get_custom(cft);
|
||||
return cs->timestamp;
|
||||
}
|
||||
|
||||
#define cfg_def_get_item_p(id) (&_cfg_def_items[id])
|
||||
#define cfg_def_get_default_unconfigured_value_hint(cmd,item) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_unconfigured_value.fn_UNCONFIGURED(cmd) : item->default_unconfigured_value.v_UNCONFIGURED)
|
||||
#define cfg_def_get_default_value_hint(cmd,item,type,profile) ((item->flags & CFG_DEFAULT_RUN_TIME) ? item->default_value.fn_##type(cmd,profile) : item->default_value.v_##type)
|
||||
#define cfg_def_get_default_value(cmd,item,type,profile) (item->flags & CFG_DEFAULT_UNDEFINED ? 0 : cfg_def_get_default_value_hint(cmd,item,type,profile))
|
||||
|
||||
@@ -661,8 +649,8 @@ static void _log_type_error(const char *path, cfg_def_type_t actual,
|
||||
_get_type_name(actual_type_name, sizeof(actual_type_name), actual);
|
||||
_get_type_name(expected_type_name, sizeof(expected_type_name), expected);
|
||||
|
||||
log_warn_suppress(suppress_messages, "WARNING: Configuration setting \"%s\" has invalid type. "
|
||||
"Found%s but expected%s.", path,
|
||||
log_warn_suppress(suppress_messages, "Configuration setting \"%s\" has invalid type. "
|
||||
"Found%s, expected%s.", path,
|
||||
actual_type_name, expected_type_name);
|
||||
}
|
||||
|
||||
@@ -802,11 +790,6 @@ static int _config_def_check_node_single_value(struct cft_check_handle *handle,
|
||||
} else if (!(def->type & CFG_TYPE_STRING)) {
|
||||
_log_type_error(rp, CFG_TYPE_STRING, def->type, handle->suppress_messages);
|
||||
return 0;
|
||||
} else if (!(def->flags & CFG_ALLOW_EMPTY) && !*v->v.str) {
|
||||
log_warn_suppress(handle->suppress_messages,
|
||||
"Configuration setting \"%s\" invalid. "
|
||||
"It cannot be set to an empty value.", rp);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default: ;
|
||||
@@ -826,12 +809,6 @@ static int _check_value_differs_from_default(struct cft_check_handle *handle,
|
||||
float f;
|
||||
const char *str;
|
||||
|
||||
if ((handle->ignoreunsupported && (def->flags & CFG_UNSUPPORTED)) ||
|
||||
(handle->ignoreadvanced && (def->flags & CFG_ADVANCED))) {
|
||||
diff = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if default value is undefined, the value used differs from default */
|
||||
if (def->flags & CFG_DEFAULT_UNDEFINED) {
|
||||
diff = 1;
|
||||
@@ -1163,29 +1140,6 @@ static int _apply_local_profile(struct cmd_context *cmd, struct profile *profile
|
||||
return override_config_tree_from_profile(cmd, profile);
|
||||
}
|
||||
|
||||
static int _config_disabled(struct cmd_context *cmd, cfg_def_item_t *item, const char *path)
|
||||
{
|
||||
if ((item->flags & CFG_DISABLED) && dm_config_tree_find_node(cmd->cft, path)) {
|
||||
log_warn("WARNING: Configuration setting %s is disabled. Using default value.", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dm_config_node *find_config_node(struct cmd_context *cmd, struct dm_config_tree *cft, int id)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
const struct dm_config_node *cn;
|
||||
|
||||
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||
|
||||
cn = dm_config_tree_find_node(cft, path);
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
const struct dm_config_node *find_config_tree_node(struct cmd_context *cmd, int id, struct profile *profile)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
@@ -1217,8 +1171,7 @@ const char *find_config_tree_str(struct cmd_context *cmd, int id, struct profile
|
||||
if (item->type != CFG_TYPE_STRING)
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as string.", path);
|
||||
|
||||
str = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile)
|
||||
: dm_config_tree_find_str(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
||||
str = dm_config_tree_find_str(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1241,8 +1194,7 @@ const char *find_config_tree_str_allow_empty(struct cmd_context *cmd, int id, st
|
||||
if (!(item->flags & CFG_ALLOW_EMPTY))
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared to allow empty values.", path);
|
||||
|
||||
str = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile)
|
||||
: dm_config_tree_find_str_allow_empty(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
||||
str = dm_config_tree_find_str_allow_empty(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_STRING, profile));
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1263,8 +1215,7 @@ int find_config_tree_int(struct cmd_context *cmd, int id, struct profile *profil
|
||||
if (item->type != CFG_TYPE_INT)
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
|
||||
|
||||
i = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile)
|
||||
: dm_config_tree_find_int(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
||||
i = dm_config_tree_find_int(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1285,8 +1236,7 @@ int64_t find_config_tree_int64(struct cmd_context *cmd, int id, struct profile *
|
||||
if (item->type != CFG_TYPE_INT)
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as integer.", path);
|
||||
|
||||
i64 = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile)
|
||||
: dm_config_tree_find_int64(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
||||
i64 = dm_config_tree_find_int64(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_INT, profile));
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1307,8 +1257,7 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
|
||||
if (item->type != CFG_TYPE_FLOAT)
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as float.", path);
|
||||
|
||||
f = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile)
|
||||
: dm_config_tree_find_float(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile));
|
||||
f = dm_config_tree_find_float(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_FLOAT, profile));
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1316,23 +1265,6 @@ float find_config_tree_float(struct cmd_context *cmd, int id, struct profile *pr
|
||||
return f;
|
||||
}
|
||||
|
||||
int find_config_bool(struct cmd_context *cmd, struct dm_config_tree *cft, int id)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
int b;
|
||||
|
||||
_cfg_def_make_path(path, sizeof(path), item->id, item, 0);
|
||||
|
||||
if (item->type != CFG_TYPE_BOOL)
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
|
||||
|
||||
b = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL)
|
||||
: dm_config_tree_find_bool(cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, NULL));
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profile)
|
||||
{
|
||||
cfg_def_item_t *item = cfg_def_get_item_p(id);
|
||||
@@ -1346,8 +1278,7 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
||||
if (item->type != CFG_TYPE_BOOL)
|
||||
log_error(INTERNAL_ERROR "%s cfg tree element not declared as boolean.", path);
|
||||
|
||||
b = _config_disabled(cmd, item, path) ? cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile)
|
||||
: dm_config_tree_find_bool(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile));
|
||||
b = dm_config_tree_find_bool(cmd->cft, path, cfg_def_get_default_value(cmd, item, CFG_TYPE_BOOL, profile));
|
||||
|
||||
if (profile_applied)
|
||||
remove_config_tree_by_source(cmd, profile->source);
|
||||
@@ -1483,7 +1414,7 @@ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
||||
cs = dm_config_get_custom(cft);
|
||||
csn = dm_config_get_custom(newdata);
|
||||
|
||||
if (cs && csn && timespeccmp(&cs->timestamp, &csn->timestamp, <))
|
||||
if (cs && csn && (cs->timestamp < csn->timestamp))
|
||||
cs->timestamp = csn->timestamp;
|
||||
|
||||
return 1;
|
||||
@@ -1495,55 +1426,6 @@ struct out_baton {
|
||||
struct dm_pool *mem;
|
||||
};
|
||||
|
||||
#define MAX_COMMENT_LINE 512
|
||||
|
||||
static int _copy_one_line(const char *comment, char *line, int *pos, int len)
|
||||
{
|
||||
int p;
|
||||
int i = 0;
|
||||
char c;
|
||||
|
||||
if (*pos >= len)
|
||||
return 0;
|
||||
|
||||
memset(line, 0, MAX_COMMENT_LINE+1);
|
||||
|
||||
for (p = *pos; ; p++) {
|
||||
c = comment[p];
|
||||
|
||||
(*pos)++;
|
||||
|
||||
if (c == '\n' || c == '\0')
|
||||
break;
|
||||
|
||||
line[i++] = c;
|
||||
|
||||
if (i == MAX_COMMENT_LINE)
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int _get_config_node_version(uint16_t version_enc, char *version)
|
||||
{
|
||||
if (dm_snprintf(version, 9, "%u.%u.%u",
|
||||
(version_enc & 0xE000) >> 13,
|
||||
(version_enc & 0x1E00) >> 9,
|
||||
(version_enc & 0x1FF)) == -1) {
|
||||
log_error("_get_config_node_version: couldn't create version string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _def_node_is_deprecated(cfg_def_item_t *def, struct config_def_tree_spec *spec)
|
||||
{
|
||||
return def->deprecated_since_version &&
|
||||
(spec->version >= def->deprecated_since_version);
|
||||
}
|
||||
|
||||
static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
||||
{
|
||||
struct out_baton *out = baton;
|
||||
@@ -1551,7 +1433,7 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
char version[9]; /* 8+1 chars for max version of 7.15.511 */
|
||||
const char *node_type_name = cn->v ? "option" : "section";
|
||||
char path[CFG_PATH_MAX_LEN];
|
||||
char commentline[MAX_COMMENT_LINE+1];
|
||||
|
||||
|
||||
if (cn->id < 0)
|
||||
return 1;
|
||||
@@ -1561,36 +1443,18 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out->tree_spec->type == CFG_DEF_TREE_LIST)
|
||||
return 1;
|
||||
|
||||
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
|
||||
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
|
||||
return 1;
|
||||
|
||||
cfg_def = cfg_def_get_item_p(cn->id);
|
||||
|
||||
if (out->tree_spec->withsummary || out->tree_spec->withcomments) {
|
||||
if (out->tree_spec->withcomments) {
|
||||
_cfg_def_make_path(path, sizeof(path), cfg_def->id, cfg_def, 1);
|
||||
fprintf(out->fp, "\n");
|
||||
fprintf(out->fp, "%s# Configuration %s %s.\n", line, node_type_name, path);
|
||||
|
||||
if (out->tree_spec->withcomments &&
|
||||
_def_node_is_deprecated(cfg_def, out->tree_spec))
|
||||
fprintf(out->fp, "%s# %s", line, cfg_def->deprecation_comment);
|
||||
|
||||
if (cfg_def->comment) {
|
||||
int pos = 0;
|
||||
while (_copy_one_line(cfg_def->comment, commentline, &pos, strlen(cfg_def->comment))) {
|
||||
fprintf(out->fp, "%s# %s\n", line, commentline);
|
||||
/* withsummary prints only the first comment line. */
|
||||
if (!out->tree_spec->withcomments)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_def_node_is_deprecated(cfg_def, out->tree_spec))
|
||||
fprintf(out->fp, "%s# This configuration %s is deprecated.\n", line, node_type_name);
|
||||
if (cfg_def->comment)
|
||||
fprintf(out->fp, "%s# %s\n", line, cfg_def->comment);
|
||||
|
||||
if (cfg_def->flags & CFG_ADVANCED)
|
||||
fprintf(out->fp, "%s# This configuration %s is advanced.\n", line, node_type_name);
|
||||
@@ -1606,15 +1470,14 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
}
|
||||
|
||||
if (out->tree_spec->withversions) {
|
||||
if (!_get_config_node_version(cfg_def->since_version, version))
|
||||
return_0;
|
||||
fprintf(out->fp, "%s# Available since version %s.\n", line, version);
|
||||
|
||||
if (_def_node_is_deprecated(cfg_def, out->tree_spec)) {
|
||||
if (!_get_config_node_version(cfg_def->deprecated_since_version, version))
|
||||
return_0;
|
||||
fprintf(out->fp, "%s# Deprecated since version %s.\n", line, version);
|
||||
if (dm_snprintf(version, 9, "%u.%u.%u",
|
||||
(cfg_def->since_version & 0xE000) >> 13,
|
||||
(cfg_def->since_version & 0x1E00) >> 9,
|
||||
(cfg_def->since_version & 0x1FF)) == -1) {
|
||||
log_error("_out_prefix_fn: couldn't create version string");
|
||||
return 0;
|
||||
}
|
||||
fprintf(out->fp, "%s# Since version %s.\n", line, version);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1623,55 +1486,15 @@ static int _out_prefix_fn(const struct dm_config_node *cn, const char *line, voi
|
||||
static int _out_line_fn(const struct dm_config_node *cn, const char *line, void *baton)
|
||||
{
|
||||
struct out_baton *out = baton;
|
||||
struct cfg_def_item *cfg_def;
|
||||
char config_path[CFG_PATH_MAX_LEN];
|
||||
char summary[MAX_COMMENT_LINE+1];
|
||||
char version[9];
|
||||
int pos = 0;
|
||||
size_t len;
|
||||
char *space_prefix;
|
||||
struct cfg_def_item *cfg_def = cfg_def_get_item_p(cn->id);
|
||||
|
||||
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
|
||||
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
|
||||
return 1;
|
||||
|
||||
cfg_def = cfg_def_get_item_p(cn->id);
|
||||
|
||||
if (out->tree_spec->type == CFG_DEF_TREE_LIST) {
|
||||
/* List view with node paths and summary. */
|
||||
if (cfg_def->type & CFG_TYPE_SECTION)
|
||||
return 1;
|
||||
if (!_cfg_def_make_path(config_path, CFG_PATH_MAX_LEN, cfg_def->id, cfg_def, 1))
|
||||
return_0;
|
||||
if (out->tree_spec->withversions && !_get_config_node_version(cfg_def->since_version, version))
|
||||
return_0;
|
||||
|
||||
summary[0] = '\0';
|
||||
if (out->tree_spec->withsummary && cfg_def->comment)
|
||||
_copy_one_line(cfg_def->comment, summary, &pos, strlen(cfg_def->comment));
|
||||
|
||||
fprintf(out->fp, "%s%s%s%s%s%s%s\n", config_path,
|
||||
*summary || out->tree_spec->withversions ? " - ": "",
|
||||
*summary ? summary : "",
|
||||
*summary ? " " : "",
|
||||
out->tree_spec->withversions ? "[" : "",
|
||||
out->tree_spec->withversions ? version : "",
|
||||
out->tree_spec->withversions ? "]" : "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Usual tree view with nodes and their values. */
|
||||
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
|
||||
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
|
||||
(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
|
||||
fprintf(out->fp, "%s\n", line);
|
||||
|
||||
fprintf(out->fp, "%s%s\n", (out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
|
||||
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
|
||||
(cfg_def->flags & CFG_DEFAULT_UNDEFINED) ? "#" : "", line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1752,10 +1575,7 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
|
||||
cn->id = def->id;
|
||||
|
||||
if (spec->unconfigured && def->default_unconfigured_value.v_UNCONFIGURED) {
|
||||
cn->v->type = DM_CFG_STRING;
|
||||
cn->v->v.str = cfg_def_get_default_unconfigured_value_hint(spec->cmd, def);
|
||||
} else if (!(def->type & CFG_TYPE_ARRAY)) {
|
||||
if (!(def->type & CFG_TYPE_ARRAY)) {
|
||||
switch (def->type) {
|
||||
case CFG_TYPE_SECTION:
|
||||
cn->v = NULL;
|
||||
@@ -1800,11 +1620,6 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft,
|
||||
return cn;
|
||||
}
|
||||
|
||||
static int _should_skip_deprecated_def_node(cfg_def_item_t *def, struct config_def_tree_spec *spec)
|
||||
{
|
||||
return spec->ignoredeprecated && _def_node_is_deprecated(def, spec);
|
||||
}
|
||||
|
||||
static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_id, int id)
|
||||
{
|
||||
cfg_def_item_t *def = cfg_def_get_item_p(id);
|
||||
@@ -1824,21 +1639,18 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
||||
}
|
||||
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->since_version > spec->version))
|
||||
return 1;
|
||||
break;
|
||||
case CFG_DEF_TREE_NEW:
|
||||
if ((def->since_version != spec->version) ||
|
||||
_should_skip_deprecated_def_node(def, spec))
|
||||
if (def->since_version != spec->version)
|
||||
return 1;
|
||||
break;
|
||||
case CFG_DEF_TREE_PROFILABLE:
|
||||
case CFG_DEF_TREE_PROFILABLE_CMD:
|
||||
case CFG_DEF_TREE_PROFILABLE_MDA:
|
||||
if (!(def->flags & CFG_PROFILABLE) ||
|
||||
(def->since_version > spec->version) ||
|
||||
_should_skip_deprecated_def_node(def, spec))
|
||||
(def->since_version > spec->version))
|
||||
return 1;
|
||||
flags = def->flags & ~CFG_PROFILABLE;
|
||||
if (spec->type == CFG_DEF_TREE_PROFILABLE_CMD) {
|
||||
@@ -1850,8 +1662,7 @@ static int _should_skip_def_node(struct config_def_tree_spec *spec, int section_
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ((def->since_version > spec->version) ||
|
||||
_should_skip_deprecated_def_node(def, spec))
|
||||
if (def->since_version > spec->version)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
@@ -1903,9 +1714,6 @@ struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec)
|
||||
if (cfg_def_get_item_p(id)->parent != root_CFG_SECTION)
|
||||
continue;
|
||||
|
||||
if (spec->ignorelocal && (id == local_CFG_SECTION))
|
||||
continue;
|
||||
|
||||
if ((tmp = _add_def_section_subtree(cft, spec, root, relay, id))) {
|
||||
relay = tmp;
|
||||
if (!root)
|
||||
@@ -2093,11 +1901,6 @@ const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct pr
|
||||
return dm_pool_strdup(cmd->mem, buf);
|
||||
}
|
||||
|
||||
const char *get_default_unconfigured_devices_cache_dir_CFG(struct cmd_context *cmd)
|
||||
{
|
||||
return "@DEFAULT_SYS_DIR@/@DEFAULT_CACHE_SUBDIR@";
|
||||
}
|
||||
|
||||
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||
{
|
||||
const char *cache_dir = NULL, *cache_file_prefix = NULL;
|
||||
@@ -2132,24 +1935,6 @@ const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profil
|
||||
return dm_pool_strdup(cmd->mem, buf);
|
||||
}
|
||||
|
||||
const char *get_default_unconfigured_devices_cache_CFG(struct cmd_context *cmd)
|
||||
{
|
||||
const char *cache_file_prefix = NULL;
|
||||
static char buf[PATH_MAX];
|
||||
|
||||
if (find_config_tree_node(cmd, devices_cache_file_prefix_CFG, NULL))
|
||||
cache_file_prefix = find_config_tree_str_allow_empty(cmd, devices_cache_file_prefix_CFG, NULL);
|
||||
|
||||
if (dm_snprintf(buf, sizeof(buf), "%s/%s.cache",
|
||||
get_default_unconfigured_devices_cache_dir_CFG(cmd),
|
||||
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
|
||||
log_error("Persistent cache filename too long.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dm_pool_strdup(cmd->mem, buf);
|
||||
}
|
||||
|
||||
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||
{
|
||||
static char buf[PATH_MAX];
|
||||
@@ -2163,11 +1948,6 @@ const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct pr
|
||||
return dm_pool_strdup(cmd->mem, buf);
|
||||
}
|
||||
|
||||
const char *get_default_unconfigured_backup_backup_dir_CFG(struct cmd_context *cmd)
|
||||
{
|
||||
return "@DEFAULT_SYS_DIR@/@DEFAULT_BACKUP_SUBDIR@";
|
||||
}
|
||||
|
||||
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||
{
|
||||
static char buf[PATH_MAX];
|
||||
@@ -2181,11 +1961,6 @@ const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct p
|
||||
return dm_pool_strdup(cmd->mem, buf);
|
||||
}
|
||||
|
||||
const char *get_default_unconfigured_backup_archive_dir_CFG(struct cmd_context *cmd)
|
||||
{
|
||||
return "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@";
|
||||
}
|
||||
|
||||
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||
{
|
||||
static char buf[PATH_MAX];
|
||||
@@ -2199,11 +1974,6 @@ const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct p
|
||||
return dm_pool_strdup(cmd->mem, buf);
|
||||
}
|
||||
|
||||
const char *get_default_unconfigured_config_profile_dir_CFG(struct cmd_context *cmd)
|
||||
{
|
||||
return "@DEFAULT_SYS_DIR@/@DEFAULT_PROFILE_SUBDIR@";
|
||||
}
|
||||
|
||||
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile)
|
||||
{
|
||||
return find_config_tree_str(cmd, activation_mirror_device_fault_policy_CFG, profile);
|
||||
|
||||
@@ -72,7 +72,6 @@ typedef int (*t_fn_CFG_TYPE_INT) (struct cmd_context *cmd, struct profile *profi
|
||||
typedef float (*t_fn_CFG_TYPE_FLOAT) (struct cmd_context *cmd, struct profile *profile);
|
||||
typedef const char* (*t_fn_CFG_TYPE_STRING) (struct cmd_context *cmd, struct profile *profile);
|
||||
typedef const char* (*t_fn_CFG_TYPE_ARRAY) (struct cmd_context *cmd, struct profile *profile);
|
||||
typedef const char* (*t_fn_UNCONFIGURED) (struct cmd_context *cmd);
|
||||
|
||||
/* configuration definition item value (for item's default value) */
|
||||
typedef union {
|
||||
@@ -89,50 +88,37 @@ typedef union {
|
||||
t_fn_CFG_TYPE_ARRAY fn_CFG_TYPE_ARRAY;
|
||||
} cfg_def_value_t;
|
||||
|
||||
typedef union {
|
||||
const char *v_UNCONFIGURED;
|
||||
t_fn_UNCONFIGURED fn_UNCONFIGURED;
|
||||
} cfg_def_unconfigured_value_t;
|
||||
|
||||
/* configuration definition item flags: */
|
||||
|
||||
|
||||
/* whether the configuration item name is variable */
|
||||
#define CFG_NAME_VARIABLE 0x001
|
||||
#define CFG_NAME_VARIABLE 0x01
|
||||
/* whether empty value is allowed */
|
||||
#define CFG_ALLOW_EMPTY 0x002
|
||||
#define CFG_ALLOW_EMPTY 0x02
|
||||
/* whether the configuration item is for advanced use only */
|
||||
#define CFG_ADVANCED 0x004
|
||||
#define CFG_ADVANCED 0x04
|
||||
/* whether the configuration item is not officially supported */
|
||||
#define CFG_UNSUPPORTED 0x008
|
||||
#define CFG_UNSUPPORTED 0x08
|
||||
/* whether the configuration item is customizable by a profile */
|
||||
#define CFG_PROFILABLE 0x010
|
||||
#define CFG_PROFILABLE 0x10
|
||||
/* whether the configuration item is customizable by a profile */
|
||||
/* and whether it can be attached to VG/LV metadata at the same time
|
||||
* The CFG_PROFILABLE_METADATA flag incorporates CFG_PROFILABLE flag!!! */
|
||||
#define CFG_PROFILABLE_METADATA 0x030
|
||||
#define CFG_PROFILABLE_METADATA 0x30
|
||||
/* whether the default value is undefned */
|
||||
#define CFG_DEFAULT_UNDEFINED 0x040
|
||||
/* whether the default value is commented out on output */
|
||||
#define CFG_DEFAULT_COMMENTED 0x080
|
||||
/* whether the default value is calculated during run time */
|
||||
#define CFG_DEFAULT_RUN_TIME 0x100
|
||||
/* whether the configuration setting is disabled (and hence defaults always used) */
|
||||
#define CFG_DISABLED 0x200
|
||||
#define CFG_DEFAULT_UNDEFINED 0x40
|
||||
/* whether the defualt value is calculated during run time */
|
||||
#define CFG_DEFAULT_RUN_TIME 0x80
|
||||
|
||||
/* configuration definition item structure */
|
||||
typedef struct cfg_def_item {
|
||||
int id; /* ID of this item */
|
||||
int parent; /* ID of parent item */
|
||||
const char *name; /* name of the item in configuration tree */
|
||||
int type; /* configuration item type (bits of cfg_def_type_t) */
|
||||
cfg_def_value_t default_value; /* default value (only for settings) */
|
||||
uint16_t flags; /* configuration item definition flags */
|
||||
uint16_t since_version; /* version this item appeared in */
|
||||
cfg_def_unconfigured_value_t default_unconfigured_value; /* default value in terms of @FOO@, pre-configured (only for settings) */
|
||||
uint16_t deprecated_since_version; /* version since this item is deprecated */
|
||||
const char *deprecation_comment; /* comment about reasons for deprecation and settings that supersede this one */
|
||||
const char *comment; /* comment */
|
||||
int id; /* ID of this item */
|
||||
int parent; /* ID of parent item */
|
||||
const char *name; /* name of the item in configuration tree */
|
||||
int type; /* configuration item type (bits of cfg_def_type_t) */
|
||||
cfg_def_value_t default_value; /* default value (only for settings) */
|
||||
uint16_t flags; /* configuration item definition flags */
|
||||
uint16_t since_version; /* version this item appeared in */
|
||||
const char *comment; /* brief comment */
|
||||
} cfg_def_item_t;
|
||||
|
||||
/* configuration definition tree types */
|
||||
@@ -146,7 +132,6 @@ typedef enum {
|
||||
CFG_DEF_TREE_PROFILABLE_CMD, /* tree of all nodes that are customizable by command profiles (subset of PROFILABLE) */
|
||||
CFG_DEF_TREE_PROFILABLE_MDA, /* tree of all nodes that are customizable by metadata profiles (subset of PROFILABLE) */
|
||||
CFG_DEF_TREE_DIFF, /* tree of all nodes that differ from defaults */
|
||||
CFG_DEF_TREE_LIST, /* list all nodes */
|
||||
} cfg_def_tree_t;
|
||||
|
||||
/* configuration definition tree specification */
|
||||
@@ -154,14 +139,10 @@ 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 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 */
|
||||
unsigned withcomments:1; /* include comments */
|
||||
unsigned withversions:1; /* include versions */
|
||||
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
|
||||
};
|
||||
|
||||
@@ -177,11 +158,11 @@ struct config_def_tree_spec {
|
||||
* Register ID for each possible item in the configuration tree.
|
||||
*/
|
||||
enum {
|
||||
#define cfg_section(id, name, parent, flags, since_version, deprecated_since_version, deprecation_comment, comment) id,
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) id,
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment) id,
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_value, deprecated_since_version, deprecation_comment, comment) id,
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, deprecated_since_version, deprecation_comment, comment) id,
|
||||
#define cfg_section(id, name, parent, flags, since_version, comment) id,
|
||||
#define cfg(id, name, parent, flags, type, default_value, since_version, comment) id,
|
||||
#define cfg_runtime(id, name, parent, flags, type, since_version, comment) id,
|
||||
#define cfg_array(id, name, parent, flags, types, default_value, since_version, comment) id,
|
||||
#define cfg_array_runtime(id, name, parent, flags, types, since_version, comment) id,
|
||||
#include "config_settings.h"
|
||||
#undef cfg_section
|
||||
#undef cfg
|
||||
@@ -203,8 +184,6 @@ struct cft_check_handle {
|
||||
unsigned skip_if_checked:1; /* skip the check if already done before - return last state */
|
||||
unsigned suppress_messages:1; /* suppress messages during the check if config item is found invalid */
|
||||
unsigned check_diff:1; /* check if the value used differs from default one */
|
||||
unsigned ignoreadvanced:1; /* do not include advnced configs */
|
||||
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
|
||||
};
|
||||
|
||||
@@ -223,8 +202,7 @@ typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_
|
||||
struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open);
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
int skip_parse);
|
||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||
int config_file_read(struct dm_config_tree *cft);
|
||||
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
|
||||
struct cmd_context *cmd);
|
||||
@@ -233,7 +211,7 @@ int config_write(struct dm_config_tree *cft, struct config_def_tree_spec *tree_s
|
||||
struct dm_config_tree *config_def_create_tree(struct config_def_tree_spec *spec);
|
||||
void config_destroy(struct dm_config_tree *cft);
|
||||
|
||||
struct timespec config_file_timestamp(struct dm_config_tree *cft);
|
||||
time_t config_file_timestamp(struct dm_config_tree *cft);
|
||||
int config_file_changed(struct dm_config_tree *cft);
|
||||
int config_file_check(struct dm_config_tree *cft, const char **filename, struct stat *info);
|
||||
|
||||
@@ -252,12 +230,6 @@ typedef enum {
|
||||
int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft,
|
||||
struct dm_config_tree *newdata, config_merge_t);
|
||||
|
||||
/*
|
||||
* The next two do not check config overrides and must only be used for the tags section.
|
||||
*/
|
||||
const struct dm_config_node *find_config_node(struct cmd_context *cmd, struct dm_config_tree *cft, int id);
|
||||
int find_config_bool(struct cmd_context *cmd, struct dm_config_tree *cft, int id);
|
||||
|
||||
/*
|
||||
* These versions check an override tree, if present, first.
|
||||
*/
|
||||
@@ -274,20 +246,12 @@ int find_config_tree_bool(struct cmd_context *cmd, int id, struct profile *profi
|
||||
* value is evaluated at runtime based on command context.
|
||||
*/
|
||||
const char *get_default_devices_cache_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
const char *get_default_unconfigured_devices_cache_dir_CFG(struct cmd_context *cmd);
|
||||
const char *get_default_devices_cache_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
const char *get_default_unconfigured_devices_cache_CFG(struct cmd_context *cmd);
|
||||
const char *get_default_backup_backup_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
const char *get_default_unconfigured_backup_backup_dir_CFG(struct cmd_context *cmd);
|
||||
const char *get_default_backup_archive_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
const char *get_default_unconfigured_backup_archive_dir_CFG(struct cmd_context *cmd);
|
||||
const char *get_default_config_profile_dir_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
const char *get_default_unconfigured_config_profile_dir_CFG(struct cmd_context *cmd);
|
||||
const char *get_default_activation_mirror_image_fault_policy_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_activation_mirror_image_fault_policy_CFG NULL
|
||||
int get_default_allocation_thin_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_thin_pool_chunk_size_CFG NULL
|
||||
int get_default_allocation_cache_pool_chunk_size_CFG(struct cmd_context *cmd, struct profile *profile);
|
||||
#define get_default_unconfigured_allocation_cache_pool_chunk_size_CFG NULL
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -29,12 +29,9 @@
|
||||
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSTEM_ID_SOURCE "none"
|
||||
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
|
||||
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_FW_RAID_COMPONENT_DETECTION 0
|
||||
#define DEFAULT_MD_CHUNK_ALIGNMENT 1
|
||||
#define DEFAULT_IGNORE_LVM_MIRRORS 1
|
||||
#define DEFAULT_MULTIPATH_COMPONENT_DETECTION 1
|
||||
@@ -47,7 +44,6 @@
|
||||
#define DEFAULT_PV_MIN_SIZE_KB 2048
|
||||
|
||||
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
||||
#define DEFAULT_ERROR_WHEN_FULL 0
|
||||
#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
|
||||
#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
|
||||
#define DEFAULT_WAIT_FOR_LOCKS 1
|
||||
@@ -56,12 +52,13 @@
|
||||
#define DEFAULT_METADATA_READ_ONLY 0
|
||||
#define DEFAULT_LVDISPLAY_SHOWS_FULL_DEVICE_PATH 0
|
||||
|
||||
#define DEFAULT_MIRRORLOG MIRROR_LOG_DISK
|
||||
#define DEFAULT_MIRROR_SEGTYPE "raid1"
|
||||
#define DEFAULT_MIRRORLOG "disk"
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
#define DEFAULT_RAID10_SEGTYPE "raid10"
|
||||
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
||||
|
||||
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
|
||||
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
|
||||
#define DEFAULT_DMEVENTD_SNAPSHOT_LIB "libdevmapper-event-lvm2snapshot.so"
|
||||
@@ -76,11 +73,9 @@
|
||||
#endif
|
||||
|
||||
#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 "-q --clear-needs-check-flag"
|
||||
#else
|
||||
# define DEFAULT_THIN_CHECK_OPTION1 "-q"
|
||||
# define DEFAULT_THIN_CHECK_OPTION2 ""
|
||||
# define DEFAULT_THIN_CHECK_OPTIONS "-q"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_THIN_REPAIR_OPTIONS ""
|
||||
@@ -95,14 +90,12 @@
|
||||
#define DEFAULT_THIN_POOL_ZERO 1
|
||||
#define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
|
||||
|
||||
#define DEFAULT_CACHE_CHECK_OPTION1 "-q"
|
||||
#define DEFAULT_CACHE_CHECK_OPTIONS "-q"
|
||||
#define DEFAULT_CACHE_REPAIR_OPTIONS ""
|
||||
#define DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
|
||||
#define DEFAULT_CACHE_POOL_CHUNK_SIZE 64 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MIN_METADATA_SIZE 2048 /* KB */
|
||||
#define DEFAULT_CACHE_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024) /* KB */
|
||||
#define DEFAULT_CACHE_POOL_CACHEMODE "writethrough"
|
||||
#define DEFAULT_CACHE_POOL_POLICY "mq"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
@@ -144,8 +137,7 @@
|
||||
|
||||
#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)
|
||||
LOG_CLASS_METADATA | LOG_CLASS_CACHE | LOG_CLASS_LOCKING)
|
||||
|
||||
#define DEFAULT_SYSLOG 1
|
||||
#define DEFAULT_VERBOSE 0
|
||||
@@ -183,7 +175,6 @@
|
||||
|
||||
#define DEFAULT_MAX_ERROR_COUNT NO_DEV_ERROR_COUNT_LIMIT
|
||||
|
||||
#define DEFAULT_REP_COMPACT_OUTPUT 0
|
||||
#define DEFAULT_REP_ALIGNED 1
|
||||
#define DEFAULT_REP_BUFFERED 1
|
||||
#define DEFAULT_REP_COLUMNS_AS_ROWS 0
|
||||
|
||||
@@ -71,21 +71,6 @@ int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str)
|
||||
return str_list_add_no_dup_check(mem, sll, str);
|
||||
}
|
||||
|
||||
/* Add contents of sll2 to sll */
|
||||
int str_list_add_list(struct dm_pool *mem, struct dm_list *sll, struct dm_list *sll2)
|
||||
{
|
||||
struct dm_str_list *sl;
|
||||
|
||||
if (!sll2)
|
||||
return_0;
|
||||
|
||||
dm_list_iterate_items(sl, sll2)
|
||||
if (!str_list_add(mem, sll, sl->str))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void str_list_del(struct dm_list *sll, const char *str)
|
||||
{
|
||||
struct dm_list *slh, *slht;
|
||||
|
||||
@@ -21,7 +21,6 @@ struct dm_pool;
|
||||
|
||||
struct dm_list *str_list_create(struct dm_pool *mem);
|
||||
int str_list_add(struct dm_pool *mem, struct dm_list *sll, const char *str);
|
||||
int str_list_add_list(struct dm_pool *mem, struct dm_list *sll, struct dm_list *sll2);
|
||||
int str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str);
|
||||
int str_list_add_h_no_dup_check(struct dm_pool *mem, struct dm_list *sll, const char *str);
|
||||
void str_list_del(struct dm_list *sll, const char *str);
|
||||
|
||||
@@ -64,9 +64,6 @@ static void _dev_init(struct device *dev, int max_error_count)
|
||||
dev->read_ahead = -1;
|
||||
dev->max_error_count = max_error_count;
|
||||
|
||||
dev->ext.enabled = 0;
|
||||
dev->ext.src = DEV_EXT_NONE;
|
||||
|
||||
dm_list_init(&dev->aliases);
|
||||
dm_list_init(&dev->open_list);
|
||||
}
|
||||
@@ -986,31 +983,12 @@ static struct device *_dev_cache_seek_devt(dev_t dev)
|
||||
*/
|
||||
struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
const char *sysfs_dir;
|
||||
struct stat info;
|
||||
struct device *d = _dev_cache_seek_devt(dev);
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
|
||||
if (!d) {
|
||||
sysfs_dir = dm_sysfs_dir();
|
||||
if (sysfs_dir && *sysfs_dir) {
|
||||
/* First check if dev is sysfs to avoid useless scan */
|
||||
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d",
|
||||
sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) {
|
||||
log_error("dm_snprintf partition failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lstat(path, &info)) {
|
||||
log_debug("No sysfs entry for %d:%d.",
|
||||
(int)MAJOR(dev), (int)MINOR(dev));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_full_scan(0);
|
||||
d = _dev_cache_seek_devt(dev);
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*************************************************************************
|
||||
* Properties saved in udev db and accesible via libudev and used by LVM *
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
* DEV_EXT_UDEV_BLKID_TYPE property with various DEV_EXT_UDEV_BLKID_TYPE_*
|
||||
* values that is saved in udev db via blkid call in udev rules
|
||||
*/
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE "ID_FS_TYPE"
|
||||
/*
|
||||
* mpath_member is forced by multipath - it's set in udev db via
|
||||
* multipath call overwriting any existing ID_FS_TYPE value for
|
||||
* a device which is a multipath component which prevents incorrect
|
||||
* claim of the device by any other block device subsystem
|
||||
*/
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE_MPATH "mpath_member"
|
||||
/* FW RAIDs are all *_raid_member types except linux_raid_member which denotes SW RAID */
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE_RAID_SUFFIX "_raid_member"
|
||||
#define DEV_EXT_UDEV_BLKID_TYPE_SW_RAID "linux_raid_member"
|
||||
#define DEV_EXT_UDEV_BLKID_PART_TABLE_TYPE "ID_PART_TABLE_TYPE"
|
||||
#define DEV_EXT_UDEV_BLKID_PART_ENTRY_DISK "ID_PART_ENTRY_DISK"
|
||||
|
||||
/*
|
||||
* DEV_EXT_UDEV_MPATH_DEVICE_PATH is set by multipath in udev db
|
||||
* with value either 0 or 1. The same functionality as
|
||||
* DEV_EXT_UDEV_BLKID_TYPE_MPATH actually, but introduced later
|
||||
* for some reason.
|
||||
*/
|
||||
#define DEV_EXT_UDEV_MPATH_DEVICE_PATH "DM_MULTIPATH_DEVICE_PATH"
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Sysfs attributes accessible via libudev and used by LVM *
|
||||
***********************************************************/
|
||||
|
||||
/* the value of size sysfs attribute is size in bytes */
|
||||
#define DEV_EXT_UDEV_SYSFS_ATTR_SIZE "size"
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 "device.h"
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#endif
|
||||
|
||||
struct ext_registry_item {
|
||||
const char *name;
|
||||
struct dev_ext *(* dev_ext_get) (struct device *dev);
|
||||
int (*dev_ext_release) (struct device *dev);
|
||||
};
|
||||
|
||||
#define EXT_REGISTER(id,name) [id] = { #name, &_dev_ext_get_ ## name, &_dev_ext_release_ ## name }
|
||||
|
||||
/*
|
||||
* DEV_EXT_NONE
|
||||
*/
|
||||
static struct dev_ext *_dev_ext_get_none(struct device *dev)
|
||||
{
|
||||
dev->ext.handle = NULL;
|
||||
return &dev->ext;
|
||||
}
|
||||
|
||||
static int _dev_ext_release_none(struct device *dev)
|
||||
{
|
||||
dev->ext.handle = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* DEV_EXT_UDEV
|
||||
*/
|
||||
static struct dev_ext *_dev_ext_get_udev(struct device *dev)
|
||||
{
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
struct udev *udev;
|
||||
struct udev_device *udev_device;
|
||||
|
||||
if (dev->ext.handle)
|
||||
return &dev->ext;
|
||||
|
||||
if (!(udev = udev_get_library_context()))
|
||||
return_NULL;
|
||||
|
||||
if (!(udev_device = udev_device_new_from_devnum(udev, 'b', dev->dev)))
|
||||
return_NULL;
|
||||
|
||||
dev->ext.handle = (void *) udev_device;
|
||||
return &dev->ext;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _dev_ext_release_udev(struct device *dev)
|
||||
{
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
if (!dev->ext.handle)
|
||||
return 1;
|
||||
|
||||
/* udev_device_unref can't fail - it has no return value */
|
||||
udev_device_unref((struct udev_device *) dev->ext.handle);
|
||||
dev->ext.handle = NULL;
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct ext_registry_item _ext_registry[DEV_EXT_NUM] = {
|
||||
EXT_REGISTER(DEV_EXT_NONE, none),
|
||||
EXT_REGISTER(DEV_EXT_UDEV, udev)
|
||||
};
|
||||
|
||||
const char *dev_ext_name(struct device *dev)
|
||||
{
|
||||
return _ext_registry[dev->ext.src].name;
|
||||
}
|
||||
|
||||
static const char *_ext_attached_msg = "External handle attached to device";
|
||||
|
||||
struct dev_ext *dev_ext_get(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
void *handle_ptr;
|
||||
|
||||
handle_ptr = dev->ext.handle;
|
||||
|
||||
if (!(ext = _ext_registry[dev->ext.src].dev_ext_get(dev)))
|
||||
log_error("Failed to get external handle for device %s [%s].",
|
||||
dev_name(dev), dev_ext_name(dev));
|
||||
else if (handle_ptr != dev->ext.handle)
|
||||
log_debug_devs("%s %s [%s:%p]", _ext_attached_msg, dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
int dev_ext_release(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
void *handle_ptr;
|
||||
|
||||
if (!dev->ext.enabled ||
|
||||
!dev->ext.handle)
|
||||
return 1;
|
||||
|
||||
handle_ptr = dev->ext.handle;
|
||||
|
||||
if (!(r = _ext_registry[dev->ext.src].dev_ext_release(dev)))
|
||||
log_error("Failed to release external handle for device %s [%s:%p].",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
else
|
||||
log_debug_devs("External handle detached from device %s [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), handle_ptr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_ext_enable(struct device *dev, dev_ext_t src)
|
||||
{
|
||||
if (dev->ext.enabled && (dev->ext.src != src) && !dev_ext_release(dev)) {
|
||||
log_error("Failed to enable external handle for device %s [%s].",
|
||||
dev_name(dev), _ext_registry[src].name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->ext.src = src;
|
||||
dev->ext.enabled = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_ext_disable(struct device *dev)
|
||||
{
|
||||
if (!dev->ext.enabled)
|
||||
return 1;
|
||||
|
||||
if (!dev_ext_release(dev)) {
|
||||
log_error("Failed to disable external handle for device %s [%s].",
|
||||
dev_name(dev), dev_ext_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->ext.enabled = 0;
|
||||
dev->ext.src = DEV_EXT_NONE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -154,7 +154,7 @@ int dev_get_block_size(struct device *dev, unsigned int *physical_block_size, un
|
||||
}
|
||||
log_debug_devs("%s: physical block size is %u bytes", name, dev->phys_block_size);
|
||||
}
|
||||
#elif defined (BLKSSZGET)
|
||||
#elif BLKSSZGET
|
||||
/* if we can't get physical block size, just use logical block size instead */
|
||||
if (dev->phys_block_size == -1) {
|
||||
if (ioctl(dev_fd(dev), BLKSSZGET, &dev->phys_block_size) < 0) {
|
||||
@@ -289,22 +289,25 @@ static int _dev_get_size_file(const struct device *dev, uint64_t *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
int fd;
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl(dev_fd(dev), BLKGETSIZE64, size) < 0) {
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||
if (!dev_close(dev))
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
|
||||
if (!dev_close(dev))
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
|
||||
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
|
||||
@@ -374,7 +377,7 @@ static int _dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64
|
||||
* Public functions
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
int dev_get_size(struct device *dev, uint64_t *size)
|
||||
int dev_get_size(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
@@ -15,11 +15,8 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "dev-type.h"
|
||||
#include "metadata.h"
|
||||
#include "xlate.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h> /* for MD detection using udev db records */
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -85,31 +82,10 @@ static uint64_t _v1_sb_offset(uint64_t size, md_minor_version_t minor_version)
|
||||
return sb_offset;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_md(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!(value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE)))
|
||||
return 0;
|
||||
|
||||
return !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID);
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_md(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns -1 on error
|
||||
*/
|
||||
static int _native_dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
int dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
{
|
||||
int ret = 1;
|
||||
md_minor_version_t minor;
|
||||
@@ -154,27 +130,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_is_md(struct device *dev, uint64_t *offset_found)
|
||||
{
|
||||
|
||||
/*
|
||||
* If non-native device status source is selected, use it
|
||||
* only if offset_found is not requested as this
|
||||
* information is not in udev db.
|
||||
*/
|
||||
if ((dev->ext.src == DEV_EXT_NONE) || offset_found)
|
||||
return _native_dev_is_md(dev, offset_found);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_md(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for MD device recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
|
||||
struct dev_types *dt,
|
||||
struct device *blkdev,
|
||||
|
||||
@@ -25,11 +25,6 @@
|
||||
#include <blkid.h>
|
||||
#endif
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#include "device-types.h"
|
||||
|
||||
struct dev_types *create_dev_types(const char *proc_dir,
|
||||
@@ -117,10 +112,6 @@ struct dev_types *create_dev_types(const char *proc_dir,
|
||||
if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
|
||||
dt->drbd_major = line_maj;
|
||||
|
||||
/* Look for DASD */
|
||||
if (!strncmp("dasd", line + i, 4) && isspace(*(line + i + 4)))
|
||||
dt->dasd_major = line_maj;
|
||||
|
||||
/* Look for EMC powerpath */
|
||||
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
|
||||
dt->emcpower_major = line_maj;
|
||||
@@ -225,18 +216,12 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
|
||||
|
||||
const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
if (MAJOR(dev->dev) == dt->device_mapper_major)
|
||||
return "DM";
|
||||
|
||||
if (MAJOR(dev->dev) == dt->md_major)
|
||||
return "MD";
|
||||
|
||||
if (MAJOR(dev->dev) == dt->drbd_major)
|
||||
return "DRBD";
|
||||
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
return "DASD";
|
||||
|
||||
if (MAJOR(dev->dev) == dt->emcpower_major)
|
||||
return "EMCPOWER";
|
||||
|
||||
@@ -287,9 +272,6 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
int parts = major_max_partitions(dt, MAJOR(dev->dev));
|
||||
|
||||
if (MAJOR(dev->dev) == dt->device_mapper_major)
|
||||
return 1;
|
||||
|
||||
/* All MD devices are partitionable via blkext (as of 2.6.28) */
|
||||
if (MAJOR(dev->dev) == dt->md_major)
|
||||
return 1;
|
||||
@@ -332,66 +314,12 @@ static int _has_partition_table(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_partitioned(struct device *dev)
|
||||
int dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_PART_TABLE_TYPE))
|
||||
return 0;
|
||||
|
||||
if (udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_PART_ENTRY_DISK))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_partitioned(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!_is_partitionable(dt, dev))
|
||||
return 0;
|
||||
|
||||
/* Unpartitioned DASD devices are not supported. */
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
return 1;
|
||||
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: failed to open device, considering device "
|
||||
"is partitioned", dev_name(dev));
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = _has_partition_table(dev);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_partitioned(dt, dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_partitioned(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for partition table recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
return _has_partition_table(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -433,7 +361,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
|
||||
*/
|
||||
if ((parts = dt->dev_type_array[major].max_partitions) > 1) {
|
||||
if ((residue = minor % parts)) {
|
||||
*result = MKDEV((dev_t)major, (dev_t)(minor - residue));
|
||||
*result = MKDEV((dev_t)major, (minor - residue));
|
||||
ret = 2;
|
||||
} else {
|
||||
*result = dev->dev;
|
||||
@@ -510,7 +438,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
|
||||
path, buffer);
|
||||
goto out;
|
||||
}
|
||||
*result = MKDEV((dev_t)major, (dev_t)minor);
|
||||
*result = MKDEV((dev_t)major, minor);
|
||||
ret = 2;
|
||||
out:
|
||||
if (fp && fclose(fp))
|
||||
@@ -532,9 +460,9 @@ 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.";
|
||||
static const char const _msg_failed_offset[] = "Failed to get offset of the %s signature on %s.";
|
||||
static const char const _msg_failed_length[] = "Failed to get length of the %s signature on %s.";
|
||||
static const char const _msg_wiping[] = "Wiping %s signature on %s.";
|
||||
const char *offset = NULL, *type = NULL, *magic = NULL,
|
||||
*usage = NULL, *label = NULL, *uuid = NULL;
|
||||
loff_t offset_value;
|
||||
@@ -542,7 +470,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
|
||||
if (!blkid_probe_lookup_value(probe, "TYPE", &type, NULL)) {
|
||||
if (_type_in_flag_list(type, types_to_exclude))
|
||||
return 2;
|
||||
return 1;
|
||||
if (blkid_probe_lookup_value(probe, "SBMAGIC_OFFSET", &offset, NULL)) {
|
||||
log_error(_msg_failed_offset, type, name);
|
||||
return 0;
|
||||
@@ -598,17 +526,12 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
|
||||
static int _wipe_known_signatures_with_blkid(struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude,
|
||||
uint32_t types_no_prompt,
|
||||
int yes, force_t force, int *wiped)
|
||||
int yes, force_t force)
|
||||
{
|
||||
blkid_probe probe = NULL;
|
||||
int found = 0, left = 0, wiped_tmp;
|
||||
int r_wipe;
|
||||
int found = 0, wiped = 0, left = 0;
|
||||
int r = 0;
|
||||
|
||||
if (!wiped)
|
||||
wiped = &wiped_tmp;
|
||||
*wiped = 0;
|
||||
|
||||
/* TODO: Should we check for valid dev - _dev_is_valid(dev)? */
|
||||
|
||||
if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) {
|
||||
@@ -629,17 +552,15 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
|
||||
while (!blkid_do_probe(probe)) {
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1)
|
||||
(*wiped)++;
|
||||
/* do not count excluded types */
|
||||
if (r_wipe != 2)
|
||||
found++;
|
||||
found++;
|
||||
if (_blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force))
|
||||
wiped++;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
r = 1;
|
||||
|
||||
left = found - *wiped;
|
||||
left = found - wiped;
|
||||
if (!left)
|
||||
r = 1;
|
||||
else
|
||||
@@ -654,7 +575,7 @@ out:
|
||||
#endif /* BLKID_WIPING_SUPPORT */
|
||||
|
||||
static int _wipe_signature(struct device *dev, const char *type, const char *name,
|
||||
int wipe_len, int yes, force_t force, int *wiped,
|
||||
int wipe_len, int yes, force_t force,
|
||||
int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found))
|
||||
{
|
||||
int wipe;
|
||||
@@ -684,24 +605,17 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*wiped)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude __attribute__((unused)),
|
||||
uint32_t types_no_prompt __attribute__((unused)),
|
||||
int yes, force_t force, int *wiped)
|
||||
int yes, force_t force)
|
||||
{
|
||||
int wiped_tmp;
|
||||
|
||||
if (!wiped)
|
||||
wiped = &wiped_tmp;
|
||||
*wiped = 0;
|
||||
|
||||
if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md) ||
|
||||
!_wipe_signature(dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
|
||||
!_wipe_signature(dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
|
||||
if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, dev_is_md) ||
|
||||
!_wipe_signature(dev, "swap signature", name, 10, yes, force, dev_is_swap) ||
|
||||
!_wipe_signature(dev, "LUKS signature", name, 8, yes, force, dev_is_luks))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -709,20 +623,19 @@ static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
|
||||
|
||||
int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
|
||||
const char *name, uint32_t types_to_exclude,
|
||||
uint32_t types_no_prompt, int yes, force_t force,
|
||||
int *wiped)
|
||||
uint32_t types_no_prompt, int yes, force_t force)
|
||||
{
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
if (find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL))
|
||||
return _wipe_known_signatures_with_blkid(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force, wiped);
|
||||
yes, force);
|
||||
#endif
|
||||
return _wipe_known_signatures_with_lvm(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force, wiped);
|
||||
yes, force);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -802,7 +715,7 @@ static unsigned long _dev_topology_attribute(struct dev_types *dt,
|
||||
}
|
||||
|
||||
log_very_verbose("Device %s: %s is %lu%s.",
|
||||
dev_name(dev), attribute, value, default_value ? "" : " bytes");
|
||||
dev_name(dev), attribute, result, default_value ? "" : " bytes");
|
||||
|
||||
result = value >> SECTOR_SHIFT;
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ struct dev_types {
|
||||
int device_mapper_major;
|
||||
int emcpower_major;
|
||||
int power2_major;
|
||||
int dasd_major;
|
||||
struct dev_type_def dev_type_array[NUMBER_OF_MAJORS];
|
||||
};
|
||||
|
||||
@@ -66,7 +65,7 @@ int dev_is_luks(struct device *dev, uint64_t *signature);
|
||||
#define TYPE_DM_SNAPSHOT_COW 0x004
|
||||
int wipe_known_signatures(struct cmd_context *cmd, struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude, uint32_t types_no_prompt,
|
||||
int yes, force_t force, int *wiped);
|
||||
int yes, force_t force);
|
||||
|
||||
/* Type-specific device properties */
|
||||
unsigned long dev_md_stripe_width(struct dev_types *dt, struct device *dev);
|
||||
|
||||
@@ -28,23 +28,6 @@
|
||||
#define DEV_O_DIRECT 0x00000020 /* Use O_DIRECT */
|
||||
#define DEV_O_DIRECT_TESTED 0x00000040 /* DEV_O_DIRECT is reliable */
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
* Any new external device info source needs to be
|
||||
* registered using EXT_REGISTER macro in dev-ext.c.
|
||||
*/
|
||||
typedef enum {
|
||||
DEV_EXT_NONE,
|
||||
DEV_EXT_UDEV,
|
||||
DEV_EXT_NUM
|
||||
} dev_ext_t;
|
||||
|
||||
struct dev_ext {
|
||||
int enabled;
|
||||
dev_ext_t src;
|
||||
void *handle;
|
||||
};
|
||||
|
||||
/*
|
||||
* All devices in LVM will be represented by one of these.
|
||||
* pointer comparisons are valid.
|
||||
@@ -64,7 +47,6 @@ struct device {
|
||||
uint32_t flags;
|
||||
uint64_t end;
|
||||
struct dm_list open_list;
|
||||
struct dev_ext ext;
|
||||
|
||||
char pvid[ID_LEN + 1];
|
||||
char _padding[7];
|
||||
@@ -81,20 +63,11 @@ struct device_area {
|
||||
uint64_t size; /* Bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
*/
|
||||
const char *dev_ext_name(struct device *dev);
|
||||
int dev_ext_enable(struct device *dev, dev_ext_t src);
|
||||
int dev_ext_disable(struct device *dev);
|
||||
struct dev_ext *dev_ext_get(struct device *dev);
|
||||
int dev_ext_release(struct device *dev);
|
||||
|
||||
/*
|
||||
* All io should use these routines.
|
||||
*/
|
||||
int dev_get_block_size(struct device *dev, unsigned int *phys_block_size, unsigned int *block_size);
|
||||
int dev_get_size(struct device *dev, uint64_t *size);
|
||||
int dev_get_size(const struct device *dev, uint64_t *size);
|
||||
int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead);
|
||||
int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes);
|
||||
|
||||
|
||||
@@ -385,7 +385,7 @@ int pvdisplay_short(const struct cmd_context *cmd __attribute__((unused)),
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return_0;
|
||||
return 0;
|
||||
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
@@ -399,8 +399,7 @@ int pvdisplay_short(const struct cmd_context *cmd __attribute__((unused)),
|
||||
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
|
||||
|
||||
log_print(" ");
|
||||
|
||||
return 1; /* ECMD_PROCESSED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lvdisplay_colons(const struct logical_volume *lv)
|
||||
@@ -624,7 +623,7 @@ int lvdisplay_full(struct cmd_context *cmd,
|
||||
|
||||
log_print(" ");
|
||||
|
||||
return 1; /* ECMD_PROCESSED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
|
||||
@@ -668,7 +667,7 @@ int lvdisplay_segments(const struct logical_volume *lv)
|
||||
lv_is_virtual(lv) ? "Virtual" : "Logical",
|
||||
seg->le, seg->le + seg->len - 1);
|
||||
|
||||
log_print(" Type\t\t%s", lvseg_name(seg));
|
||||
log_print(" Type\t\t%s", seg->segtype->ops->name(seg));
|
||||
|
||||
if (seg->segtype->ops->target_monitored)
|
||||
log_print(" Monitoring\t\t%s",
|
||||
@@ -696,7 +695,7 @@ void vgdisplay_full(const struct volume_group *vg)
|
||||
|
||||
log_print("--- Volume group ---");
|
||||
log_print("VG Name %s", vg->name);
|
||||
log_print("System ID %s", (vg->system_id && *vg->system_id) ? vg->system_id : vg->lvm1_system_id ? : "");
|
||||
log_print("System ID %s", vg->system_id);
|
||||
log_print("Format %s", vg->fid->fmt->name);
|
||||
if (vg->fid->fmt->features & FMT_MDAS) {
|
||||
log_print("Metadata Areas %d",
|
||||
@@ -856,7 +855,7 @@ void display_name_error(name_error_t name_error)
|
||||
case NAME_INVALID_EMPTY:
|
||||
log_error("Name is zero length.");
|
||||
break;
|
||||
case NAME_INVALID_HYPHEN:
|
||||
case NAME_INVALID_HYPEN:
|
||||
log_error("Name cannot start with hyphen.");
|
||||
break;
|
||||
case NAME_INVALID_DOTS:
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#include "activate.h"
|
||||
#include "str_list.h"
|
||||
|
||||
static const char *_errseg_name(const struct lv_segment *seg)
|
||||
{
|
||||
return seg->segtype->name;
|
||||
}
|
||||
|
||||
static int _errseg_merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
{
|
||||
seg1->len += seg2->len;
|
||||
@@ -78,6 +83,7 @@ static void _errseg_destroy(struct segment_type *segtype)
|
||||
}
|
||||
|
||||
static struct segtype_handler _error_ops = {
|
||||
.name = _errseg_name,
|
||||
.merge_segments = _errseg_merge_segments,
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
.add_target_line = _errseg_add_target_line,
|
||||
@@ -94,8 +100,10 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
if (!segtype)
|
||||
return_NULL;
|
||||
|
||||
segtype->cmd = cmd;
|
||||
segtype->ops = &_error_ops;
|
||||
segtype->name = "error";
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -27,17 +27,6 @@ static int _and_p(struct dev_filter *f, struct device *dev)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _and_p_with_dev_ext_info(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_ext_enable(dev, external_device_info_source());
|
||||
r = _and_p(f, dev);
|
||||
dev_ext_disable(dev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _composite_destroy(struct dev_filter *f)
|
||||
{
|
||||
struct dev_filter **filters;
|
||||
@@ -73,7 +62,7 @@ static void _wipe(struct dev_filter *f)
|
||||
(*filters)->wipe(*filters);
|
||||
}
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters)
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
{
|
||||
struct dev_filter **filters_copy, *cft;
|
||||
|
||||
@@ -94,7 +83,7 @@ struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct d
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cft->passes_filter = use_dev_ext_info ? _and_p_with_dev_ext_info : _and_p;
|
||||
cft->passes_filter = _and_p;
|
||||
cft->destroy = _composite_destroy;
|
||||
cft->dump = _dump;
|
||||
cft->wipe = _wipe;
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 "filter.h"
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)dev->ext.handle, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID) && strstr(value, DEV_EXT_UDEV_BLKID_TYPE_RAID_SUFFIX))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
log_verbose("%s: Firmware RAID detection is not supported by LVM natively. "
|
||||
"Skipping firmware raid detection. ", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dev_is_fwraid(struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_fwraid(dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_fwraid(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for firmware RAID recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ignore_fwraid(struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!fwraid_filtering())
|
||||
return 1;
|
||||
|
||||
ret = _dev_is_fwraid(dev);
|
||||
|
||||
if (ret == 1) {
|
||||
log_debug_devs("%s: Skipping firmware RAID component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
log_debug_devs("%s: Skipping: error in firmware RAID component detection",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
if (f->use_count)
|
||||
log_error(INTERNAL_ERROR "Destroying firmware RAID filter while in use %u times.", f->use_count);
|
||||
|
||||
dm_free(f);
|
||||
}
|
||||
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt __attribute__((unused)))
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dm_zalloc(sizeof(*f)))) {
|
||||
log_error("Firmware RAID filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = _ignore_fwraid;
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = NULL;
|
||||
|
||||
log_debug_devs("Firmware RAID filter initialised.");
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt __attribute__((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -29,8 +29,7 @@ static int _ignore_md(struct dev_filter *f __attribute__((unused)),
|
||||
ret = dev_is_md(dev, NULL);
|
||||
|
||||
if (ret == 1) {
|
||||
log_debug_devs("%s: Skipping md component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
log_debug_devs("%s: Skipping md component device", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
#include "lib.h"
|
||||
#include "filter.h"
|
||||
#include "activate.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
@@ -145,33 +141,7 @@ static int _get_parent_mpath(const char *dir, char *name, int max_size)
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_mpath(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
|
||||
return 1;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
|
||||
if (value && !strcmp(value, "1"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_mpath(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
const char *part_name, *name;
|
||||
@@ -230,25 +200,10 @@ static int _native_dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
return lvm_dm_prefix_check(major, minor, MPATH_PREFIX);
|
||||
}
|
||||
|
||||
static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_mpath(f, dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_mpath(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for mpath recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ignore_mpath(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
if (_dev_is_mpath(f, dev) == 1) {
|
||||
log_debug_devs("%s: Skipping mpath component device [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
log_debug_devs("%s: Skipping mpath component device", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,14 +19,40 @@
|
||||
static int _passes_partitioned_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
const char *name = dev_name(dev);
|
||||
int ret = 0;
|
||||
uint64_t size;
|
||||
|
||||
if (dev_is_partitioned(dt, dev)) {
|
||||
log_debug_devs("%s: Skipping: Partition table signature found [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: Skipping: open failed", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* Check it's not too small */
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed", name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: Too small to hold a PV", name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev_is_partitioned(dt, dev)) {
|
||||
log_debug_devs("%s: Skipping: Partition table signature found",
|
||||
name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _partitioned_filter_destroy(struct dev_filter *f)
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
#include "filter.h"
|
||||
#include "config.h"
|
||||
#include "lvm-file.h"
|
||||
#include "activate.h"
|
||||
|
||||
struct pfilter {
|
||||
char *file;
|
||||
struct dm_hash_table *devices;
|
||||
struct dev_filter *real;
|
||||
struct timespec ctime;
|
||||
time_t ctime;
|
||||
struct dev_types *dt;
|
||||
};
|
||||
|
||||
@@ -106,7 +107,7 @@ int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out
|
||||
}
|
||||
|
||||
if (!stat(pf->file, &info))
|
||||
lvm_stat_ctim(&pf->ctime, &info);
|
||||
pf->ctime = info.st_ctime;
|
||||
else {
|
||||
log_very_verbose("%s: stat failed: %s", pf->file,
|
||||
strerror(errno));
|
||||
@@ -177,7 +178,6 @@ static int _persistent_filter_dump(struct dev_filter *f, int merge_existing)
|
||||
struct pfilter *pf;
|
||||
char *tmp_file;
|
||||
struct stat info, info2;
|
||||
struct timespec ts;
|
||||
struct dm_config_tree *cft = NULL;
|
||||
FILE *fp;
|
||||
int lockfd;
|
||||
@@ -193,7 +193,7 @@ static int _persistent_filter_dump(struct dev_filter *f, int merge_existing)
|
||||
if (!dm_hash_get_num_entries(pf->devices)) {
|
||||
log_very_verbose("Internal persistent device cache empty "
|
||||
"- not writing to %s", pf->file);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_cache_has_scanned()) {
|
||||
log_very_verbose("Device cache incomplete - not writing "
|
||||
@@ -228,8 +228,7 @@ static int _persistent_filter_dump(struct dev_filter *f, int merge_existing)
|
||||
/*
|
||||
* If file contents changed since we loaded it, merge new contents
|
||||
*/
|
||||
lvm_stat_ctim(&ts, &info);
|
||||
if (merge_existing && timespeccmp(&ts, &pf->ctime, !=))
|
||||
if (merge_existing && info.st_ctime != pf->ctime)
|
||||
/* Keep cft open to avoid losing lock */
|
||||
persistent_filter_load(f, &cft);
|
||||
|
||||
@@ -289,6 +288,10 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
log_error("Failed to hash device to filter.");
|
||||
return 0;
|
||||
}
|
||||
if (!device_is_usable(dev)) {
|
||||
log_debug_devs("%s: Skipping unusable device", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
return pf->real->passes_filter(pf->real, dev);
|
||||
}
|
||||
|
||||
@@ -354,7 +357,7 @@ struct dev_filter *persistent_filter_create(struct dev_types *dt,
|
||||
|
||||
/* Only merge cache file before dumping it if it changed externally. */
|
||||
if (!stat(pf->file, &info))
|
||||
lvm_stat_ctim(&pf->ctime, &info);
|
||||
pf->ctime = info.st_ctime;
|
||||
|
||||
f->passes_filter = _lookup_p;
|
||||
f->destroy = _persistent_destroy;
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 "filter.h"
|
||||
#include "activate.h" /* device_is_usable */
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
static const char *_too_small_to_hold_pv_msg = "Too small to hold a PV";
|
||||
|
||||
static int _native_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
uint64_t size;
|
||||
int ret = 0;
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
log_debug_devs("%s: Skipping: open failed [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's not too small */
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_debug_devs("%s: Skipping: dev_get_size failed [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg,
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
const char *size_str;
|
||||
char *endp;
|
||||
uint64_t size;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!(size_str = udev_device_get_sysattr_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_SYSFS_ATTR_SIZE))) {
|
||||
log_debug_devs("%s: Skipping: failed to get size from sysfs [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
size = strtoull(size_str, &endp, 10);
|
||||
if (errno || !endp || *endp) {
|
||||
log_debug_devs("%s: Skipping: failed to parse size from sysfs [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg,
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int _udev_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _check_pv_min_size(struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_check_pv_min_size(dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_check_pv_min_size(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for PV min size check "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _passes_usable_filter(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
filter_mode_t mode = *((filter_mode_t *) f->private);
|
||||
struct dev_usable_check_params ucp = {0};
|
||||
int r;
|
||||
|
||||
/* check if the device is not too small to hold a PV */
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
/* fall through */
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
if (!_check_pv_min_size(dev))
|
||||
return 0;
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
}
|
||||
|
||||
/* further checks are done on dm devices only */
|
||||
if (!dm_is_dm_major(MAJOR(dev->dev)))
|
||||
return 1;
|
||||
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
ucp.check_empty = 1;
|
||||
ucp.check_blocked = 1;
|
||||
ucp.check_suspended = ignore_suspended_devices();
|
||||
ucp.check_error_target = 1;
|
||||
ucp.check_reserved = 1;
|
||||
break;
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
ucp.check_empty = 1;
|
||||
/*
|
||||
* If we're scanning for lvmetad update,
|
||||
* we don't want to hang on blocked/suspended devices.
|
||||
* When the device is unblocked/resumed, surely,
|
||||
* there's going to be a CHANGE event so the device
|
||||
* gets scanned via udev rule anyway after resume.
|
||||
*/
|
||||
ucp.check_blocked = 1;
|
||||
ucp.check_suspended = 1;
|
||||
ucp.check_error_target = 1;
|
||||
ucp.check_reserved = 1;
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
ucp.check_empty = 0;
|
||||
ucp.check_blocked = 1;
|
||||
ucp.check_suspended = ignore_suspended_devices();
|
||||
ucp.check_error_target = 0;
|
||||
ucp.check_reserved = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(r = device_is_usable(dev, ucp)))
|
||||
log_debug_devs("%s: Skipping unusable device", dev_name(dev));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _usable_filter_destroy(struct dev_filter *f)
|
||||
{
|
||||
if (f->use_count)
|
||||
log_error(INTERNAL_ERROR "Destroying usable device filter while in use %u times.", f->use_count);
|
||||
|
||||
dm_free(f->private);
|
||||
dm_free(f);
|
||||
}
|
||||
|
||||
struct dev_filter *usable_filter_create(struct dev_types *dt __attribute__((unused)), filter_mode_t mode)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dm_zalloc(sizeof(struct dev_filter)))) {
|
||||
log_error("Usable device filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = _passes_usable_filter;
|
||||
f->destroy = _usable_filter_destroy;
|
||||
f->use_count = 0;
|
||||
if (!(f->private = dm_zalloc(sizeof(filter_mode_t)))) {
|
||||
log_error("Usable device filter mode allocation failed");
|
||||
dm_free(f);
|
||||
return NULL;
|
||||
}
|
||||
*((filter_mode_t *) f->private) = mode;
|
||||
|
||||
log_debug_devs("Usable device filter initialised.");
|
||||
|
||||
return f;
|
||||
}
|
||||
@@ -20,11 +20,9 @@
|
||||
#include "dev-cache.h"
|
||||
#include "dev-type.h"
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
|
||||
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *md_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *fwraid_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *mpath_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *partitioned_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *persistent_filter_create(struct dev_types *dt,
|
||||
@@ -42,13 +40,6 @@ struct dev_filter *sysfs_filter_create(void);
|
||||
|
||||
struct dev_filter *regex_filter_create(const struct dm_config_value *patterns);
|
||||
|
||||
typedef enum {
|
||||
FILTER_MODE_NO_LVMETAD,
|
||||
FILTER_MODE_PRE_LVMETAD,
|
||||
FILTER_MODE_POST_LVMETAD
|
||||
} filter_mode_t;
|
||||
struct dev_filter *usable_filter_create(struct dev_types *dt, filter_mode_t mode);
|
||||
|
||||
int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out);
|
||||
|
||||
#endif /* _LVM_FILTER_H */
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#define LVM_BLK_MAJOR 58
|
||||
|
||||
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
|
||||
#define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */
|
||||
#define MAX_PE_SIZE (16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L)
|
||||
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
|
||||
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
|
||||
#define MAX_PE_TOTAL ((uint32_t) -2)
|
||||
@@ -245,6 +247,4 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
int export_vg_number(struct format_instance *fid, struct dm_list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter);
|
||||
|
||||
int generate_lvm1_system_id(struct cmd_context *cmd, char *s, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -180,8 +180,6 @@ out:
|
||||
static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda __attribute__((unused)),
|
||||
struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)),
|
||||
unsigned *use_previous_vg __attribute__((unused)),
|
||||
int single_device __attribute__((unused)))
|
||||
{
|
||||
struct volume_group *vg;
|
||||
@@ -495,13 +493,25 @@ static int _format1_vg_setup(struct format_instance *fid, struct volume_group *v
|
||||
if (!vg->max_pv || vg->max_pv >= MAX_PV)
|
||||
vg->max_pv = MAX_PV - 1;
|
||||
|
||||
if (!vg_check_new_extent_size(vg->fid->fmt, vg->extent_size))
|
||||
return_0;
|
||||
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
||||
log_error("Extent size must be between %s and %s",
|
||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE),
|
||||
display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE));
|
||||
|
||||
/* Generate lvm1_system_id if not yet set */
|
||||
if (!*vg->lvm1_system_id &&
|
||||
!generate_lvm1_system_id(vg->cmd, vg->lvm1_system_id, ""))
|
||||
return_0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg->extent_size % MIN_PE_SIZE) {
|
||||
log_error("Extent size must be multiple of %s",
|
||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Redundant? */
|
||||
if (vg->extent_size & (vg->extent_size - 1)) {
|
||||
log_error("Extent size must be power of 2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -597,8 +607,7 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
fmt->alias = NULL;
|
||||
fmt->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME;
|
||||
fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE |
|
||||
FMT_RESTRICTED_READAHEAD | FMT_OBSOLETE |
|
||||
FMT_SYSTEMID_ON_PVS;
|
||||
FMT_RESTRICTED_READAHEAD | FMT_OBSOLETE;
|
||||
fmt->private = NULL;
|
||||
|
||||
dm_list_init(&fmt->mda_ops);
|
||||
|
||||
@@ -69,14 +69,14 @@ int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
|
||||
|
||||
/* Store system_id from first PV if PV belongs to a VG */
|
||||
if (vg && !*vg->lvm1_system_id)
|
||||
strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
if (vg && !*vg->system_id)
|
||||
strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
|
||||
if (vg &&
|
||||
strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
|
||||
strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id)))
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
pv_dev_name(pv), vg->lvm1_system_id);
|
||||
pv_dev_name(pv), vg->system_id);
|
||||
|
||||
/*
|
||||
* If exported, we still need to flag in pv->status too because
|
||||
@@ -125,12 +125,12 @@ int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int generate_lvm1_system_id(struct cmd_context *cmd, char *s, const char *prefix)
|
||||
static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
|
||||
{
|
||||
|
||||
if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
prefix, cmd->hostname, time(NULL)) < 0) {
|
||||
log_error("Generated LVM1 format system_id too long");
|
||||
log_error("Generated system_id too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -156,18 +156,16 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
}
|
||||
|
||||
/* Preserve existing system_id if it exists */
|
||||
if (vg && vg->lvm1_system_id && *vg->lvm1_system_id)
|
||||
strncpy((char *)pvd->system_id, vg->lvm1_system_id, sizeof(pvd->system_id));
|
||||
else if (vg && vg->system_id && *vg->system_id)
|
||||
if (vg && *vg->system_id)
|
||||
strncpy((char *)pvd->system_id, vg->system_id, sizeof(pvd->system_id));
|
||||
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && vg_is_exported(vg)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!*vg->lvm1_system_id ||
|
||||
strncmp(vg->lvm1_system_id, EXPORTED_TAG,
|
||||
if (!*vg->system_id ||
|
||||
strncmp(vg->system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, EXPORTED_TAG))
|
||||
return_0;
|
||||
}
|
||||
if (strlen((char *)pvd->vg_name) + sizeof(EXPORTED_TAG) >
|
||||
@@ -180,22 +178,22 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute__((unused
|
||||
}
|
||||
|
||||
/* Is VG being imported? */
|
||||
if (vg && !vg_is_exported(vg) && vg->lvm1_system_id && *vg->lvm1_system_id &&
|
||||
!strncmp(vg->lvm1_system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG))
|
||||
if (vg && !vg_is_exported(vg) && *vg->system_id &&
|
||||
!strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, IMPORTED_TAG))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* Generate system_id if PV is in VG */
|
||||
if (!pvd->system_id[0])
|
||||
if (!generate_lvm1_system_id(cmd, (char *)pvd->system_id, ""))
|
||||
if (!_system_id(cmd, (char *)pvd->system_id, ""))
|
||||
return_0;
|
||||
|
||||
/* Update internal system_id if we changed it */
|
||||
if (vg && vg->lvm1_system_id &&
|
||||
(!*vg->lvm1_system_id ||
|
||||
strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
if (vg &&
|
||||
(!*vg->system_id ||
|
||||
strncmp(vg->system_id, (char *)pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->system_id, (char *)pvd->system_id, NAME_LEN);
|
||||
|
||||
//pvd->pv_major = MAJOR(pv->dev);
|
||||
|
||||
@@ -227,9 +225,11 @@ int import_vg(struct dm_pool *mem,
|
||||
if (!(vg->name = dm_pool_strdup(mem, (char *)dl->pvd.vg_name)))
|
||||
return_0;
|
||||
|
||||
if (!(vg->lvm1_system_id = dm_pool_zalloc(mem, NAME_LEN + 1)))
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN + 1)))
|
||||
return_0;
|
||||
|
||||
*vg->system_id = '\0';
|
||||
|
||||
if (vgd->vg_status & VG_EXPORTED)
|
||||
vg->status |= EXPORTED_VG;
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
len = _area_length(lvm, le);
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0,
|
||||
NULL, 1, len, 0, 0, 0, NULL))) {
|
||||
NULL, NULL, 1, len, 0, 0, 0, NULL))) {
|
||||
log_error("Failed to allocate linear segment.");
|
||||
return 0;
|
||||
}
|
||||
@@ -298,7 +298,7 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
if (!(seg = alloc_lv_segment(segtype, lvm->lv,
|
||||
lvm->stripes * first_area_le,
|
||||
lvm->stripes * area_len,
|
||||
0, lvm->stripe_size, NULL,
|
||||
0, lvm->stripe_size, NULL, NULL,
|
||||
lvm->stripes,
|
||||
area_len, 0, 0, 0, NULL))) {
|
||||
log_error("Failed to allocate striped segment.");
|
||||
|
||||
@@ -101,8 +101,6 @@ static int _check_usp(const char *vgname, struct user_subpool *usp, int sp_count
|
||||
static struct volume_group *_pool_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda __attribute__((unused)),
|
||||
struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)),
|
||||
unsigned *use_previous_vg __attribute__((unused)),
|
||||
int single_device __attribute__((unused)))
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
@@ -194,7 +194,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
|
||||
area_len * usp->num_devs, 0,
|
||||
usp->striping, NULL, usp->num_devs,
|
||||
usp->striping, NULL, NULL, usp->num_devs,
|
||||
area_len, 0, 0, 0, NULL))) {
|
||||
log_error("Unable to allocate striped lv_segment structure");
|
||||
return 0;
|
||||
@@ -234,7 +234,7 @@ static int _add_linear_seg(struct dm_pool *mem,
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
|
||||
area_len, 0, usp->striping,
|
||||
NULL, 1, area_len,
|
||||
NULL, NULL, 1, area_len,
|
||||
POOL_PE_SIZE, 0, 0, NULL))) {
|
||||
log_error("Unable to allocate linear lv_segment "
|
||||
"structure");
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "lvm-string.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lvmetad.h"
|
||||
#include "memlock.h"
|
||||
#include "toolcontext.h"
|
||||
#include "locking.h"
|
||||
|
||||
@@ -256,9 +255,6 @@ int backup_locally(struct volume_group *vg)
|
||||
|
||||
int backup(struct volume_group *vg)
|
||||
{
|
||||
/* Unlock memory if possible */
|
||||
memlock_unlock(vg->cmd);
|
||||
|
||||
/* Don't back up orphan VGs. */
|
||||
if (is_orphan_vg(vg->name))
|
||||
return 1;
|
||||
@@ -308,7 +304,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
|
||||
if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL, 0)))
|
||||
if (!(vg = mda->ops->vg_read(tf, vg_name, mda, 0)))
|
||||
stack;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "segtype.h"
|
||||
#include "text_export.h"
|
||||
#include "lvm-version.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
@@ -328,7 +327,7 @@ int out_config_node(struct formatter *f, const struct dm_config_node *cn)
|
||||
return dm_config_write_node(cn, _out_line, f);
|
||||
}
|
||||
|
||||
static int _print_header(struct cmd_context *cmd, struct formatter *f,
|
||||
static int _print_header(struct formatter *f,
|
||||
const char *desc)
|
||||
{
|
||||
char *buf;
|
||||
@@ -351,8 +350,6 @@ static int _print_header(struct cmd_context *cmd, struct formatter *f,
|
||||
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||
_utsname.version, _utsname.machine);
|
||||
if (cmd->system_id && *cmd->system_id)
|
||||
outf(f, "creation_host_system_id = \"%s\"", cmd->system_id);
|
||||
outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
|
||||
|
||||
return 1;
|
||||
@@ -393,8 +390,6 @@ static int _out_tags(struct formatter *f, struct dm_list *tagsl)
|
||||
static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
char buffer[4096];
|
||||
const struct format_type *fmt = NULL;
|
||||
uint64_t status = vg->status;
|
||||
|
||||
if (!id_write_format(&vg->id, buffer, sizeof(buffer)))
|
||||
return_0;
|
||||
@@ -403,35 +398,17 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
|
||||
outf(f, "seqno = %u", vg->seqno);
|
||||
|
||||
if (vg->original_fmt)
|
||||
fmt = vg->original_fmt;
|
||||
else if (vg->fid)
|
||||
fmt = vg->fid->fmt;
|
||||
if (fmt)
|
||||
outfc(f, "# informational", "format = \"%s\"", fmt->name);
|
||||
if (vg->fid && vg->fid->fmt)
|
||||
outfc(f, "# informational", "format = \"%s\"", vg->fid->fmt->name);
|
||||
|
||||
/*
|
||||
* Removing WRITE and adding LVM_WRITE_LOCKED makes it read-only
|
||||
* to old versions of lvm that only look for LVM_WRITE.
|
||||
*/
|
||||
if ((status & LVM_WRITE) && vg_flag_write_locked(vg)) {
|
||||
status &= ~LVM_WRITE;
|
||||
status |= LVM_WRITE_LOCKED;
|
||||
}
|
||||
|
||||
if (!_print_flag_config(f, status, VG_FLAGS))
|
||||
if (!_print_flag_config(f, vg->status, VG_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &vg->tags))
|
||||
return_0;
|
||||
|
||||
|
||||
if (vg->system_id && *vg->system_id)
|
||||
outf(f, "system_id = \"%s\"", vg->system_id);
|
||||
else if (vg->lvm1_system_id && *vg->lvm1_system_id)
|
||||
outf(f, "system_id = \"%s\"", vg->lvm1_system_id);
|
||||
|
||||
if (vg->lock_type)
|
||||
outf(f, "lock_type = \"%s\"", vg->lock_type);
|
||||
|
||||
outsize(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
||||
vg->extent_size);
|
||||
@@ -617,7 +594,6 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
int seg_count;
|
||||
struct tm *local_tm;
|
||||
time_t ts;
|
||||
uint64_t status = lv->status;
|
||||
|
||||
outnl(f);
|
||||
outf(f, "%s {", lv->name);
|
||||
@@ -629,16 +605,7 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
/*
|
||||
* Removing WRITE and adding LVM_WRITE_LOCKED makes it read-only
|
||||
* to old versions of lvm that only look for LVM_WRITE.
|
||||
*/
|
||||
if ((status & LVM_WRITE) && vg_flag_write_locked(lv->vg)) {
|
||||
status &= ~LVM_WRITE;
|
||||
status |= LVM_WRITE_LOCKED;
|
||||
}
|
||||
|
||||
if (!_print_flag_config(f, status, LV_FLAGS))
|
||||
if (!_print_flag_config(f, lv->status, LV_FLAGS))
|
||||
return_0;
|
||||
|
||||
if (!_out_tags(f, &lv->tags))
|
||||
@@ -777,7 +744,7 @@ static int _text_vg_export(struct formatter *f,
|
||||
if (!_build_pv_names(f, vg))
|
||||
goto_out;
|
||||
|
||||
if (f->header && !_print_header(vg->cmd, f, desc))
|
||||
if (f->header && !_print_header(f, desc))
|
||||
goto_out;
|
||||
|
||||
if (!out_text(f, "%s {", vg->name))
|
||||
@@ -800,7 +767,7 @@ static int _text_vg_export(struct formatter *f,
|
||||
if (!out_text(f, "}"))
|
||||
goto_out;
|
||||
|
||||
if (!f->header && !_print_header(vg->cmd, f, desc))
|
||||
if (!f->header && !_print_header(f, desc))
|
||||
goto_out;
|
||||
|
||||
r = 1;
|
||||
|
||||
@@ -34,7 +34,6 @@ static const struct flag _vg_flags[] = {
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG},
|
||||
{CLUSTERED, "CLUSTERED", STATUS_FLAG},
|
||||
{SHARED, "SHARED", STATUS_FLAG},
|
||||
{PARTIAL_VG, NULL, 0},
|
||||
@@ -54,7 +53,6 @@ static const struct flag _pv_flags[] = {
|
||||
static const struct flag _lv_flags[] = {
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG},
|
||||
{FIXED_MINOR, "FIXED_MINOR", STATUS_FLAG},
|
||||
{VISIBLE_LV, "VISIBLE", STATUS_FLAG},
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
@@ -63,7 +61,6 @@ static const struct flag _lv_flags[] = {
|
||||
{LV_REBUILD, "REBUILD", STATUS_FLAG},
|
||||
{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
|
||||
{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
|
||||
{LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG},
|
||||
{LV_NOSCAN, NULL, 0},
|
||||
{LV_TEMPORARY, NULL, 0},
|
||||
{POOL_METADATA_SPARE, NULL, 0},
|
||||
@@ -91,8 +88,6 @@ static const struct flag _lv_flags[] = {
|
||||
{CACHE_POOL, NULL, 0},
|
||||
{CACHE_POOL_DATA, NULL, 0},
|
||||
{CACHE_POOL_METADATA, NULL, 0},
|
||||
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
|
||||
{LV_REMOVED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
@@ -72,14 +72,13 @@ void rlocn_set_ignored(struct raw_locn *rlocn, unsigned mda_ignored)
|
||||
* NOTE: Currently there can be only one vg per text file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Only used by vgcreate.
|
||||
*/
|
||||
static int _text_vg_setup(struct format_instance *fid,
|
||||
static int _text_vg_setup(struct format_instance *fid __attribute__((unused)),
|
||||
struct volume_group *vg)
|
||||
{
|
||||
if (!vg_check_new_extent_size(vg->fid->fmt, vg->extent_size))
|
||||
return_0;
|
||||
if (vg->extent_size & (vg->extent_size - 1)) {
|
||||
log_error("Extent size must be power of 2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -412,11 +411,6 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8)));
|
||||
struct raw_locn *rlocn, *rlocn_precommitted;
|
||||
struct lvmcache_info *info;
|
||||
struct lvmcache_vgsummary vgsummary_orphan = {
|
||||
.vgname = FMT_TEXT_ORPHAN_VG_NAME,
|
||||
};
|
||||
|
||||
memcpy(&vgsummary_orphan.vgid, FMT_TEXT_ORPHAN_VG_NAME, sizeof(FMT_TEXT_ORPHAN_VG_NAME));
|
||||
|
||||
rlocn = mdah->raw_locns; /* Slot 0 */
|
||||
rlocn_precommitted = rlocn + 1; /* Slot 1 */
|
||||
@@ -454,7 +448,8 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
|
||||
bad:
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)))
|
||||
lvmcache_update_vgname_and_id(info, &vgsummary_orphan);
|
||||
lvmcache_update_vgname_and_id(info, FMT_TEXT_ORPHAN_VG_NAME,
|
||||
FMT_TEXT_ORPHAN_VG_NAME, 0, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -502,8 +497,6 @@ static int _raw_holds_vgname(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct device_area *area,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int precommitted,
|
||||
int single_device)
|
||||
{
|
||||
@@ -532,26 +525,19 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
}
|
||||
|
||||
/* FIXME 64-bit */
|
||||
if (!(vg = text_vg_import_fd(fid, NULL, vg_fmtdata, use_previous_vg, single_device, area->dev,
|
||||
if (!(vg = text_vg_import_fd(fid, NULL, single_device, area->dev,
|
||||
(off_t) (area->start + rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (area->start + MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, rlocn->checksum, &when,
|
||||
&desc)) && (!use_previous_vg || !*use_previous_vg))
|
||||
&desc)))
|
||||
goto_out;
|
||||
log_debug_metadata("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
|
||||
PRIu64, vg->name, precommitted ? "pre-commit " : "",
|
||||
vg->seqno, dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
|
||||
if (vg)
|
||||
log_debug_metadata("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
|
||||
PRIu64, vg->name, precommitted ? "pre-commit " : "",
|
||||
vg->seqno, dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
else
|
||||
log_debug_metadata("Skipped reading %smetadata from %s at %" PRIu64 " size %"
|
||||
PRIu64 " with matching checksum.", precommitted ? "pre-commit " : "",
|
||||
dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
|
||||
if (vg && precommitted)
|
||||
if (precommitted)
|
||||
vg->status |= PRECOMMITTED;
|
||||
|
||||
out:
|
||||
@@ -561,8 +547,6 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int single_device)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
@@ -571,7 +555,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
if (!dev_open_readonly(mdac->area.dev))
|
||||
return_NULL;
|
||||
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, single_device);
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, 0, single_device);
|
||||
|
||||
if (!dev_close(mdac->area.dev))
|
||||
stack;
|
||||
@@ -581,9 +565,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg)
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct volume_group *vg;
|
||||
@@ -591,7 +573,7 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
if (!dev_open_readonly(mdac->area.dev))
|
||||
return_NULL;
|
||||
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, 0);
|
||||
vg = _vg_read_raw_area(fid, vgname, &mdac->area, 1, 0);
|
||||
|
||||
if (!dev_close(mdac->area.dev))
|
||||
stack;
|
||||
@@ -902,8 +884,6 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg __attribute__((unused)),
|
||||
int single_device __attribute__((unused)))
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mda->metadata_locn;
|
||||
@@ -913,9 +893,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg __attribute__((unused)))
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mda->metadata_locn;
|
||||
struct volume_group *vg;
|
||||
@@ -1144,24 +1122,26 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vgname_from_mda(const struct format_type *fmt,
|
||||
struct mda_header *mdah, struct device_area *dev_area,
|
||||
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
|
||||
const char *vgname_from_mda(const struct format_type *fmt,
|
||||
struct mda_header *mdah,
|
||||
struct device_area *dev_area, struct id *vgid,
|
||||
uint64_t *vgstatus, char **creation_host,
|
||||
uint64_t *mda_free_sectors)
|
||||
{
|
||||
struct raw_locn *rlocn;
|
||||
uint32_t wrap = 0;
|
||||
const char *vgname = NULL;
|
||||
unsigned int len = 0;
|
||||
char buf[NAME_LEN + 1] __attribute__((aligned(8)));
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
uint64_t buffer_size, current_usage;
|
||||
unsigned used_cached_metadata = 0;
|
||||
|
||||
if (mda_free_sectors)
|
||||
*mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
|
||||
|
||||
if (!mdah) {
|
||||
log_error(INTERNAL_ERROR "vgname_from_mda called with NULL pointer for mda_header");
|
||||
return 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
/* FIXME Cope with returning a list */
|
||||
@@ -1170,16 +1150,13 @@ int vgname_from_mda(const struct format_type *fmt,
|
||||
/*
|
||||
* If no valid offset, do not try to search for vgname
|
||||
*/
|
||||
if (!rlocn->offset) {
|
||||
log_debug("%s: found metadata with offset 0.",
|
||||
dev_name(dev_area->dev));
|
||||
return 0;
|
||||
}
|
||||
if (!rlocn->offset)
|
||||
goto out;
|
||||
|
||||
/* Do quick check for a vgname */
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
NAME_LEN, buf))
|
||||
return_0;
|
||||
goto_out;
|
||||
|
||||
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
|
||||
len < (NAME_LEN - 1))
|
||||
@@ -1189,7 +1166,7 @@ int vgname_from_mda(const struct format_type *fmt,
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(buf))
|
||||
return_0;
|
||||
goto_out;
|
||||
|
||||
/* We found a VG - now check the metadata */
|
||||
if (rlocn->offset + rlocn->size > mdah->size)
|
||||
@@ -1198,39 +1175,36 @@ int vgname_from_mda(const struct format_type *fmt,
|
||||
if (wrap > rlocn->offset) {
|
||||
log_error("%s: metadata too large for circular buffer",
|
||||
dev_name(dev_area->dev));
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Did we see this metadata before? */
|
||||
vgsummary->mda_checksum = rlocn->checksum;
|
||||
vgsummary->mda_size = rlocn->size;
|
||||
|
||||
if (lvmcache_lookup_mda(vgsummary))
|
||||
used_cached_metadata = 1;
|
||||
|
||||
/* FIXME 64-bit */
|
||||
if (!text_vgname_import(fmt, dev_area->dev,
|
||||
(off_t) (dev_area->start + rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (dev_area->start + MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, vgsummary->vgname ? 1 : 0,
|
||||
vgsummary))
|
||||
return_0;
|
||||
if (!(vgname = text_vgname_import(fmt, dev_area->dev,
|
||||
(off_t) (dev_area->start +
|
||||
rlocn->offset),
|
||||
(uint32_t) (rlocn->size - wrap),
|
||||
(off_t) (dev_area->start +
|
||||
MDA_HEADER_SIZE),
|
||||
wrap, calc_crc, rlocn->checksum,
|
||||
vgid, vgstatus, creation_host)))
|
||||
goto_out;
|
||||
|
||||
/* Ignore this entry if the characters aren't permissible */
|
||||
if (!validate_name(vgsummary->vgname))
|
||||
return_0;
|
||||
if (!validate_name(vgname)) {
|
||||
vgname = NULL;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!id_write_format((struct id *)&vgsummary->vgid, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
if (!id_write_format(vgid, uuid, sizeof(uuid))) {
|
||||
vgname = NULL;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_debug_metadata("%s: %s metadata at %" PRIu64 " size %" PRIu64
|
||||
log_debug_metadata("%s: Found metadata at %" PRIu64 " size %" PRIu64
|
||||
" (in area at %" PRIu64 " size %" PRIu64
|
||||
") for %s (%s)",
|
||||
dev_name(dev_area->dev),
|
||||
used_cached_metadata ? "Using cached" : "Found",
|
||||
dev_area->start + rlocn->offset,
|
||||
rlocn->size, dev_area->start, dev_area->size, vgsummary->vgname, uuid);
|
||||
dev_name(dev_area->dev), dev_area->start + rlocn->offset,
|
||||
rlocn->size, dev_area->start, dev_area->size, vgname, uuid);
|
||||
|
||||
if (mda_free_sectors) {
|
||||
current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
|
||||
@@ -1243,16 +1217,19 @@ int vgname_from_mda(const struct format_type *fmt,
|
||||
*mda_free_sectors = ((buffer_size - 2 * current_usage) / 2) >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
out:
|
||||
return vgname;
|
||||
}
|
||||
|
||||
static int _scan_raw(const struct format_type *fmt, const char *vgname __attribute__((unused)))
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct dm_list *raw_list;
|
||||
const char *scanned_vgname;
|
||||
struct volume_group *vg;
|
||||
struct format_instance fid;
|
||||
struct lvmcache_vgsummary vgsummary = { 0 };
|
||||
struct id vgid;
|
||||
uint64_t vgstatus;
|
||||
struct mda_header *mdah;
|
||||
|
||||
raw_list = &((struct mda_lists *) fmt->private)->raws;
|
||||
@@ -1273,11 +1250,13 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
|
||||
goto close_dev;
|
||||
}
|
||||
|
||||
/* TODO: caching as in vgname_from_mda() (trigger this code?) */
|
||||
if (vgname_from_mda(fmt, mdah, &rl->dev_area, &vgsummary, NULL)) {
|
||||
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0);
|
||||
if ((scanned_vgname = vgname_from_mda(fmt, mdah,
|
||||
&rl->dev_area, &vgid, &vgstatus,
|
||||
NULL, NULL))) {
|
||||
vg = _vg_read_raw_area(&fid, scanned_vgname, &rl->dev_area, 0, 0);
|
||||
if (vg)
|
||||
lvmcache_update_vg(vg, 0);
|
||||
|
||||
}
|
||||
close_dev:
|
||||
if (!dev_close(rl->dev_area.dev))
|
||||
@@ -1318,7 +1297,7 @@ static int _write_single_mda(struct metadata_area *mda, void *baton)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Only for orphans - FIXME That's not true any more */
|
||||
/* Only for orphans */
|
||||
static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv)
|
||||
{
|
||||
struct format_instance *fid = pv->fid;
|
||||
@@ -1332,8 +1311,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
|
||||
/* Add a new cache entry with PV info or update existing one. */
|
||||
if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id,
|
||||
pv->dev, pv->vg_name,
|
||||
is_orphan_vg(pv->vg_name) ? pv->vg_name : pv->vg ? (const char *) &pv->vg->id : NULL, 0)))
|
||||
pv->dev, pv->vg_name, NULL, 0)))
|
||||
return_0;
|
||||
|
||||
label = lvmcache_get_label(info);
|
||||
@@ -1603,9 +1581,9 @@ static int _text_pv_initialise(const struct format_type *fmt,
|
||||
if (rp->extent_count)
|
||||
pv->pe_count = rp->extent_count;
|
||||
|
||||
if ((pv->pe_start + pv->pe_count * (uint64_t)pv->pe_size - 1) > pv->size) {
|
||||
if ((pv->pe_start + pv->pe_count * pv->pe_size - 1) > (pv->size << SECTOR_SHIFT)) {
|
||||
log_error("Physical extents end beyond end of device %s.",
|
||||
pv_dev_name(pv));
|
||||
pv_dev_name(pv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2172,7 +2150,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
* LABEL_SCAN_SIZE.
|
||||
*/
|
||||
pe_end = pv->pe_count ? (pv->pe_start +
|
||||
pv->pe_count * (uint64_t)pv->pe_size - 1) << SECTOR_SHIFT
|
||||
pv->pe_count * pv->pe_size - 1) << SECTOR_SHIFT
|
||||
: 0;
|
||||
|
||||
if (pe_start || pe_start_locked) {
|
||||
@@ -2462,8 +2440,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
fmt->orphan_vg_name = ORPHAN_VG_NAME(FMT_TEXT_NAME);
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
|
||||
FMT_UNLIMITED_VOLS | FMT_RESIZE_PV |
|
||||
FMT_UNLIMITED_STRIPESIZE | FMT_BAS | FMT_CONFIG_PROFILE |
|
||||
FMT_NON_POWER2_EXTENTS;
|
||||
FMT_UNLIMITED_STRIPESIZE | FMT_BAS | FMT_CONFIG_PROFILE;
|
||||
|
||||
if (!(mda_lists = dm_malloc(sizeof(struct mda_lists)))) {
|
||||
log_error("Failed to allocate dir_list");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user