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

Compare commits

..

1 Commits

Author SHA1 Message Date
Marian Csontos
05716c2d8a clvmd: Fix stack overflow on 64 bit ARM
Seems the amount of allocated data on stack is dependent on page size.
As the page size on aarch64 is 64kiB writing to memory allocated by
alloca results in stack overflow as at the time of allocation the are
already 2 pages allocated. Clearly 128kiB is not sufficient and at least
3 pages are needed.
2014-09-16 17:34:32 +02:00
524 changed files with 11974 additions and 36169 deletions

View File

@@ -1,6 +1,6 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -15,8 +15,6 @@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
SUBDIRS = conf daemons include lib libdaemon libdm man scripts tools
@@ -93,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
View File

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

View File

@@ -1 +1 @@
2.02.123(2)-git (2015-06-20)
2.02.112(2)-git (2014-09-01)

View File

@@ -1 +1 @@
1.02.100-git (2015-06-20)
1.02.91-git (2014-09-01)

304
WHATS_NEW
View File

@@ -1,297 +1,6 @@
Version 2.02.123 -
=================================
Version 2.02.122 - 20th June 2015
=================================
Flush stdout before printing to stderr.
Use pre-allocated buffer for printed LV names in display_lvname.
Support thins with size of external origin unaligned with thin pool chunk.
Allow extension of reduced thin volumes with external origins.
Consider snapshot and origin LV as unusable if component devices suspended.
Fix lvmconfig segfault on settings with undefined default value (2.02.120).
Add explicit 's' (shared) LV activation mode.
Ignore hyphens in long options names (i.e. --long-option == --longoption).
Version 2.02.121 - 12th June 2015
=================================
Distinguish between on-disk and lvmetad versions of text metadata.
Remove DL_LIBS from Makefiles for daemons that don't need them.
Zero errno in before strtoul call in dmsetup if tested after the call.
Zero errno in before strtoul call in lvmpolld.
Fix a segfault in pvscan --cache --background command.
Fix test for AREA_PV when checking for failed mirrors.
Do not use --sysinit in lvm2-activation{-early,-net}.service if lvmpolld used.
Maintain outdated PV info in lvmetad till all old metadata is gone from disk.
Do not fail polling when poll LV not found (already finished or removed).
Replace poll_get_copy_vg/lv fns with vg_read() and find_lv() in polldaemon.
Close all device fds only in before sleep call in polldaemon.
Simplify Makefile targets that generate exported symbols.
Move various -D settings from Makefiles to configure.h.
Version 2.02.120 - 15th May 2015
================================
Make various adjustments to Makefile compilation flags.
Add lvmpolld debug message class.
Add lvmpolld client mode for querying running server instance for status info.
Fix some libdaemon socket creation and reuse error paths.
Daemons (libdaemon) support exit on idle also in non-systemd environment.
Provide make dist and make rpm targets
Configure lvm.conf for use_lvmetad and use_lvmpolld.
Add lvpoll for cmdline communication with lvmpolld.
Add lvmpolld acting as a free-standing version of polldaemon.
Avoid repeated identical lvmetad VG lookups in commands processing all VGs.
Handle switches to alternative duplicate PVs efficiently with lvmetad.
Properly validate PV size for pvcreate --restorefile.
Fix check if pvcreate wiped device (2.02.117).
Fix storing of vgid when caching metadata (2.02.118).
Fix recursive lvm-config man page. (2.02.119)
Refactor polldaemon interfaces to poll every operation by VG/LV couple
Skip wait after testing in _wait_for_single_lv when polling finished
Return 'None' in python for empty string properties instead of crashing.
Distinguish signed numerical property type in reports for lvm2app library.
Reread raid completion status immediately when progress appears to be zero.
lvm2app closes locking on lvm_quit().
Configure detects /run or /var/run.
Add missing newline in clvmd --help output.
Version 2.02.119 - 2nd May 2015
===============================
New LVM_LOG_FILE_EPOCH, LVM_EXPECTED_EXIT_STATUS env vars. Man page to follow.
Remove detailed content from lvm.conf man page: use lvmconfig instead.
Generate complete config files with lvmconfig or 'make generate'.
Also display info on deprecated config with lvmconfig --withcomments.
Display version since which config is deprecated in lvmconfig --withversions.
Add --showdeprecated to lvmconfig to also display deprecated settings.
Hide deprecated settings in lvmconfig output for all types but current,diff.
Introduce support for exit on idle feature in libdaemon
Add --showunsupported to lvmconfig to also display unsupported settings.
Display unsupported settings for lvmconfig --type current,diff only by default
Honour lvmconfig --ignoreunsupported and --ignoreadvanced for all --type.
Make python bindings usable with python3 (and compatible with 2.6 & 2.7).
Add lvmconfig -l|--list as shortcut for lvmconfig --type list --withsummary.
Add lvmconfig --type list to display plain list of configuration settings.
Introduce lvmconfig as the preferred form of 'lvm dumpconfig'.
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.
@@ -299,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.

View File

@@ -1,62 +1,5 @@
Version 1.02.100 -
================================
Version 1.02.99 - 20th June 2015
================================
New dm_tree_node_set_thin_pool_read_only(DM_1_02_99) for read-only thin pool.
Enhance error message when thin-pool message fails.
Fix dmeventd logging to avoid threaded use of static variable.
Remove redundant dmeventd SIGALRM coded.
Version 1.02.98 - 12th June 2015
================================
Add dm_task_get_errno() to return any unexpected errno from a dm ioctl call.
Use copy of errno made after each dm ioctl call in case errno changes later.
Version 1.02.97 - 15th May 2015
===============================
New dm_task_get_info(DM_1_02_97) supports internal_suspend state.
New symbols are versioned and comes with versioned symbol name (DM_1_02_97).
Version 1.02.96 - 2nd May 2015
==============================
Fix selection to not match if using reserved value in criteria with >,<,>=,<.
Fix selection to not match reserved values for size fields if using >,<,>=,<.
Include uuid or device number in log message after ioctl failure.
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

View File

@@ -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
View File

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

View File

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

View File

@@ -18,7 +18,6 @@ global {
lvdisplay_shows_full_device_path=0
}
report {
compact_output=0
aligned=1
buffered=1
headings=1

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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=[]
}

View File

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

882
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
###############################################################################
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
## Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
## Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
##
## This copyrighted material is made available to anyone wishing to use,
## modify, copy, or redistribute it subject to the terms and conditions
@@ -26,9 +26,10 @@ AC_CONFIG_AUX_DIR(autoconf)
dnl -- Get system type
AC_CANONICAL_TARGET([])
AS_IF([test -z "$CFLAGS"], [COPTIMISE_FLAG="-O2"])
case "$host_os" in
linux*)
CFLAGS="$CFLAGS"
COPTIMISE_FLAG="-O2"
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
ELDFLAGS="-Wl,--export-dynamic"
# FIXME Generate list and use --dynamic-list=.dlopen.sym
@@ -38,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])

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld
.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

View File

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

View File

@@ -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);

View File

@@ -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] = ' ';

View File

@@ -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);

View File

@@ -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) {

View File

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

View File

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

View File

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

View File

@@ -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)", "")

View File

@@ -26,6 +26,9 @@
#include <stdint.h>
#include <unistd.h>
#include <math.h> /* fabs() */
#include <float.h> /* DBL_EPSILON */
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
typedef struct {
@@ -37,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 {
@@ -58,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);
}
@@ -80,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);
}
@@ -423,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;
@@ -558,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:
@@ -566,13 +496,65 @@ bad:
return reply_fail("out of memory");
}
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
/* Test if the doubles are close enough to be considered equal */
static int close_enough(double d1, double d2)
{
return fabs(d1 - d2) < DBL_EPSILON;
}
enum update_pvid_mode { UPDATE_ONLY, REMOVE_EMPTY, MARK_OUTDATED };
static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
{
int r = 0;
if (a->type > b->type)
return 1;
if (a->type < b->type)
return -1;
switch (a->type) {
case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
case DM_CFG_EMPTY_ARRAY: return 0;
}
if (r == 0 && a->next && b->next)
r = compare_value(a->next, b->next);
return r;
}
static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
{
int result = 0;
if (a->v && b->v)
result = compare_value(a->v, b->v);
if (a->v && !b->v)
result = 1;
if (!a->v && b->v)
result = -1;
if (a->child && b->child)
result = compare_config(a->child, b->child);
if (result) {
// DEBUGLOG("config inequality at %s / %s", a->key, b->key);
return result;
}
if (a->sib && b->sib)
result = compare_config(a->sib, b->sib);
if (a->sib && !b->sib)
result = 1;
if (!a->sib && b->sib)
result = -1;
return result;
}
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
/* You need to be holding the pvid_to_vgid lock already to call this. */
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
const char *vgid, int mode)
const char *vgid, int nuke_empty)
{
struct dm_config_node *pv;
struct dm_hash_table *to_check;
@@ -592,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;
@@ -623,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) {
@@ -641,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;
}
@@ -693,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;
@@ -742,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;
@@ -768,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);
}
@@ -804,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);
@@ -858,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");
@@ -882,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)
@@ -918,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;
@@ -934,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);
@@ -944,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);
}
@@ -953,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)
@@ -1026,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 {
@@ -1074,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");
@@ -1104,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);
@@ -1152,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)
@@ -1185,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);
@@ -1247,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);

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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.)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);

View File

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

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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 */

View File

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

View File

@@ -30,7 +30,6 @@
#include "lvmcache.h"
#include "lvmetad.h"
#include "archiver.h"
#include "lvmpolld-client.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
@@ -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();

View File

@@ -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 */
@@ -146,8 +126,6 @@ struct cmd_context {
char system_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
char display_buffer[NAME_LEN * 10]; /* Ring buffer for upto 10 longest vg/lv names */
unsigned display_lvname_idx; /* Index to ring buffer */
};
/*
@@ -167,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

View File

@@ -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);

View File

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

View File

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

View File

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

View File

@@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);

View File

@@ -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);

View File

@@ -95,23 +95,8 @@ const char *get_percent_string(percent_type_t def)
const char *display_lvname(const struct logical_volume *lv)
{
char *name;
int r;
if ((lv->vg->cmd->display_lvname_idx + NAME_LEN) >= sizeof((lv->vg->cmd->display_buffer)))
lv->vg->cmd->display_lvname_idx = 0;
name = lv->vg->cmd->display_buffer + lv->vg->cmd->display_lvname_idx;
r = dm_snprintf(name, NAME_LEN, "%s/%s", lv->vg->name, lv->name);
if (r < 0) {
log_error("Full LV name \"%s/%s\" is too long.", lv->vg->name, lv->name);
return NULL;
}
lv->vg->cmd->display_lvname_idx += r;
return name;
/* On allocation failure, just return the LV name. */
return lv_fullname_dup(lv->vg->cmd->mem, lv) ? : lv->name;
}
#define BASE_UNKNOWN 0
@@ -400,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;
@@ -414,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)
@@ -639,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)
@@ -683,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",
@@ -711,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",
@@ -871,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:

View File

@@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 */

View File

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

View File

@@ -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);

View File

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

View File

@@ -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.");

View File

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

View File

@@ -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");

View File

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

View File

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

View File

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

View File

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